changeset 3977:172d31051316

dummy merge for repo head
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:15:52 +0200
parents b7b8e625ec82 (diff) ecab7e7804a9 (current diff)
children 3aec5a42696a
files flys-client/.classpath flys-client/.project flys-client/FLYS.launch flys-client/FLYSTest-dev.launch flys-client/FLYSTest-prod.launch flys-client/src/main/java/de/intevation/flys/client/server/BaseServlet.java flys-client/src/main/webapp/images/addWMS.png flys-client/src/main/webapp/images/getFeatureInfo.png flys-client/src/main/webapp/images/getFeatureInfo_Selected.png flys-client/src/main/webapp/images/measureLine.png flys-client/src/main/webapp/images/measureLine_Selected.png flys-client/src/main/webapp/images/measurePolygon.png flys-client/src/main/webapp/images/measurePolygon_Selected.png flys-client/src/main/webapp/images/theme_bottom.png flys-client/src/main/webapp/images/theme_down.png flys-client/src/main/webapp/images/theme_top.png flys-client/src/main/webapp/images/theme_up.png flys-client/src/main/webapp/images/zoom-1.png flys-client/src/main/webapp/images/zoom-back.png flys-client/src/main/webapp/images/zoom-in.png flys-client/src/main/webapp/images/zoom-in_Selected.png flys-client/src/main/webapp/images/zoom-out.png
diffstat 1101 files changed, 132460 insertions(+), 10958 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/ChangeLog	Fri Sep 28 12:15:52 2012 +0200
@@ -1,10 +1,11105 @@
+2012-09-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java:
+	  Also add the artifact name to the artifact description.
+
+2012-09-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* doc/conf/conf.xml,
+	  src/main/java/de/intevation/flys/artifacts/GaugeDischargeCurveArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/AbstractStaticStateArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeCurveFacet.java:
+	  Implement new Artifacts and State for displaying discharge curves at a
+	  gauge.
+
+2012-09-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/StaticState.java:
+	  Make addOuput public. Allow StaticArtifacts to add static outputs to the
+	  state.
+
+2012-09-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  Add protected method addFacets to allow child classes to add facets
+	  without accessing the member variable.
+
+2012-09-28  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/meta-data.xml: Added 'info' column to the dem section of the
+	  datacage.
+
+2012-09-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Work on issue724 (i18n in minfo).
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  i18n strings.
+
+2012-09-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java:
+	  Whitespace-cosmetics.
+
+	* src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java:
+	  Doc.
+
+2012-09-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Work on issue724 (i18n in minfo).
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  i18n strings.
+
+	* src/main/java/de/intevation/flys/exports/MiddleBedHeightGenerator.java:
+	  Fix typo.
+
+2012-09-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Removed invalid entries of the SQL projection.
+
+2012-09-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java,
+	  Added more data fields from SedDB to calculate the fraction parts.
+
+	  src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java:
+	  Have now previous and next Measurement attached.
+
+2012-09-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix part of issue871 (selected flow-veloc- parameter shown wrong).
+
+	* src/main/java/de/intevation/flys/artifacts/states/DischargeState.java:
+	  Fix conditional.
+
+2012-09-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue863 (gaps in middle height bed data).
+
+	* src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java:
+	  Handle missing data.
+
+2012-09-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/wsplgen/FacetCreator.java: Set
+	  missing 'originalExtent' attribute of the WSPLGEN layer.
+
+2012-09-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Towards fix issue863 (gaps in middle height bed data).
+
+	* src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightData.java
+	  (addAll): Do not expose single add*-Methods, instead always add a full
+	  set of data.
+	  Added new isEmpty-data and query it before exporting data as
+	  double[][] to e.g. ChartGenerator.
+	  
+	* src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java:
+	  Do not use single add()*-Methods, instead call new addAll method.
+	  Find out whether a gap-value is present.
+	  
+	* src/main/java/de/intevation/flys/exports/MiddleBedHeightGenerator.java:
+	  Prevent skipping of NaNs (gaps).
+
+2012-09-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/map/WMSLayerFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java:
+	  Removed trailing whitespace.
+
+2012-09-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurements.java
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java:
+	  Add more symbols.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Adjust symbols.
+
+2012-09-26	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	Change createOutputModes method to be private. It is not used in a child
+	class.
+
+2012-09-26	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java:
+	  Mark FLYSArtifact data member as private and add setter method.
+
+2012-09-26	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml:
+	  Enable line labels for Delta W/t sector average lines (#896).
+
+2012-09-26  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/mapserver/db_layer.vm: Set initial projection of the database
+	  to "epsg:31467".
+
+	* doc/conf/mapserver/mapfile.vm: Set initial projection of the database to
+	  "epsg:31467". Set the max extent to the extent of the river Saar.
+
+	    TODO: Set the max extent to the extent of germany!
+
+	* src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryPolyArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSGaugeLocationArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/MapArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java:
+	  Added a parameter "reproject" to the getExtent() method. If reproject is
+	  set, the method should return the extent of the layer in the projection
+	  that is specified for the relevant river in the configuration.
+	  Otherwise, this method should return the extent in the projection that
+	  is used by the database.
+
+	* src/main/java/de/intevation/flys/artifacts/model/map/WMSLayerFacet.java:
+	  Added new attributes and methods for the original extent of a layer. The
+	  original extent is used in the XML document that is generated by
+	  toXML().
+
+	* src/main/java/de/intevation/flys/exports/MapGenerator.java: Use the
+	  getOriginalExtent() method of WMSLayerFacet to determine the max extent
+	  for the map (maps should be in the river projection specified in the
+	  configuration).
+
+2012-09-26	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml,
+	  doc/conf/artifacts/manualpoints.xml,
+	  doc/conf/themes.xml,
+	  src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java,
+	  src/main/java/de/intevation/flys/artifacts/FixationArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java:
+	  Rename fix_derivate facet to enable manual points in the derived curve chart.
+
+2012-09-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/manualpoints.xml: Re-enable manualpoints
+	  compatibility.
+
+2012-09-24	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java:
+	  Fix for #825 ?
+
+2012-09-24  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverview.java:
+	  Fixed SQL statement. Exclude data where km is null.
+
+2012-09-24	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java:
+	  Fixing analysis longitudinal section chart has now initially
+	  deactivated A1/B facets. W/Q and W(t) has activated facets. (#874)
+
+2012-09-24	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java:
+	  Remove info-url from gauge and river in the response and add official
+	  number to the river.
+
+2012-09-23	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/default-themes.xml,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  W(Q) chart: q sectors are now black and labeled by default (#875).
+
+2012-09-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeInfoService.java:
+	  Cosmetics.
+
+2012-09-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
+	  Removed trailing whitespace.
+
+2012-09-23	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Themes and i18n of Delta W/t's A1/B facets (#876).
+
+2012-09-23	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml,
+	  doc/conf/themes.xml,
+	  doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml,
+	  src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Add reference period facet to delta W/t chart (#877).
+
+2012-09-22	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Longitudinal section chart does now respect the bounds of the drawn
+	  areas, so that no clipping occurs (#878).
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  i18n corrections.
+
+2012-09-22	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java:
+	  Cosmetics, doc.
+
+2012-09-22	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Prevent ArrayIndexOutOfBounds.
+
+2012-09-22	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Document issue880 (extrapolation of wkms).
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
+	  Do not extrapolate, mention further issues with the code.
+
+2012-09-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffYearResult.java,
+	  src/main/java/de/intevation/flys/artifacts/states/minfo/DifferencesState.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedDifferenceEpochGenerator.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedDifferenceYearGenerator.java:
+	  Removed trailing whitespace.
+
+2012-09-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* 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 for bedheight difference charts.
+
+2012-09-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/themes.xml,
+	  doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml:
+	  Added themes for bedheight difference charts.
+
+2012-09-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/meta-data.xml:
+	  Add river annotations to bedheight difference charts.
+
+2012-09-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/minfo/BedDiffHeightYearInfoGenerator.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedDiffHeightYearGenerator.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedDiffEpochInfoGenerator.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedDiffYearInfoGenerator.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedDifferenceEpochGenerator.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedDifferenceYearGenerator.java:
+	  New. Chart generators for bedheight diff calculation charts.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/DifferencesState.java:
+	  Add facets to generate outputs.
+
+	* src/main/java/de/intevation/flys/artifacts/access/BedDifferencesAccess.java:
+	  Extract calculation relevant data.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedDifferencesResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffYearResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffEpochResult.java:
+	  Updated result set data fields.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffCalculation.java:
+	  Updated the bedheight difference calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added new facet types.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffEpochFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffYearFacet.java:
+	  New facets for bedheight differences.
+
+	* doc/conf/conf.xml:
+	  Added ouput generators.
+
+	* doc/conf/artifacts/minfo.xml:
+	  Added facets to outputmodes.
+
+2012-09-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeight.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightSingle.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightEpoch.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFactory.java:
+	  Updated data fields to fit the needs of bedheight difference calculation.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java:
+	  Return also the gauge official number in a service response.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java:
+	  Use Gauge and River fetchInfoURL instead of getInfoURL until the URLs are
+	  fetched from the db.
+
+2012-09-21	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue887 (HYKs in New Chart).
+
+	* src/main/java/de/intevation/flys/artifacts/HYKArtifact.java:
+	  Lower the Casting requirement to FLYSArtifact instead of
+	  WINFOArtifact.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java:
+	  Return also the gauge and river info-url in a service response.
+
+2012-09-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue886 (do not show waterline if out of range).
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Do not extrapolate waterlines.
+
+2012-09-21	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Better Partial issue880 (diverse DC).
+
+	* doc/conf/meta-data.xml: Remove double entry for annotations in
+	  longitudinal section case but keep recommending it.
+
+2012-09-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial issue880 (diverse DC).
+
+	* doc/conf/meta-data.xml: Remove double entry for annotations in
+	  longitudinal section case.
+
+2012-09-20	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml,
+	  src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java,
+	  src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java:
+	  Theme area transparency fixed for longitudinal section chart (#879).
+
+2012-09-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Improvements for manual points in fixation diags.
+
+	* doc/conf/artifacts/fixanalysis.xml: Add LS-manual points.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Add missing ChartTypes.
+
+2012-09-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffCalculation.java:
+	  New. Calcuation for bed height differences.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedDifferencesResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffEpochResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffYearResult.java:
+	  New. Bed height calculation results.
+
+	* src/main/java/de/intevation/flys/artifacts/access/BedDifferencesAccess.java:
+	  New. Access object to get bed height difference parameters from artifact.
+
+2012-09-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFactory.java:
+	  Create separate objects for bed height epochs and single bed heights.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeight.java:
+	  Added morph. width.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightEpoch.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightSingle.java:
+	  New. Separate classes for bed height epochs and single bed heights.
+
+2012-09-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/minfo/BedQualityExporter.java:
+	  Add dates to csv header.
+
+2012-09-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* 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 string for bed quality CSV export.
+
+2012-09-20	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml,
+	  doc/conf/artifacts/manualpoints.xml,
+	  src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java,
+	  src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java:
+	  Work on manual points in fix analysis charts (not yet working).
+
+2012-09-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/minfo/BedQualityExporter.java:
+	  Removed superfluous imports.
+
+2012-09-19  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/minfo/BedQualityExporter.java:
+	  New. CSV exporter for bed quality calculation result.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedParametersResult.java:
+	  Added getter with km as parameter.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java:
+	  Added facet for csv export.
+
+	* doc/conf/artifacts/minfo.xml:
+	  Added output mode.
+
+	* doc/conf/conf.xml:
+	  Added export generator.
+
+2012-09-19	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java:
+	  Return also the station in a service response.
+
+2012-09-18	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java:
+	  Cosmetics.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java:
+	  A and B facets of fix analysis are now deactivated by default (#717).
+
+2012-09-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/extreme/ExtremeCalculation.java:
+	  Extract parameters needed for calculation from access.
+
+	* src/main/java/de/intevation/flys/utils/DoubleUtil.java(isValid):
+	  Added method to check if 2d double array is valid.
+
+2012-09-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java,
+	  src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Use generics aware Collections.emptyList().
+
+2012-09-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java,
+	  src/main/java/de/intevation/flys/exports/OutputHelper.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/themes/ThemeFactory.java,
+	  src/main/java/de/intevation/flys/themes/ThemeMapping.java,
+	  src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java:
+	  The usual whitespace and import cleanups.
+
+2012-09-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java:
+	  Avoid loading empty data sets.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java:
+	  Load bedload data sets...
+
+2012-09-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/CharDiameter.java:
+	  Removed incorrect characteristic diameter.
+
+2012-09-18	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/default-themes.xml:
+	  Update point themes of fixing W/Q chart to show point descriptions
+	  per default (#685).
+
+2012-09-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	i18n for area label (fix issue487).
+
+	* src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Get internationalized label and numberformat, pass it to renderer,
+	  where its used.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Area label translations.
+
+2012-09-18	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/CollectionDescriptionHelper.java,
+	  src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Add robustness checks to prevent NPEs (#859).
+
+2012-09-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Brought showarea-theme setting back (fix issue865).
+
+	* doc/conf/default-themes.xml, doc/conf/second-themes.xml:
+	  Define showarea theme prop where its needed.
+
+2012-09-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java:
+	  Added setter for date range.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java
+	  Set correct date range for result.
+
+2012-09-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Refactor MINFO bed quality resultsets and facets.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedLoadBedQualityResult.java,
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java:
+	  Removed.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java:
+	  Container wrapping the single calculation results.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityDiameterResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedParametersResult.java:
+	  New. Results containing calculated average diameter, porosity and density.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedPorosityFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDensityFacet.java:
+	  Facets now return the concrete datatype using the facet index.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java:
+	  Create a facet for each resultset.
+
+	* src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java:
+	  Use the classes containing the results.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java:
+	  Use new classes for results and calculate porosity and density once
+	  each period.
+
+2012-09-17  Ingo Weinzierl <ingo@intevation.de>
+
+	Tagged RELEASE 2.9.1
+
+2012-09-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* 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 still missing
+	  translations for state.
+
+2012-09-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* 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 missing translations
+	  for state to select soundings.
+
+	* src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java:
+	  Added more debug output to find out how many single and epochs where
+	  found.
+
+2012-09-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml: Defined initial colors.
+
+	* src/main/java/de/intevation/flys/exports/OutputHelper.java,
+	  src/main/java/de/intevation/flys/themes/ThemeFactory.java,
+	  src/main/java/de/intevation/flys/themes/ThemeMapping.java: Added more
+	  debug output to understand why theme mappings don't match to facets.
+
+2012-09-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java:
+	  Extract characteristic diameter only if the user selected a diameter.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java:
+	  Calculate for selected diameter only.
+
+2012-09-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverview.java,
+	  src/main/java/de/intevation/flys/artifacts/model/SQOverview.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveExporter.java,
+	  src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java:
+	  Fixed wrong assigned loggers.
+
+2012-09-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java:
+	  Please _DO NOT_ use FLYSUtils in new code based on Access*!
+	  Now the river name is fetch via access.getRiver().
+
+	* src/main/java/de/intevation/flys/artifacts/access/RiverAccess.java:
+	  New. Almost all calculations need accessing the river name.
+
+	* src/main/java/de/intevation/flys/artifacts/access/SQRelationAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FixAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/ExtremeAccess.java:
+	  Now extend RiverAccess.
+
+2012-09-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/ExtremeAccess.java:
+	  Implemented the access methods needed for
+	  "Auslagerung extremer Wasserspiegellagen".
+
+	* src/main/java/de/intevation/flys/artifacts/model/Segment.java:
+	  Move segment parsing to DoubleUtil to be usable with more data types.
+	  The wire protocol should be the same for:
+	  - "WINFO: W fuer ungleichwertige Abfluesse",
+	  - "WINFO: Auslagerung extremer Wasserspiegellagen"
+	  - "Fixierungsanalyse: Auslagerung von Wasserspiegellagen"
+
+	* src/main/java/de/intevation/flys/utils/DoubleUtil.java:
+	  Now contains the the code to parse segments. Found segments
+	  are propagated back with a callback.
+
+	* src/main/java/de/intevation/flys/artifacts/model/RangeWithValues.java:
+	  Added toString() method.
+
+2012-09-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	More infrastructure stuff for the "Auslagerung extremer Wasserspiegellagen".
+
+	* src/main/java/de/intevation/flys/artifacts/model/extreme/ExtremeCalculation.java:
+	  New. Stub for "Auslagerung extremer Wasserspiegellagen" calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/model/extreme/ExtremeResult.java:
+	  New. Stub for the cacheable results of the calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/states/extreme/ExtremeCompute.java:
+	  New. Stub compute state for the calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/access/ExtremeAccess.java:
+	  New. Sub access to the artifact to extract the relevant data.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java:
+	  A little code reordering to keep related stuff together more closely.
+
+2012-09-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/BedHeightsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/QSectorArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/FixationArtifact.java:
+	  Removed some superfluous implementations of FacetTypes.
+	  TODO: FacetTypes should be broken into smaller pieces.
+	  ATM a lof of class implement it and share a lot of unnecessary
+	  stuff.
+
+2012-09-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java,
+	  src/main/java/de/intevation/flys/artifacts/geom/VectorUtils.java:
+	  Deleted. Some nice code from the early days of the cross sections
+	  but its unused nowadays.
+
+2012-09-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java:
+	  Removed superfluous imports.
+
+	* src/main/java/de/intevation/flys/jfree/JFreeUtil.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedLoadBedQualityResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDensityFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedPorosityFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedQualityInfoGenerator.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java:
+	  Removed trailing whitespace.
+
+2012-09-15	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/resources/Resources.java,
+	  src/main/java/de/intevation/flys/utils/Formatter.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  i18n messages are now formatted with correct (client) locale, not
+	  server VM locale (#852)..
+
+2012-09-15	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml,
+	  doc/conf/artifacts/manualpoints.xml,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java:
+	  Try to add support for ManualPoints in fixing charts (not working yet).  
+
+2012-09-14  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java:
+	  Fixed SQL-statement.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurements.java:
+	  Added getter for all kms.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java:
+	  Implemented the bed quality calculation. There are still some fixes to do,
+	  e.g. extract a single result object for porosity and density.
+
+2012-09-14  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java:
+	  Getter for characteristic diameter.
+
+2012-09-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java:
+	  Create i18n facet descriptions.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: New i18n strings for facets
+	  in bed quality calculation.
+
+2012-09-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: Splitted facets for diameter of bed into
+	  two facets: diameter for sublayer and toplayer.
+
+	* doc/conf/themes.xml,
+	  doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml: Splitted themes for diameter of bed into
+	  two themes.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Splitted facets for diameter of bed into two facets.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java:
+	  New method to retrieve the diameter data.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java:
+	  New methods to retrieve the porosity, density and diameter data.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java:
+	  Create two facets for bed diameter instead of a single one.
+
+	* src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java:
+	  Insert data supported by facets into chart.
+
+2012-09-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/JFreeUtil.java: Added function to
+	  generate a randomized line.
+
+2012-09-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Defined new mappings for the six bed quality
+	  facets.
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml: Added themes for new mappings in
+	  themes.xml. The themes in second-themes are the same as in
+	  default-themss.
+
+2012-09-14  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedLoadBedQualityResult.java:
+	  Updated bed quality result objects.
+
+2012-09-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: Splitted porosity and density facets into
+	  two facets: a toplayer and a sublayer facet for each.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added
+	  the new facets for toplayer and sublayer for porosity and density.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java:
+	  Create Facets based on the calculation results.
+
+	* src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java:
+	  Use concrete result types in doXXXOut().
+
+2012-09-13	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml,
+	  doc/conf/themes.xml,
+	  src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java:
+	  Work on ManualPoints integration in fix analysis charts (wip).
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java:
+	  Fix missing import.
+
+2012-09-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java:
+	  Added getter for calculation parameters.
+
+	* src/main/java/de/intevation/flys/artifacts/model/BedQualityCalculation.java:
+	  Removed. Moved to package de.intevation.flys.artifacts.model.minfo.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedLoadBedQualityResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedBedQualityResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java:
+	  New. Calculation results and some more calculation stub.
+
+2012-09-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml,
+	  src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/states/DischargeState.java,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Renamed MINFO parameter
+	  'main.channel' -> 'main_channel' and 'total.channel' -> 'total_channel'.
+
+2012-09-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurement.java:
+	  Added depth parameter to bed quality data.
+
+2012-09-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/conf.xml: Registered new OutGenerators BedQualityGenerator and
+	  BedQualityInfoGenerator.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/BedPorosityFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiameterFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedDensityFacet.java:
+	  New Facets for serving data for bed quality exports/charts.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java:
+	  Add some dummy Facets to force chart creation.
+
+	* src/main/java/de/intevation/flys/exports/minfo/BedQualityInfoGenerator.java,
+	  src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java:
+	  New OutGenerators for bed quality charts.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: New I18N strings for bed
+	  quality charts.
+
+2012-09-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java:
+	  The factory can load bedload and bed data from seddb now.
+
+2012-09-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Objects and factory for minfo bedquality calculation data.
+
+	* src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurements.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurement.java:
+	  New. Data objects and factory for minfo bed quality calculation.
+
+2012-09-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Added missing images for datacage config manual doc.
+
+	* doc/datacage-config-manual/figures/bsh_logo.png,
+	  doc/datacage-config-manual/figures/intevation-logo.eps,
+	  doc/datacage-config-manual/figures/intevation-logo.pdf:
+	  Logos for DC conf doc.
+
+2012-09-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java:
+	  Add also min and max q values to the river info.
+
+2012-09-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/BedloadKMChartService.java,
+	  src/main/java/de/intevation/flys/artifacts/services/BedKMChartService.java:
+	  Removed trailing whitespace.
+
+2012-09-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/BedloadKMChartService.java,
+	  src/main/java/de/intevation/flys/artifacts/services/BedKMChartService.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedOverview.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverview.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedOverviewFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverviewFactory.java:
+	  New. Services, data structures and factories for overview charts in minfo
+	  bed quality calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityPeriodsSelect.java:
+	  New. State for period input in minfo bed quality that displays the overview
+	  charts.
+
+	* doc/conf/artifacts/minfo.xml:
+	  Added states and transitions for minfo bed quality calculation.
+
+	* doc/conf/conf.xml:
+	  Added services.
+
+2012-09-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/BedQualityCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java,
+	  src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java:
+	  Removed trailing whitespace.
+
+2012-09-12  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: Defined facets for bed quality chart.
+
+	* src/main/java/de/intevation/flys/artifacts/model/BedQualityCalculation.java:
+	  Calculation stub for bed quality.
+
+	* src/main/java/de/intevation/flys/artifacts/access/BedQualityAccess.java:
+	  Access stub for bed quality data.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added
+	  facets defined in minfo.xml.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java:
+	  Override computeAdvance; no calculation and facet creation takes place
+	  yet.
+
+2012-09-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java:
+	  Made AEo and datum attributes NPE proof.
+
+2012-09-11	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java:
+	  Use getGaugeValue method also for aeo and datum. Also add some javadoc for
+	  the getGaugeValue method.
+
+2012-09-11	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Fix for line text annotations in Delta W(t) charts (#837).
+
+2012-09-10	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/GaugeTimerangeState.java:
+	  Add additional check to prevent NPE (fix for #844)
+
+2012-09-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/RangeWithValues.java:
+	  Extends Range now.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java:
+	  Adjusted to use slightly different method names of Range.
+
+2012-09-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Range.java:
+	  Added disjoint method.
+
+	* src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java:
+	  Find a list of segments intersecting a given range.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	  Generate a list of ranges needed for the input of Qs
+	  in the "Auslagerung extremer Wasserspiegellagen.".
+
+2012-09-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/extreme/Curve.java:
+	  Added type safety.
+
+2012-09-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* pom.xml: Java 1.5 -> 1.6
+
+2012-09-10	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml:
+	  Remove unnecessary attributes for fixation derived curve (#836).
+
+2012-09-10	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* doc/conf/conf.xml,
+	  src/main/java/de/intevation/flys/artifacts/services/GaugeOverviewInfoService.java:
+	  Add new artifact service for the gauge overview
+
+2012-09-09	Christian Lins 	<christian.lins@intevation.de>
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml,
+	  doc/conf/virtual-themes.xml,
+	  src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java:
+	  Theme transparency attribute support (part of #840).
+
+2012-09-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/extreme/Curve.java:
+	  Store Ws and Qs in double arrays instead of WQ objects (as
+	  they are return from WstValueTable.interpolateTabular()).
+	  This simplifies the code and should be more memory effective.
+
+2012-09-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/Linear.java:
+	  Added a vectorwise weighting.
+
+	  src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	  Added methods to interpolate tabulated values only.
+	  Need in "Auslagerung extremer Wasserspiegellagen".
+
+2012-09-09	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml,
+	  doc/conf/virtual-themes.xml:
+	  Updating themes for issue #840 (wip).
+
+2012-09-09	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/second-themes.xml:
+	  Modify every theme to differ from default theme (#835).
+
+	* src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java:
+	  Use gauge.getMainValues() instead of gauge.fetchMainValues() which fixes
+	  a compiling issue on my setup.
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Some models for representing results for the upcoming
+	"Auslagerung extremer Wasserspiegellagen". Work im progress.
+
+	* src/main/java/de/intevation/flys/artifacts/math/NaNFunction.java:
+	  New. Function always return NaNs.
+
+	* src/main/java/de/intevation/flys/artifacts/math/UnivariateRealFunctionFunction.java:
+	  New. Adapter to bridge between our Functions and UnivariateRealFunctions
+	  of Apache Common Math.
+
+	* src/main/java/de/intevation/flys/artifacts/model/extreme/Curve.java:
+	  New. Part of the result model of "Auslagerung extremer Wasserspiegellagen".
+	  Its a function for a given km that uses a spline interpolation
+	  for the tabulated Q range (which is effectively the same as the
+	  calculated discharge curve for this km) and an extrapolated
+	  function beyond the tabulated values.
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/DefaultState.java,
+	  src/main/java/de/intevation/flys/themes/DefaultTheme.java:
+	  More iterator code simplification.
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/themes/DefaultThemeField.java:
+	  Simplified code.
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java:
+	  Simplified code.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java:
+	  Improved robustness and performance.
+	  Only expose date events as Collections not TreeSets.
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/QW.java:
+	  New. a pure model for discharge and waterlevel. No extras.
+
+	  Makes reuse in upcoming "Auslagerung extremer Wasserspiegellagen"
+	  a lot easier.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java:
+	  Removed.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QWI.java:
+	  Re-inserted here. Extends the new QW and adds all the extra bells
+	  and whistles needed in the fixings analysis.
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java,
+	  src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Adjusted QW to QWI.
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java;
+	  Removed because code is found in backend already.
+
+	* src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java:
+	  Simplified. Please _DO_NOT_ use NullPointerExceptions for regular flow control!
+	  This hides unintended errors.
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Removed code duplication.
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	   Removed trailing whitespace.
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/CharDiameter.java:
+	  Removed superfluous imports.
+
+2012-09-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java,
+	  src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java,
+	  src/main/java/de/intevation/flys/artifacts/ChartArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java,
+	  src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixATExport.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/TypeSection.java,
+	  src/main/java/de/intevation/flys/jfree/DoubleBounds.java,
+	  src/main/java/de/intevation/flys/jfree/Bounds.java:
+	  Cosmetics, docs.
+
+2012-09-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml:
+	  Add data fields for characteristic bed and bedload diameter.
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/CharDiameter.java:
+	  Use parametermatrix as UI provider and set the correct data.
+
+	* src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/MultiStringArrayState.java:
+	  Updated method parameter.
+
+	* 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-09-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 791.
+
+	* src/main/java/de/intevation/flys/artifacts/states/EnterMultipleLocationsState.java:
+	  Add start km to data to compare reference and target km in next state.
+
+2012-09-07  Ingo Weinzierl <ingo@intevation.de>
+
+	Tagged RELEASE 2.9
+
+2012-09-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java:
+	  Removed superfluous imports.
+
+2012-09-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java:
+	  Removed the deprecated method.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Call the new Gauge model method fetchDurationCurveData().
+
+2012-09-06	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java:
+	  Mark getDurationCurveData as deprecated. The instance method of Gauge with
+	  the same name should be used instead.
+
+2012-09-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java:
+	  Revert accidentally committed experiment.
+
+2012-09-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java:
+	  Comments, changed order of columns as requested in issue825.
+
+2012-09-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java:
+	  Only goto down to Q = 0.0001 to circumvent some numerial issues
+	  with steep functions around zero.
+
+2012-09-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java:
+	  Increase Q max about 5% (as it should be).
+
+2012-09-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Fix for issue687
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java:
+	  Rewrote AT export to fix it.
+
+2012-09-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix for issue820.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Changed label for middle height/depth.
+
+2012-09-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Default horizontal and vertical placement of logo to "center" and
+	  "top" instead of "none."
+
+2012-09-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Improved comment regarding image placement.
+
+2012-09-03  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Fixed URLs for logos.
+
+2012-09-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue744 (wrong ranges for w/q input).
+
+	* src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java:
+	  Do not add items for gauges that do not intersect with given range.
+
+2012-09-01	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue829 (wrong fixation names).
+
+	* src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java:
+	  Fix check, column indices start with 0.
+
+2012-09-01	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* 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/FacetTypes.java,
+	  src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChoiceStringAttribute.java:
+	  Removed trailing whitespace.
+
+2012-08-31	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Fix cast.
+
+2012-08-31  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* 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 for minfo bed quality parameters.
+
+2012-08-31	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/ModuleService.java,
+	  src/main/java/de/intevation/flys/artifacts/model/Module.java,
+	  src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java,
+	  src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties,
+	  doc/conf/conf.xml:
+	  Add a module service. It's now possible to configure the modules which are
+	  available for a client. With the selected attribute it is possible to give
+	  a hint for the client which module should be pre selected by default.
+
+2012-08-31  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/minfo/CharDiameter.java:
+	  New. States for minfo bed quality calculation.
+
+	* doc/conf/artifacts/minfo.xml:
+	  Added states and transitions for minfo bed quality calculation.
+
+2012-08-31  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java:
+	  Refactored state to use FLYSArtifact instead of WINFOArtifact.
+
+2012-08-31	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue817 (double datacage entries).
+
+	* doc/conf/meta-data.xml: removed double entries.
+
+2012-08-30	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	issue729, default line labels for waterlines in cross sections.
+
+	* doc/conf/default-themes.xml: Default line label and level label
+	  to true for lines in crossections..
+
+2012-08-30	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	issue814, line labels do not follow zoom.
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Move line label into visible area if otherwise outside.
+
+2012-08-30	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	issue695, show waterlevel as line label.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java:
+	  Fix path to showlevel style property.
+
+2012-08-30	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Mention how/where to change predefined logos in comment.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Mention how/where to change predefined logos in comment,
+	  Use resource for images.
+
+	* src/main/resources/images/bfg_logo.gif,
+	  src/main/resources/images/intevation.png:
+	  Added sample logos of intevation and bfg.
+
+2012-08-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Copy and slightly modified XYChartGenerators logo mechanism.
+
+2012-08-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  (getLeftX, getRightX): New and overridden to deal with inverted axis
+	  for logo placement in longitudinalsection charts.
+
+2012-08-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Use RectangleAnchor to set anchor of logo.
+
+2012-08-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Add Logo settings to CrossSection ChartSettings.
+
+2012-08-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Split logo-placement property in two, one for horizontal, one for
+	vertical placement.
+
+	* src/main/java/de/intevation/flys/exports/ChartSettings.java,
+	  src/main/java/de/intevation/flys/exports/ChartSection.java:
+	  Accessors for split property.
+        
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java
+	  (logoHPlace,logoVPlace,logoPlace): Use split properties for vertical
+	                                     and horizontal placement of logo.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Use split properties, respect in placement.
+
+2012-08-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Sloppy logo placement property implementation.
+
+	* src/main/java/de/intevation/flys/exports/ChartSettings.java:
+	  Parse and set logo placement property value.
+	  
+	* src/main/java/de/intevation/flys/exports/ChartSection.java:
+	  Accessors for Logo placement property.
+	  
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java
+	  (logoPlace): New, get logo placement property value.
+	  (showLogo): Default to "none".
+	  
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Sloppy interpretation of the logo placement property.
+
+2012-08-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  (addLogo): New, add an image annotation to plot, very stubby,
+	             use hard-coded paths for now.
+
+2012-08-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Preparations for logo-inclusion in charts.
+
+	* src/main/java/de/intevation/flys/exports/ChoiceStringAttribute.java:
+	  New string attribute type to trigger different UI (selectboxes)
+	  in client.
+	  
+	* src/main/java/de/intevation/flys/exports/TypeSection.java
+	  (setChoiceStringValue): Create new ChoiceStringAttribute.
+	  
+	  
+	* src/main/java/de/intevation/flys/exports/ChartSection.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartSettings.java:
+	  Accessors to show logo-property.
+
+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,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartSettings.java:
+	  (setDisplayGird, setDisplayGrid): Fixed typos.
+
+2012-08-23  Raimund Renkert <raimund.renkert@intevation.de>
+
+	FixA: Changed sector average form point to line in delta W(t) chart.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Add data points for sector average and changed time unit for analysis period
+	  from month to day.
+
+	* doc/conf/default-themes.xml:
+	  Changed theme for sector average to color line.
+
+2012-08-23  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 716. FixA: Spilt reference and analysis period themes into one theme for each event.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java:
+	  Create a facet for each event and use new facet for sector average in
+	  longitudinal section chart.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java:
+	  The facets now return data for a single event.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAvSectorFacet.java:
+	  New. This facet returns an analysis period containing the calculated
+	  average.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java:
+	  Added methods to get the dates for all reference and analysis period events.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Fixed range combining.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java:
+	  Adjusted generators to use the data returned by the facets.
+
+	* 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-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java:
+	  Using trove to map int->int instead of bloated generics.
+
+2012-08-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Prevent another NPE. Removed dead code.
+
+2012-08-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java:
+	  Each analysis period has its own index scheme now.
+
+2012-08-22	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Fix for NullPointerException.
+
+2012-08-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java:
+	  Made indices of analysis periods QWs zero based.
+
+2012-08-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java:
+	  Store index, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java:
+	  Adjusted to keep constructors in sync.
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java:
+	  Set QD index to the values of the column cache columns.
+
+2012-08-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Use the column cache to establish a consistent index scheme.
+	TODO: Store the index values in the created QWDs.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  doFitting() fetches the columns from column cache, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java:
+	  Reuse same column cache from fitting to have the same index scheme.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java:
+	  Adjusted to use the column cache.
+
+2012-08-22	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/HYKFacet.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Fix NullPointerExceptions in cross section diagrams that occurred when
+	  no HYKs are available for the selected kms.
+
+	* src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_de.properties:
+	  Typo, see issue #806
+
+2012-08-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixATExport.java:
+	  Removed superfluous import. s/Double.valueOf/Double.parseDouble/.
+
+2012-08-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixATExport.java:
+	  Removed debug outputs.
+
+2012-08-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixATExport.java:
+	  New. Exporter for FixAnaylsis AT files.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java:
+	  Add facet for AT export.
+
+	* doc/conf/conf.xml:
+	  Added out generator for fix AT export.
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Added outputmode for AT export.
+
+2012-08-16	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Add more facets to
+	  compat list, removed doubled wq output.
+
+2012-08-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java:
+	  Shorten overlong lines. Simplified code.
+
+2012-08-16	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java:
+	  Interpolate and reduce WQKms if currentKm found in context.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Handle WQKms in WQOuts.
+
+2012-08-16	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Add longitudinal section
+	  facet type to compatibility list of W/Q diags.
+
+2012-08-16  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java:
+	  Added getter for ui provider.
+
+2012-08-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  BasicStroke constructor takes an float as first argument
+	  so there is no need to blow up an 'int' to an Integer
+	  which is auto-unboxed to int which is implicitly cast to float.
+
+2012-08-15	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Do not hard-recommend gauge-dis. for fixwq.
+
+2012-08-15	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java:
+	  Fail more gracefully.
+
+2012-08-14	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: More former calculations in fixA (dwt) DC.
+
+2012-08-14	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: More former calculations in fixA DC.
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Add discharge curve facet to
+	  compat. list.
+
+	* doc/conf/meta-data.xml: Show discharge curves for FixA WQ DC.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Handle discharge curve data.
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Add more facets to compat. list.
+
+	* doc/conf/meta-data.xml: Show more additional data in FixA w/q-diag.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Handle new, annotation-type facets.
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Added wqkms facets to comp. list.
+
+	* doc/conf/meta-data.xml: Add wq-basedata and other stubs to fixA dc.
+
+	* src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java
+	  (getWQAtKm): Adjusted behaviour such that passed km can be
+	  respected.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Handle WQFacets.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQFacet.java:
+	  Pass contexts current_km if available.
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Added deltawt-out.
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Show former calculations in FixA WQ-DC.
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Show more former calculations in DeltaWTs
+	  and fix query (and/or/() precedences).
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Show more former calculations in fixA LS.
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/conf.xml: Renamed qsector(s) factory.
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Load annotations for fixA long.sections.
+	  Add stubs for "old calculations"-dc-conf for various FixA outs.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java:
+	  Handle annotation outs.
+
+2012-08-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes.xml, doc/conf/default-themes.xml:
+	  Added theme fields for qsectors label.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Add markers for the qsectors.
+
+2012-08-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes.xml, doc/conf/default-themes.xml:
+	  Fix some typos, correct defaults and add mapping for qsector-theme.
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Cosmetics.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Add accidentally omitted change, stub for style-handling.
+
+2012-08-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/QSectorFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/states/QSectorSingleState.java,
+	  src/main/java/de/intevation/flys/artifacts/QSectorArtifact.java:
+	  Wording and i18n of qsectors.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Add Markers to plot for qsectors.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  i18n for qsectors.
+
+2012-08-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/QSectorSingleState.java:
+	  New, accidentally omitted single state of a qsector-artifact.
+
+2012-08-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Add qsectors-facet to
+	  compatibility list.
+
+	* doc/conf/conf.xml: Register qsector artifact and its factory.
+
+	* doc/conf/meta-data.xml: Recommend qsectors in fix w/q settings.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Add qsector facet type.
+
+2012-08-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/qsector.xml:
+	  Trivial state model for qsector artifact.
+
+	* src/main/java/de/intevation/flys/artifacts/model/QSectorFacet.java:
+	  Rather trivial facet to get QSectors from QSectorArtifact.
+
+	* src/main/java/de/intevation/flys/artifacts/QSectorArtifact.java:
+	  New QSectorArtifact.
+
+2012-08-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java,
+	  src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java:
+	  Cosmetics.
+
+2012-08-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java:
+	  Removed superfluous imports.
+
+2012-08-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Set info attribute (will evaluate as tooltip
+	  in GUI.
+
+2012-08-07	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Reflect fact that there can be only one reference station.
+
+2012-08-07	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue798.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Set Tick Units dependant on cm/m scale on X axis.
+
+2012-08-01	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Fix for flys/issue748
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java:
+	  Only remove one data point per outlier removal iteration.
+
+2012-07-31	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/Outlier.java:
+	  Only evict only one(!) data point as outlier.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  Recalculate the function when one point is removed.
+
+2012-07-31	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/Outlier.java:
+	  Corrected the formulas of Grubbs' test for outliers.
+	  TODO: Remove only one(!) data point. Currently it removes
+	  more than on point without recalculating the fitting curve.
+	  This leads to too much removed points.
+
+2012-07-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  Setup better initial activity for the facets of the S/Q results.
+
+2012-07-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Use getCurrentKmFromRequest().doubleValue() in i18n formatting.
+
+2012-07-29	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  getCurrentKmFromRequest returns Double(!) not double.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java:
+	  Use Double.parseDouble() instead od Double.valueOf().
+
+2012-07-29	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  Initially activate/deactivate facets.
+
+2012-07-29	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/AttributeWriter.java,
+	  src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java:
+	  Refactored to use the new Chain-of-responsibility pattern in facet
+	  activation.
+
+2012-07-29	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeInfoService.java:
+	  Made expensive XMLUtils.toString() debug output conditional.
+
+2012-07-29	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Use the new infrastructure to figure out if a facet should
+	be initially active or not.
+
+	* src/main/java/de/intevation/flys/collections/AttributeWriter.java:
+	  Uses the FacetActivity.Registry to look up the initial acitiviy.
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  Do not use sub classing any more.
+
+	* src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/HYKArtifact.java:
+	  Register to FacetActivity.Registry now. TODO: Make it configurable.
+
+2012-07-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/themes/ThemeFactory.java,
+	  src/main/java/de/intevation/flys/collections/CollectionAttribute.java,
+	  src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java,
+	  src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/ChartArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java,
+	  src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/MapArtifact.java:
+	  s/container.size() == 0/container.isEmpty()/
+
+2012-07-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  Lowered logging output level from info to debug.
+	  Made some more debug outputs conditional.
+
+2012-07-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  Some code simplifications.
+
+2012-07-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Extented the result data model of the S/Q calculation to
+	store the curve coefficients for each iteration step
+	of the outlier elimination. The starting data set of S/Qs
+	is stored as well.
+
+	TODOs:
+	- Create the new facets as inactive.
+	- Repair the facet to style mapping.
+
+	* doc/conf/themes.xml: Added mappings for new facets.
+
+	* doc/conf/artifacts/minfo.xml: Configured the new facets.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationExporter.java:
+	  Adjusted to new data model.
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  Generate facets for outlier curves and measurements. Simplified code.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  New facet types for outlier curves and meassurements.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  New set() method to set an array of values by their names.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Segment.java:
+	  Removed trailing whitespace.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQMeasurementFacet.java:
+	  Adjusted to new data model. Curves are drawn over the whole length of the
+	  starting S/Q dataset.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierCurveFacet.java:
+	  New. Facet for the curves of the outlier test iterations.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierMeasurementFacet.java
+	  New. Facet for the meassurement data remainind after outlier test iteration.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Now creates the new data model.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java:
+	  Refactorted to have more control over the data structures to be generated.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java:
+	  The new data model to represnt a fraction result. Each outlier test iteration
+	  results in a different iteration object.
+
+	* 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 for new facets.
+
+2012-07-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/QWDDateRange.java:
+	  Added method getQWD() to retrieve the QWD property.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Avoid class cast exceptions; a QWDDateRange object is returned by WQ
+	  sector average Facet - not a QWD object. Use new getter method to
+	  retrieve the required data object.
+
+2012-07-27  Ingo Weinzierl <ingo@intevation.de>
+
+	Tagged module as '2.8.1'.
+
+2012-07-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/QWDDateRange.java:
+	  New class. QWD and a DateRange.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java:
+	  Produce QWDDateRanges in state, consume in generator.
+
+2012-07-26  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Registered new Output
+	  'fix_vollmer_wq_curve'.
+
+	* doc/conf/conf.xml: Registered new FixWQCurveGenerator for
+	  'fix_vollmer_wq_curve'.
+
+	* 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 new names for Facets
+	  used in 'fix_vollmer_wq_curve' Output.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java:
+	  Make use of FitResult (parent of FixAnalysisResult) which is enough for
+	  these Facets instead of casting the calculation result to
+	  FixAnalysisResult.
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixAnalysisAccess.java:
+	  Fixed potential NullpointerException.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java:
+	  Create new Facets for WQ curve, fix events and outliers.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Add subtitles only if the required data (date period and referenence
+	  period) are existing. Otherwise do not add a subtitle.
+
+2012-07-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Adjusted i18n strings (vollmer).
+
+2012-07-26	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/virtual-themes.xml,
+	  src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/themes/ThemeAccess.java,
+	  src/main/java/de/intevation/flys/themes/TextStyle.java,
+	  src/main/java/de/intevation/flys/themes/LineStyle.java,
+	  src/main/java/de/intevation/flys/themes/ThemeFactory.java,
+	  src/main/java/de/intevation/flys/themes/PointStyle.java,
+	  src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java,
+	  src/main/java/de/intevation/flys/jfree/XYStyle.java,
+	  src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java:
+	  Line labels and point labels share same styles and code.
+	  Point labels can have a background color.
+
+2012-07-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Adjusted i18n strings (vollmer).
+
+2012-07-26  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Registered new Output
+	  'fix_waterlevel_export' for FixRealizingCompute State.
+
+	* doc/conf/conf.xml: Registered new WaterlevelExport Generator for
+	  'fix_waterlevel_export'.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java:
+	  Create proper CSV, WST and PDF Facets with hash and State id.
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Made
+	  WaterlevelExporter support FixRealizingResult objects.
+
+2012-07-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWaterlevelFacet.java:
+	  Removed instanceof hack to fetch the WQKms of the fix realizations.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWaterlevelFacet.java:
+	  New. Subclass of WaterlevelFacet. Used to fetch the WQKms the fix realization way.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java:
+	  Create the subclassed waterlevel facets.
+
+2012-07-25  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java:
+	  Create proper facets for Ws and Qs.
+
+2012-07-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java:
+	  Also add Q-Facet.
+
+2012-07-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java:
+	  Add WaterlevelFacet.
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Add output and facet compability.
+
+2012-07-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixRealizingAccess.java:
+	  Fix data names in FixRealizingAccess.
+
+2012-07-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java:
+	  Handle slightly different access to Fixation-WQKms.
+
+2012-07-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java:
+	  Handle slightly different access to Fixation-WQKms.
+
+2012-07-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationSelect.java:
+	  Fix (last?) vol(l)mer naming issue.
+
+2012-07-24	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/StateFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java
+	  src/main/java/de/intevation/flys/themes/ThemeMapping.java:
+	  s/.equals("")/.length() == 0/
+
+2012-07-24	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java,
+	  src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java,
+	  src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Removed some superfluous casts.
+
+2012-07-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Removed some inner whitespace.
+
+2012-07-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java:
+	  New base class for fixing analysis results.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingResult.java:
+	  Inherits from FixResult.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java:
+	  Calculation returns FixRealizingResult.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java:
+	  Remove superfluous import.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation4.java:
+	  Cosmetics.
+
+2012-07-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Broke over long line.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Segment.java:
+	  Added some getters.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java:
+	  Calculated the Q -> Ws. TODO: Produce result.
+
+2012-07-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Adjusted i18n strings (vollmer).
+
+2012-07-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/LocationSelect.java:
+	  Set ld_mode so that FLYSUtils can use it.
+
+2012-07-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Adjusted i18n strings (vollmer).
+
+2012-07-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java:
+	  Handle FixationArtifacts with as much care as WINFOArtifacts,
+	  by using refactore FLYSUtils.
+
+2012-07-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Towards per-Gauge-input of W/Q values for FixationArtifact.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/utils/FLYSUtils.java:
+	  (getGauges): Refactored, moved from WINFOArtifact to FLYSUtils.
+	
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java:
+	  Handle unlucky differences in names of data for
+	  WINFOArtifact/FixationArtifact.
+	
+	* doc/conf/artifacts/fixanalysis.xml:
+	  (Re-)use WQAdapted State for fix.analysis.
+
+2012-07-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml,
+	  src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/HYKFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/QSelect.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java,
+	  src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java,
+	  src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Cosmetics, docs.
+
+2012-07-23	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Segment.java,
+	  src/main/java/de/intevation/flys/artifacts/model/Calculation4.java:
+	  Moved code to convert W to Q at gauge to segments to be reusable.
+
+2012-07-23	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/themes.xml,
+	  doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml:
+	  Remove line style attributes from FixingReferenceEvents theme.
+
+2012-07-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation4.java
+	  src/main/java/de/intevation/flys/artifacts/model/Segment.java:
+	  Moved reference point comparator to segment class be be reusable
+	  in FixA 'ausgelagerte Wasserspiegellagen'.
+
+2012-07-23	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Simplify annotation code.
+
+2012-07-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Made abstract. Sub classes have to overwrite innerCalculate()
+	  calculate() now figures out the fixings overview and the function
+	  to fit and passes it to innerCalculate()
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java:
+	  Overrides innerCalculate() now.
+
+2012-07-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  Prevent NPE in getOutputForState(). Why does this happen?
+
+2012-07-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Made curve fitting over the given calculation range reusable. Removed dead code.
+
+2012-07-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java:
+	  Moved more common code into base class.
+
+2012-07-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/fixoverview2html.xsl: Clip the displayed from/to ranges
+	  of the gauges to the max extent of the events.
+
+2012-07-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/fixoverview2html.xsl: Embed german and english translations
+	  into the stylesheet. This should be better done by importing
+	  an external resource depending on the choosen locale!
+
+2012-07-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/fixoverview2html.xsl: Introduced i18n to transformation.
+
+2012-07-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Wrong epsilon was taken so sector aggregation was not working
+	  leading to too large result documents and wrong range display
+	  on client side.
+
+2012-07-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/fixoverview2html.xsl: Render the names of the gauges into
+	  the header line. Full name and spread is displayed as a tooltip.
+
+2012-07-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: Use SQPeriodSelect state for the input of
+	  a time range. The difference to PeriodSelect is the UI provider desired
+	  by this state.
+
+	* src/main/java/de/intevation/flys/artifacts/states/sq/SQPeriodSelect.java:
+	  New subclass of PeriodSelect; this state wants to be rendered in a
+	  'sq.period.select' UI provider.
+
+2012-07-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/fixoverview2html.xsl: To help developing the 
+	  HTML overview stylsheet more quickly bring back in sync with
+	  version of the flys-client.
+
+2012-07-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: Changed the parameters for SQ relation
+	  period selection; only a single period is allowed now.
+
+	* src/main/java/de/intevation/flys/artifacts/states/PeriodSelect.java: New
+	  class that allows the selection of a time period.
+
+	* src/main/java/de/intevation/flys/artifacts/access/SQRelationAccess.java:
+	  Reduced support of time periods to a single period.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Adapted the usage of SQRelationAccess which method signature has
+	  changed; it returns a single DateRange instance only.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Modified the keys of the
+	  state for SQ relation time period input.
+
+2012-07-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java:
+	  Disabled legends in this overview.
+
+2012-07-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java:
+	  Removed superfluous imports.
+
+2012-07-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/resources/messages_de.properties,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties:
+	  Fixed anomalies.
+
+2012-07-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReportGenerator.java,
+	  src/main/java/de/intevation/flys/exports/AbstractExporter.java,
+	  src/main/java/de/intevation/flys/exports/ATExporter.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/MapGenerator.java,
+	  src/main/java/de/intevation/flys/exports/OutGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java:
+	  Added a setCollection() method that allows the caller of OutGenerators
+	  to set a reference to a FLYSArtifactCollection.
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Use setCollection() to set the reference to the current
+	  FLYSArtifactCollection before using OutGenerators.
+
+	* doc/conf/conf.xml: Registered the SQOverviewGenerator.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Add a list of gauges which intersect the range of the selected columns:
+
+	    <fixings>
+	      <gauges from="..." to="..." name="..."/>
+	      ...
+	      <gauges from="..." to="..." name="..."/>
+	    </fixings>
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeRange.java:
+	  Store the name of the gauge, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeFinderFactory.java:
+	  Load the names of the gauges from database, too.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java:
+	  Some minor refactoring.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java:
+	  Call super constructor to retrieve the common data from the artifact.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  New. Common base class for Fix*Calculations.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java:
+	  Moved common stuff to base class FixCalculation.
+
+	 * src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java:
+	   Inherit from FixCalculation.
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixRealizingAccess.java:
+	  Extract parameters that are only relevant for the
+	  'Ausgelagerte Wasserspiegellagen' calculation.
+
+	  isQ():         Must we convert the given values from W to Q first?
+	                 Used data field: 'fix_isq'
+	  getSegments(): Segments same semantics as WINFO's 
+	                 'W fuer ungleichwertige Abfluesse.'
+	                 Used data field: 'fix_segments'
+
+	* src/main/java/de/intevation/flys/artifacts/model/Segment.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FixAccess.java:
+	  Cosmetics.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixAccess.java:
+	  New. Common base class for the Fix*Access.
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixAnalysisAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FixRealizingAccess.java:
+	  Now inherit from FixAccess.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java:
+	  Prevent NPE.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixFacetUtils.java:
+	  Use constant to lookup column instead of dynamically allocated array.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java:
+	  Removed.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisResult.java:
+	  Re-added here.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java,
+	  src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java,
+	  src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java:
+	  Adjusted.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixRealizingCalculation.java:
+	  New. Stub for 'Ausgelagerte Wasserspiegellagen' calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixRealizingAccess.java:
+	  New. Stub for accessing the artifact to extract the relevant parameters
+	  for the 'ausgelagerte Wasserspiegellagen' calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java:
+	  Call the calculation if the state is reached.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DefaultState.java:
+	  Removed trailing whitespace.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationVolmerCompute.java:
+	  Deleted.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixRealizingCompute.java:
+	  Re-added here.
+
+	* doc/conf/artifacts/fixanalysis.xml: Adjusted. BTW: Vollmer is spelled with two 'l's.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Removed.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixAnalysisCompute.java:
+	  Re-added.
+
+	* doc/conf/artifacts/fixanalysis.xml: Adjusted.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Deleted
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisCalculation.java:
+	  Re-added.
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixAnalysisAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Adjusted class name usage.
+
+2012-07-19	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  native2ascii with properties files.
+	  Show analysis periods as subtitle in W/Q chart.
+
+2012-07-19	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Add subtitle to Fix W/Q chart.
+	  Move addSubtitle() code from generators up to ChartGenerate which saves 
+	  a lot of duplicate code.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java:
+	  Deleted.
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixAnalysisAccess.java:
+	  Re-added.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Adjusted class name usage.
+
+2012-07-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/DefaultState.java:
+	  Sourced code to set default values of a parameter to an own method.
+	  Subclasses should override this method.
+
+	* src/main/java/de/intevation/flys/artifacts/states/OutliersInput.java:
+	  Set default value for outliers to "3".
+
+2012-07-19	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Add kilometer info to chart titles.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java,
+	  src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/utils/FLYSUtils.java,
+	  src/main/java/de/intevation/flys/exports/ChartSettings.java,
+	  src/main/java/de/intevation/flys/jfree/XYStyle.java:
+	  Use Integer.parseInt() instead of Integer.valueOf() + Autounboxing.
+	
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Replaced "string -> object -> native -> object" by simple "string -> object".
+	  Removed stupid duplicate XPathing.
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java:
+	  Use only blue as point color.
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Adjusted Delta W(t) CSV exporter to customers wishes.
+
+	* src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java:
+	  Reordered columns, removed description, added W and formatted date
+	  via i18n.
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java:
+	  Added method to get a formatter based on pattern and locale.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Adjusted i18n strings.
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Classify each discharge range by the gauges which intersect it.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Range.java:
+	  Added convinience constructor.
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeFinder.java:
+	  Added method to return all gauges.
+
+2012-07-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  Use bandwidth parameter for width of band, adjusted name to be
+	  displayed in legend.
+
+2012-07-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/default-themes.xml,
+	  src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  Change bandwidth type to double (still bugged, round integers still
+	  work, though).
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java:
+	  Added column for time range.
+
+	* 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.
+
+	* src/main/java/de/intevation/flys/artifacts/resources/Resources.java:
+	  Fixed stupid formatting bug.
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java:
+	  Added discharge column.
+
+	* 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 missing strings.
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Removed trailing whitespace.
+
+2012-07-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java,
+	  src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java,
+	  src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java,
+	  src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java,
+	  src/main/java/de/intevation/flys/collections/CollectionAttribute.java:
+	  Cosmetics, doc.
+
+2012-07-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial implementation of issue720 (bandwith for curves), in
+	longitudinal section ws only, no styling, integer-based.
+
+	* doc/conf/default-themes.xml: Add bandwidth to fields of longitudinal
+	  section facets.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java: Add bandwidth
+	  theme parsing.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  If bandwidth is set, add an area data series with datapoints
+	  above/under the actual data points.
+
+	* src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java:
+	  Helper for adding points with offset.
+
+2012-07-17	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java:
+	  Use Q_BPEGEL as symbolic name for Q
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Out commented the LEFT JOINs which produce a lot of empty and
+	  redundant data. Bring them back in when we treat subsamples right.
+
+2012-07-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Added getValue() method.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Store location of calculation in result, too.
+	  
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java:
+	  Added method getTotalCount() to return the number of used S/Q pairs.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQResult.java:
+	  Store location of result, too.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationExporter.java:
+	  Write parameters as export result.
+
+2012-07-16	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java:
+	  Bit of doc.
+
+	* src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java:
+	  TODO for automatic official lines added.
+
+2012-07-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Out commented debug output which caused OOM errors.
+
+2012-07-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/SQOverview.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Q is not taken from MESSUNG.Q but from MESSUNG.Q_BPEGEL
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java:
+	  Fixed indentation. More macros.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Removed trailing whitespace.
+
+2012-07-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* Tagged module as '2.8'.
+
+2012-07-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/StyledXYSeries.java,
+	  src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java,
+	  src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java,
+	  src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java,
+	  src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/SQRelation.java,
+	  src/main/java/de/intevation/flys/artifacts/states/OutliersInput.java,
+	  src/main/java/de/intevation/flys/artifacts/states/PeriodsSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java,
+	  src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java,
+	  src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WQKmsFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WQFacet.java:
+	  Removed same package imports.
+
+2012-07-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Lowered log level.
+
+2012-07-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Allow manual loading of official lines in
+	  longitudinal_discharge diagrams.
+
+2012-07-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java:
+	  Prevent nasty NPE (hidden by autobox).
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java:
+	  Suppress data points with values <= 0 because they kill JFreeChart's
+	  log/log diagrams.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Fixed more SQL syntax errors.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Generate more than one SQResult (To my big suprise it's possible).
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java.
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java:
+	  Made more NPE bullet proof.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Fixed problem with string operation precedence.
+
+2012-07-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: very basic official lines matching the current
+	  artifact (for this it is wrongly placed in previous calc.-part, for
+	  now.
+
+2012-07-13	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/MapfileGenerator.java:
+	  Create shapefile directory instead of shapefile 'file'.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java:
+	  Removed translation whitespace.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java:
+	  Finally! SQResult is build and should be ready for display. :-)
+
+2012-07-13	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/MapfileGenerator.java,
+	  src/main/java/de/intevation/flys/utils/GeometryUtils.java:
+	  Fix and workaround NullPointerExceptions.
+
+2012-07-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/wsplgen/WSPLGENCallable.java,
+	  src/main/java/de/intevation/flys/wsplgen/FacetCreator.java,
+	  src/main/java/de/intevation/flys/wsplgen/JobObserver.java,
+	  src/main/java/de/intevation/flys/wsplgen/ProblemObserver.java,
+	  src/main/java/de/intevation/flys/wsplgen/Scheduler.java,
+	  src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/MapArtifact.java,
+	  src/main/java/de/intevation/flys/utils/MapfileGenerator.java,
+	  src/main/java/de/intevation/flys/exports/MapGenerator.java: 
+	  Organized and added missing imports.
+
+2012-07-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/GeometryUtils.java: Added new
+	  functions to reproject an Envelope from one CoordinateReferenceSystem to
+	  antoher.
+
+	* src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryPolyArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSGaugeLocationArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java:
+	  The getExtent() method will now return the extent of the layer in the
+	  coordinate reference system that is configured for the specific river.
+
+2012-07-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WMSDBLayerFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WSPLGENLayerFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WSPLGENCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WSPLGENReportFacet.java:
+	  Moved to subpackage map.
+
+	* src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENLayerFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/map/WMSLayerFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENJob.java,
+	  src/main/java/de/intevation/flys/artifacts/model/map/WMSDBLayerFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/map/WSPLGENReportFacet.java:
+	  Moved from upper package.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOverviewFacet.java,
+	  src/main/java/de/intevation/flys/exports/OutputHelper.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java:
+	  Added missing vim lines.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOverviewFacet.java,
+	  src/main/java/de/intevation/flys/exports/OutputHelper.java:
+	  Removed trailing whitespace.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOverviewFacet.java,
+	  src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Removed superfluous imports.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Only use first period of the time periods given by the UI.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQResult.java:
+	  Added some more index checking.
+
+2012-07-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOverviewFacet.java:
+	  New. Facet for chart overview in sq relation.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQOverviewGenerator.java:
+	  New. Generator for chart overview. This generator is not used jet.
+	  Currently we generate the overview on client side by putting all charts in a
+	  simple grid, cause the charts rendered by this generator are empty.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added new Facet type.
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  Add facets for overview.
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Avoid a NPE in legend entry aggregation.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Moved log output to avoid NPE.
+
+	* doc/conf/artifacts/minfo.xml:
+	  Added new output for chart overview.
+
+2012-07-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Refactored. Moved some functionality to FLYSContext and OutputHelper.
+
+	* src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java:
+	  Added 'getOutGenerator' to get a concrete generator. Moved from
+	  FLYSArtifactCollection.
+
+	* src/main/java/de/intevation/flys/exports/OutputHelper.java:
+	  New. Provides the 'doOut' functionality for FYLSArtifactCollection.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurements.java:
+	  Handle the error case of accessing wrong indexed SQ relation
+	  more smoothly.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java:
+	  Added access to the data of GSIEBSATZ and SSIEBUNG.
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Added the left joins to the GSIEBSATZ and SSIEBUNG tables.
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Do not store null values from database.
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurements.java:
+	  New. Container for measurements. Helps to extract the S/Q fractions.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Now uses the measurements container.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java:
+	  Added convenience methods to extract the different fractions.
+	  DONE: Q, S_SS, S_SF
+	  TODO: S_BL_S, S_BL_FG, S_BL_CG, S_BL
+
+	* src/main/java/de/intevation/flys/artifacts/model/SQOverview.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Relax existence of SIEBSATZID.
+	  We have to use a left join during data extraction anyway.
+	  We force the existence of Q because we cannot do the fitting if
+	  we don't have them.
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Measurement.java:
+	  New. Access to the data from the SedDB.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/MeasurementFactory.java:
+	  Load measurements from SedDB.
+	
+	* src/main/java/de/intevation/flys/artifacts/model/SQOverview.java:
+	  Force NOT NULL for discharge values, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/SQOverviewFactory.java:
+	  Indentation fix.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Iterate over all given periods.
+	  
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/SQKMChartService.java:
+	  Fixed wrong logger class.
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	 src/main/java/de/intevation/flys/artifacts/model/SQOverview.java:
+	 Filter out the meassures which don't have a related 'Siebsatz'.
+
+	 doc/conf/cache.xml: Added forgotten cache for sq-overview.
+
+	 src/main/java/de/intevation/flys/artifacts/model/SQOverviewFactory.java:
+	 Added vim line.
+
+2012-07-12	Christian Lins <christian.lins@intevation.de>
+
+	* doc/conf/default-themes.xml,
+	  doc/conf/virtual-themes.xml,
+	  src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/themes/ThemeAccess.java:
+	  Add showpointlabel style attribute. Refactor some styles to make use of
+	  general attributes in the virtual themes.
+
+	* src/main/java/de/intevation/flys/utils/GeometryUtils.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java:
+	  Suppress or fix some warnings.
+
+2012-07-12	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/conf.xml: Fix class name.
+
+2012-07-11	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/DefaultState.java,
+	  src/main/java/de/intevation/flys/utils/FLYSUtils.java,
+	  src/main/java/de/intevation/flys/exports/ChartExportHelper.java,
+	  src/main/java/de/intevation/flys/exports/WstWriter.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java,
+	  src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java:
+	  Various cosmetic doc fixes.
+
+2012-07-11	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Make official lines available in dc for
+	  manual loading in longitudinal sections.
+
+2012-07-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Sieve.java:
+	  Simulates a sieve to separate the differen fractions from each other.
+
+2012-07-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/DateRange.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Removed trailing whitespace.
+
+2012-07-11	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/DateRange.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Delta W(t) chart subtitle now with real values and correct i18n.
+
+
+2012-07-11	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Re-add HYK rendering code again to CrossSectionGenerator (fix for #712).
+
+
+2012-07-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/SQKMChartService.java,
+	  src/main/java/de/intevation/flys/artifacts/model/SQOverview.java:
+	  Removed superfluous imports.
+
+2012-07-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/SQOverview.java:
+	  Made km separating of dates epsilon tolerant and avoid empty date lists.
+
+2012-07-10  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/SQKMChartService.java:
+	  New. Service that generates an overview chart for measuring points.
+
+	* src/main/java/de/intevation/flys/artifacts/model/SQOverview.java:
+	  New. Instance of measuring points overview data.
+
+	* src/main/java/de/intevation/flys/artifacts/model/SQOverviewFactory.java:
+	  New. Foctory for overview data objects.
+
+	* doc/conf/conf.xml:
+	  Added new service to config.
+
+	* 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-07-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix for issue694.
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
+	  Also resolve edge cases (last/first cross section km).
+
+2012-07-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial fix for issue694 (Heightmarks snap to nearest cross section
+	line).
+
+	* src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java:
+	  Extended signature of getWaterLines to allow behaviour of only
+	  delivering data if it snaps to the km (is closest).
+
+	* src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Documentation, updated signature of getWaterLines().
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
+	  Remember if Heightmarks are displayed, if so deliver data
+	  only if cross-section is closest (snap).
+
+	* src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java:
+	  Make next and previous km of cross-sections available as data.
+
+	* src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java:
+	  Provide next and previous cross-section km via blackboard, adjusted
+	  call to getWaterLines.
+
+2012-07-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	  Removed trailing whitespace.
+
+2012-07-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java,
+	  src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java,
+	  src/main/java/de/intevation/flys/exports/AbstractExporter.java,
+	  src/main/java/de/intevation/flys/exports/ChartExportHelper.java,
+	  src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/MiddleBedHeightGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/OutGenerator.java,
+	  src/main/java/de/intevation/flys/exports/FlowVelocityGenerator.java:
+	  Fix various documentation issues.
+
+2012-07-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQKms.java,
+	  src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/transitions/DefaultTransition.java,
+	  src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/WDifferencesExporter.java,
+	  src/main/java/de/intevation/flys/exports/ChartHelper.java,
+	  src/main/java/de/intevation/flys/exports/MiddleBedHeightGenerator.java,
+	  src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java,
+	  src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java:
+	  Fix various issues in the hard-to-find documentation.
+
+2012-07-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* pom.xml: Configure javadoc mojo to include doc for protected/private.
+
+2012-07-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/themes2html.xsl: Create a list of direct sub themes
+	  of a theme.
+
+2012-07-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/datacage-config-manual/Makefile: New, added Makefile.
+
+2012-07-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation2.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java,
+	  src/main/java/de/intevation/flys/jfree/HasLabel.java:
+	  Cosmetics, docs.
+
+2012-07-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java:
+	  Fixed XPath typo.
+
+2012-07-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Removed dynamic XPaths to pervent potential XPath injections.
+
+2012-07-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/themes2html.xsl: New. Transformation to get a better
+	  overview of themes.xml. Usage:
+
+	  $ xsltproc --path doc/conf    \
+	        contrib/themes2html.xsl \
+	        doc/conf/themes.xml     \
+	        > themes.xhtml
+
+	  Use browser to view the resulting file.
+
+2012-07-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/second-themes.xml: Name the second themegroup 'second'
+	  instead of 'default' to avoid clashes with the real 'default'
+	  themegroup.
+
+2012-07-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/default-themes.xml,
+	  doc/conf/virtual-themes.xml,
+	  doc/conf/themes.xml,
+	  doc/conf/second-themes.xml:
+	  Added xml processing instruction.
+
+2012-07-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/InvLog.java,
+	  src/main/java/de/intevation/flys/artifacts/access/Access.java,
+	  src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorA.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorB.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorC.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorD.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorE.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorF.java,
+	  src/main/java/de/intevation/flys/exports/ChartArea.java,
+	  src/main/java/de/intevation/flys/jfree/StyledValueMarker.java,
+	  src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java:
+	  Added vim lines.
+
+2012-07-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java,
+	  src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java:
+	  Replaced tabs with four spaces each.
+
+2012-07-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartArea.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Removed superfluous imports.
+
+2012-07-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java,
+	  src/main/java/de/intevation/flys/jfree/StyledValueMarker.java,
+	  src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java,
+	  src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Removed trailing whitespace.
+
+2012-07-06	Christian Lins <christian.lins@intevation.de>
+
+	* doc/conf/*-themes.xml,
+	  src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/jfree/StyledValueMarker.java,
+	  src/main/java/de/intevation/flys/jfree/StyledDomainMarker.java,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Add styles for W(t) domain markers.
+
+	* src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java:
+	  Remove false @override.
+
+2012-07-06	Christian Lins <christian.lins@intevation.de>
+
+	* doc/conf/themes.xml,
+	  doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml:
+	  Add missing themes for fixation charts.
+
+2012-07-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue705 (names for mainvalues in export).
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java:
+	  Documentation and use NamedMainValues irrespective of WQ-type (
+	  single vs range).
+
+2012-07-06	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  W(t) chart label rotation now working (see #684)
+
+2012-07-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Removed solved TODO.
+
+2012-07-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue710 (crashing diagrams with only one point).
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Expand the range/bounds where its added.
+
+2012-07-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java
+	  (expandPointRange): Fix weird code with help of new ChartHelper
+	  method.
+
+2012-07-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartHelper.java
+	  (expandBounds): New, expand bounds by given percentage.
+
+2012-07-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/Distance.java:
+	  New distance helper module.
+
+2012-07-06	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Remove debugging code.
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Remove HYK references and code.
+
+2012-07-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/datacage-config-manual/datacage-config-manual.tex:
+	  Changed inclusions to include new content file.
+
+	* doc/datacage-config-manual/content.tex: Content from doc/datacage.txt,
+	  xml formatted.
+
+2012-07-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/datacage-config-manual/datacage-config-manual.tex,
+	  doc/datacage-config-manual/README,
+	  doc/datacage-config-manual/title.tex:
+	  Added stub of tex-version of datacage config documentation.
+
+2012-07-05	Christian Lins <christian.lins@intevation.de>
+
+	* doc/*-themes.xml:
+	  Add textorientation field.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartArea.java:
+	  Move annotation related code to base class ChartGenerator.
+
+2012-07-04	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Prevent casting exception.
+
+2012-07-04	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	issue487 (wrong area calculation).
+
+	* src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java:
+	  Fix area calculation.
+
+2012-07-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Moved theme groups to own XML files to improve the
+	  structure.
+
+	* doc/conf/second-themes.xml,
+	  doc/conf/default-themes.xml,
+	  doc/conf/virtual-themes.xml: New XML files for themes / theme groups; each
+	  theme group in one single file.
+
+	* src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java:
+	  Improved logging; print number of theme groups and themes in it as INFO.
+
+2012-07-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Only show labels if enabled in theme. Commented (failed) trials to get the
+	  text rotation right.
+
+2012-07-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Fix certain AIOOBs that were caused by the fact that QWDs can end up in two
+	  different series.
+
+2012-07-03  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Implemented mergeRanges to combine y bounds in timeseries charts.
+
+2012-07-03  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveInfoGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtInfoGenerator.java:
+	  New. Added chart info generator for WQ and delta W(t) chart.
+
+	* doc/conf/conf.xml:
+	  Added info generators to config.
+
+2012-07-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Very basic, unstyled, always-on labels of points in DeltaWt-Diagrams.
+
+2012-07-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Replaced Arrays.asList(new String[] { "a", "b" }).contains("a") code.
+
+2012-07-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/themes.xml,
+	  src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java:
+	  Removed trailing whitespace.
+
+2012-07-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Added missing themes for middle bed height curves.
+
+2012-07-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FlowVelocityAccess.java:
+	  New Access objects to access relevant information of Artifacts specific
+	  to bed heights and flow velocity calculations.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java:
+	  Use *Access objects to get required information from Artifact.
+
+	* src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java: Moved
+	  methods to access specific information for calculations to *Access
+	  objects.
+
+2012-07-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue695 (labeling of waterlines).
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java
+	  (doCrossSectionWaterLineOut): Handle labels more individually.
+
+	* src/main/java/de/intevation/flys/jfree/XYStyle.java
+	  (applyShowLineLabel): Tell renderer that there is something to do in case
+	  any label is switched on.
+
+2012-07-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/DifferenceCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/geom/VectorUtils.java,
+	  src/main/java/de/intevation/flys/artifacts/geom/Lines.java,
+	  src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java,
+	  src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java,
+	  src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationExporter.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/themes/ThemeAccess.java,
+	  src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java:
+	  Fixed various bugs (package declarations, moved classes to correct
+	  places).
+
+2012-07-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Removed line properties from fixation point themes
+	  and added missing point properties.
+
+2012-07-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/ManualPointsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java:
+	  Cosmetics.
+
+2012-07-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	issue654.
+
+	* src/main/java/de/intevation/flys/exports/LegendProcessor.java:
+	  Do not include type in hash for legend item.
+
+2012-07-02	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java:
+	  Generate CSV for facet 'fix_parameters'.
+
+	* src/main/java/de/intevation/flys/exports/AbstractExporter.java:
+	  Be more eloquent on which kind of facet the exporter does not
+	  like.
+
+2012-07-02	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  Made it more symmetrical to FixationCompute.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Removed fake result stuff. Fetch parameters from SQRelationAccess.
+
+2012-07-01	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java:
+	  Remove some evidence that the authors of this software
+	  do not know Java at all.
+
+2012-07-01	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Part of flys/issue687
+
+	* src/main/java/de/intevation/flys/exports/ATWriter.java:
+	  New. Samples fitting function to AT files.
+
+	  !!! Untested and expected to be slightly broken. !!!
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixATWriter.java:
+	  Made some formatting things public to be reusable.
+
+	* 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 for AT headers.
+
+2012-07-01	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/artifact-db.xml,
+	  doc/conf/cache.xml,
+	  doc/conf/meta-data.xml: Removed trailing whitespace.
+
+2012-07-01	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Removed embedded class IdGenerator.
+
+	* src/main/java/de/intevation/flys/utils/IdGenerator.java:
+	  New. Re-added the id generator as top level class.
+
+2012-06-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Added parameter exporter for fixings analysis.
+	Part of flys/issue689
+
+	* src/main/java/de/intevation/flys/exports/fixings/ParametersExporter.java:
+	  New. Exports the contents of the parameters of the fix analysis.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Added visitor interface to visit all rows of the parameters.
+
+	* doc/conf/artifacts/fixanalysis.xml: Added new facet for
+	  parameter export.
+
+	* doc/conf/conf.xml: Register the new parameter exporter.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added facet type.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Fixed indentation.
+	  Removed some programming oddities.
+	  Create facet for parameter export.
+
+	* src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java:
+	  Removed code which is already contained in the base class.
+
+	* src/main/java/de/intevation/flys/exports/AbstractExporter.java:
+	  Cleaned up code.
+
+2012-06-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DeltaWtExporter.java:
+	  Deleted
+
+	* src/main/java/de/intevation/flys/exports/fixings/DeltaWtExporter.java:
+	  Re-added here
+
+	* doc/conf/conf.xml: Adjusted package name of DeltaWtExporter.
+
+2012-06-29	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveInfoGenerator.java:
+	  New. Added chart info companion for FixDerivedCurveGenerator.
+
+	* doc/conf/conf.xml: Added to configuration.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java:
+	  Code clean up.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixFunction.java:
+	  Simplified. Not Serializable any more because its only a transient object.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java:
+	  Clean up. Simplified. Removed dependency from Function2DAdapter because
+	  we are doing our own sampling.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionInfoGenerator.java:
+	  Removed empty last line.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Small cosmetics.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java:
+	  Do not notify listeners when add data series.
+
+	* src/main/java/de/intevation/flys/jfree/Function2DAdapter.java:
+	  Removed. Obsolete.
+
+2012-06-29	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Removed superfluous import.
+
+2012-06-29	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionInfoGenerator.java:
+	  New. Added chart info companion for FixLongitudinalSectionGenerator.
+
+	* doc/conf/conf.xml: Added to configuration.
+
+2012-06-29	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Unfinished work on generalizing annotations in ChartGenerators.
+
+2012-06-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java:
+	  Fixed parameter name.
+
+	* src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_de.properties:
+	  Fixed typo.
+
+2012-06-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/SQRelationAccess.java:
+	  Finished the access to the S/Q relation stuff.
+
+	* doc/conf/artifacts/minfo.xml:
+	  State "state.minfo.sq.periods" returns the value as string
+	  symmetrical to state "state.fix.analysisperiods".
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/DateRange.java:
+	  Deleted.
+
+	* src/main/java/de/intevation/flys/artifacts/model/DateRange.java:
+	  Re-added here because its of use not only in the fix analysis
+	  but also in the S/Q relation.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java,
+	  src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java,
+	  src/main/java/de/intevation/flys/artifacts/access/Access.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Adjusted the imports for the moved DateRange.
+
+2012-06-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/SQRelationAccess.java:
+	  New. Artifact access for the S/Q relation. TODO: Add more parameters.
+
+	* src/main/java/de/intevation/flys/artifacts/access/Access.java:
+	  Remove trailing whitespace.
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java:
+	  Added more debug output.
+
+2012-06-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/Access.java: New.
+	  Base class for *Access of FLYSArtifacts.
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java:
+	  Extends Access now.
+
+2012-06-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java:
+	  Removed dead code.
+
+2012-06-28	Christian Lins <christian.lins@intevation.de>
+
+	* doc/conf/themes.xml,
+	  src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/themes/ThemeAccess.java:
+	  Set text orientation to horizontal for points in Fixation W/Q curve.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Fix overlapping indices of facets.
+
+2012-06-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java:
+	  Added method to figure out which discharge sectors of the
+	  the analysis periods really contains data.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Only emit analysis period / discharge sectors which really contain data.
+
+2012-06-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Moved FixationArtifactAccess into own package access because there are
+	more *Access to come e.g. SQRelationAccess.
+
+	TODO: Refactor the code for WINFO to use this *Access pattern. This
+	results in much cleaner, better scaling and better understandable code.
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java: Deleted.
+	* src/main/java/de/intevation/flys/artifacts/access/FixationArtifactAccess.java: New.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/access,
+	  src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Adjusted imports.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  Removed superfluous imports.
+
+2012-06-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  If fitting fails for tolerance of 1e-10 increase it incremental
+	  by factor of 10 to 1e-3 and only bail out if it fails on this level.
+
+2012-06-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Exp.java:
+	  Fixed da/dQ but the fitting still does not work for the function. :-/
+
+2012-06-27	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Show only dates as point labels.
+
+2012-06-27	Christian Lins <christian.lins@intevation.de>
+
+	* doc/conf/conf.xml:
+	  Fix typo in generator class for fix_longitudinal_section_curve
+
+2012-06-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Create and handle new manual line facets.
+
+	* src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java:
+	  Added new constructor to play nice with upcoming facet-type.
+
+	* src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java:
+	  Added functionality to serve as WaterLineFacet (calculate water
+	  line against cross section profile).
+
+	* src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java:
+	  Extended to generate cross section water line facets, too.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Handle new Facet Type.
+
+2012-06-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	FacetType for upcoming cross_section.manualline facet.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added Facet Type and IS-helper dor upcoming facet.
+
+2012-06-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Configure Themes and compatibility of upcoming
+	cross_section.manualline facet.
+
+	* doc/conf/artifacts/winfo.xml,
+	  doc/conf/artifacts/manualpoint.xml:
+	  Add upcoming facet to compatibility lists.
+
+	* doc/conf/themes.xml: Register theme for upcoming facet.
+
+2012-06-27	Christian Lins <christian.lins@intevation.de>
+
+	* doc/conf/conf.xml:
+	  Add output generator for 'fix_derived_curve'
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Add some ugly formatted point labels.
+
+2012-06-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Moved describe() and the generating of output into FLYSArtifact.
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  This the base class so it should contain common code!
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/FixationArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/ChartArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/MapArtifact.java:
+	  Moved common code into base class.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Removed superfluous imports.
+
+2012-06-27	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Use JFreeUtil.sampleFunction2D() to sample a StyledXYSeries.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java:
+	  Add ctor with addtional custom facet index parameter.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Introduce IdGenerator to generate unique facets IDs within an output,
+	  so themes can now be applied properly to points and lines.
+
+2012-06-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/AttributeParser.java:
+	  Removed some expensive XPath usage. Some quick profiling
+	  showed that up to 7% of our code (excluding Hibernate, H2, Restlet, etc.)
+	  were spend in these XPaths. A lot of time
+
+	  !!! Please, please, dear fellow programmers do not use XPath for fetching
+	  !!! trivial things that are easily accessible via DOM, too!
+
+2012-06-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java:
+	  Refactored to better fit the data types of SQResult.
+
+2012-06-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/LegendProcessor.java:
+	  Removed trailing whitespace.
+
+2012-06-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQ.java:
+	  Added method to validate point.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java:
+	  Added method to callback to re-initialize the function to fit.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java:
+	  New. Shell for fitting of one SQ fraction.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Removed superfluous import.
+
+2012-06-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java:
+	  New. Specialized outlier test for the S/Q relation.
+	  Outliers are accepted in multiples of the standard deviation.
+
+2012-06-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Only generate outlier facet when we done the prepocessing.
+
+2012-06-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Enable legend aggregation in time series charts.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Call super.aggregateLegendEntries.
+
+2012-06-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Legend Item Aggregation refactoring.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java
+	  (aggregateLegendEntries): Moved up from XYChartGenerator to ChartGenerator.
+
+2012-06-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Legend Item Aggregation refactoring.
+
+	* src/main/java/de/intevation/flys/exports/LegendProcessor.java:
+	  New (extracted from XYChartGenerator).
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Extracted legend item aggregation to LegendProcessor.
+
+2012-06-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Removed trailing whitespace.
+
+2012-06-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Minor polish for LegendItem-Aggregation.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Define and use static SPACE Shape.
+
+2012-06-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/InvLogLinear.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvQuad.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvPow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvSQPow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvLogLinear.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java:
+	  Completed inverse stubs.
+
+2012-06-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/FunctionFactory.java:
+	  Register the singletons instead of new objects.
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Pow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvQuad.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/SQPow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvPow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvSQPow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvLogLinear.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java:
+	  Link the functions to there inverses via getInverse().
+
+2012-06-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Implemenation of the inverses of the fitting functions. Needed
+	for the AT export of the calculated curves.
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java:
+	  Added abstract method getInverse() to get the inverse of the
+	  function.
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Pow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/SQPow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Linear.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Log.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Exp.java:
+	  Implements the getInverse() method.
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/InvLog.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvLogLinear.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvQuad.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvPow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvExp.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvSQPow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/InvLinear.java:
+	  Implements the inverses of the function above. Some are still
+	  stubs.
+
+2012-06-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue663 ("step" curves for Q).
+
+	* src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java
+	  (addStepPointsKmQ): New, add "step" points for series.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  Use new StyledSeriesBuilder function.
+
+2012-06-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Fix LegendAggregation; prevent single aggregated legend item to
+	  overflow by splitting it into many, but iconless legenditems.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Fixed typo in I18N key.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Finished I18N.
+
+	* src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java:
+	  Accept callback to label legend items.
+
+	* src/main/java/de/intevation/flys/jfree/ShapeRenderer.java: Added interface
+	  LabelGenerator to create labels for entries.
+
+	* 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 strings.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java:
+	  Removed trailing whitespace.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java:
+	  Removed superfluous imports.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Uses I18N now.
+
+	* src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java:
+	  Added convenience constructor for creating date formatters with strings.
+
+	* src/main/java/de/intevation/flys/artifacts/resources/Resources.java:
+	  Added variadic method format().
+
+	* 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 strings.
+
+2012-06-25  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixLongitudinalSectionGenerator.java:
+	  New. Generator for longitudinal sections in fix analysis.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalDeviationFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalAnalysisFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixLongitudinalReferenceFacet.java:
+	  New. Facets for longitudinal sections chart in fix analysis.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added new facet types.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Add facets for new chart.
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Fixed NPE.
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Added facets to config.
+
+	* doc/conf/themes.xml:
+	  Added new themes.
+
+	* doc/conf/conf.xml:
+	  Added new chart generator.
+
+	* 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-06-25  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Look for the attribut "outline" to render shape outlines in charts.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Add the "outline" attribute.
+
+2012-06-25  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Do not add entries ending with " " to legend.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Prevent that the plot becomes to small if only one point is drawn.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Added debug output about the concrete coeffs found by the fitting.
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Log.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java:
+	  Re-checked the partial deviations to the coeffs. Write the formulas
+	  more human readable.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/ShapeRenderer.java: If a label collides
+	  with a other labels try to draw it on the other side of the point.
+	  This results in more labeled points which is useful because you cannot zoom
+	  in for details in the fixings km chart.
+
+	* src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java:
+	  Paint measured points blue and interpolated green.
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Set background color to white.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Interpolated and measured values where switched.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Label the points in diagram and show if they are interpolated or not.
+
+	* src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java:
+	  New. Extended XYSeriesCollection to cope with QWs
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java: Added formatters
+	  to be fetched only over CallMeta. CallContext are not present in services.
+
+	* src/main/java/de/intevation/flys/java2d/ShapeUtils.java: New. Some code
+	  to handle Shapes.
+
+	* src/main/java/de/intevation/flys/jfree/ShapeRenderer.java: New. Shape
+	  renderer. This is a simplified version of the shape renderer
+	  from fixings analysis in desktop FLYS.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Re-added accidentially removed code.
+
+2012-06-24	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/jfree/StyledXYSeries.java:
+	  Removed trailing whitespace.
+
+2012-06-24	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Removed TODOs about I18N
+
+	* 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 strings for fixing analysis.
+
+2012-06-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	 * src/main/java/de/intevation/flys/utils/KMIndex.java:
+	   OpenJDK javac 1.6.0_24 seems to be more picky about
+	   correct usage of generics.
+
+2012-06-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/add-i18n-numbers.py: New. Script to prefix
+	  the values of property files with a small number to
+	  make the keys identifiable even through the UI.
+
+	  Apply in the same manner as contrib/check-i18n-properties.py
+
+2012-06-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/resources/messages_de.properties,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties:
+	  Repaired inconsistencies.
+
+2012-06-24	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/themes/ThemeFactory.java,
+	  src/main/java/de/intevation/flys/jfree/XYStyle.java:
+	  Add debug logs.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/jfree/StyledXYSeries.java:
+	  Draw the W/Q function as StyledXYSeries.
+
+2012-06-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Re-enable legend entry aggregation, take the threshold from
+	  settings.
+
+2012-06-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartSettings.java:
+	  Parse and set legend aggregation value.
+
+2012-06-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java,
+	  src/main/java/de/intevation/flys/artifacts/model/GaugeFinderFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java:
+	  Removed trailing whitespace.
+
+2012-06-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Added bug output when creating Q sector markers.
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeRange.java:
+	  Added toString() method.
+
+2012-06-22	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Set the aggregation threshold value.
+
+2012-06-22	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java,
+	  src/main/java/de/intevation/flys/collections/OutputParser.java:
+	  Cosmetics, doc.
+
+2012-06-22	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/WstWriter.java:
+	  Cosmetics.
+
+2012-06-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Draw domain markers for borders of Q sectors. There is some kind of glitch
+	  in in the Q sector classifaction code or the db data is strange.
+
+	  Because of the common code basis this affects the fixings calculations, too. :-(
+
+2012-06-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Calculate the standard deviation of the Q sector delta Ws, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java:
+	  Store the standard deviation of the Q sector delta Ws, too.
+	  Indexed 0..3; NaN means the std dev for this sector is not existing.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeRange.java:
+	  added method getSectorBorder(int). With this method you can figure
+	  the three discharge sector borders. Returns NaN if border is
+	  not there. Usage:
+
+	    GaugeFinderFactory ggf = GaugeFinderFactory.getInstance();
+	    GaugeFinder gf = ggf.getGaugeFinder("Elbe");
+	    if (gf == null) { /* FAIL */ }
+	    GaugeRange gr = gf.find(km); // km is the km where you are.
+	    if (gr == null) { /* FAIL */ }
+
+	    double m0 = gr.getSectorBorder(0); // Draw as marker if not NaN
+	    double m1 = gr.getSectorBorder(1); // Draw as marker if not NaN
+	    double m2 = gr.getSectorBorder(2); // Draw as marker if not NaN
+
+	  Labels should be:
+	    '(MNQ+MQ)/2' for m0
+	    '(MQ+MHQ)/2' for m1
+	    'HQ5'        for m2
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeFinderFactory.java:
+	  New. Cache access to per river gauge finders. This very useful
+	  if you want to draw the discharge sectors of river at a given
+	  km into a diagram.
+
+	* doc/conf/cache.xml: Added cache 'gauge-finders'.
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeFinder.java:
+	  Added find(double km) method to find GaugeRange by km.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Uses the instance of the GaugeFinderFactory to access the
+	  gauge ranges.
+
+	* src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java:
+	  Simplified code.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeFinder.java:
+	  New. Moved out of FixingsOverview.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Moved GaugeFinder into top level class.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeRange.java:
+	  New. Moved out of FixingsOverview.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Moved GaugeRange into top level class.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Prevent some NPEs.
+	  !!! This is not a fix for the real problem !!!
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java,
+	  src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Removed superfluous imports.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Range.java:
+	  New. Moved out of FixingsOverview.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Moved Range into top level class.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java,
+	  src/main/java/de/intevation/flys/artifacts/services/FixingsOverviewService.java:
+	  Adjusted imports.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Fixed problem with select the wrong meta data (date, descriptions, etc.)
+	  for a data column.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java:
+	  Fixed stupid i/j switch bug.
+
+2012-06-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Updated i18n.
+
+	* 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 string for delta W(t) chart.
+
+2012-06-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Added attribution for single series styling.
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Skip legend items for interpolated point series.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  Split analysis and reference points into two chart series. Added attribute
+	  for interpolated points for different styling.
+
+	* src/main/java/de/intevation/flys/jfree/Style.java:
+	  Added getter for renderer.
+
+	* src/main/java/de/intevation/flys/jfree/XYStyle.java:
+	  Implemented getter for renderer.
+
+2012-06-21	Christian Lins <christian.lins@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Split fix_sector_average_wq in four facet types, one for each class (_0, _1, ..)
+
+	* doc/conf/themes.xml:
+	  Update themes for WQ curve
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Fix for small issue with sector average points
+
+2012-06-21	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Adapt doAverageSectorOut() to reflect changes in Facet.
+
+2012-06-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added delta W(t) chart in fix analysis.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added facet types for deta W(t) chart.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java:
+	  Changed facet index to determine the sector index and the analysis period
+	  index.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Calculate a facet index including the sector index and the analysis period
+	  index.
+	  Added new facet for delta W(t) chart.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixDeviationFacet.java:
+	  New. Facet to display the standard deviation in delta W(t) chart.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDeltaWtGenerator.java:
+	  New. Generator for the delta W(t) chart.
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Updated facets in outputmodes.
+
+	* doc/conf/conf.xml:
+	  Added output generator to config.
+
+2012-06-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  New methods to add domain and value axis markers to the plot.
+
+2012-06-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DeltaWtExporter.java:
+	  Added reference events to CSV export.
+
+2012-06-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java:
+	  Changed data type from QW[] to QWD[] to have delta Ws in reference events.
+
+2012-06-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  Moved function instantiation to alway have a valid function instance.
+
+2012-06-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Fixed binary search.
+
+2012-06-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Bring binarySearch with epsilon more to source of binarySearch of Collections.
+	  Still not working properly. Why?
+
+2012-06-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Avoid problems with corrected Ws in cross-sections; hacky solution,
+	issue680.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java
+	  (waterLineC): New, get corrected W.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java:
+	  Create C-facet with other index.
+
+2012-06-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Cosmetics, doc.
+
+2012-06-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java:
+	  Cosmetics, doc.
+
+2012-06-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Now respects the selected events and reference period correctly.
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java:
+	  referenceStart and referenceEnd are now melted into referencePeriod.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Add a new filter IdsFilter which is more efficent to check than a
+	  OrFilter with a list of IdFilters inside.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java:
+	  Expose the new IdsFilter to the XML representation in form of
+	  <columns cids="<list of whitespace separated ids"/>
+
+2012-06-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java:
+	  Fixed broken naming of chart curves.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Renamed facets for SQ
+	  relation chart curves.
+
+2012-06-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  Create a compound index value for SQOutlierFacets. This index is based
+	  on the index of the result object (to get the correct data) and the
+	  iteration of the outliers. This compound index is used to make
+	  SQOutlierFacets unique to FLYSCollection's DESCRIBE document.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java:
+	  Parse the index of the result object and the iteration number from index
+	  property.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java:
+	  Added some more debug output.
+
+2012-06-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Create only SQ objects with values > 0. Otherwise JFreeChart will break
+	  during chart creation (values for logarithmic axes have to be > 0).
+
+2012-06-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Adjusted the color of SQ Facets (lines and points)
+	  as shown in examples.
+
+2012-06-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  Create new Facets with proper i18n label.
+
+	* 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 for facet
+	  names.
+
+2012-06-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorA.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorB.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorC.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorD.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorE.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGeneratorF.java:
+	  New concrete chart generators. Each fraction of the SQ relation
+	  calculation has its own generator now. This is because they all have
+	  different chart titles and labels.
+
+	* doc/conf/conf.xml: Let SQ relation charts use more concrete generators.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java:
+	  Implemented getDefaultXAxisLabel() getDefaultYAxisLabel().
+
+	* 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 for chart
+	  titles and axes labels.
+
+2012-06-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue681 (wrong vertical lines in duration curve q-mainvalues on
+	second y-axis).
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Fix vertical line if on second y-axis.
+
+2012-06-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java:
+	  Restrict q-filter facet to the differences case.
+
+2012-06-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/waterlevel.xml: Add Q-facets to compatibility list.
+
+	* src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java:
+	  Add Q-facets to filter facet list.
+
+2012-06-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Removed trailing whitespace.
+
+2012-06-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/JFreeUtil.java: Directly
+	  sample "our" Function objects instead of JFreeChart Function2Ds.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java:
+	  Removed JFreeChart Function2D wrapper and directly use our Function
+	  objects.
+
+2012-06-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Removed superfluous imports.
+
+2012-06-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  Calculate the standard deviation of the delta Ws of the referencen points, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Store the standard deviation of delta Ws of reference points into
+	  a parameters column "std-dev".
+
+2012-06-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/JFreeUtil.java: New function to
+	  sample a Function2D. This method is used, because JFreeChart's
+	  DataUtilities.sampleFunction2D() returns an instance of XYSeries but we
+	  need StyledXYSeries.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java: Added a
+	  method to retrieve parameter values for a list of parameter names.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Create a fake Parameters object for the SQ curve.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java:
+	  Added getMinQ() and getMaxQ() to determine the Q range.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQFunction.java: New
+	  model class that stores a Function and a min and max Q value.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java:
+	  Return a SQFunction instance based on the parameters and Q range of the
+	  SQFractionResult.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java: Use
+	  JFreeUtil's new function sampleFunction2D to create a StyledXYSeries for
+	  the SQ curve.
+
+2012-06-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Store into QWs if they are interpolated.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java:
+	  Stores boolean if the values are interpolated.
+
+2012-06-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/SQPow.java:
+	  Name derivative S'(Q).
+
+2012-06-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Add Q-Facets to compatibility list of dis-c.
+
+2012-06-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Added theme mappings for sq relation fractions b - f.
+
+2012-06-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQResult.java: Renamed
+	  the former SQResult to SQFractionResult. This class is now used to store a
+	  set of SQFractionResults for each SQ calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQFractionResult.java:
+	  Former SQResult.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Create new fake SQFractionResults for fraction A, B and C (used for
+	  testing).
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQMeasurementFacet.java:
+	  Added the 'fractionIdx' property to get to know which fraction should be
+	  represented.
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: Create
+	  Facets for each SQResult and SQFractionResult.
+
+2012-06-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/SQPow.java:
+	  New. S(Q) = a*Q^b
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/FunctionFactory.java:
+	  Registered new function.
+
+2012-06-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQMeasurementFacet.java:
+	  Implemented getData(). It returns the SQ[] of
+	  SQResult.getMeasurements().
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java: Create
+	  proper facet for sq measurements and corrected constructor call of
+	  SQOutlierFacet.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java:
+	  Generalized doSQMeasurementsOut() and doSQOutliersOut() to one single
+	  method doSQOut() which is able to handle SQ[] data.
+
+2012-06-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java: Changed the
+	  default behavior: line labels are not visible if no config option is set!
+
+2012-06-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/conf.xml: Load config of rest server and floodmap over
+	  external entities, too.
+
+	* doc/conf/floodmap.xml, doc/conf/rest-server.xml: New.
+	  External config.
+
+2012-06-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  The reference points are now wrapped in QWDs. This enables the
+	  plotting of Delta W(t) data for the reference points.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java:
+	  Added convenience constructor.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Adjusted.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixFacetUtils.java:
+	  Cosmetics.
+
+2012-06-18	Christian Lins <christian.lins@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Remove fix_analysis_periods_wq from fix_wq_curve facet.
+
+	* doc/conf/themes.xml:
+	  Add fixing themes for other theme groups.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java:
+	  Debug output added.
+
+2012-06-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixFacetUtils.java:
+	  Added vim line, made class public.
+
+2012-06-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/conf.xml: Using external system entities to configure databases.
+	  !!!
+	  !!! FROM NOW ON YOU CAN YOUR conf.xml FROM TRUNK.
+	  !!! Adjust the database credentials via the *-db.xml files
+	  !!! which are included.
+	  !!!
+
+	* doc/conf/artifact-db.xml: New. Configuration for the artifact database.
+	* doc/conf/seddb-db.xml: New. Configuration for the SedDB
+	* doc/conf/backend-db.xml: New. Configuration for the FLYS3 database.
+	* doc/conf/datacage-db.xml: Configuration for the datacage datacage.
+
+2012-06-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java:
+	  Fixed constructor.
+
+2012-06-18	Christian Lins <christian.lins@intevation.de>
+
+	* doc/conf/themes.xml:
+	  Add themes for fixing facets.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java:
+	  Use FixFacetUtils.getMaxQ() to retrieve max Q.
+	  Interpolate km values instead of strict binary search.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixFacetUtils.java:
+	  Added, contains static getMaxQ() method.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Some issues fixed.
+
+2012-06-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Fixed broken color strings.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added new functions
+	  that return colors for points.
+
+	* src/main/java/de/intevation/flys/themes/ThemeAccess.java: Added new
+	  function that returns the color for points.
+
+	* src/main/java/de/intevation/flys/jfree/XYStyle.java: Added new method to
+	  apply the color of points (independent of the specified line color).
+
+2012-06-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Added themes for SQ relation charts
+	  ('sq_a_measurement', sq_a_outlier' and 'sq_a_curve').
+
+2012-06-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixChartGenerator.java:
+	  New. Abstract chart generator for fix analysis. This generator adds the
+	  current km to the context.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Generators now extend the FixCahrtGenerator.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java:
+	  Get the current km from context.
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Removed getter for current km.
+
+2012-06-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/map/PrintMap.java,
+	  src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/SQRelation.java,
+	  src/main/java/de/intevation/flys/artifacts/states/DischargeState.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java,
+	  src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/collections/CollectionDescriptionHelper.java:
+	  Removed repeated x.size() calls from for loops.
+
+2012-06-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Removed superfluous imports.
+
+2012-06-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WWQQJRDataSource.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WQTJRDataSource.java:
+	  Added missing 'else's in if/else ladders.
+
+2012-06-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java:
+	  Fixed string comparision for identity.
+
+2012-06-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/**/*.java: Added missing vim lines.
+
+2012-06-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Removed tabs. Set log level from INFO to DEBUG because this case
+	  is much too common.
+
+2012-06-17	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Comments added.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java:
+	  Logging output added.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java:
+	  Max Q is now determined by parameter.interpolate().
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Use getCurrentKmFromRequest() in output generation.
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Typo in method description.
+
+2012-06-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java:
+	  The getData() method now takes a km parameter to get the data at a specific
+	  km.
+
+2012-06-15  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQ.java: New model to
+	  store values for S/Q.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQResult.java: New
+	  model class that should be used to store calculation results of SQ
+	  relation.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java:
+	  Create a fake SQResult.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java:
+	  Set missing required properties, so that this facet will be able to
+	  re-calculate results again if the results are not in cache.
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  Create correct number of facets for parameter A for outliers Facet.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java:
+	  Create a JFreeChart XYSeries from SQResult's outliers Facet.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Added a
+	  method to create X axes. The SQRelationGenerator overrides this method,
+	  because it requires a logarithmic axis.
+
+2012-06-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Added getter for current km.
+
+2012-06-15  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added
+	  new functions to determine if a Facet is a SQ curve, measurement or
+	  outlier independend of their parameter.
+
+	* src/main/java/de/intevation/flys/exports/sq/SQRelationInfoGenerator.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationGenerator.java,
+	  src/main/java/de/intevation/flys/exports/sq/SQRelationExporter.java:
+	  Stubs for chart and export generators.
+
+	* doc/conf/conf.xml: Registered new output-generators for SQ relation
+	  charts and exports.
+
+	* 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 for CSV
+	  export of SQ relations.
+
+2012-06-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/**/*.java: Removed trailing whitespace.
+
+2012-06-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/conf.xml: Added out commented block for SedDB configuration.
+
+2012-06-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java:
+	  Some code cleanup.
+
+2012-06-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  Added more debug output.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java:
+	  Interpolate the coeffs for the function to be drawn.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Made code more robust for none existing data.
+
+2012-06-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added
+	  new Facets for MINFO SQ relation calculation.
+
+	* doc/conf/artifacts/minfo.xml: Added output for chart and data export for
+	  sq relation calculation. Registered new facets.
+
+	* src/main/java/de/intevation/flys/artifacts/model/sq/SQRelationCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/sq/SQMeasurementFacet.java:
+	  Stubs for calculation and Facets used for SQ relation calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  Override computeAdvance() and implemented a stub for calculation and
+	  Facet creation.
+
+2012-06-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java:
+	  Changed filter string to 'Messstelle'.
+
+2012-06-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java:
+	  Fetch only cross section tracks that have a name 'qps' set for WSPLGEN
+	  calculation.
+
+2012-06-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java:
+	  Use binary search again.
+
+2012-06-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java:
+	  Removed superfluous import.
+
+2012-06-13	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java:
+	  Workaround for IndexOutOfBoundsException.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixDerivedCurveGenerator.java:
+	  Output generator for fixing derived curve.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java:
+	  Use binary search with epsilon again.
+
+2012-06-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java:
+	  Added more debug/warn log statements.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java: Do
+	  not add empty objects into the calculation result.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Take care on empty QWD objects.
+
+2012-06-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java:
+	  Max Q is store in column "max_q" in Parameters now. So function can be plotted
+	  bewtween calculated kms, too.
+	  For function sampling use something like this.:
+
+	    double [] maxQ = parameters.interpolate("km", 42.3", new String [] { "max_q" });
+	    double maxSampleQ = 10000d;
+
+	    if (maxQ != null) {
+	        maxSampleQ = Math.min(2000d, Math.abs(maxQ[0]));
+	        maxSampleQ += 0.05*maxSampleQ;
+	   }
+
+2012-06-13	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Add missing imports and correct coding issues.
+
+2012-06-12	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java:
+	  Use KMIndex.search() (with epsilon) instead of KMIndex.binarySearch().
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Move marker generation to XYChartGenerator.
+
+2012-06-12	Christian Lins	<christian.lins@intevation.de>
+
+	* doc/conf/conf.xml:
+	  Add fix_wq_curve output generator.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java:
+	  Add additional null-checks to prevent NullPointerExceptions when accessing empty
+	  facets.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java:
+	  getMaxQ() now returns constant '1000' until it is properly fixed.
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Code for generating charts more or less complete but untested due to bugs in facets.
+
+2012-06-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Added method double [] interpolate(keyName, key, columnNames).
+	  This construct is better suited for the extraction of
+	  coefficients for building functions. In pseudo code:
+
+	    fitting.Function function =
+		    FunctionFactory.getInstance().getFunction("log");
+
+	    double km = 42.35;
+
+	    double [] coeffs = parameters.interpolate(
+		    "km", km, function.getParamterNames());
+
+	    math.Function f = function.instantiate(coeffs);
+
+2012-06-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java,
+	  src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java:
+	  Removed superfluous imports.
+
+2012-06-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Added interpolate methods that return an array of linear interpolated
+	  values for a given key. Say you have a column named "km" you can call
+	  'values = parameters.interpolate("km", 12)' to fetch a set
+	  of proportional interpolated parameters even if there are only
+	  "km": 10 and "km": 15 in the data structure. Returns null if out of bounds.
+
+2012-06-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml:
+	  Added states and transitions for S-Q-relation.
+
+	* src/main/java/de/intevation/flys/artifacts/states/PeriodsSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/OutliersInput.java,
+	  src/main/java/de/intevation/flys/artifacts/states/SQRelation.java:
+	  New. States for multiple periods input, outliers input and final
+	  S-Q-relation.
+
+	* src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java:
+	  Added name filter for locations.
+
+	* 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 for states.
+
+2012-06-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java:
+	  Fixed broken logger class.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Re-establish old indentation.
+
+2012-06-07	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java:
+	  (doWOut): Interpolate values from WKms.
+
+2012-06-07	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java:
+	  Enable caching.
+
+2012-06-07	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Simplified choice of gauges for discharge c.
+
+	* src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java:
+	  Create better name for facets, minor refactoring, polishing.
+
+	* 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-06-07	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java:
+	  Cosmetics, docs
+
+2012-06-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/PreprocessingSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Use i18n strings.
+
+	* 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-06-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Changed facet description.
+
+2012-06-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java,
+	  src/main/java/de/intevation/flys/utils/FLYSUtils.java:
+	  Cosmetics, doc.
+
+2012-06-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java:
+	  Fix issues, import river, documentation, more debug.
+
+2012-06-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java:
+	  Hard-code state id, instruct computation to result in facets.
+
+2012-06-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
+	  Doc.
+
+2012-06-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added facet for derivate curve and fixed facet names.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixDerivateFacet.java:
+	  New. Facet for derivate curve.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java:
+	  Added name for facet to constructor.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Add one facet for each output using a different name.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added facet names.
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Changed facet names.
+
+2012-06-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/MiddleBedHeightExporter.java:
+	  Trivial doc.
+
+2012-06-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/datacage.txt: More documentation of datacage conf.
+
+2012-06-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added new facet for analysis periods and updated facet names.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisPeriodsFacet.java:
+	  New. Facet for analysis periods. Returns the date ranges for the analysis
+	  periods.
+
+	* doc/conf/artifacts/fixanalysis.xml,
+	  src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added new facet and updated facet names.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java:
+	  Updated facet names.
+
+2012-06-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java:
+	  Minor doc.
+
+2012-06-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/datacage.txt: More documentation of datacage conf.
+
+2012-06-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Implemented facets and splitted up the event facet.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixEventsFacet.java:
+	  Removed.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAnalysisEventsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixReferenceEventsFacet.java:
+	  New. Facets for events.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java:
+	  Implemented getData().
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Add new event facets.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java:
+	  Fixed return value.
+
+2012-06-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/Function2DAdapter.java:
+	  New. Adapter class to brigde de.intevation.flys.artifacts.math.Function
+	  to org.jfree.data.function.Function2D.
+
+	  Function2D objects can be used by org.jfree.data.general.DatasetUtilities
+	  to sample functions into XYDatasets.
+	  See DatasetUtilities.sampleFunction2D()
+
+2012-06-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/datacage.txt: New file that will contain datacage configuration
+	  documentation.
+
+2012-06-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Fixed outputmodes.
+
+2012-06-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  Local variable shadowed instance variable.
+
+2012-06-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Fixed index problem with name of chi^2.
+
+2012-06-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added facets for fix analysis.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixAvSectorFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixWQCurveFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixOutlierFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixEventsFacet.java:
+	  New. Facets for W/Q-Chart in fix analysis. FixAvSectorFacet is implemented,
+	  the others are just stubs.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Add facets to artifact after calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java:
+	  Added method to get the current km for charts. The km is used for
+	  synchronous navigation in fix analysis charts.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added new facet types.
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Added facets to config.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Added some binary search methods. TODO: Sort by column.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DeltaWtExporter.java:
+	  Use new data structures for export.
+
+	* src/main/java/de/intevation/flys/utils/KMIndex.java:
+	  Implements java.lang.Iterable now.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWT.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java:
+	  Removed. Obsolete.
+
+	* src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java:
+	  Removed superfluous import.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java:
+	  Prevent duplicates in analysis periods.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/DateRange.java:
+	  Added equals.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/EpsilonComparator.java:
+	  Removed. Obsolete now.
+
+2012-06-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/JFreeUtil.java:
+	  Improved collision detection.
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Avoid collisions of line labels, documentation.
+
+	* src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java:
+	  Use JFreeUtil.
+
+	* src/main/java/de/intevation/flys/jfree/CollisionFreeLineLabelEntity.java:
+	  New, ChartEntity class for Line labels.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  Store the QWs that are actually used in the fitting as referenced.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Store the referenced QWs for each km. TODO: Use same index structure.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java:
+	  Store the referenced QWs, too.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixResults.java:
+	  Removed. Obsolete.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriodsKM.java:
+	  Removed. Not needed any longer.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Store the AnalysisPeriod per km into FixResult.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java:
+	  Uses KMIndex<AnalysisPeriod []> instead of DeltaWTsKM now.
+
+	* src/main/java/de/intevation/flys/exports/DeltaWtExporter.java:
+	  Commented out old code.
+	  TODO: Rewrite exporter to use AnalysisPeriods.
+
+2012-06-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: Override
+	  endOfLife() to remove files and directories produced for WMS output.
+
+2012-06-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/JFreeUtil.java:
+	  New jfreechart-related utility class.
+
+2012-06-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java:
+	  (getMeterFormat): New.
+	  Doc.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  i18n and formatting for line labels.
+
+2012-06-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Added better doc and TODO.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java:
+	  Now uses the KMIndex for outliers.
+	  TODO: Use KMIndex for DeltaWTs, too.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/KMIndex.java: New.
+	  Serializable index structure to find objects by there km.
+	  TODO: Use in fixings analysis.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/EpsilonComparator.java:
+	  Fixed sign problem in comparison.
+
+2012-06-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Implemented outlier checks in fixings analysis. Expected to be
+	still broken, but the code is in the right place now and has the
+	right structure.
+
+	* src/main/java/de/intevation/flys/artifacts/math/Outlier.java:
+	  Fixed endless loop.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Added further set methods for indexed access.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/Fitting.java:
+	  New. Out factored fitting code from FixCalculation. Checks for outliers, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Moved fitting code out to separate class. Streamlined code a bit.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java:
+	  Store the outliers from fitting in separate data structure, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QW.java: New.
+	  Base class for delta W/t data. Used as storage for outliers.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java:
+	  Is a sub class of QW now.
+
+2012-06-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Store Chi^2 of fitting into result, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Added indexed set method.
+
+2012-05-31	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java:
+	  Added inner class Derivative representing the first derivative of the
+	  function. Can be instantiated with a given set of parameters.
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Log.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Pow.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Linear.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/Exp.java,
+	  src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java:
+	  Added the derivatives of all fitting functions.
+
+2012-05-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Calculate the Delta W/ts +
+	  the average Delta W/ts per Q sector per analysis period.
+	  !!! Very complicated stuff !!!
+	  TODO:
+	  - Store results into the new data structures AnalysisPeriod and
+	    AnalysisPeriods.
+	  - Remove the old DeltaWTsKM and DeltaWT.
+	  - Adjust the facets and the export.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java:
+	  Added convinience constructor.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Added sector filter.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java:
+	  Expose the new sector filter to the fixing overview service. Syntax:
+	  <sector value="<value>"/>
+
+2012-05-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/DateAverager.java:
+	  New. Averages a list of dates preventing overflows.
+
+2012-05-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Added a km filter to find columns which touches a given km.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java:
+	  Expose the new km filter to the fixing overview service. Syntax:
+	  <position km="<value>"/>
+
+2012-05-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Better persistence model for delta w/t calculations. Supports
+	storage of Q sector averages, too. TODO: Use the new model.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/QWD.java:
+	  New. Will be used as a replacement for DeltaWT.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriod.java:
+	  New. Will be used as a replacement for DeltaWTsKM.KM.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/AnalysisPeriodsKM.java:
+	 New. List<AnalysisPeriodsKM> Will be used as a replacement for DeltaWTsKM.
+
+2012-05-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java:
+	  Use DateRange objects now.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/DateRange.java: New.
+	  Model for date ranges. To be used in re-factored persistance model.
+
+2012-05-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Added method to find the Q sector of fixing column for a given km.
+	  Useful to classify fixing events at certain kms.
+
+2012-05-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java:
+	  Fixed access to analysis periods.
+
+2012-05-30  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Changed data fields to a single string data field. The data contains a
+	  string of semi-colon separated 'long' value pairs.
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java:
+	  Process the new data.
+
+2012-05-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java:
+	  trivial doc.
+
+	* src/main/java/de/intevation/flys/themes/ThemeAccess.java:
+	  Removed disturbing comment.
+
+	* src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java
+	  (SimpleAxis): Add ommitted Y_AXIS2 to enum.
+
+2012-05-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	solve issue417: duration curve annotations as line to curve.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java
+	  (createStickyLineAnnotation): New.
+	  Resolved todos, use the line style.
+
+2012-05-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Doc, TODOs added.
+
+2012-05-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Consider theme setting before drawing line to curve.
+
+2012-05-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes.xml: Donate own theme for mainvalues.
+
+2012-05-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Fit from Q to W not from W to Q!
+	  Delta w/t's are now in cm.
+	  Slimmed down fitting error report.
+
+	* src/main/java/de/intevation/flys/exports/DeltaWtExporter.java:
+	  Changed default column header of delta W to cm.
+
+2012-05-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Made Delta W/t calculation work.
+
+	* src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java:
+	  Added toString() method.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsColumn.java:
+	  Fixed problem accessing Ws.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Fixed silly 'name.equals(name)' bug. This mainly prevented delta W/t
+	  computation from working.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java:
+	  More deug code.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  More debug code. Simplified access to data a bit.
+
+	* src/main/java/de/intevation/flys/exports/AbstractExporter.java:
+	  Allow CSV exporter to throw IOExceptions.
+
+	* src/main/java/de/intevation/flys/exports/DeltaWtExporter.java:
+	  More debug output. Flush CSV after writing.
+
+2012-05-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Units of step is in meter and not km. Added more debug output.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Stupidly forgot to add facet to return the delta w/t as CSV.
+
+2012-05-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java:
+	  There was a cast to WINFOArtifact where a cast to FLYSArtifact
+	  is sufficient. This prevented generating error reports that
+	  does not inherit from WINFOArtifact like FixationArtifact.
+
+2012-05-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml,
+	  doc/conf/conf.xml: Added CSV and error report generator/facets.
+
+2012-05-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java:
+	  CrossSectionFactory.isNewest() will return true if the CrossSection is
+	  the only CrossSection found in the database. No IndexOutOfBounds is
+	  thrown.
+
+2012-05-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* Tagged module as '2.7'.
+
+2012-05-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Don't break chart creation if no hyks are existing.
+
+2012-05-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java,
+	  src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java,
+	  src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java:
+	  Removed superfluous imports.
+
+2012-05-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java:
+	  Added getters to access the inner data structures.
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java: Added formatting
+	  support for delta w/t exports of fix analysis.
+
+	* src/main/java/de/intevation/flys/exports/DeltaWtExporter.java:
+	  New. CSV exporter for delta w/ts of fix analysis.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Reordered imports.
+
+2012-05-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FitResult.java:
+	  Removed. Obsolete.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixResult.java:
+	  New. Stores the result of the fixing analysis.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Return the right structure (FixResult) from the calculation.
+
+2012-05-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Fixed stupid index bug.
+
+2012-05-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  Call the computing.
+
+2012-05-25  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/conf.xml: Use the correct Artifacts for wms fixpoints and
+	  floodmaps (they were interchanged).
+
+2012-05-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixResults.java:
+	  New. Stores all results of a fixing analysis.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWTsKM.java:
+	  New. Km indexed container for Delta W/t diagrams.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Create FixResults and DeltaWTsKM now to store the results.
+
+2012-05-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/AttributeParser.java:
+	  Replaced another silly "@attribute" XPATH with direct getAttribute()
+	  call.
+
+2012-05-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Draw line of mainvalues to duration curve hit point to ground.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Also work for q-value case on second y-axis, refactored.
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java:
+	  Doc and fix.Doc and fix.
+
+2012-05-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Also draw lines to curve from q-mainvalues in dur. curve
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java:
+	  In analogy to the W-case, calculate where line from main value hits
+	  a wqday-curve from DurationCurve.
+
+2012-05-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Draw line of w-mainvalue to duration curve hit point to ground.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  If StickyAxisAnnotation has a hit point set, also add line annotation
+	  from the crossing point to the x-axis.
+
+2012-05-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Draw line of w-mainvalue to duration curve, baby version.
+
+	* src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java:
+	  Added field "hitPoint", when a line to a point should be drawn
+	  - leveraging this annotation into the second dimension.
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java:
+	  Calculate where mainvalue hits a duration curve.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  If StickyAxisAnnotation has a hit point set, add line annotation
+	  to hit (the duration) curve.
+
+2012-05-25  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/themes.xml:
+	  Added a warning to not use virtual themes for facets.
+
+2012-05-25  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/themes.xml:
+	  Added concrete themes for maps.
+
+2012-05-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Moved parameter of addAnnotations out, renamed to addVisibleAnnotation.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Adjusted.
+
+2012-05-25  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/themes.xml:
+	  Added concrete themes for areas.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Load mainvalues in reference curves.
+
+	* doc/conf/artifacts/winfo.xml: Add mainvalues to compatibility list
+	  of reference curves; fix typo.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Render mainvalues as annotations.
+
+	* src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java:
+	  Render static wkms data.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Cosmetic.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java,
+	  src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java:
+	  (flipStickyAxis): Allow easy change of sticky axes.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java
+	  (getWaterlevelData): Exception for discharge case.
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java
+	  (getLocations): Exception for discharge case.
+
+2012-05-24  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 667.
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java:
+	  Added data to jfreechart data source.
+
+2012-05-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/services/ThemeListingService.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/HYKArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/AreaArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java,
+	  src/main/java/de/intevation/flys/themes/ThemeGroup.java: Removed
+	  needless imports.
+
+2012-05-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/GeometryUtils.java: Reproject
+	  geometries into the coordinate reference system defined in the
+	  configuration.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Include other "thematic" heights for
+	  reference curve relative points dc conf.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java:
+	  Cosmetics.
+
+	* src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java:
+	  Added TODO.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/relativepoint.xml,
+	  doc/conf/conf.xml: Remove relativepoint artifact remainders, so far
+	  all cases are covered by facet.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java:
+	  Handle reference curve case, slightly refactored.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Handle points in doOut.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java:
+	  Expose data via blackboard.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Serve fixations
+	  with relative points for reference curves.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java
+	  (getReferenceStartKm, getReferenceEndKms): Made public.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Add relative point to compatibility
+	  list of reference curve out.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Remove second facet from
+	  StaticWKmsArtifact from compatibility list of duration curves.
+
+	* doc/conf/themes.xml: Add basic theme for relativepoint.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Serve floodprotections and heightmarks
+	  with relative points for duration curves.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Handle relative points in doOut.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Serve fixations with relative points
+	  for duration curves.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java:
+	  Use superclass static field and method.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java:
+	  Handle duration curve case. Do a linear interpolation of the day.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java:
+	  Be a DataProvider, provide the duration curve and its km.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
+	  (getWAtKmLin): Linear interpolating version of getWAtKm.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/RelativePointFacet.java:
+	  Add (dummy-) implementation of a relative point facet.
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
+	  Use superclass infrastructure. Spawn RelativePointFacet.
+
+	* doc/conf/winfo.xml: Add relativepoint facet to compatibility list
+	  of duration curve out.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Add RELATIVE_POINT Facet Type.
+
+2012-05-23  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java:
+	  Allow instantiation of a function with concrete parameters.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  Enable indexed access to parameter names.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FitResult.java:
+	  New. Bundles the results of the fitting.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/DeltaWT.java:
+	  New. Stores results of Delta W/t calcs.
+
+	* src/main/java/de/intevation/flys/artifacts/model/fixings/FixCalculation.java:
+	  Calculate Delta W/t s, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Make component filters ('and', 'or') more easy to construct.
+
+2012-05-23  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java,
+	  src/main/java/de/intevation/flys/themes/ThemeFactory.java:
+	  Improved startup performance.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java
+	  (getDatacageIDValue): New, extracted from various duplicates.
+
+	* src/main/java/de/intevation/flys/artifacts/HYKArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/AreaArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java:
+	  Use getDatacageIDValue() from superclass or static context.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java:
+	  Define XPath to access "id" value of element coming from datacage-document.
+
+	* src/main/java/de/intevation/flys/artifacts/HYKArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/AreaArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java:
+	  Use xpath defined in superclass.
+
+2012-05-23	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java:
+	  Whitespace-Cosmetics.
+
+2012-05-23  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/relativepoint.xml: New artifact-state-config for upcoming
+	  artifact.
+
+	* doc/conf/conf.xml: Register artifact factory and artifact for
+	  upcoming artifact.
+
+2012-05-23  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/themes/ThemeGroup.java:
+	  New. A theme group takes a set of themes configured in the themes.xml.
+
+	* src/main/java/de/intevation/flys/themes/ThemeFactory.java:
+	  Read the theme groups configured in the themes.xml.
+	  Improved reading the xml file. Thanks to Sascha for the patch.
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Get a theme using the new parameter themegroup.
+
+	* src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java:
+	  Create theme groups while configuring themes.
+
+	* src/main/java/de/intevation/flys/artifacts/services/ThemeListingService.java:
+	  New. This service returns a list with all configured theme groups, each
+	  containing exactly one theme filtered by name.
+	  The theme name has to be provided as parameter.
+
+	* doc/conf/conf.xml:
+	  Added new service to config.
+
+	* doc/conf/themes.xml:
+	  Introduced theme groups and added new group.
+
+2012-05-23  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Repair CS-DC-Conf, allow loading
+	  waterlevels, add fixations and heightmarks.
+
+2012-05-23  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Cosmetics.
+
+2012-05-22  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Allow loading of fixations in cross-sections.
+
+2012-05-22  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java:
+	  More debugging of discharge curve issue.
+
+2012-05-22  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java
+	  (getDischargeCurveData): Moved to more specific class.
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java:
+	  Cosmetics, be louder in miscondition.
+
+2012-05-22  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Allow loading of fixations and thmatic
+	  heights in longitudinal sections, make discharge-curve-misbehavior
+	  testable with trunk.
+
+2012-05-22  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java:
+	  Render discharge outs (was own out once).
+
+2012-05-22  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Allow cross-section stuff in
+	  dischargelongitudinal state.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java:
+	  Add CrossSectionWaterLineFacets, will trigger the cross section output.
+
+2012-05-22  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifact.java:
+	  Added vim line.
+
+	* src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java:
+	  Removed empty line.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Removed invalid/not helpful comments.
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java
+	  (outputExists): Doc.
+
+2012-05-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/ReferencePeriod.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/AnalysisPeriods.java:
+	  Adjusted ui providers to make parameter names unique in client.
+
+2012-05-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Fixed short evaluation problem.
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java:
+	  Added more debuf output.
+
+2012-05-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifactAccess.java:
+	  New. Access the state data of fixings artifacts.
+
+2012-05-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml: Make "start" and "end" parameters
+	  unique in fixings artifact states.
+
+2012-05-21  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/winfo.xml: Extend compatibility lists.
+
+	* doc/conf/conf.xml: Add gaugedischarge factory and artifact.
+
+	* src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/GaugeDischargeState.java:
+	  New, State, Facet and Artifact to access discharge curves of gauges.
+
+	* doc/conf/gaugedischarge.xml: New trivial state model for gaugedis.
+
+2012-05-21  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Allow loading of prev. reference curves.
+
+2012-05-21  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: (yet unused) sceleton for ref-curve dc conf.
+
+2012-05-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* 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 for fix analysis.
+
+2012-05-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/EventSelect.java:
+	  Implemented static data for state.
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Changed transition in 'volmer' states.
+
+
+2012-05-21  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java:
+	  Include km in names of duration curve facets.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Adjusted i18n for
+	  duration curve facet names (now include km).
+
+2012-05-21  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Allow loading of previous duration curves and
+	  fixations in duration curves.
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java:
+	  Take the current km range into account in getOptions().
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java,
+	  doc/conf/artifacts/minfo.xml: Adapted facets for middle bed height. We
+	  now distinguish between epochs and singles.
+
+	* doc/conf/conf.xml: Registered new output generator for middle bed height.
+
+	* doc/conf/themes.xml: Added new themes for middle bed height epoch and
+	  single curves.
+
+	* src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java:
+	  Take the km range into account.
+
+	* src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java:
+	  Create facets for single and epochs.
+
+	* src/main/java/de/intevation/flys/exports/MiddleBedHeightInfoGenerator.java,
+	* src/main/java/de/intevation/flys/exports/MiddleBedHeightGenerator.java:
+	  Chart and info generator for middle bed height charts.
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightData.java:
+	  Added new methods that create names for singles and epochs.
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java: Added number
+	  formatters used to export middle bed heights values.
+
+	* src/main/java/de/intevation/flys/exports/MiddleBedHeightExporter.java:
+	  New exporter for middle bed heights values.
+
+	* doc/conf/conf.xml: Registered new output generator for middle bed height
+	  exports.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: New i18n strings for middle
+	  bed height facets and csv export.
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightData.java:
+	  New model class for storing data for middle bed height exports (chart,
+	  data exports).
+
+	* src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java:
+	  New Calculation that generates new MiddleBedHeightData.
+
+	* src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightFacet.java:
+	  New Facet which is used for middle bed height charts.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added
+	  new facet type for middle bed height curves.
+
+	* src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java:
+	  Calculate middle bed height data using MiddleBedHeightCalculation and
+	  create new facets for charts and csv export.
+
+	* src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java: Added new
+	  methods that return the IDs of selected single bed heights and epoch bed
+	  heights.
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java:
+	  Implemented getOptions() and getLabelFor().
+
+2012-05-16  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Stabilized legend item aggregation.
+
+2012-05-16  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Extensive - although mostly trivial - doc adds.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: Added states and transitions for MINFO
+	  middle bed height calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/states/MultiStringArrayState.java:
+	  New. Nearly a copy of MultiIntArrayState but uses String values.
+
+	* src/main/java/de/intevation/flys/artifacts/states/SoundingsSelect.java:
+	  New subclass of MultiStringArrayState. It will be used for bed heights
+	  selection. We need to do handle the values as string, because singles
+	  and epochs are mixed, so the DB ID is not enough as parameter value.
+
+	* src/main/java/de/intevation/flys/artifacts/states/MiddleBedHeight.java:
+	  New. This state will trigger the calculation for middle bed height in
+	  MINFO module.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/MultiIntArrayState.java:
+	  Do not add a <art:choices> element to the dynamic DESCRIBE but add the
+	  <art:item> directly to <art:select> which allows using default mechanism
+	  in FLYS client.
+
+2012-05-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Replaced event name by its description, which combines the
+	  description of the fixing (= WST file description) and the name
+	  of the column.
+
+	* contrib/fixoverview2html.xsl: Adjusted.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: Added a chart output and relevant facets to
+	  flow velocity state.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added
+	  new facet types for mainchannel, totalchannel and tau of flow velocity
+	  calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FlowVelocityFacet.java:
+	  New Facet that returns FlowVelocityData in getData().
+
+	* src/main/java/de/intevation/flys/artifacts/model/FlowVelocityData.java:
+	  Added new methods that return xy points for mainchannel, totalchannel and
+	  tau.
+
+	* src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java:
+	  Create new mainchannel, totalchannel and tau Facets for each
+	  FlowVelocityData instance retrieved by FlowVelocityCalculation.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Commented
+	  legend aggregation out.
+
+	* src/main/java/de/intevation/flys/exports/FlowVelocityInfoGenerator.java,
+	  src/main/java/de/intevation/flys/exports/FlowVelocityGenerator.java: New
+	  chart generator for flow velocity data and its info generator.
+
+	* doc/conf/conf.xml: Registered the chart and chart info generator for flow
+	  velocity data.
+
+	* doc/conf/themes.xml: Added new themes for mainchannel, totalchannel and
+	  tau of flow velocity calculation.
+
+	* 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 for flow
+	  velocity facets.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/MultiIntArrayState.java:
+	  Add a 'label' attribute to each <data> element in the static DESCRIBE.
+	  In addition to that, the <data> element created in this class can have
+	  multiple <item> elements which consist of a 'value' and a 'label'
+	  attribute. This 'label' attribute is taken from getLabelFor() which is
+	  abstract and needs to be implemented by subclasses.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DischargeState.java:
+	  Implemented the abstract method getLabelFor().
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_de.properties: New i18n strings for MINFO
+	  parameter names.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: New i18n strings for MINFO
+	  states.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/FlowVelocityExporter.java:
+	  Append the name of a location for the km row which is provided by
+	  FLYSUtils.getLocationDescription(km);
+
+	* 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 for flow
+	  velocity CSV export headers.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: Added new state and csv export for MINFO flow
+	  velocity calculation.
+
+	* doc/conf/conf.xml: Registered a new CSV exporter for flow velocity
+	  values.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FlowVelocityCalculation.java:
+	  New calculation for MINFO flow velocity. Actually, this is no
+	  calculation but a bundling of data.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FlowVelocityData.java:
+	  New model class that is used to store flow velocity relevant data.
+
+	* src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java:
+	  New state that triggers the FlowVelocityCalculation and creates new
+	  facets. Currently, only a CSV Facet is created.
+
+	* src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java: Added
+	  methods to retrieve the IDs of main channels and total channels for the
+	  flow velocity calculation.
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java: New formatters
+	  that are used in CSV exporter for flow velocity.
+
+	* src/main/java/de/intevation/flys/exports/FlowVelocityExporter.java: New
+	  concrete subclasses of AbstractExporter that currently implements the
+	  path to export FlowVelocityData as CSV.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/HYKArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java:
+	  Removed getDataAsDouble() which is now implemented in FLYSArtifact.
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  Implemented getDataAsDouble(). This method will return a Double based on
+	  a given parameter name.
+
+2012-05-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Changed data type for state 'eventselect'.
+
+2012-05-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/FixationArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/QSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/ReferencePeriod.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationVolmerCompute.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/PreprocessingSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationPeriod.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/GaugeRange.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/LocationSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/AnalysisPeriods.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryPolyArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSGaugeLocationArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Removed superfluous imports.
+
+2012-05-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Adjusted state data fields.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/ReferencePeriod.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/PreprocessingSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/AnalysisPeriods.java:
+	  Implemented states.
+
+2012-05-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java:
+	  Fixed constructor. Descriptions are now available.
+
+2012-05-15  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: Added new transistions and states for
+	  MINFO flow velocity calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/states/MultiIntArrayState.java:
+	  New abstract states that might be used to append a list of available
+	  integer values to the DESCRIBE document.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DischargeState.java:
+	  Concrete subclass of MultiIntArrayState which implements the abstract
+	  method getOptions().
+
+2012-05-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Parameters.java:
+	  New. Model for storing fitting results in cache.
+
+2012-05-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java:
+	  Removed the computeFeed() method that created Facets for discharge
+	  curves to make this state ready to use in MINFO calculations.
+
+2012-05-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/minfo.xml: New Artifact configuration for module
+	  MINFO.
+
+	* src/main/java/de/intevation/flys/artifacts/MINFOArtifact.java: New
+	  Artifact for module INFO.
+
+	* src/main/java/de/intevation/flys/artifacts/states/CalculationSelectMinfo.java:
+	  New. The state is used for choosing the calculation in module MINFO.
+
+	* doc/conf/conf.xml: Registered the MINFO Artifact.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: New strings for states and
+	  calculations.
+
+2012-05-13  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Removed unused code.
+
+2012-05-13  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Doc.
+
+2012-05-13  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Allow duration_curve.q loading via datacage.
+
+2012-05-11  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Allow hyk loading also when in non-
+	  recommendation mode.
+
+2012-05-11  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Improved middle height calculations for waterlevels.
+
+	* src/main/java/de/intevation/flys/artifacts/geom/Lines.java
+	 (area): Improved or even corrected area calculation.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Corrected middle height calculated, have a very verbose label for
+	  the time being.
+
+2012-05-11  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Somewhat improve area calculation during line computation.
+	Still faulty.
+
+	* src/main/java/de/intevation/flys/artifacts/geom/Lines.java
+	 (fillWater): Piecewise calculate area in more cases.
+
+2012-05-11  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Tackle water-through-mountain issue that exists since r4099.
+
+	* src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java
+	  (addPoints): Add parameter that decides whether or not to skip NaNs.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java:
+	  Set new parameter to StyledSeriesBuilder.addPoints calls.
+	  For waterlines it is important that NaNs stay included!
+
+2012-05-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WMSGaugeLocationArtifact.java:
+	  New Artifact for storing geometries for gauges.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added
+	  a new facet type for WMSGaugeLocationArtifact 'floodmap.gaugelocation'.
+
+	* doc/conf/artifacts/winfo.xml,
+	  doc/conf/artifacts/map.xml: Added 'floodmap.gaugelocation' facet to the
+	  list of valid facets for map and floodmap output.
+
+	* doc/conf/conf.xml: Added a factory for creating
+	  WMSGaugeLocationArtifacts.
+
+	* doc/conf/themes.xml: Added a theme for 'floodmap.gaugelocation' facets.
+
+	* doc/conf/meta-data.xml: Added a datacage section for gauge locations to
+	  the floodmap and map section.
+
+2012-05-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added
+	  new facet types 'floodmap.hydr_boundaries' and
+	  'floodmap.hydr_boundaries_poly'
+
+	* doc/conf/artifacts/winfo.xml,
+	  doc/conf/artifacts/map.xml: Registered 'floodmap.hydr_boundaries' and
+	  'floodmap.hydr_boundaries_poly' for floodmap and map output types.
+
+	* doc/conf/conf.xml:
+
+	* doc/conf/themes.xml: Added themes for 'floodmap.hydr_boundaries' and
+	  'floodmap.hydr_boundaries_poly'.
+
+	* doc/conf/meta-data.xml: Improved datacage configuration specific to
+	  floodmaps and maps.
+
+	* src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryPolyArtifact.java:
+	  New artifacts to save information about hydrological boundaries.
+
+	* src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java:
+	  Moved the methods getRiverId() and getTitle() into WMSDBArtifact.
+
+2012-05-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/mapserver/wsplgen_layer.vm,
+	  doc/conf/mapserver/shapefile_layer.vm: Added a 'PROJECTION' section.
+
+2012-05-10  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/geom/Lines.java:
+	  Minor refactoring, doc.
+
+2012-05-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/mapserver/layer.vm: Added a 'PROJECTION' section.
+
+2012-05-10  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/geom/Lines.java:
+	  Minimal doc, TODO.
+
+2012-05-10  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Fix issue620: synchron navigation at impossible kms.
+
+	* src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java
+	  (searchCrossSectionLine): Do not return a CrossSectionLine if there
+	  is none found within 1km.
+
+2012-05-10  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Minimal cosmetics.
+
+2012-05-10  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Preparations for fix issue620: Synchron navigation on non-existing km.
+
+	* src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java
+	  (getData): Return empty lines if no cross section found.
+
+2012-05-09  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Display mittlere hoehe (which is not yet calculated).
+
+	* doc/conf/themes.xml: Added theme prop to display middlere hoehe or not.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java:
+	  (parseShowMiddleHeight): New, parse the new theme prop.
+
+	* src/main/java/de/intevation/flys/artifacts/geom/Lines.java:
+	  (fillWater, ListWithArea): Return new type wich also contains area.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Respect new theme prop and adjust label if set.
+
+2012-05-09  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Beginning of calculation of Mittlere Hoehe: area calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java:
+	  Adjusted to LineData constructor.
+
+	* src/main/java/de/intevation/flys/artifacts/geom/Lines.java
+	  (area): New, calculate area of a polygon.
+	  Added todos where area calculation code paths are missing.
+
+2012-05-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/meta-data.xml: Moved the hws layers out to an own node.
+
+	* src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java: Moved the
+	  'name' property from WMSCatchmentArtifact to WMSDBArtifact.
+
+	* src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java: Create
+	  more specific filter and extent that takes the 'name' into account.
+
+2012-05-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/meta-data.xml: Moved the catchments out to an own node.
+
+	* src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java:
+	  Parse the name of required catchments fetch name specific catchments
+	  only.
+
+2012-05-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/map.xml: Added the 'floodmap.floodmaps' facet to the
+	  list of valid facets of the 'map' output.
+
+	* doc/conf/themes.xml: Renamed the 'Line' theme used for floodmaps to
+	  'FloodmapLines'.
+
+2012-05-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/mapserver/db_layer.vm: Added a PROJECTION section which is
+	  filled by the LayerInfo object.
+
+	* src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java: Added
+	  a 'srid' property.
+
+	* src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Set the
+	  'srid' property of all LayerInfo objects.
+
+2012-05-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  Changed state data and added new state.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation/QSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/EventSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationPeriod.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/GaugeRange.java:
+	  Modified states and added new state for concrete event selection.
+
+2012-05-04	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes: Add text-bg properties to  Area style.
+
+	* src/main/java/de/intevation/flys/themes/ThemeAccess.java
+	  (TextStyle.apply): Apply text bg theme-properties to renderer.
+
+	* src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java:
+	  Cosmetics.
+
+	* src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java:
+	  Added field to store labels background color, calculate arithmetic
+	  middles of polygons, to put label there (improves situation slightly).
+
+2012-05-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java
+	  (parseShowArea): parse show area field of theme.
+
+	* src/main/java/de/intevation/flys/themes/ThemeAccess.java
+	  (TextStyle.apply): Be applicable to StableXYDifferenceRenderers.
+
+	* src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java:
+	  Apply setting from theme to renderer.
+
+	* src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java:
+	  Simplified area calculation (always calculate). Added getters and
+	  setters for text for label style, respect most of that.
+
+2012-05-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes: Let Area style not inherit from colorlines (as labels
+	  work slightly different. Enable showarea property. Comment dupe Lines.
+
+2012-05-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java
+	  (doArea): Add Lines.LineData datatype to areable data types.
+
+2012-05-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes.xml: Add two new options for waterlevel label in cs.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java:
+	  Parse new theme properties.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Adjust label according to chosen properties.
+
+2012-05-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java
+	  (parseShowLineLabelBG): parse show line label bg field of theme.
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Respect show line label bg setting of theme.
+
+	* src/main/java/de/intevation/flys/jfree/XYStyle.java:
+	  Apply setting from theme to renderer.
+
+2012-05-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Added a 'helpText' field to each state.
+	  The 'helpText' field represents in this case a message in the i18n
+	  resources which should be a link to a online help page.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DefaultState.java:
+	  Append the 'helpText' to the DESCRIBE document.
+
+	* 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 links to help text in
+	  the FLYS wiki.
+
+2012-05-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Use the colors specified in theme document for linelabel.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java:
+	  New methods to find colors specified for linelabels.
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Store and use background and foreground color for linelabels.
+
+	* src/main/java/de/intevation/flys/jfree/XYStyle.java:
+	  Communicate colors of linelabels to renderer.
+
+2012-05-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Actually use the font specified in theme document for linelabel.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java:
+	  Fixed paths for linelabel-related fields in theme doc.
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Set font for linelabel.
+
+2012-05-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes.xml: No default background show for linelabels.
+
+2012-05-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	  * src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java:
+	    Cosmetic, added annotation.
+
+2012-05-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Parse font for linelabels, do not use it yet.
+
+	* doc/conf/themes.xml: Add more theme properties related to linelabels.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java
+	  (parseTextSize, parseLineLabelSize): New and slightly refactored.
+	  (parseLineLabelFont): New.
+	  (parseTextStyle, parseLineLabelStyle): New and slightly refactored.
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java
+	  (setLineLabelFont, getLineLabelFont): New, accessors to
+	                                        linelabelfont field.
+
+	* src/main/java/de/intevation/flys/jfree/XYStyle.java
+	  (applyLineLabelFont): New.
+
+2012-05-02	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java:
+	  Make it compile again after signature change in backend.
+
+2012-04-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Doc.
+
+2012-04-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/geom/Lines.java:
+	  Added local class LineData and return it to also include
+	  Length of lines.
+
+	* src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java:
+	  Changed signature of interfaces getWaterLines.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java:
+	  (getWaterLines): adjusted signature.
+
+	* src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java:
+	  Adjusted to return type of Lines.createWaterLines.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Include length in label (stub).
+
+	* src/main/java/de/intevation/flys/jfree/HasLabel.java:
+	  New interface.
+
+	* src/main/java/de/intevation/flys/jfree/StyledXYSeries.java:
+	  Implement new HasLabel interface.
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Take into account that StyledXYSeries are HasLabel.
+
+2012-04-26  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Initial transition configuration and artifact/state stubs for fixation
+	analysis.
+
+	* doc/conf/artifacts/fixanalysis.xml:
+	  New. Initial transition configuration.
+
+	* doc/conf/conf.xml:
+	  Added artifact and factory entry to config.
+
+	* src/main/java/de/intevation/flys/artifacts/FixationArtifact.java:
+	  New. Stub with initial implementation.
+
+	* src/main/java/de/intevation/flys/artifacts/states/fixation,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/QSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/ReferencePeriod.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationVolmerCompute.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/PreprocessingSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationPeriod.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FunctionSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/GaugeRange.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/LocationSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/AnalysisPeriods.java,
+	  src/main/java/de/intevation/flys/artifacts/states/fixation/FixationCompute.java:
+	  New. Stubs for fixation states.
+
+	* 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-04-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/geom/Lines.java:
+	  Add method to calculate length of water lines.
+
+2012-04-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Most of issue454: Label waterlevels.
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java
+	  (drawSecondaryPass): Use correct label for lines.
+
+2012-04-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java
+	  (showSeriesMinimunX, showLineLabel): Renamed field.
+	  (isShowLineLabel, setShowLineLabel): Added getters and setters for
+	                                       showLineLabel field.
+	  (drawSecondaryPass): Respect showLineLabel field, draw static text
+	                       as placeholder for real label (stub).
+
+	* doc/conf/themes.xml: Define theme prop 'showlinelabel' for Lines.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java: Parse theme
+	                                                         theme prop.
+
+	* src/main/java/de/intevation/flys/jfree/XYStyle.java: Apply showline
+	                                                       theme prop.
+
+2012-04-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+          Cosmetics, doc.
+
+2012-04-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/Outlier.java:
+	  Gah! Checked in out dated version.
+
+	* src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java:
+	  Removed superfluous imports.
+
+2012-04-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/Outlier.java:
+	  New. Simple Grubb's outlier test. Needs testing. ;-)
+
+2012-04-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java
+	  (isMinimumX): Implemented minimum finding for x in analogy to the ones for
+	  y values. Stub to label dataset curves in plot.
+
+2012-04-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Cosmetics, added doc, TODO and an OPTIMIZE.
+
+2012-04-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java:
+	  Make it cross platform.
+
+2012-04-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java:
+	  Make it compilable.
+
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 657.
+
+	* src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java:
+	  New. Service to upload a file as base64 string embedded in xml structure.
+
+	* src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java:
+	  Extract shape files from zip archive and move them to artifact directory.
+	  Add the user shapefile as parameter for wsplgen calculation.
+
+	* src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java:
+	  Remove the artifact directory on step back.
+
+	* src/main/java/de/intevation/flys/utils/MapfileGenerator.java,
+	  src/main/java/de/intevation/flys/exports/MapGenerator.java:
+	  Create layer to display the uploaded shapefile.
+
+	* src/main/java/de/intevation/flys/wsplgen/FacetCreator.java:
+	  Create a facet to output the user defined layer.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added type for user shape file.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java:
+	  Resized array for '-lin' parameter.
+
+	* doc/conf/artifacts/winfo.xml:
+	  Added facet to diplay user defined shapefile.
+
+	* doc/conf/conf.xml:
+	  Added file upload service.
+
+	* 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 string.
+
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 560.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WSPLGENLayerFacet.java:
+	  New. Facet for WSPLGEN layers.
+
+	* src/main/java/de/intevation/flys/wsplgen/FacetCreator.java:
+	  Create a new WSPLGEN facet when creating uesk layers.
+
+	* src/main/java/de/intevation/flys/utils/MapfileGenerator.java,
+	  src/main/java/de/intevation/flys/exports/MapGenerator.java:
+	  Use WSPLGENLayerFacet to create uesk layer.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java:
+	  Switch back to false as return value in isQueryable().
+
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 560.
+
+	* src/main/java/de/intevation/flys/utils/MapfileGenerator.java:
+	  Generate WSPLGEN-Layer with its own template and set the layertitle to
+	  an i18n string.
+
+	* src/main/java/de/intevation/flys/exports/MapGenerator.java:
+	  Call createUeskLayer with a CallContext.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java:
+	  Set queryable to true.
+
+	* doc/conf/mapserver/wsplgen_layer.vm:
+	  New. Template for WSPLGEN-Layer.
+
+2012-04-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Removed superfluous imports.
+
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/themes.xml:
+	  Added mapping for manual points in historical discharge chart.
+
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Fixed duplicated legend entry for manual points.
+
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 494.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Create manual points with text annotations in time charts.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Add manual points to the chart.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added historical discharge to chart types.
+
+	* doc/conf/artifacts/winfo.xml,
+	  doc/conf/artifacts/manualpoints.xml:
+	  Added manual points facet to output modes.
+
+2012-04-17	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/fixoverview2html.xsl: Render optional check boxes.
+	  Use different font. TODO: Move to client,
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Ignore hours and seconds.
+
+2012-04-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 528, 637
+
+	* src/main/java/de/intevation/flys/artifacts/model/WWQQJRDataSource.java:
+	  Added fields for new columns.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Added columns for 'W at gauge' and fixed column header.
+
+	* 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 filenames for new pdf export templates.
+
+2012-04-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/jasper/reference_gauge_end.jasper,
+	  doc/conf/jasper/reference_gauge.jasper,
+	  doc/conf/jasper/reference_gauge_start_end.jasper:
+	  Small fixes in pdf templates.
+
+2012-04-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 528, 637.
+
+	* doc/conf/jasper/reference_gauge.jasper,
+	  doc/conf/jasper/reference_en_gauge.jasper:
+	  Modified templates.
+
+	* doc/conf/jasper/reference_gauge_end.jasper,
+	  doc/conf/jasper/reference_gauge_start_end.jasper,
+	  doc/conf/jasper/reference_en_gauge_end.jasper,
+	  doc/conf/jasper/reference_en_gauge_start_end.jasper:
+	  New. Templates for reference curve pdf export.
+
+2012-04-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 528, 637.
+
+	* doc/conf/jasper/reference.jasper,
+	  doc/conf/jasper/reference_en.jasper:
+	  Fixed column header.
+
+	* doc/conf/jasper/reference_gauge.jasper,
+	  doc/conf/jasper/reference_en_gauge.jasper:
+	  New.
+
+2012-04-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/check-i18n-properties.py: Checked in unsaved version. :-/
+
+2012-04-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 656.
+
+	* src/main/resources/messages_en.properties:
+	  Added missing i18n strings.
+
+2012-04-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/check-i18n-properties.py: New. Script to check inconsistencies
+	of i18n properties files: Detects duplicates and keys not defined in other
+	properties files. Usage:
+
+	$ find -name messages\*.properties | \
+	  xargs contrib/check-i18n-properties.py
+
+2012-04-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Generate error message when more than one Q is found for given
+	  Q in "W auf freier Strecke".
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation.java:
+	  Added feature to adopt problems from other reports.
+
+	* 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 for the error message.
+
+2012-04-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/WQSelect.java:
+	  Use factor to calculate steps in range input mode.
+
+2012-04-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/cache.xml: Increased number of fixings columns a bit.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsColumnFactory.java:
+	  Corrected misspelled cache name. Added bebug output.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverviewFactory.java:
+	  Added debug output.
+
+2012-04-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Small fixes: The service works as expected but there seems
+	  to be a caching issue.
+
+2012-04-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Generate chart and deliver the image as the response of the service.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsColumnFactory.java:
+	  Return null when looking for a fixing data column that does not exist.
+
+2012-04-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsColumnFactory.java:
+	  Load ws and qs from database. Cache the fixings columns.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsColumn.java:
+	  Removed column id and added q values.
+
+	* doc/conf/cache.xml: Added cache for the columns of the fixings.
+
+2012-04-05  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Fix for 'W free' validation and theme names.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java:
+	  Append the current Q values to theme name if the previous theme has
+	  the same name.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WQSelect.java:
+	  Use the start km to get min/max W values in distance mode and use the
+	  first km to get min/max W values if in location mode.
+
+2012-04-05  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 499.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WQSelect.java:
+	  Added validation for 'W free' using WstValueTable min/max values.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Added getter for WstValueTable.
+
+2012-04-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Defined a theme for WSPLGEN layers.
+
+	* src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java:
+	  Made style creation more robust against nullpointers and added an
+	  Expression class.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added a static
+	  method createWSPLGENStyle() and some helpers to create a WSPLGEN style.
+
+	* src/main/java/de/intevation/flys/exports/MapGenerator.java,
+	  src/main/java/de/intevation/flys/utils/MapfileGenerator.java: Methods
+	  for creating the WSPLGEN layer now take a style document.
+
+2012-04-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  Extract parameters from input xml and fetch fixings filters and overview
+	  to find the columns to be viewed.
+	  TODO: Generate chart.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsColumn.java: Added
+	  boolean result to indicate if value comes from table or is interpolated.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsColumnFactory.java:
+	  New. Factory to fetch fixings column data from cache or database. Stub by now.
+
+2012-04-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java:
+	  New. Service to generate a chart of fixings for given river and km applied
+	  some filters.
+
+	  Usage:
+	     $ curl http://localhost:8181/service/fixings-km-chart \
+	       -d @fix-overview.xml > chart.png
+
+	  The input XML is nearly the same as for the overview service.
+	  Besides the river, filters and range it accepts elements
+	  <km value="..."/>                  for passing the river km,
+	  <extent width="..." height="..."/> for the extent of the output chart,
+	  <mime type="..."/>                 for type of result. Currently ignored.
+
+	  ATM only a static fixed sized PNG image is delivered.
+
+	* doc/conf/conf.xml: Added service to list of services.
+
+2012-04-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Made bullet proof for null filters and ranges.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java:
+	  Fixed bug which leeds to always generating a null range filter.
+
+2012-04-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java:
+	  Squashed performance bug introduced in rev4070, which slowed down
+	  CSV export about 245 times!
+
+	* src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java:
+	  Added debug output about savings when joining neighbored nodes.
+
+2012-04-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsOverviewService.java:
+	  Removed the code for filter building.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsFilterBuilder.java:
+	  New. Now contains the code for filter building. This useful because other
+	  services like the "Fixierungs-Rohdaten am KM" service need this filtering, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Refactored the code to obtain a filtered list of fixings columns without
+	  the XML serialization, too. The "Fixierungs-Rohdaten am KM" service
+	  does not need the overview data but the ids of the fixing columns to be
+	  displayed.
+
+2012-04-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/CacheInvalidationService.java,
+	  src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java,
+	  src/main/java/de/intevation/flys/artifacts/services/FLYSService.java:
+	  Derive from XMLService now.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Removed superfluous import.
+
+2012-03-30  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue460 (W-Differenzen: Frühere Berechnungen aus den Datenkorb werden doppelt geladen)
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Removed
+	  code to find out all Outputs of this Artifacts. A method getOutputs()
+	  had been implemented some time ago that does exactly this work.
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Heavy
+	  bugfix! Adding the current state id to the list of previous state ids
+	  for temporary usage was no good idea! Now, the list of previous state
+	  ids only modifified in advance(). This solves the problem of having
+	  duplicated Outputs in the Artifact's DESCRIBE document.
+
+2012-03-29  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue366 (W-INFO / Abflusskurve, Diagramm: Umbenennen von Themen und Anzeige im Diagramm)
+
+	* src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Use description from ArtifactAndFacet objects for JFreeChart Series
+	  creation.
+
+2012-03-28  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue362 (W-Info / Abflusskurve, Diagramm)
+
+	* doc/conf/themes.xml: Adjusted text color of w and q main values for
+	  computed discharge curves.
+
+2012-03-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	  flys/issue639: Bezugsliniendiagramm,Achsen-Intervall-Skalierung vereinheitlichen
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Render only axis ticks in meters.
+
+2012-03-22	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes.xml: Let hyks have a text orientation in themes.
+
+2012-03-22	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue491, if area fill between curve and axis, draw not only
+	to zero.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java
+	  (doArea): Add an artificial dataset to set lower bounds for area.
+
+	* src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java
+	  (addPoints): New convenience method to be used in future.
+	  (createGroundAtInfinity, createCeilingAtInfinity): Create artificial
+	  datasets for better areas.
+
+2012-03-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 506.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Create the date from long values instead of the year.
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java:
+	  Added method to transform a String into an array of long values.
+
+	* doc/conf/artifacts/winfo.xml:
+	  changed data type from intrange to longrange.
+
+2012-03-20  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue544 (Historische ATs: Eingabeunterstützung W/Q)
+
+	* src/main/java/de/intevation/flys/artifacts/services/GaugeInfoService.java:
+	  New service that returns information for gauges based on a specified
+	  river.
+
+	* doc/conf/conf.xml: Registered the GaugeInfoService.
+
+2012-03-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/DischargeInfoService.java:
+	  Skip DischargeTables that have no time interval set or that are marked
+	  as master DischargeTable.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Skip
+	  DischargeTables that have no time interval set.
+
+2012-03-20  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue146 (In WINFO Diagramm Abflusskurve raus, wenn nicht gewünscht)
+
+	* doc/conf/artifacts/winfo.xml: Do not create outputs for discharge curves
+	  at gauge any longer.
+
+2012-03-20  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue252 (W-INFO: Wasserspiegellagenberechnung / Mitführung der Jährlichkeiten in der Diagramm-/Ergbnisausgabe)
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Added
+	  the numeric value of a selected named main value to the WST column name.
+
+2012-03-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/mapserver/db_layer.vm: Set the FILTER expression into double
+	  quotes (") instead of single quotes (') which allows single quotes in
+	  expressions.
+
+	* doc/conf/meta-data.xml: Moved the floodmaps from kilometrage to its
+	  parent folder.
+
+	* src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java:
+	  Fixed broken filter expression and set geometry type (MapServer does not
+	  know a 'MULTIPOLYGON').
+
+2012-03-16  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Remove unnecessary outputs from attributes instead of copying outs to
+	  new attribute element.
+
+2012-03-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* Tagged module as 'pre2.7-2012-03-16'.
+
+2012-03-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Removed useless imports.
+
+2012-03-16  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue523 (W-INFO / Bezugslinienverfahren / Linieneinstellungen / Min+Max anzeigen)
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Improved the look of the minimum and maximum shape of a series. They are
+	  now rectangles with a darker fill color as the line color is.
+
+2012-03-15  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue522 (W-INFO / Bezugslinienverfahren / Schriftgröße der Achsenbeschriftung)
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Label and
+	  tick label fonts for axes will now always be the same.
+
+	* src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java:
+	  Removed the createYAxis() method which is already implemented in an
+	  upper class. There, the method also takes the ChartSettings into account.
+
+2012-03-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 547.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java:
+	  Use date format with MEDIUM style.
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java:
+	  Added date format with MEDIUM style.
+
+2012-03-15  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartHelper.java: Added a new
+	  method that returns the Bounds for a given XYDataset. Based on the
+	  concrete type of the XYDataset, the call is dispatched to a more specific
+	  method.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Removed the whole "range" stuff and some methods that are implemented in
+	  upper classes.
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java: Removed the
+	  setXRange() and setYRange() methods. In our own code, we will use Bounds
+	  instead of JFreeChart's Range instances to save range/bounds information.
+	  This is necessary to save information which is not not from type double
+	  (which is the case in Timeseries charts).
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Replaced
+	  usage of Range with Bounds in the whole class.
+
+	* src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Adapted the method signature of zoom() and zoomX().
+
+2012-03-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Copied the adjustAxes() method from XYChartGenerator which enables axes
+	  label font sizes.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Removed unnecessary axes creation method which is implemented in upper
+	  classes.
+
+2012-03-14  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 640.
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Remove all unnecessary output settings from attributes.
+
+2012-03-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial for flys/issue358, rough stub for legenditem aggregation.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Added rough stub for legend aggregation.
+
+2012-03-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Fixed broken XML syntax.
+
+2012-03-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/meta-data.xml: Modified the datacage structure of 'floodmaps'.
+
+2012-03-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java: New.
+	  This Artifacts allows loading 'floodmaps'.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added a
+	  new Facet type "floodmap.floodmaps" which are created by
+	  WMSFloodmapsArtifact.
+
+	* doc/conf/artifacts/winfo.xml: Registered the "floodmap.floodmaps" facet
+	  for "floodmap" output.
+
+	* doc/conf/conf.xml: Registered the new WMSFloodmapsArtifact.
+
+	* doc/conf/themes.xml: Added a theme for the "floodmap.floodmaps" facet.
+
+	* 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 string for
+	  "floodmap.floodmaps" title.
+
+2012-03-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/meta-data.xml: Improved datacage configuration to serve
+	  floodmaps.
+
+2012-03-05  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue566 (ÜSK: Formalien in der Parametrisierung)
+
+	* src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java:
+	  Override getLabelFor() method to return better I18N strings for selected
+	  floodplain option.
+
+	* 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 options
+	  for floodplain (active/inactive) and adapted a german I18N string.
+
+2012-03-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue 528 for csv.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Fixed column order, reworked todos.
+
+2012-03-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Fixed column order.
+
+2012-03-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Stub to export the "W (cm)" column conditionally on Gauge presence.
+
+2012-03-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/StepCSVWriter.java:
+	  New utility to handle csv rows of more "dynamical" length.
+
+2012-03-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/StepCSVWriter.java:
+	  New utility to handle csv rows of more "dynamical" length.
+
+2012-03-01	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue501 (manual points have two legend entries).
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Respect wish to not have a legend entry.
+
+2012-03-01	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue636 (cross-section: name of waterlevel facets).
+
+	* src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java:
+	  Corrected name for waterlevel facets.
+
+2012-03-01	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial fix flys/issue615 (datacage: events for fixations).
+
+	* doc/conf/meta-data.xml: Adjusted to make loading single events
+	  possible.
+
+2012-03-01	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial Dontcrash on flys/issue647 (NaNs from WstValueTable interpolation).
+
+	* src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java:
+	  Do not add data pairs where a NaN is present.
+
+2012-03-01	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java:
+	  Cosmetics, doc.
+
+2012-02-27  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Added functions to be used for fitting in
+	the "Fixierungsanalyse" and "Extremwertermittlung".
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/Function.java: New.
+	  Abstract base class for functions to fit. Provides the name of the function,
+	  a short description, the names of the parameters and an initial parameter guess
+	  for the fit processe. Sub classes have to overwite the function evaluation and
+	  the partial derivative of the function in respect to the parameters.
+
+	  TODO: Add a meachnism for the inverse function (needed for AT export) and
+	  the first derivative (needed for the respective diagram).
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/FunctionFactory.java:
+	  New. Factory to fetch a function by its name.
+
+	 * src/main/java/de/intevation/flys/artifacts/math/fitting/Exp.java: New.
+	   exp: W(Q) = m * a^Q + b
+
+	 * src/main/java/de/intevation/flys/artifacts/math/fitting/Quad.java: New.
+	   quad: W(Q) = n*Q^2 + m*Q + b
+
+	 * src/main/java/de/intevation/flys/artifacts/math/fitting/Linear.java: New.
+	   linear: W(Q) = m*Q + b
+
+	 * src/main/java/de/intevation/flys/artifacts/math/fitting/LogLinear.java: New.
+	   log-linear: W(Q) = a*ln(m*Q + b)
+
+	 * src/main/java/de/intevation/flys/artifacts/math/fitting/Log.java: New
+	   log: W(Q) = m*ln(Q + b)
+
+	 * src/main/java/de/intevation/flys/artifacts/math/fitting/Pow.java: New.
+	   pow: W(Q) = a*Q^c + d
+
+	   !!! This power function is new in the pool of functions to be fit. !!!
+	   See my mail "Manuelle Punkte in der Fixierungsanalyse" 2011-10-27 for details.
+	   The function exp-new found in the old FLYS function pool is omitted
+	   because it is worthless and was maybe never used.
+
+	* src/main/java/de/intevation/flys/artifacts/math/fitting/App.java: New.
+	  Small test driver to check if the fitting is working. The points to
+	  fit are read from stdin the function to fit is determined by the
+	  system property 'function'. Example usage:
+
+	    $ mvn -e \
+	    -Dfunction=linear \
+	    -Dexec.mainClass=de.intevation.flys.artifacts.math.fitting.App exec:java <<EOF
+	    357.390696917 7546.72096163
+	    61.4291036312 1334.54835721
+	    799.962128234 16836.7698076
+	    126.52761023 2703.69789985
+	    900.448553398 18955.0578748
+	    EOF
+
+2012-02-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages_de.properties:
+	  Added ommitted translations.
+
+2012-02-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	fix flys/issue638.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java
+	  (doArea): Ract to WKms as upper/lower area data again.
+
+2012-02-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial fix flys/issue637.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java,
+	  src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Modified translations.
+
+2012-02-21  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	 * src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	   - Calculate the extent of the river by the extents of the fixings.
+	   Reason: The river Elbe has only has fixings up to km 351. The other half
+	   of the river is empty which results in a sparse looking overview.
+	   - Add the name of the river as name attribute to resulting <river> element.
+
+	 * contrib/fixoverview2html.xsl: New. Demo XSL transformation to turn
+	   the output of the overview service directly into HTML. Used in the
+	   client a variant of this script could be used for producing the content
+	   of the assistance widget. Usage:
+
+	   $ curl http://localhost:8181/service/fixings-overview \
+	     -d @fix-overview.xml |                              \
+	     xsltproc contrib/fixoverview2html.xsl -             \
+	     > fixings-overview.html
+
+2012-02-20  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsOverviewService.java:
+	  Made the filter mechanisms available via the incoming XML document.
+
+	  1 - range: Simply add a <range from="..." to="..."/> element next to the
+	      <river> element. Optional. Defaults to full extent.
+
+	  2 - filters: Add a <filter> element next to the <river> element.
+	      Optional. Defaults to accepting all.
+	      The <filter> element can contain the following elements:
+
+	        <column cid="..."/>: Creates an IdFilter.
+	        <date when="..."/>: Creates a DateFilter.
+	        <date-range from="..." to="..."/>: Creates a DateRangeFilter.
+	        <sector-range from="..." to="..."/>: Create a SectorRangeFilter.
+	        <not>...</not>: Creates a NotFilter. The nested element is negated.
+	        <and>...</and>: Create an AndFilter: The nested elements are 'and'ed.
+	        <or>...</or>: Create an OrFilter: The nested elements are 'or'ed.
+
+	  These filters need testing!
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Made date format a public constant.
+
+2012-02-20  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Added a filter mechanism for generating output.
+
+	  There are two kinds of filters:
+
+	  1 - A range. Defaults to [-Double.MAX_VALUE, Double.MAX_VALUE]
+	      The resulting sectors are cut to this range. Sectors outside
+	      this range are omitted.
+
+	  2 - column filters: Given a fixing column they can decide to keep
+	      or not to keep it. Following filters exist:
+
+	      - IdFilter: Keep column if column id matches.
+	      - DateFilter: Keep column if column date matches.
+	      - DateRangeFilter: Keep column if column date is in range.
+	      - SectorRangeFilter: Keep colum if one of its q sectors is in given range.
+	      - NotFilter: Negates another nested filter.
+	      - AndFilter: Keep column if all nested filters accept column.
+	      - OrFilter: Keep column if at least one of the nested filters accepts it.
+
+2012-02-20  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  Refactored to build the Q sectors once at construction time and not
+	  every time output is generated.
+	  This will ease the job of applying filters to the Overview.
+
+2012-02-19  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	  Service to generate the data needed to build the "Fixerungen pro Fluss Uebersicht"
+
+	* src/main/java/de/intevation/flys/artifacts/services/FixingsOverviewService.java:
+	  New. A service that serves an XML overview version of the fixings of a given river.
+
+	  The input documents look like this:
+
+	    <?xml version="1.0" encoding="UTF-8"?>
+	    <fixings>
+	      <river name="Saar"/>
+	    </fixings>
+
+	  The output documents looks like this:
+
+	  <?xml version="1.0" encoding="UTF-8"?>
+	  <fixings>
+	    <river from="0.0" rid="1" to="93.0"/>
+	    <events>
+	      ...
+	      <event cid="85" date="29.01.1995 00:00" name="Fixierungen/0-93_1988-2001.wst">
+	        <sector class="0" from="82.7" to="92.85"/>
+	      </event>
+	      <event cid="86" date="13.11.1996 00:00" name="Fixierungen/0-93_1988-2001.wst">
+	        <sector class="2" from="0.0" to="50.599999"/>
+	        <sector class="1" from="50.6" to="65.89"/>
+	      </event>
+	      ...
+	    </events>
+	  </fixings>
+
+	  The <river> element contains the extent of the whole river
+	  and its db id.
+	  The <events> sections contains serveral <event> elements.
+	  They have a meassure date, db id, a name and a number of <sector>s.
+	  These sectors are q classified from/to ranges. Classes are:
+
+	  0: smaller (MNQ+MQ)/2
+	  1: (MNQ+MQ)/2 to (MQ+MHQ)/2
+	  2: (MQ+MHQ)/2 to HQ5
+	  3: greater HQ5
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java:
+	  New. Cacheable instance of the overview.
+	  TODO: Apply a filter mechanism when generating the output.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FixingsOverviewFactory.java:
+	  New. Fetched the fixing overviews from cache if configured.
+
+	* doc/conf/conf.xml: Added the service.
+	* doc/conf/cache.xml: Configured the cache for the fixing overviews.
+
+2012-02-17  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(getMinMaxQ):
+	  Argh! Forget to check in the range method.
+
+2012-02-17  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(getMinMaxQ):
+	  Symmetrical to getMinMaxW() add two methods to find min/max Q for a given
+	  km or a range. The range method is maybe a bit slow.
+
+2012-02-17  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(getMinMaxW):
+	  Added signature to give w extend for a given km range.
+
+2012-02-17  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(getMinMaxW):
+	  Added method to find the w extent for a given km. Useful
+	  for validating "W auf freier Strecke".
+
+	* src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java:
+	  Removed superfluous import.
+
+2012-02-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WQSelect.java,
+	  src/main/java/de/intevation/flys/utils/FLYSUtils.java,
+	  doc/conf/artifacts/winfo.xml:
+	  Renamed state data fields: wq_mode      -> wq_isq
+	                             wq_free      -> wq_isfree
+	                             wq_selection -> wq_isrange
+
+2012-02-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java:
+	  Write the description instead of the Q value to CSV file.
+
+	* src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java:
+	  Added parameter to overriden method.
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java:
+	  Get Qs without range.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Adjusted i18n string for CSV metadata.
+
+2012-02-17  Ingo Weinzierl <ingo@intevation.de>
+
+	Part II/III flys/issue497 (Diagrammeigenschaften in Zeitseriendiagrammen)
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Apply legend specific settings (show/hide).
+
+2012-02-17  Ingo Weinzierl <ingo@intevation.de>
+
+	Part I/III flys/issue497 (Diagrammeigenschaften in Zeitseriendiagrammen)
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Moved
+	  adjustPlot() from XYChartGenerator to ChartGenerator which enables the
+	  TimeseriesChartGenerator to call this method as well.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Call adjustPlot() in generateChart() to apply the settings specific to
+	  gridlines in the timeseries plot.
+
+2012-02-16  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Refactored the wq data fields.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WQSelect.java:
+	  Changed the wq data fields to boolean values.
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java:
+	  Changed the wq data fields to boolean values and added method that
+	  returns the km input mode.
+
+2012-02-16  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation4.java:
+	  Fixed W->Q conversion for "W fuer ungleichwertige Abflusslaengsschnitte."
+
+2012-02-16  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue509 (Dauerlinie: Q-Achse sollte bei 0 beginnen)
+
+	* src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Set the lower bounds of the Q axis to 0 to avoid displaying negative
+	  discharge values.
+
+2012-02-16	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WKms.java:
+	  (guessWaterIncreasing): Removed from interface.
+
+2012-02-16	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue150 (exposure of gravitational anomalies)
+
+	* src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WKms.java:
+	  (guessWaterIncreasing): In analogy to W->WQ->WQKms defined and
+				  implemented.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  (needInvertAxis): Changed Parameter type to WKms (was WQKms).
+	  (doW): Use in this case weaker wkms cast to find out whether axis
+		 has to be inverted.
+
+2012-02-15  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java: Fixed
+	  SQL statement to fetch hyk formations for rivers with 'km_up' = 0.
+
+2012-02-14  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Another partial fix for flys/issue499: Do the W to Q conversions
+	needed for "W am Pegel" correctly.
+
+	* src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java:
+	  Repaired getQsForW(): The mapping from W to Q is not unique! There
+	  could be more then one Q having the the same W.
+	  Ws are not strictly monoton/sorted so doing a binary search on this
+	  is just a fail. We now scan them linearly.
+
+	  XXX: The whole class is mess. The scaling stuff is a stupid
+	  and there is no caching.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Fetch the master discharge table for converting Ws to Qs. Handle
+	  the case that there are more Qs for a given W.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java,
+	  src/main/java/de/intevation/flys/artifacts/model/Calculation4.java:
+	  Adjusted to new semantic.
+
+2012-02-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial Fix flys/issue500: text-orientation for texts.
+
+	* doc/conf/themes.xml: Change default text orientation for text
+	  annotations.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Minor cosmetics.
+
+	* src/main/java/de/intevation/flys/themes/ThemeAccess.java:
+	  Parse and apply text rotation field.
+
+2012-02-13  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Partial fix for flys/issue499 (Wasserspiegellagen: Berechnung für W frei und Pegel kaputt)
+	There are still validation issue in the client.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Fixed state evaluation for "W auf freier Strecke"/"W am Pegel".
+	  There is still an issue in the client with the input validation
+	  which prevents entering the right W values for
+	  "W auf freier Strecke". :-/
+
+2012-02-13  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Make it compilable again.
+
+2012-02-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial Fix flys/issue500: text-backgrounds for manual points.
+
+	* doc/conf/themes.xml: Added text-related style items to manual
+	  point themes.
+
+2012-02-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial Fix flys/issue500
+
+	* src/main/java/de/intevation/flys/themes/ThemeAccess.java:
+	  Parse whether to show text background. Apply to textannotation.
+
+2012-02-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue490
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Pass artifact and facet for doAnnotation.
+
+2012-02-10  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java:
+	  Use AddScaleFunction instead of LinearFunction.
+
+	* src/main/java/de/intevation/flys/artifacts/math/AddScaleFunction.java:
+	  New. f(x) = m*(x+b). I know its aequivalent to m*x + m*b but it
+	  makes more clear that the datum [m] (PNP) is substracted before the
+	  scaling to cm is done.
+
+2012-02-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Bugfix: take
+	  care on empty ArtifactAndFacet objects in doAnnotations().
+
+2012-02-10  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java:
+	  Inherits from ReferenceCurveGenerator now which really simplifies it a lot.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Added to methods to be overwritten by sub classes.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Adjusted i8n.
+
+2012-02-10  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java:
+	  Indexed access to getInCm.
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java:
+	  Simplified. Do not provide any data to blackboard. Only side effect the
+	  call context.
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Added convinience method to i18n string with defaulting to key name.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Label the axis according the scale types of the data.
+	  TODO: Let the NormalizedReferenceCurveGenerator be a sub class of
+	  this.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: i18n for the reference curve axes.
+
+2012-02-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java:
+	  Fixed wrong double array dimension for PDF exports and write correct
+	  differences into PDF.
+
+2012-02-10	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java:
+	  Adjust function to deliver data provider ('blackboard') keys.
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java:
+	  Change the way we exploit the blackboard-mechanism. TODOs added.
+
+2012-02-10  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	  Argh! Finally found the stupid bug in the W~W relation:
+	  Used iQ1 index on W2(Q2).
+
+2012-02-10  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	  Improved error messsages even more.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Adjusted messages.
+
+2012-02-10  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java:
+	  Forget to put new created WWAxisType onto blackboard.
+
+2012-02-10  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java:
+	  Adjust offset of linear function by same factor as the values.
+
+2012-02-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: Write
+	  correct min and max values for date axes into the info document.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Enabled zooming for timeseries charts.
+
+2012-02-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/Bounds.java,
+	  src/main/java/de/intevation/flys/jfree/TimeBounds.java,
+	  src/main/java/de/intevation/flys/jfree/DoubleBounds.java: Added a method
+	  applyBounds(ValueAxis, int) that might be used to adapt the range of the
+	  axis to the bounds adding a space to the left and right.
+
+2012-02-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java: Defined
+	  new abstract methods for setting and getting Bounds. Modified and
+	  renamed getValueAxisRange(). This method is now called
+	  getValueAxisRangeFromRequest() and returns no longer a Range object but
+	  a String array that consists of the raw string values speicified in the
+	  request document.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Implemented the missing method getDomainAxisRange(). This method returns
+	  a Range object based on the String array returned from
+	  getValueAxisRangeFromRequest().
+
+2012-02-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/TimeBounds.java: Added new
+	  methods getLowerAsDate() and getUpperAsDate(). The toString() method
+	  will now return a string that contains a human readable date string.
+
+	* src/main/java/de/intevation/flys/jfree/DoubleBounds.java: Made 'lower'
+	  always be smaller than 'upper' in the default constructor.
+
+2012-02-10  Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	  Give more precise message when an error occurs in W~W relation.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Improved error messages.
+
+2012-02-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java: Modified
+	  and renamend getDomainAxisRange(). This method is now called
+	  getDomainAxisRangeFromRequest() and returns no longer a Range object but
+	  a String array that consists of the raw string values specified in the
+	  request document.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Implemented the missing method getDomainAxisRange(). This method returns
+	  a Range object based on the String array returned from
+	  getDomainAxisRangeFromRequest().
+
+2012-02-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartHelper.java: Added a
+	  helper function to determine the min and max bounds (x and y) for
+	  TimeSeriesCollections.
+
+2012-02-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/TimeBounds.java,
+	  src/main/java/de/intevation/flys/jfree/DoubleBounds.java: Removed
+	  useless imports.
+
+2012-02-10  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WW.java:
+	  Add accessors to relative heights.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Add relative heights (to gauge) to csv export.
+
+2012-02-09  Ingo Weinzierl <ingo@intevation.de>
+
+	* pom.xml: Added dependency to GeoTools swing module.
+
+	* src/main/java/de/intevation/flys/artifacts/map/PrintMap.java: Standalone
+	  demo application to print WMS layers to file.
+
+2012-02-09  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/TimeBounds.java,
+	  src/main/java/de/intevation/flys/jfree/DoubleBounds.java,
+	  src/main/java/de/intevation/flys/jfree/Bounds.java: New model classes that
+	  should be used for adapting axes ranges later.
+
+2012-02-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation5.java:
+	  Generate a valid intial i18n name.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java:
+	  Pass call context to calculation.
+
+2012-02-09  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue485 (Themen können umgenannt werden, dies wird nicht in der Legende reflektiert)
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Use ArtifactAndFacet.setFacetDescription() to set the description for
+	  themes which are stored in the Collection's XML attribute.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	* src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Some refactoring of doXXXOut() methods. We pass the ArtifactAndFacet
+	  objects of doOut() into those concrete doOut() methods which allows us to
+	  generate series names for chart curves.
+
+2012-02-09  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Replaced dashes by underscores in entities
+	  to ease translation.
+
+2012-02-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Fixed problem with including Y-Zeros.
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Removed superfluous imports.
+
+2012-02-09  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Allow points in "new chart"s.
+
+	* doc/conf/artifacts/chart.xml: Added manualpoint facets to
+	  compatibility lists.
+
+2012-02-09  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/Style.java: New. A Style object
+	  needs to implements a method applyTheme() which takes a
+	  XYLineAndShapeRenderer.
+
+	* src/main/java/de/intevation/flys/jfree/XYStyle.java: New. This subclass of
+	  Style modifies the XYLineAndShapeRenderer specified in applyTheme().
+
+	* src/main/java/de/intevation/flys/jfree/StyledSeries.java: New. This
+	  interface defines two methods getStyle() and setStyle() to adjust and
+	  retrieve the Style of a series.
+
+	* src/main/java/de/intevation/flys/jfree/StyledTimeSeries.java: New.
+	  Implementation of StyledSeries that subclasses JFreeChart's TimeSeries.
+
+	* src/main/java/de/intevation/flys/jfree/StyledXYSeries.java: Removed the
+	  code for adapting a XYLineAndShapeRenderer. Instead of implementing this
+	  stuff in StyledXYSeries itself, this instance now implements StyledSeries
+	  and stores an instance of XYStyle.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Create new instances of StyledTimeSeries now which enables styling in this
+	  chart.
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java: Enabled
+	  styling of series for all series that implement StyledSeries.
+
+2012-02-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(relateWs):
+	  Be more conservative about arrays and indices in "Bezugslinienverfahren".
+
+2012-02-09  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Allow areas in new chart/longitudinal_section.
+
+	* doc/conf/artifacts/chart.xml: Added area facet to compatibility
+	  list.
+
+2012-02-09  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue490. Allow CollisionFree..Annotations to collide with
+	non-collision-free annotations.
+
+	* src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotationEntity.java:
+	  New, to take advantage of cheap instanceof operator.
+
+	* src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java:
+	  Only avoid collisions with members of same family (i.e. allow
+	  collision with annotations of other types).
+
+2012-02-09  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Added themes for historical discharge curves and
+	  the differences to a reference curve.
+
+2012-02-09  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Some
+	  bugfixes and improvements:
+	  1) take only historical discharge tables into account for calculation
+	  2) use the correct values for computing differences
+	  3) moved timerange preparation into an own method
+
+2012-02-09  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/EnterMultipleLocationsState.java:
+	  Fix call to StringUtils.join .
+
+2012-02-09  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* 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 string for waterlevels (from datacage).
+
+2012-02-09  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/EnterMultipleLocationsState.java:
+	  Locale-format multiple double values also.
+
+2012-02-09  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Registered a new facet for difference curves
+	  to the historical discharge output.
+
+	* src/main/java/de/intevation/flys/artifacts/model/HistoricalWQTimerange.java:
+	  New model that is able to store a further double value "diff" besides a W,
+	  Q and a Timerange.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Create
+	  new HistoricalWQTimerange instances with difference between the reference
+	  discharge table and the historical discharge tables.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: New type
+	  for historical differences.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java: Cast
+	  Timerange array in getTimeranges().
+
+	* src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeDifferenceFacet.java:
+	  New Facet for historical discharge difference curves.
+
+	* src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java:
+	  Create new Facets for the difference curves if the processed data are from
+	  type HistoricalWQTimerange.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Added doOut() path for difference curves.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java:
+	  Increased the size of a double array to be able to get results from
+	  HistoricalWQTimerange.
+
+	* 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 translation for warning
+	  if no reference discharge table was found for the specified gauge.
+
+2012-02-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added PDF export to reference curve calculation.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Added PDF export.
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java,
+	  doc/conf/artifacts/winfo.xml:
+	  Add facet for PDF export to state.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WWQQJRDataSource.java:
+	  New. Datasource for JasperReports containing reference curve data.
+
+	* 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 for JasperReports template file and calculation mode.
+
+	* doc/conf/jasper/reference.jasper,
+	  doc/conf/jasper/reference_en.jasper:
+	  New. Templates for reference curve PDF export.
+
+2012-02-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java(getReferenceEndKms):
+	  Prevent duplicates in end kms for reference curve calculation.
+
+2012-02-09  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  doc/conf/artifacts/winfo.xml: Renamed data item names to allow
+	  translations.
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java:
+	  Give (Normalized)ReferenceCurveFacets are more appropriate
+	  description (to be seen in client).
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Prepare Reference curves to eat multiple locations as 'Ziel'.
+
+	* src/main/java/de/intevation/flys/artifacts/states/EnterLocationState.java:
+	  Cosmetics.
+
+	* src/main/java/de/intevation/flys/artifacts/states/EnterMultipleLocationsState.java:
+	  New. State to provoke multi_location_panel.
+
+	* doc/conf/artifacts/winfo.xml: Made end state of ref curves a (new)
+	  EnterMultipleLocationState.
+
+2012-02-08  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue483 (Historische Abflusstafeln ohne Ergebnis)
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Add
+	  a problem for the calculation report if no discharge tables were found
+	  for the given timerange.
+
+	* 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 translation for error
+	  messages created by Calculation6.
+
+2012-02-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java:
+	  Format kms in error reports at least with one digit after
+	  the decimal separator.
+
+2012-02-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Fix flys/issue468 (Fehler beim Projekt-Duplizieren)
+
+	* src/main/java/de/intevation/flys/exports/ReportGenerator.java:
+	  Always create a new XML document when calling report generation.
+	  XXX: There is a bug somewhere which calls error reporting twice
+	  when cloning a collection. Speculation: It has something to do with
+	  the settings stuff.
+
+	* src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Remove superfluous imports.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WSPLGENCalculation.java:
+	  Added missing Override annotation.
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java:
+	  Handle Manual Point Facets, added TODO.
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java:
+	  Subclass BlackboardDataFacet to repair areas over cross sections.
+
+2012-02-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Let text
+	  and line annotations placed at x or y axes always be in foreground.
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue474 (manual points in reference curves).
+
+	* doc/conf/artifacts/winfo.xml,
+	  doc/conf/artifacts/manualpoints.xml:
+	  Add manualpoints to lists just so that really everybody knows.
+
+	* doc/conf/themes.xml: Add styles for manual points in ref curves.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Add ref curve chart types.
+
+	* src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Handle manual point facets.
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial Fix flys/issue474.
+
+	* 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 translation for
+	  normalized_reference_curve.
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue475.
+
+	* doc/conf/themes.xml: Register theme for reference_curve_normalized.
+
+2012-02-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java: Add a "/" to the
+	  URL of the user wms if the URL configured in conf.xml doesn't end with
+	  a "/".
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue472.
+
+	* doc/conf/themes.xml: Added theme for discharge_curve manualpoints.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added discharge_curve as chart type.
+
+2012-02-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Fix flys/issue484 ((i18n: Ungleichwertige... Report))
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Fixed key spelling.
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue478 (Manuelle Punkte: Stil nicht änderbar).
+
+	* doc/conf/themes: Map correct theme to manualpoint themes.
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial fix flys/issue472 .
+
+	* doc/conf/artifacts/winfo.xml: Add manual points to compatibility
+	  list of cross_sections.
+
+	* doc/conf/artifacts/manualpoints.xml: Add manualpoints to list of
+	  generated facets.
+
+2012-02-08  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes.xml: Commented styling option for show area until
+	  area calculation works.
+
+2012-02-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation.java:
+	  i18n the km of the error report.
+
+	* src/main/java/de/intevation/flys/artifacts/resources/Resources.java:
+	  Fixed potential race conditions.
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java: Added
+	  formatter for error report kms.
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveExporter.java:
+	  Removed superfluous imports.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Commented out some imports. They are used be out commented code.
+
+2012-02-07  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java:
+	  Use the correct km key for an unspecific km for fetching the whole river
+	  annotations.
+
+2012-02-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/conf.xml: Added missing config of chart info generator
+	  of normalized reference curve.
+
+2012-02-07  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/conf.xml: Fixed wrong chart info generator name for historical
+	  discharge curves.
+
+2012-02-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added PDF export for historical discharge curve calculations.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java:
+	  Implemented PDF export for calculation results.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQTJRDataSource.java:
+	  New. Datasource for JasperReports.
+
+	* doc/conf/artifacts/winfo.xml:
+	  Added facet for PDF export to historical discharge curve output mode.
+
+	* 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 for historical discharge curve export.
+
+	* doc/conf/jasper/historical-discharge.jasper,
+	  doc/conf/jasper/historical-discharge_en.jasper:
+	  New. Templates for JasperReports PDF creation.
+
+2012-02-07  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Handle WWQQs, extended CSV export of reference curves.
+
+2012-02-07  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/DurationCurveExporter.java,
+	  src/main/java/de/intevation/flys/exports/WaterlevelExporter.java,
+	  src/main/java/de/intevation/flys/exports/AbstractExporter.java:
+	  Recactored, moved Formatter accessors to base class AbstractExporter.
+
+2012-02-07  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Let reference curve calculation result in specific WWQQ, extended CSV
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java
+	  (getWW,getWWQQ): Renamed and changed result type.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation5.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java:
+	  Result in WWQQs, not in WWs.
+
+2012-02-07  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	  Log error as warning.
+
+2012-02-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/math/LinearFunction.java:
+	  New. Linear function f(x) = m*x + b.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java:
+	  Do the normalizing. Cascading functions is not required.
+
+2012-02-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveInfoGenerator.java:
+	  Added missing chart info generator for the normalized reference curves.
+
+2012-02-06  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_de.properties: Fix i18n.
+
+2012-02-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java:
+	  Added optional boolean flag to indicated if the data should be 'normalized'.
+	  TODO: Build the cascading normalising function call chain.
+
+	* src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Fetch WWAxisTypes from call context to do the right scaling.
+
+2012-02-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added service for discharge infos at a specific gauge.
+
+	* doc/conf/conf.xml: Added service factory entry.
+
+	* src/main/java/de/intevation/flys/artifacts/services/DischargeInfoService.java:
+	  New. Returns description, start year and end year of discharges at a
+	  specific gauge.
+
+	* src/main/java/de/intevation/flys/artifacts/states/GaugeTimerangeState.java:
+	  Return a more specific ui provider string.
+
+2012-02-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/conf.xml: Registered generator for normalized reference curves.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added "reference_curve_normalized".
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java:
+	  Added facets for normalized reference curves.
+
+	* src/main/java/de/intevation/flys/exports/NormalizedReferenceCurveGenerator.java:
+	  Generator for normalized reference curves.
+
+2012-02-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Added config for "reduzierte Bezugslinie".
+
+2012-02-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Added error report.
+
+2012-02-06  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: Set
+	  proper bounds for date axis elements; tell the transformation matrix which
+	  type it is (number/date).
+
+2012-02-06  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Include location description string in csv output of referencecurve-
+	  exporter.
+
+2012-02-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WW.java: Added constructor call.
+	* src/main/java/de/intevation/flys/artifacts/model/WWQQ.java: New.
+	  Stores the Qs for the Ws, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation5.java: Create
+	  WWQQs instead of WWs.
+
+2012-02-06  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Added further i18n stubs and slightly more data.
+
+2012-02-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java(relateWs):
+	  Return the Qs of the Ws, too.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation5.java:
+	  Adjusted to cope with the return Qs. TODO: Create WQWQ or WWQQ dataset
+	  for storing the result.
+
+2012-02-06  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Added further i18n stubs.
+	  Also added a second Y axis (experimental, to ease axis labeling etc.).
+
+2012-02-06  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Register new export output and csv
+	  facet for reference curves.
+
+	* doc/conf/conf.xml: Register Exporter for reference curve.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveExporter.java:
+	  Primitive exporter, bland copy of another one.
+
+2012-02-06  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Enabled some i18n of labels.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties: Basic i18n for reference
+	  curves added.
+
+2012-02-06  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/conf.xml: Registered the HistoricalDischargeCurveInfoGenerator.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveInfoGenerator.java:
+	  New. This info generator returns information of a
+	  HistoricalDischargeCurveGenerator.
+
+	* src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java: Add an
+	  attribute "axistype" to axes nodex based on the JFreeChart Axis type.
+	  Number axes get a "number", date axes a "date".
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java: Defined an
+	  abstract method getRangesForAxis().
+
+	* src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java: Awaits
+	  now an instance of ChartGenerator instead of XYChartGenerator.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Implemented the getRangesForAxis() method (copied from XYChartGenerator).
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Added
+	  @Override annotation to getRangesForAxis().
+
+2012-02-06  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/WQSelect.java,
+	  src/main/java/de/intevation/flys/exports/WDifferencesExporter.java:
+	  Cosmetics.
+
+2012-02-06  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java:
+	  Add CSV facet (not yet evaluated).
+
+2012-02-06  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveExporter.java:
+	  New. This OutGenerator exports historical discharge curves to CSV and PDF.
+	  Currently, only the CSV export is implemented!
+
+	* doc/conf/artifacts/winfo.xml: Registered a new Output CSV for historical
+	  discharge curves.
+
+	* doc/conf/conf.xml: Registered the HistoricalDischargeCurveExporter.
+
+	* src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java:
+	  Generate new Facets for CSV and PDF  output.
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java: Added new functions
+	  that return number formatters for historical discharge curves and a date
+	  formatter for short dates.
+
+	* 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 strings for CSV header of
+	  historical discharge curve export.
+
+2012-02-06  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Adjusted to name change in River ('hibernate fix').
+
+2012-02-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Adapted the data type of W/Q input values
+	  for historical discharge curve calculation (intarray -> doublearray).
+
+	* src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeState.java:
+	  Adapted the data type of W/Q input values.
+
+2012-02-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	First steps to serve the data in cm if we are are gauges only.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Fetch map gauge station -> gauge datum from backend for reference curve.
+
+	* src/main/java/de/intevation/flys/artifacts/math/LinearFilterFunction.java:
+	  New. Linear transforms another function.
+
+	* src/main/java/de/intevation/flys/artifacts/math/FilterFunction.java:
+	  New. Allows cascading functions.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WWAxisTypes.java:
+	  New. Classifier what kind of axis types are needed.
+
+	* src/main/java/de/intevation/flys/artifacts/model/NormalizedReferenceCurveFacet.java:
+	  Removed. Is now obsolete.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WW.java:
+	  Stores gauge station kms for start and end km if they are any.
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java:
+	  Should generate a WWAxisTypes classifier via side effect to the
+	  call context.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation5.java:
+	  Figure out for each start/end km if its a gauge station and store this
+	  information in the result WWs.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Uses the WWAxisTypes classifier now to generate the right data.
+	  TODO: Use the blackboard object.
+
+2012-02-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/EnterLocationState.java:
+	  Removed superfluous imports.
+
+2012-02-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	  Set number of interpolation steps for relation curve to 200.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Do not sort the XYSeries.
+
+2012-02-03  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveInputState.java:
+	  Removed. Was stub.
+
+2012-02-03  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Improved Reference Curves.
+
+	* doc/conf/artifacts/winfo.xml: Add start/end input step for reference
+	  curves.
+
+	* doc/conf/themes.xml: Add theme for reference curve.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Disable start/end point-hack for reference curve. Go with 'live'
+	  values.
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java:
+	  i18n.
+
+	* src/main/java/de/intevation/flys/artifacts/states/EnterLocationState.java:
+	  New. State to enter location.
+
+	* src/main/java/de/intevation/flys/artifacts/states/InputDoubleState.java:
+	  New.
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Take WW name to display in themepanel.
+
+	* 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 translations.
+
+2012-02-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Use
+	  the current date for discharge tables which doesn't have a stop time set.
+	  A warning message is written to log.
+
+	* src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java:
+	  Generate report facet before leaving the computeXXX() method when no
+	  calculation results has been computed.
+
+2012-02-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a function
+	  that returns the name of a reference gauge (for historical discharge
+	  curves).
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Create title, subtitle and axes labels for charts of this type.
+
+	* 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 title, subtitle and axes
+	  labels for historical discharge curves.
+
+2012-02-03  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	  Fix.
+
+2012-02-03  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* 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 translations for
+	  states (will be shown in client).
+
+2012-02-03  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Ja!vadoc.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Declare getYAxisWalker as abstract to avoid weird issue with
+	  overriden methods of this name.
+
+2012-02-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java:
+	  Use the WW.ApplyFunctionIterator to fetch the data.
+
+	* src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java:
+	  Removed superfluous imports.
+
+2012-02-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Registered a ReportFacet for historical
+	  discharge curve report.
+
+	* doc/conf/conf.xml: Registered a ReportGenerator for historical discharge
+	  curves.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Add
+	  problems if we were not able to find a Q for a given W.
+
+	* src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java:
+	  Generate a ReportFacet if there were problems during calculcation.
+
+	* 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 error messages for the
+	  case that we were not able to find a Q for a given W while calculating
+	  historical discharge curve data.
+
+2012-02-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Improved adding new data for historical discharge curves: skip NaN
+	  values; use JFreeChart's Day TimePeriod instead of Second.
+
+2012-02-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java: Refactoring:
+	  moved addDatasets(), applyThemes() and some other methods into
+	  ChartGenerator; enhanced the AxisDataset interface.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Implemented necessary abstract methods and improved internal AxisDataset
+	  class (added new methods).
+
+2012-02-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartHelper.java: Added a
+	  function that expands a given range. Take care on NaN in getRanges().
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Prevent of NullPointerExceptions in isMinimumShapeVisible() and
+	  isMaximumShapeVisible().
+
+2012-02-02  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Create new AxisDatasets and new TimeSeriesCollections for each Facet.
+
+2012-02-02  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java: Added a
+	  method getTimerange(idx) that returns the Timerange at a given index.
+
+	* src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeFacet.java:
+	  Return the correct WQTimerange object in getData().
+
+2012-02-02  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java: More
+	  refactoring: the AxisDataset is defined by an interface in ChartGenerator
+	  now. Each subclass of ChartGenerator should implement its own AxisDataset.
+	  This allows us to provide multiple XYDataset types in different charts.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Implemented some necessary methods (abstract definitions of parent class)
+	  and create new empty timeseries charts.
+
+2012-02-02  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ChartHelper.java: New helper
+	  class for working with charts.
+
+2012-02-02  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Removed useless import.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java: More
+	  refactoring: moved more base code from XYChartGenerator to its parent
+	  class ChartGenerator.
+
+2012-02-02  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java:
+	  Refactored. Use supers static field.
+
+	* src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java:
+	  Refactored. Use static field.
+
+	* src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java,
+	  src/main/java/de/intevation/flys/utils/FLYSUtils.java
+	  (getMinMax, getRiverMinMax): Refactored. Moved to FLYSUtils.
+
+	* src/main/java/de/intevation/flys/artifacts/states/MinMaxState.java:
+	  Add so-called javadoc.
+
+2012-02-02  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java: Moved
+	  further base code from XYChartGenerator into its ChartGenerator.
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  Override generateChart() instead of generate() which is now implemented
+	  in ChartGenerator.
+
+2012-02-02  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java:
+	  New. This ChartGenerator should be used for timeseries charts. Currently,
+	  this class is a stub only! WORK IS IN PROGRESS!
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  Subclasses TimeseriesChartGenerator now instead of XYChartGenerator,
+	  because historical discharge curve charts will have a time x axis set.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java: Moved some
+	  basic stuff from XYChartGenerator into ChartGenerator.
+
+2012-02-02  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/charts/TimeseriesStepChart.java:
+	  Added standalone demo app for evaluating different timeseries charts.
+
+2012-02-02  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 466: CSV export for chart themes.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Export a CSV file if the requested format is 'csv'.
+
+	* src/main/java/de/intevation/flys/exports/ChartExportHelper.java:
+	  Generate the CSV file containing X-Y-data of all activated themes.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java:
+	  Moved code to load values of a discharge table into an own static
+	  function to be able to reuse it in Calculation6.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java:
+	  Implemented the findValueForW().
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fake some reference curve input values to have working prototype
+	to work on.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Syntax-stunt fake reference inputs.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WW.java
+	  (getW1): Accessor for first w at index (for the raw ww).
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java
+	  (doReferenceOut): Plot the raw W-over-W.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Create time
+	  millis for timerange used in Calculation6.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: Added
+	  the first step of the calculation: fetch relevant discharge tables based
+	  on the given input parameters. The calculated values are not the right
+	  ones! Finding Ws and Qs in discharge tables is still not implemented! WORK
+	  IN PROGRESS!
+
+	* src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java:
+	  Create facets for each WQTimerange object calculated by Calculation6.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Timerange.java: Added a
+	  new constructor that takes Date objects for start and end time.
+
+2012-02-01	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/W.java:
+	  Forget to create ws data in constructor.
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Replaced Reference Curve input state
+	  with LocationSelect-State for debugging purposes. Add output to
+	  reference.curve- state.
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/conf.xml: Register ReferenceCurve*Generators.
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java:
+	  Cosmetics.
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java:
+	  Added pro forma facet.
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java:
+	  Added comment.
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added reference curve facet type.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Fetch
+	  necessary parameters for 'historical discharge curve' calculation and call
+	  Calculation6 with those parameters.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java:
+	  Modified default constructor and calculate() signatures and added a
+	  parameter check which is evaluated before the calculation starts.
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/ReferenceCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ReferenceCurveInfoGenerator.java:
+	  Added outline of a new chart-generator.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Timerange.java: New.
+	  This class might be used to store timeranges. Start and end time are
+	  stores as long (milliseconds since january 1, 1970).
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQTimerange.java:
+	  New. This class should be used to save Ws, Qs and timeranges.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added helper
+	  methods to extract int[] and double[] from string.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Registered new facet type
+	  'historical_discharge.historicalq' to the 'historical_discharge' output.
+
+	* doc/conf/conf.xml: Registered new HistoricalDischargeCurveGenerator for
+	  output type 'historical_discharge'.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java: Added
+	  new facet type for HISTORICAL_DISCHARGE_Q.
+
+	* src/main/java/de/intevation/flys/exports/HistoricalDischargeCurveGenerator.java:
+	  New. This ChartGenerator is used to generate new charts for historical
+	  discharge curves. WORK IN PROGRESS!
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation6.java: New.
+	  This class should 'compute' the historical discharge curves. WORK IN
+	  PROGRESS!
+
+	* src/main/java/de/intevation/flys/artifacts/model/HistoricalDischargeFacet.java:
+	  New. This Facet is used during the calculation of historical discharge
+	  curves.
+
+	* src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java,
+	  src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Added stubs
+	  to trigger the calculation of data used for generating historical
+	  discharge curve charts.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/artifacts/states/DefaultState.java:
+	  Removed needless imports.
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages_de.properties,
+	  src/main/resources/messages_de_DE.properties:
+	  Fixed "W bei ..m" -> "W fuer ...n" .
+
+2012-02-01  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
+	  Avoid NPE, add warning to log to not forget about it.
+
+2012-01-31	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation.java:
+	  Fixed problems with unformatted numbers in error message.
+
+2012-01-31  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeState.java:
+	  Override getLabelFor() to return the I18N string for the selected
+	  evaluation mode.
+
+2012-01-31  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Modified types of parameters in the
+	  'historical discharge curves' transitions.
+
+2012-01-30  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Fix transition type (Stupid Bug 1.0 reverse).
+
+2012-01-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceGaugeState.java:
+	  Override getLabelFor() method defined in DefaultState to return the name
+	  of a Gauge based on the official number which is stored in the
+	  parameterization.
+
+2012-01-30  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Allow manual points in more diagram types.
+
+	* doc/conf/artifacts/winfo.xml: Add respective facet types to
+	  compatibility lists of output modes.
+
+	* doc/conf/artifacts/manualpoints.xml: Mention facet types.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added ChartType enum to ease later iteration.
+	  (IS.MANUALPOINTS): Added helper.
+
+	* src/main/java/de/intevation/flys/artifacts/model/ManualPointsFacet.java:
+	  Help artifact figuring out which data to provide by passing facet
+	  name.
+
+	* src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java:
+	  Respond to getPointData with correct data item, depending on facet
+	  name.
+
+	* src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java:
+	  Iterate over chart types. Add facets if corresponding data is found.
+
+	* src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Handle manual point facets.
+
+2012-01-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Clone
+	  StateData model objects to save parameters in this Artifact - create
+	  new StateData instances only if no StateData model was found for a
+	  parameter. This solves the problem of loosing the type of a StateData.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DefaultState.java:
+	  Implemented a getLabelFor() method that is used to format a parameter
+	  value.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java:
+	  Adapted method signature of transform().
+
+	* src/main/java/de/intevation/flys/artifacts/states/MinMaxState.java:
+	  Override getLabelFor() method to create a well formatted label for min/max
+	  values.
+
+2012-01-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/StateFactory.java:
+	  Bugfix: use correct order of parameters in DefaultStateData constructor.
+
+2012-01-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Fixed a stupid bug. Use
+	  ValueCompareTransition instead of DefaultTransition to evaluate values.
+
+2012-01-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/MinMaxState.java:
+	  Write default values for min and max items into the DESCRIBE document.
+
+2012-01-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WW.java:
+	  Added field 'startKm' and 'endKm' to make it easier to associate
+	  gauge to km to return Ws in cm if km is at a gauge.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation5.java:
+	  Construct the WWs with startKm and endKm. This is necessary because
+	  if an error occurs in calcuting an in between km in a list of end kms
+	  the index does not correspond to the input value any more.
+
+2012-01-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Added transitions for "historical discharge
+	  curves" calculation.
+
+2012-01-30  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  (doPoints): Skip 'inactive' points.
+
+2012-01-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WW.java:
+	  Removed the createNormalized() method because it did not
+	  solve all problems with the transformation of the W~W data we have.
+
+	  - We need to shift the values to be based in (0, 0).
+	  - We need to linear transform the values if they are at gauges.
+	  - Copying the data is memory expensive.
+
+	  Therefore there is now a new inner class ApplyFunctionIterator
+	  that is able to transform the values in an iterator like manner.
+	  The transform functions default to the identity.
+
+	* src/main/java/de/intevation/flys/artifacts/math/Sub.java: New.
+	  Simple function that subtract a scalar from the parameter.
+
+	* src/main/java/de/intevation/flys/artifacts/model/W.java: Added
+	  method minWs() to calulate the minimal W of the data.
+
+	* src/main/java/de/intevation/flys/artifacts/model/NormalizedReferenceCurveFacet.java:
+	  getData() returns a WW.ApplyFunctionIterator with identity transform.
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java:
+	  getData() returns a WW.ApplyFunctionIterator with a base shift to (0, 0).
+
+2012-01-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WW.java:
+	  Added method createNormalized() to shift the data to start in (0, 0).
+
+	* src/main/java/de/intevation/flys/artifacts/model/NormalizedReferenceCurveFacet.java:
+	  Returns the 'normalized' data of the reference curve.
+
+2012-01-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/NormalizedReferenceCurveFacet.java:
+	  New. Facet for the normalized W~W relation.
+	  TODO: Implement the on-the-fly creation logic.
+
+	* src/main/java/de/intevation/flys/artifacts/model/ReferenceCurveFacet.java:
+	  New. Facet for the W~W relation.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java: Cosmetics.
+
+2012-01-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java:
+	  Added stub loop for creating facets.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java:
+	  Cosmetics.
+
+2012-01-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Call the 'Bezugslinienverfahren'.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  I18N for the 'Bezugslinienverfahren' error messages.
+
+2012-01-27  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/themes.xml: Better theme for manual points.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Theme text part of manual points. Offset it a bit.
+
+2012-01-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation5.java:
+	  Fixed stupid bug.
+
+2012-01-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceGaugeState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeComputeState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/HistoricalDischargeState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/GaugeTimerangeState.java:
+	  New. States used in the 'historical discharge curve' calculation.
+
+2012-01-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/MinMaxState.java: New
+	  state that eases adding min/max value pairs to describe document.
+
+	* src/main/java/de/intevation/flys/artifacts/states/IntRangeState.java:
+	  New. Subclasses MinMaxState and allows adding min/max integer value pairs.
+
+2012-01-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/DefaultState.java: Moved
+	  code to add items to a data node for dynamich UI into an own method.
+
+2012-01-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java: Removed
+	  useless import.
+
+2012-01-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* 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 strings which are used n
+	  the calculation "historical discharge curve".
+
+2012-01-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	 * src/main/java/de/intevation/flys/artifacts/model/Calculation5.java:
+	   New. Calcutation to be created from WINFOArtifact
+	   for the 'Bezugslinienverfahren'.
+
+	 * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
+	   Added TODO about optimization of the 'Bezugslinienverfahren'.
+	   Added number of default samples of the W~W relation.
+
+	 * src/main/java/de/intevation/flys/artifacts/model/WW.java:
+	   Added convinience constructor to store the calculation results.
+
+	 * ChangeLog: Removed false TODO.
+
+2012-01-27  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveExporter.java,
+	  src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java,
+	  src/main/java/de/intevation/flys/exports/WDifferencesExporter.java:
+	  Read jasper template file from resources to support i18n reports.
+
+	* doc/conf/jasper/wdifferences.jasper,
+	  doc/conf/jasper/duration.jasper,
+	  doc/conf/jasper/computed-discharge.jasper,
+	  doc/conf/jasper/waterlevel.jasper:
+	  Updated report template. Resized left margin.
+
+	* doc/conf/jasper/computed-discharge_en.jasper,
+	  doc/conf/jasper/duration_en.jasper,
+	  doc/conf/jasper/wdifferences_en.jasper,
+	  doc/conf/jasper/waterlevel_en.jasper:
+	  New. Templates for english reports.
+
+	* 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 for template files and modes.
+
+2012-01-27  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Prevent second Legend Entry for points (prior was one for the
+		  TextAnnotations and one for the points).
+
+2012-01-27  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Blindly render Text of manual points if it does not collide with
+	other text.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Handle TextAnnotations, create some for manual points.
+
+	* src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java:
+	  Added setter for TextAnnotations, documentation.
+
+2012-01-27  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+
+2012-01-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Refactored class hierachy to integrate model for W~W:
+
+	NamedObjImpl
+	\-- W
+	    +-- WW
+	    \-- WQ
+	        +-- WQDay
+	        \-- WQKms
+	            \-- WQCKms
+
+	* src/main/java/de/intevation/flys/artifacts/model/W.java:
+	  New. Base class
+
+	* src/main/java/de/intevation/flys/artifacts/model/WW.java:
+	  New. Model for W~W
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQKms.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WQDay.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WQ.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WQCKms.java:
+	  Adjusted to follow the new class hierarchy.
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java,
+	  src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java:
+	  Removed superfluous imports.
+
+2012-01-27  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties,
+	  src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java:
+	  i18n for ManualPointsFacets.
+
+2012-01-27  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 138: PDF output for calculations.
+
+	* src/main/java/de/intevation/flys/exports/WDifferencesExporter.java:
+	  Create the PDF data source and generate the PDF report output.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java:
+	  Add the PDF facet to state. Add export facets only once.
+
+	* doc/conf/artifacts/winfo.xml:
+	  Added PDF facet to state.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java:
+	  Added new field type 'differences'.
+
+	* doc/conf/jasper/wdifferences.jasper:
+	  New. Template for w-differences PDF export.
+
+2012-01-27  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java:
+	  New method that creates and returns the chosen differences of w-difference
+	  calculation as string.
+
+2012-01-27  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 138: PDF output for calculations.
+
+	* src/main/java/de/intevation/flys/exports/DurationCurveExporter.java:
+	  Create the PDF data source and generate the PDF report output.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java,
+	  doc/conf/artifacts/winfo.xml:
+	  Added PDF facet to state.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java:
+	  Added new field type 'day'.
+
+	* doc/conf/jasper/duration.jasper:
+	  New. Template for duration curve PDF report.
+
+2012-01-26  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 138: PDF output for calculations.
+
+	* src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java:
+	  Create the PDF datasource and generate the PDF report output.
+
+	* src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java,
+	  doc/conf/artifacts/winfo.xml:
+	  Added PDF facet to state.
+
+	* doc/conf/jasper/computed-discharge.jasper:
+	  New. Template for computed discharge PDF report.
+
+2012-01-26  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 138: PDF output for calculations.
+
+	* pom.xml: New Dependency to net.sf.jasperreports/jasperreports and
+	  org.codehaus.groovy/groovy-all.
+
+	* src/main/java/de/intevation/flys/exports/AbstractExporter.java:
+	  Added methods for PDF generation.
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java:
+	  Create the PDF data source and generate the PDF report output.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java:
+	  New. Data source for jasper reports containing the waterlevel calculation
+	  result.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java:
+	  Added facet for PDF export to state.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added PDF facet type.
+
+	* src/main/java/de/intevation/flys/exports/DurationCurveExporter.java,
+	  src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java,
+	  src/main/java/de/intevation/flys/exports/WDifferencesExporter.java:
+	  Added stub for inherited abstract method.
+
+	* doc/conf/artifacts/winfo.xml:
+	  Added PDF facet to outputmode 'export'.
+
+	* doc/conf/jasper,
+	  doc/conf/jasper/waterlevel.jasper:
+	  New. Folder for jasperreports templates and first template for
+	  waterlevel report.
+
+	* 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 string for calculation mode.
+
+2012-01-26  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Renderer 'manual' points in LongitudinalSectionGenerator.
+
+	* pom.xml: New dependency to org.json/json.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  (doOut): Handle manual points.
+	  (doPoints): Add point- series.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added MANUALPOINTS Facet Type.
+
+	* doc/conf/themes.xml: Added Default Theme for Manual Points.
+
+	* doc/conf/artifacts/winfo.xml: Added manual point facet to
+	  compatibility list of longitudinal section diagram.
+
+2012-01-26  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Cosmetics.
+
+	* src/main/java/de/intevation/flys/artifacts/model/ManualPointsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java:
+	  Removed obsolete imports.
+
+2012-01-26  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Add initial infrastructure for user-provided data ('manual points').
+
+	* doc/conf/artifacts/manualpoints.xml: Trivial state model for new
+					       Artifact.
+
+	* doc/conf/conf.xml: Registered manualpoint artifact and factory.
+
+	* src/main/java/de/intevation/flys/artifacts/model/ManualPointsFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java,
+	  src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java:
+	  New. Basic infrastructure for ManualPoints.
+
+2012-01-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Removed superfluous condition checks.
+
+2012-01-25  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  Cosmetics, documentation.
+
+2012-01-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Add states/transitions stubs for
+	"Bezugsllinenverfahren."
+
+	* src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ReferenceCurveInputState.java:
+	  Stubs for the two new states.
+
+2012-01-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* contrib/visualize-transitions.xsl: Fixed output of the conditions
+	  of the transitions. Now you can see the circumstances
+	  when a branch is taken.
+
+2012-01-25  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 461.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Override buildChartSection() to disable the chart subtitle entry in
+	  ChartSettings.
+
+2012-01-24	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	I18N for WINFO calculations messages.
+
+	* src/main/java/de/intevation/flys/artifacts/model/Calculation.java:
+	  Allow optional arguments in error messages to support meaningful
+	  formatting containing e.g. numbers.
+
+	* src/main/java/de/intevation/flys/artifacts/resources/Resources.java:
+	  Added a convenience getMsg() method.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java,
+	  src/main/java/de/intevation/flys/artifacts/model/Calculation2.java,
+	  src/main/java/de/intevation/flys/artifacts/model/Calculation3.java,
+	  src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java,
+	  src/main/java/de/intevation/flys/artifacts/model/Calculation4.java:
+	  Adjusted the code to use the I18N symbols now.
+
+	* 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 the I18N strings.
+
+2012-01-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Handle the case in "W auf freier Strecke" where more than
+	  one Q is related to a W. TODO: Generate user report.
+
+2012-01-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  Added code for the simple case of "Bezugslinienverfahren" ("W auf freier Strecke").
+	  TODO: Handle case if the model returns more than one Q for a given W.
+
+	* src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java,
+	  src/main/java/de/intevation/flys/artifacts/states/WQSelect.java:
+	  Micro optimizations.
+
+2012-01-23  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue452 (Annotations at second y-axis).
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Added new type (duration_curve.mainvalues.q).
+
+	* doc/conf/themes.xml: Added theme mapping for new facet type.
+
+	* src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java:
+	  Create another Facet.
+
+	* doc/conf/artifacts/winfo.xml: Added new facet type to compatibility
+	  list.
+
+	* src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Handle new Facet.
+
+	* src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java:
+	  Added field to be able to remember which axis to stick to.
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java:
+	  Tell Annotations to stick to Q axis in the special duration_curve
+	  environment.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  (AxisDataset): Added plotAxisIndex to now have a
+			 two-way-association.
+	  Tell own axisDatasets to which 'jfreechart'-axis they are assigned.
+	  Evaluate which axis the StickyAxisAnnotations should be sticked to,
+	  and calculate text and line positions accordingly.
+	  Removed junk.
+
+2012-01-23  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix compilation.
+
+	* src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java:
+	  Use StickyAxisAnnotations instead of XYTextAnnotations.
+
+2012-01-23  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Some unification of Annotation handling.
+
+	* src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java:
+	  Add a third annotation type (now have text, hyk and sticky).
+
+	* src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java:
+	  Use double instead of float values, removed commented code.
+
+	* src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java:
+	  Reduced to keep information about placements etc only. Not a
+	  Annotation (in JFreeChart sense) anymore.
+
+	* src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java,
+	  src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java:
+	  Use StickyAxisAnnotations instead of XYTextAnnotations.
+
+	* src/main/java/de/intevation/flys/themes/ThemeAccess.java:
+	  Added new LineStyle class.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Call addAnnotationsToRenderer later, where positioning information
+	  is already known.
+	  (addAnnotationsToRenderer): Deal with the three Annotation types.
+				      Instead of StickyAnnotations, add
+				      CollisionFreeXYText- and
+				      XYLineAnnotations.
+	  (Area): Helper class.
+
+2012-01-23  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Some unification of Annotation handling.
+
+	* src/main/java/de/intevation/flys/exports/ChartExportHelper.java:
+
+2012-01-23  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue395 (SVG/PDF-Export: Längsschitt enthält keine
+		Streckenfavoriten.)
+
+	* src/main/java/de/intevation/flys/exports/ChartExportHelper.java:
+	  Fix pdf/svg rendering of annotatios, by adding a
+	  ChartRenderingInfo-object to the chart.draw call.
+
+2012-01-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  Added new key and getter for a short subtitle. The short subtitle is
+	  used if no range exists.
+
+	* 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 string for shor subtitle.
+
+2012-01-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/ChartArtifact.java:
+	  Removed state validation. Validation prevents drawing the diffenrences
+	  diagramm and all states except of WDifferencesState always return
+	  true.
+
+2012-01-20  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/CollisionFreeXYTextAnnotation.java:
+	  New. Candidate to replace StickyAxisAnnotation eventually.
+
+2012-01-20  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java:
+	  Added null-guards to functions parameters.
+
+2012-01-20  Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java:
+	  Respect flowing direction of river when finding valid
+	  hykformations.
+
+2012-01-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java:
+	  Add an empty facet to this state if the artifact is a Chartartifact.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  Do not add the range to subtitle if no range exists.
+
+2012-01-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	'New chart' for cross sections.
+
+	* doc/conf/artifacts/chart.xml: Updated the states and transitions for
+	  new charts.
+
+	* doc/conf/meta-data.xml: Added cross sections to datacage.
+
+	* src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java:
+	  Changed cast from WINFOArtifact to FLYSArtifact.
+
+	* src/main/java/de/intevation/flys/artifacts/ChartArtifact.java:
+	  Changed artifact data strings for chart_type.
+
+	* src/main/resources/messages.properties,
+	  src/main/resources/messages_de_DE.properties,
+	  src/main/resources/messages_en.properties,
+	  src/main/resources/messages_de.properties:
+	  Changed i18n string for cross sections and logitudinal sections.
+
+2012-01-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Add basic (text) styling for HYKs.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Minor cleanup, pass HYK theme on.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Apply TextStyle to TextAnnotation part for HYK zones.
+
+	* src/main/java/de/intevation/flys/themes/ThemeAccess.java:
+	  (TextStyle): New class to bundle text-styling info.
+
+	* src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java:
+	  Refactored constructors to ease setting Style in the newly
+	  created usage scenario.
+
+2012-01-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java:
+	  Cleanup. Mark spot where State-based caching could happen.
+
+2012-01-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/HYKFacet.java:
+	  Cosmetics.
+
+2012-01-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/cache.xml: Added Cache for HYKS.
+
+2012-01-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java:
+	  Made HYKFactory.Zone Serializable.
+
+2012-01-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/HYKArtifact.java:
+	  Cosmetics.
+
+2012-01-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Added style definition for hyks.
+
+	* doc/conf/themes.xml: Added hyk style (text).
+
+2012-01-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/cache.xml: Removed cache "service-distanceinfo".
+
+	* src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java:
+	  Now uses the annotations from the LocationProvider and the
+	  XML documents are no longer cached.
+
+2012-01-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/cache.xml: Removed "annotations" cache.
+
+	* src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java:
+	  Removed annotation caching.
+
+	* src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java:
+	  Changed internal data structure to FastAnnotations which are also cached.
+
+	* src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java:
+	  Use FastAnnotations now which are fetched via the LocationProvider.
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java: Added
+	  time measurement for writing the CVS output.
+
+	* src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java:
+	  Removed superfluous import.
+
+2012-01-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Respect visibility flag of HYK facet.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Log malcondition, make colored hyk-box a bit smaller.
+
+2012-01-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/model/DataFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java,
+	  src/main/java/de/intevation/flys/exports/ChartGenerator.java:
+	  Cosmetics, docs, improved logging.
+
+2012-01-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/meta-data.xml: Recommend hyks for current river if hit by
+	  a crosssection-out.
+
+2012-01-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Somewhat improved HYK handling and rendering.
+
+	* src/main/java/de/intevation/flys/artifacts/HYKArtifact.java:
+	  Store ids in more sensibly named data item and expose it.
+	  Spawn all facets in inactive state.
+
+	* src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java:
+	  Make HYK name accessible, do not query hyks by river, but by hyk-id,
+	  made query more real-world.
+
+	* src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java:
+	  Use hyks name as facet name, pass hyk-id when asking for hyks.
+
+2012-01-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Somewhat improved HYK handling and rendering.
+
+	* src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java:
+	  Added ability to store 'zones', next to text annotations.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  (getLowestYValue, getUppestYValue, colorForHYKZone),
+	  (addBoxAnnotations): New. Create box annotations from zones.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  (doHYK): New, handle hyk facets by adding zones to annotation
+		   container.
+
+2012-01-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Preparing improved HYK handling.
+
+	* src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java:
+	  (Zone.getTo): New accesor.
+	  TODOs and documentation added.
+
+2012-01-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	'New Chart' for w-differences curve.
+
+	* doc/conf/artifacts/chart.xml: Added empty facet to output mode.
+
+	* src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java:
+	  Add an empty facet if the artifact is a ChartArtifact.
+
+2012-01-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	'New Chart' for discharge longitudinal section curve.
+
+	* doc/conf/artifacts/chart.xml: Added transition for location input.
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
+	  Changed cast from WINFOArtifact to FLYSArtifact.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java:
+	  Add an empty facet if the artifact is a ChartArtifact.
+
+2012-01-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	'New Chart' for duration curve.
+
+	* doc/conf/artifacts/chart.xml: Added state and transition for location input.
+
+	* src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java:
+	  Changed cast from WINFOArtifact to FLYSArtifact.
+
+	* src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java:
+	  Add an empty facet if the artifact is a ChartArtifact.
+
+2012-01-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Added accidentally ommitted HYKFacet, fixing build.
+
+	* src/main/java/de/intevation/flys/artifacts/model/HYKFacet.java:
+	  New, stubby facet for hyk infrastructure.
+
+2012-01-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	'New Chart' for computed discharge curve.
+
+	* doc/conf/artifacts/chart.xml: Fixed transitions and added state for km input.
+
+	* src/main/java/de/intevation/flys/artifacts/model/EmptyFacet.java:
+	  New. Added an empty facet to avoid deleting an empty output.
+
+	* src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java,
+	  src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java,
+	  src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java:
+	  Changed some return values if the artifact is a ChartArtifact.
+
+	* src/main/java/de/intevation/flys/exports/ChartGenerator.java,
+	  src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java:
+	  Changed casts from WINFOArtifact to FLYSArtifact.
+
+	* src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java:
+	  Add an empty facet if the artifact is a ChartArtifact.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Set a default axis range if the range is null.
+
+2012-01-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Added stub hyk infrastructure.
+
+	* doc/conf/artifacts/hyk.xml: Added trivial transition configuration
+	  for hyk artifacts.
+
+	* doc/conf/conf.xml: Register HYK artifact and its transition conf.
+
+	* src/main/java/de/intevation/flys/artifacts/HYKArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/model/HYKFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java:
+	  Added static 'hyk' artifact, facet and state.
+
+2012-01-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  Add 'hyk' facet type.
+
+2012-01-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Add hyk facet to compatibility list of winfo.xml .
+
+	* doc/conf/artifacts/winfo.xml: Add hyk facets to compatibility list.
+
+2012-01-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a
+	  method getDataAsLong that returns a Long representation of a data item or
+	  null if no such data item is existing or it cannot be parsed as Long.
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java: Added a function
+	  that returns the selected reference gauge (specified by 'reference_gauge'
+	  parameter) of a FLYSArtifact.
+
+2012-01-17	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java:
+	  Cache a TreeMap<km, annotation string> of the annotation values of whole
+	  rivers. This is _much_ more efficient than firing an HQL/SQL statement for
+	  each km and caching these results.
+
+2012-01-17	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLine.java:
+	  Deleted. It is in the backend now.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionChunk.java,
+	  src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLineFactory.java,
+	  src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Adjusted to use the fast cross section line from backend now.
+
+	* doc/conf/cache.xml: Store cross section lines cache on disk.
+
+	* src/main/java/de/intevation/flys/artifacts/states/StaticWQKmsState.java,
+	  src/main/java/de/intevation/flys/artifacts/model/DataFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: Removed
+	  superfluous imports.
+
+2012-01-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix assignment of stateId/hash in WaterlevelFacet.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java:
+	  More verbose logging, fix hash/stateid assignment.
+
+	* src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java:
+	  (deepCopy): implemented.
+
+2012-01-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	"Ported" StaticWQKmsArtifact to use compute-type caching mechanism.
+
+	* doc/conf/artifacts/staticwqkms.xml: Declare trivial info.
+
+	* doc/conf/conf.xml: Register staticwqkms artifact and factory.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java:
+	  Sublacss DataFacet.
+
+	* src/main/java/de/intevation/flys/artifacts/states/StaticWQKmsState.java:
+	  New. State.
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java:
+	  Refactored. Most computation and stuff now done in State and Facet.
+
+2012-01-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java:
+	  Minor cosmetics.
+
+2012-01-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Refactoring.
+
+	* src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java:
+	  Added new constructor.
+
+	* src/main/java/de/intevation/flys/artifacts/model/DataFacet.java:
+	  Refactored, subclass BlackboardDataFacet.
+
+	* src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java:
+	  Refactored, subclass DataFacet.
+
+	* src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java:
+	  Adjusted.
+
+2012-01-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/DataFacet.java:
+	  Cosmetics, added new constructor.
+
+2012-01-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	  Use improved caching for cross section data.
+	  !!! This commit needs heavy testing !!!
+
+	* src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java:
+	  Refactored to provide the map to determine the nearest cross section line
+	  neighbors for a given km to the public. This is a bit hackish because
+	  it hhould have its own factory which is then used by this service and
+	  other parts of the code.
+
+	* src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java:
+	  searchCrossSectionLine() now returns a FastCrossSectionLine. To find this
+	  line efficiently it uses the map of the CrossSectionKMService which
+	  already provides a nearest neighbor searching mechanism for cross
+	  section lines. The FastCrossSectionLine is fetched with the
+	  FastCrossSectionLineFactory which uses a cache as described in the
+	  previous commit.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java
+	  src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java,
+	  src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Uses
+	  the FastCrossSectionLine instead of CrossSectionLines now.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLine.java:
+	  Added method fetchCrossSectionProfile() to access the point data in
+	  the profile generating compatible way.
+
+	* src/main/java/de/intevation/flys/artifacts/ChartArtifact.java: Removed
+	  superfluous import.
+
+2012-01-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/cache.xml: Added cache for fast section lines chunks.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionChunk.java:
+	  New. Chunks of FastCrossSectionLines. Stores cross section lines for ranges
+	  of one KM.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLineFactory.java:
+	  New. Access fast cross section lines. It uses the cache 'fast-cross-section-lines'
+	  configured in cache.xml to store chunks of cross section lines.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FastCrossSectionLine.java:
+	  New. Stores the important data (points) of a cross section line.
+
+2012-01-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java:
+	  Added a new calculation option for historical discharge curves.
+
+	* 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 translations for
+	  historical discharge curves.
+
+2012-01-16	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/winfo.xml: Added certain facets to to
+	  compatibility matrices.
+
+2012-01-16	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/annotation.xml: Fixed accidental change.
+
+2012-01-16	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* doc/conf/artifacts/annotation.xml: Cosmetics.
+
+2012-01-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/meta-data.xml: Enabled old floodmap calculations for output
+	  type 'map'.
+
+2012-01-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Initial implementation for module 'new chart'.
+
+	* src/main/java/de/intevation/flys/artifacts/ChartArtifact.java:
+	  New. Artifact for module 'new chart'.
+
+	* doc/conf/artifacts/chart.xml:
+	  New. Artifact description for the new artifact.
+
+	* doc/conf/conf.xml:
+	  Added new artifact to config.
+
+	* 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 for 'new chart' chart types.
+
+2011-01-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java:
+	  Cosmetics.
+
+2011-01-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  Avoid NPE when copying data from one artifact to another.
+
+2011-01-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  (expandRange): Prevent collapse due to negative values.
+
+2012-01-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/artifacts/map.xml,
+	  doc/conf/conf.xml,
+	  src/main/java/de/intevation/flys/artifacts/MapArtifact.java:
+	  Changed the MapArtifact name to 'new_map'.
+
+2011-01-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java:
+	  Added code to calculate the area of the generated polygons.
+	  TODO: Render the generated area sum to the plot.
+
+2011-01-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	 * src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java:
+	   Replaced System.err.println()s with proper logging.
+
+	  * src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	    src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java,
+	    src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Removed
+	    superfluous imports.
+
+2011-01-12	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	flys/issue450 (i18n: Datenkorb: longitudinal-section)
+
+	* doc/conf/meta-data.xml: Replaced dash by underscore in
+	  longitudinal-section.
+
+2011-01-12	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Towards areas on other than the first axes.
+
+	* src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java:
+	  Changed signature on which to provide data via the blackboard.
+	  Include facets name to allow unique identification.
+
+	* src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java:
+	  Store name of one of the facets involved in area creation.
+	  (AreaFacet.Data): New class to hold result data.
+
+	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
+	  New methods to find out whether we have a general Q or W type of
+	  facet.
+
+	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
+	  (doArea): Use new Result-Data object instead of Object[], resolve
+		    which axis to put area to.
+	  (axisIdxForFacet): New.
+
+	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
+	  Subclass LongitudinalSectionGenerator.
+
+2011-01-12	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java:
+	  Do not intefere with CrossSections.
+
+2011-01-12	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Cosmetics, cleanups.
+
+	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
+	  (getCrossSections, getCrossSectionNames): Removed.
+
+2011-01-11	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	flys/issue439 (Streckenfavoriten lassen sich nicht über den Datenkorb
+		hinzuladen)
+
+	* doc/conf/meta-data.xml: Made Annotations available via datacage
+	  in longitudinal section, cosmetics.
+
+2012-01-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* doc/conf/conf.xml:
+	  Added output generator for output type 'map'.
+
+	* doc/conf/artifacts/map.xml:
+	  Changed output name to 'map'.
+
+	* doc/conf/meta-data.xml:
+	  Added new output type 'map'.
+
+2011-01-11	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue446 (Dauerline/Abflusskurve am Pegel: Eigenschaften vom
+	Hauptwertthema nicht aufrufbar)
+
+	* doc/conf/themes.xml: Add default styles for mainvalues.q/w and other
+	  themes.
+
+2012-01-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java:
+	  Removed XPath injection security hole. A serious one because it allowed
+	  inspecting the conf.xml file ... with all the db passwords.
+
+2012-01-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Removed superfluous imports.
+
+2012-01-11  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/meta-data.xml: Added the definition of old calculation results
+	  for floodmaps.
+
+2012-01-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java: Added
+	  methods getLayers() and removeLayer().
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Added a
+	  method getFacets() which returns a list of Facets supported by this
+	  Artifact. In addition, the FLYSArtifact is now more verbose while
+	  filtering Facets for Outputs.
+
+	* src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java:
+	  Implemented initialize() which now copies the shapefile directory of the
+	  model Artifact and modifies its Facets (adapts the shapepath which is the
+	  uuid of the Artifact).
+
+2012-01-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/collections/AttributeWriter.java,
+	  src/main/java/de/intevation/flys/collections/OutputParser.java: Made
+	  them more verbose for better debugging.
+
+2012-01-09  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
+	  Initialize() now also calls State.initialize() for each State.
+
+	* src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java:
+	  Override initialize() which is defined in AbstractState. NOTE: Currently,
+	  this method has no code.
+
+2012-01-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/CacheInvalidationService.java:
+	  New. The service to invalidate the caches. (Argh! Forgot to 'svn add')
+
+2012-01-06  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue298 (Karte: Automatischer Zoom auf Berechnungsergebnisse)
+
+	* src/main/java/de/intevation/flys/wsplgen/FacetCreator.java: Added a
+	  debug statement that prints out the WSPLGEN extent.
+
+	* src/main/java/de/intevation/flys/exports/MapGenerator.java: Create new
+	  Envelope instances for initial and max extent if they are not existing.
+	  Some debug statements have now been removed.
+
+2011-01-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Add cache for 'static' wqkms (e.g. BaseData) to default cache conf.
+
+	* doc/conf/cache.xml: Add Cache Config for static wqkms.
+
+	* src/main/java/de/intevation/flys/artifacts/model/StaticWQKmsCacheKey.java:
+	  Adjust typo in cache name, minor cosmetic.
+
+2011-01-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/MapArtifact.java:
+	  The map artifact has two states now and overrides describe() to
+	  generate UI sections in the describe response.
+	  The map state overrides computeAdvance() instead of computeFeed().
+
+	* src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java:
+	  Changed the WMSDBArtifact in WMSDBState to FLYSArtifact and adjusted
+	  constructors in state classes.
+
+	* doc/conf/artifacts/map.xml:
+	  Added initial state and transition.
+
+	* 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 for new state.
+
+2011-01-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial fix for flys/issue437 (Querprofil: Zugeladene Basisdaten
+	ignorieren W/Q-heit, falsche Namen).
+
+	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
+	  Set name also for first column (zero based).
+
+2012-01-06  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue196 (i18n/l10n: Zahlenformate einheitlich)
+
+	* src/main/java/de/intevation/flys/artifacts/model/WQ.java: New method
+	  getRawValue() that extracts the raw double value from 'name' parameter.
+
+	* src/main/java/de/intevation/flys/utils/Formatter.java: New method
+	  getRawFormatter() that returns a NumberFormat instance for the current
+	  locale.
+
+	* src/main/java/de/intevation/flys/exports/WaterlevelExporter.java:
+	  Localized the W/Q labels in CSV exports.
+
+2011-01-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	flys/issue442 (i18n: Datenkorb: flood-protections)
+
+	* doc/conf/meta-data.xml: Replaced dash in flood-protection by
+	  underscore to allow translation.
+
+2011-01-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	flys/issue438 (i18n: Datenkorb: additionals)
+
+	* doc/conf/meta-data.xml: Fix typo.
+
+2011-01-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/artifacts/services/CacheInvalidationService.java:
+	  New. Uses the CacheFactory to invalidate caches by their names.
+	  This can be used by external ETL processes like the AFT/DIPS importer
+	  to prevent cache inconsistencies.
+
+	  Input documents look like this:
+
+	    <caches>
+	      <cache name="my-cache"/>
+	      ...
+	      <cache name="your-cache"/>
+	    </caches>
+
+	  Output documents look like this:
+
+	    <caches>
+	      <cache name="my-cache">All elements removed.</cache>
+	      ...
+	      <cache name="your-cache">Error: Cache not found.</cache>
+	    </caches>
+
+	 * doc/conf/conf.xml: Added the cache invalidation service.
+
+	* src/main/java/de/intevation/flys/artifacts/services/FLYSService.java:
+	  Added Override annotation.
+
+2011-01-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	flys/issue432 (Diagrammeigenschaften/Flächenrenderer:
+	Legenden-schriftgröße für Flächenthemen wird ignoriert)
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java:
+	  Respect legend item size when generating legend items for
+	  area dataseries.
+
+2011-12-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Implemented new module "new map".
+
+	* src/main/java/de/intevation/flys/artifacts/MapArtifact.java:
+	  New. Artifact for the new module, extends RiverAxisArtifact and
+	  contains the MapState class.
+
+	* src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java,
+	  src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java:
+	  Added empty constructor to embedded state classes to allow instantiation
+	  of MapState that extends the RiverAxisState.
+
+	* src/main/java/de/intevation/flys/exports/MapGenerator.java:
+	  Do not generate an initialExtent element if the initial extent is
+	  empty.
+
+	* doc/conf/artifacts/map.xml:
+	  New. Describes the state for the new module.
+
+	* doc/conf/conf.xml:
+	  Added new config file.
+
+2012-01-05  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue444 (error_no_export_found bei "W bei ungleichwertigem Abfluss")
+
+	* src/main/java/de/intevation/flys/utils/FLYSUtils.java: If no boolean
+	  value "wq_free" exists in getWQMode(), false is the default.
+
+2011-01-05	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	flys/issue443 (Querprofile: Hibernate LazyInitializationException)
+
+	* doc/conf/cache.xml: Disable cache for cross-sections.
+
+2012-01-05  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue447 (W-Differenzen: Fehler beim Hinzufügen einer Parameterisierung)
+
+	* src/main/java/de/intevation/flys/collections/CollectionAttribute.java:
+	  Added a new method cleanEmptyOutputs() which removes Outputs that have
+	  no Facets set.
+
+	* src/main/java/de/intevation/flys/collections/AttributeWriter.java: Call
+	  CollectionAttribute.cleanEmptyOutputs() at the end of write() to remove
+	  empty Outputs that have been added during the merge process.
+
+2012-01-05  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue440 (Karte: WSPLGEN Berechnungen für Mosel schlagen fehl)
+
+	* src/main/java/de/intevation/flys/utils/GeometryUtils.java: Modified the
+	  getRiverBoundary() method because the signature of
+	  RiverAxis.getRiverAxis() has changed. This method will now take each
+	  geometry into account, that is retrieved by
+	  RiverAxis.getRiverBoundary().
+
+	* src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java:
+	  Use GeometryUtils.getRiverBoundary() to determine the boundary of a
+	  river.
+
+	* src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java:
+	  Create the riveraxis shapefile with all geometries returned by
+	  RiverAxis.getRiverAxis().
+
+2012-01-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Repaired
+	  broken items in legend. The new renderer requires the current plot. This
+	  is set now.
+
+2012-01-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/conf/themes.xml: Added a new field 'pointsize' to the virtual theme
+	  'HiddenColorLines'.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added methods to
+	  parse the new field of 'HiddenColorLines'.
+
+	* src/main/java/de/intevation/flys/jfree/StyledXYSeries.java: Apply the
+	  pointsize defined in themes.
+
+2012-01-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Use correct keys for buffering in getMinimum() and getMaximum().
+
+2012-01-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/StyledXYSeries.java,
+	  src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java,
+	  src/main/java/de/intevation/flys/exports/EnhancedLineAndShapeRenderer.java:
+	  Moved to de.intevation.flys.jfree.
+
+	* src/main/java/de/intevation/flys/jfree/StyledXYSeries.java,
+	  src/main/java/de/intevation/flys/jfree/StyledAreaSeriesCollection.java,
+	  src/main/java/de/intevation/flys/jfree/EnhancedLineAndShapeRenderer.java:
+	  Moved from de.intevation.flys.exports.
+
+	* src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java,
+	  src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/XYChartGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java,
+	  src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java:
+	  Added necessary imports.
+
+2012-01-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/exports/EnhancedLineAndShapeRenderer.java:
+	  Buffered the computation results of getMinimum() and getMaximum().
+
+2012-01-04  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue393 (Themenstileditor: Minimum anzeigen / Beschriftung anzeigen)
+
+	* src/main/java/de/intevation/flys/exports/EnhancedLineAndShapeRenderer.java:
+	  New renderer that overrides JFreeChart's XYLineAndShapeRenderer. This
+	  renderer brings the option to explicitly display the minimum and/or
+	  maximum or a series as shape. Currently, there are no options to adjust
+	  the style of those shapes.
+
+	* doc/conf/themes.xml: Added a new virtual theme 'MinMaxPoints'. All line
+	  theme inherit from that theme now.
+
+	* src/main/java/de/intevation/flys/utils/ThemeUtil.java: Added methods to
+	  parse the fields 'showminimum' and 'showmaximum' of 'MinMaxPoints' theme.
+
+	* src/main/java/de/intevation/flys/exports/StyledXYSeries.java: Added
+	  methods to apply the fields of the new Theme 'MinMaxPoints'.
+
+	* src/main/java/de/intevation/flys/exports/XYChartGenerator.java: Modified
+	  the getRenderer() method which now always returns a new instance of
+	  EnhancedLineAndShapeRenderer.
+
 2011-01-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
 
 	Allow styling of outline of areas.
 
 	* src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java:
 	  Allow styling of outline of areas.
-	
+
 	* src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java:
 	  Parse outline style for areas, apply it to renderer.
 
@@ -420,7 +11515,7 @@
 
 	* src/main/java/de/intevation/flys/utils/ThemeUtil.java: Helper to
 	  access transparency setting in theme.
-	
+
 	* src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java:
 	  Respect transparency setting.
 
@@ -780,7 +11875,7 @@
 	  be implemented by subclasses.
 
 	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
-	  Override buildAxisSections() of XYChartGenerator to create an AxisSection 
+	  Override buildAxisSections() of XYChartGenerator to create an AxisSection
 	  for each axis that is able to be displayed in this sort of chart. In
 	  addition, there is a new method getYAxisLabel(int) that returns the label
 	  for a specific Y axis.
@@ -890,7 +11985,7 @@
 	* src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java:
 	  Convenience cosmetic.
 
-	* src/main/java/de/intevation/flys/utils/DataUtil.java: 
+	* src/main/java/de/intevation/flys/utils/DataUtil.java:
 	  vim-magicosmetic.
 
 2011-12-14	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
@@ -992,14 +12087,14 @@
 	  (getCrossSectionData): Removed, most functionality contained in
 				 CrossSectionArtifact.
 	  (getWaterLines): Now get CrossSectionLines to calculate water line.
-	 
+
 	* src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java:
 	  Get a CrossSectionLine from blackboard.
-	
+
 	* src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java:
 	  Hard TODO, commented out function needed for subtitle to allow
 	  compilation.
-	
+
 	* src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java:
 	  Added Empty-Dataset- guard.
 
@@ -1357,7 +12452,7 @@
 
 	  This is to be called when doing a "W auf freier Strecke" calculation
 	  to find out the Qs belonging to the user given W.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java,
 	  src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java,
 	  src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java:
@@ -1420,7 +12515,7 @@
 	  Keep relation between index and dataset, once its added. Compute
 	  ranges per index. Allow subclasses to override createAxes to specify
 	  internationalized labels etc.
-	
+
 	* src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java,
 	  src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java,
 	  src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java,
@@ -1725,9 +12820,9 @@
 	  at the given km.
 
 	* src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java:
-	  Spliting by NaNs definition holes _should_ work now. Needs 
+	  Spliting by NaNs definition holes _should_ work now. Needs
 	  some more testing.
-	  TODOs: 
+	  TODOs:
 	  - Use log4j instead of println for logging.
 	  - Subclass XYDifferenceRenderer instead of replacing it totally.
 
@@ -1949,7 +13044,7 @@
 	Handle Annotations in DischargeLongitudinalSection diagrams.
 
 	* src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java:
-	  Call doAnnotations for LONGITUDINAL_ANNOTATION facets. 
+	  Call doAnnotations for LONGITUDINAL_ANNOTATION facets.
 
 2011-11-10  Felix Wolfsteller <felix.wolfsteller@intevation.de>
 
@@ -1958,7 +13053,7 @@
 	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java
 	  (doAnnotationsOut): Removed duplicate code.
 	  Theoretically handle WQKMS data.
-	
+
 	* src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java:
 	  Adjusted call to doAnnotationOut.
 
@@ -1979,7 +13074,7 @@
 2011-11-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
 	* src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java:
-	  Use separate XYDataset for each curve. This is needed because 
+	  Use separate XYDataset for each curve. This is needed because
 	  "Raum/Flaeche" needs specialized renderers, which are not compatible
 	  with the standard renderers.
 
@@ -2207,7 +13302,7 @@
 
 	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
 	  Be more specific in what to catch.
-	
+
 2011-11-04  Ingo Weinzierl <ingo@intevation.de>
 
 	* doc/conf/meta-data.xml: Added the CrossSectionTracks to the "floodmap"
@@ -2304,7 +13399,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java:
 	  Createing ThemeMapping with output attribute from configuration.
-	  
+
 	* src/main/java/de/intevation/flys/themes/ThemeFactory.java:
 	  (getTheme(FLYSContext, string)): Removed, never called.
 	  (getTheme): Added outputName argument, match it.
@@ -2329,16 +13424,16 @@
 
 	* src/main/java/de/intevation/flys/artifacts/model/StaticWQKmsCacheKey.java:
 	  Cache Key for static wqkms data.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java:
 	  Facet for WQKms.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/model/WQKmsFactory.java:
 	  Factory to access WQKms.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java:
 	  Artifact that provides 'static' WQKms.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
 	  Added STATIC_WQKMS type.
 
@@ -2415,7 +13510,7 @@
 	  needed any longer.
 
 2011-11-03  Sascha L. Teichmann <sascha.teichmann@intevation.de>
-	
+
 	* src/main/java/de/intevation/flys/utils/Pair.java: New. A generic pair.
 
 	* src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java:
@@ -2476,23 +13571,23 @@
 
 	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
 	  Added new FacetType HEIGHTMARK_POINTS.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java:
 	  Allow name to be given in constructor.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
 	  If heightmarks were loaded, give respective name in WKmsFacet
 	  generation.
 
 	* doc/conf/themes.xml: Added virtual "Points" and concrete
 	  heightmark_points - theme.
-	
+
 	* doc/conf/artifacts/winfo.xml: Made longitudinal_section output
 	  compatible with heightmarks_points.
 
 	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
 	  Render heightmarks like other wkms.
-	
+
 	* doc/conf/meta-data.xml: Changed heightmark ids such that it can be
 	  identified in StaticWKmsFacet .
 
@@ -2796,7 +13891,7 @@
 
 2011-10-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
 
-	* src/main/java/de/intevation/flys/collections/AttributeWriter.java: 
+	* src/main/java/de/intevation/flys/collections/AttributeWriter.java:
 	  Survive case where a given output doesnt exist in compatibility
 	  matrix.
 
@@ -2804,7 +13899,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/states/StaticState.java:
 	  Added simpler constructor.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java,
 	  src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java:
 	  Adjusted construction of StaticStates.
@@ -2882,10 +13977,10 @@
 
 	* src/main/java/de/intevation/flys/utils/FLYSUtils.java
 	  (getFlysContext): Added, extracted from FLYSArtifact.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
 	  (getFlysContext): Moved to FLYSUtils, updated callers.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java,
 	  src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
 	  Update callers to getFlysContext.
@@ -3103,7 +14198,7 @@
 
 	To obtain the size of a diagram it is rendered twice. The
 	second time the generated image is omitted so the concrete
-	rendered image is not needed. To save CPU cycles in this pass 
+	rendered image is not needed. To save CPU cycles in this pass
 	the image is rendered to to /dev/null Graphics2D object.
 
 	* src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java:
@@ -3137,7 +14232,7 @@
 	* src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java:
 	  New. Service to lookup the Nth nearest neighbors for a set of given
 	  cross section ids and kms.
-	
+
 	* doc/conf/conf.xml: Registered service.
 
 	* doc/conf/cache.xml: Cache config.
@@ -3346,7 +14441,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java:
 	  Removed dependence on "kind", but fetch name for created WKms.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
 	  Remove dependence on Kind.
 
@@ -3371,10 +14466,10 @@
 
 	* src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java:
 	  New, artifact with single state to get WKms from WKmsFactory.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java:
 	  New Facet to display W over km.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java:
 	  Added new type name.
 
@@ -3410,7 +14505,7 @@
 2011-10-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
 
 	Fix issue that Annotations do not come with theme/style.
-	
+
 	* doc/conf/themes.xml: Added "Annotations" default style.
 
 	* src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java:
@@ -3852,7 +14947,7 @@
 	* src/main/java/de/intevation/flys/artifacts/model/WKms.java(allKms, allWs):
 	  Added methods to fetch all kms and all ws.
 
-	* src/main/java/de/intevation/flys/utils/DataUtil.java: Generalized to 
+	* src/main/java/de/intevation/flys/utils/DataUtil.java: Generalized to
 	  get WKms as arguments.
 
 	* src/main/java/de/intevation/flys/artifacts/model/WQKms.java,
@@ -4655,7 +15750,7 @@
 	Added CSV Export for W-Differences.
 
 	* doc/conf/conf.xml: Added Exporter.
-	
+
 	* doc/conf/artifacts/winfo.xml: Removed transition over distances
 	  state, added export outputmode and facet.
 
@@ -4669,7 +15764,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/model/DataFacet.java:
 	  Cosmetics, docs.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java,
 	  src/main/java/de/intevation/flys/exports/AbstractExporter.java,
 	  src/main/java/de/intevation/flys/exports/DurationCurveExporter.java:
@@ -4707,7 +15802,7 @@
 	  CallContext.addBackgroundMessage(). We use instances of
 	  CalculationMessage here, that makes the WINFOArtifact able to put
 	  progress information into the Artifact's DESCRIBE as well.
-	  
+
 	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Write
 	  status message and progress information into the DESCRIBE if the
 	  Artifact has started a background process.
@@ -5733,12 +16828,12 @@
 2011-08-22  Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
 	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Moved all
-	  WINFO specific code to WINFOArtifact. FLYSArtifact is now only revolving 
+	  WINFO specific code to WINFOArtifact. FLYSArtifact is now only revolving
 	  about state affairs.
 
 	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Re-inserted
 	  the specific stuff here.
-	  
+
 	* src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java,
 	  src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java,
 	  src/main/java/de/intevation/flys/artifacts/states/WQSelect.java,
@@ -5872,16 +16967,16 @@
 	               a2.state          AS state,
 	               a2.creation       AS creation,
 	               ci2.collection_id AS collection_id
-	        FROM   collection_items ci2 
-	               JOIN artifacts a2 
-	                 ON ci2.artifact_id = a2.id 
-	               JOIN (SELECT ci.collection_id AS c_id, 
-	                            MIN(a.creation)  AS oldest_a 
-	                     FROM   collection_items ci 
-	                            JOIN artifacts a 
-	                              ON ci.artifact_id = a.id 
-	                     GROUP  BY ci.collection_id) o 
-	                 ON o.c_id = ci2.collection_id 
+	        FROM   collection_items ci2
+	               JOIN artifacts a2
+	                 ON ci2.artifact_id = a2.id
+	               JOIN (SELECT ci.collection_id AS c_id,
+	                            MIN(a.creation)  AS oldest_a
+	                     FROM   collection_items ci
+	                            JOIN artifacts a
+	                              ON ci.artifact_id = a.id
+	                     GROUP  BY ci.collection_id) o
+	                 ON o.c_id = ci2.collection_id
 	        WHERE  a2.creation = o.oldest_a;
 
 	 TODO: Use the view in the templates.
@@ -6204,8 +17299,8 @@
 	  To use this feature you can add an "connection" attribute
 	  to <dc:context> with the name of the connection to use.
 	  If no connection name is given the last used is used again.
-	  Initially the first connection in the given list is used. 
-	  If the context is left the connection that was active before 
+	  Initially the first connection in the given list is used.
+	  If the context is left the connection that was active before
 	  will be active again in a stacking manner.
 
 	  When creating NamedConnection objects you can set a boolean flag
@@ -6242,7 +17337,7 @@
 	* src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java,
 	  src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java:
 	  Forwarded kill collections and artifacts events to datacage.
-	
+
 	* src/main/resources/datacage-sql/org-h2-driver.properties,
 	  src/main/resources/datacage-sql/org-postgresql-driver.properties:
 	  Added statement to delete artifact by uuid.
@@ -6259,7 +17354,7 @@
 
 	  TODO  I: Added some cleanup for orphaned artifacts.
 	  TODO II: Figure out a way to delete collections/artifacts
-	           which are delete from backend without the 
+	           which are delete from backend without the
 			   backend API.
 
 	* src/main/resources/datacage-sql/org-h2-driver.properties,
@@ -6300,7 +17395,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java:
 	  New. Proxies backend listener calls to datacage.
-	 
+
 	* src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java:
 	  Implements backend listener. TODO: Update the datacage database
 	  according the change calls.
@@ -6320,7 +17415,7 @@
 
 2011-08-01  Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
-	* doc/conf/conf.xml: For documentation purposes added a out-commented 
+	* doc/conf/conf.xml: For documentation purposes added a out-commented
 	  section with the default configuration of the datacage.
 
 2011-07-31  Sascha L. Teichmann <sascha.teichmann@intevation.de>
@@ -6451,7 +17546,7 @@
 	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java:
 	  Make the current outs of an artifact accessible only with
 	  the global context.
-	
+
 2011-07-27  Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
 	* doc/conf/datacage.sql: Added ON DELETE CASCADE constraints.
@@ -6643,7 +17738,7 @@
 	  with 'macro'. There bodies can contain all valid elements
 	  including other 'macro's and 'call-macro's. They are
 	  called with their 'name' with 'call-macro'. The control flow
-	  is continued inside the body of the called macro and 
+	  is continued inside the body of the called macro and
 	  will continue right after the calling 'call-macro' when
 	  the macro body is finished.
 
@@ -6723,7 +17818,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/services/meta/StackFrames.java:
 	  Implements now variable provider for XPath expressions.
-	
+
 	* src/main/java/de/intevation/flys/artifacts/services/meta/Builder.java:
 	  Added new choose/when/otherwise construct similiar to XSLT
 
@@ -7264,7 +18359,7 @@
 	  The functionality we need is in 1.1 so this downgrade should
 	  cause no problems.
 
-	  Would be nice if we would support the maintainers of trove to 
+	  Would be nice if we would support the maintainers of trove to
 	  bring there new versions back into the main maven repos.
 
 2011-06-28  Ingo Weinzierl <ingo@intevation.de>
@@ -7365,7 +18460,7 @@
 	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
 	  The reference gauge for calculations "am Pegel" was determined
 	  wrong.
-	  
+
 2011-06-25  Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
 	* src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java:
@@ -7411,7 +18506,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java:
 	  Generate AT facets.
-	
+
 2011-06-23  Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
 	* src/main/java/de/intevation/flys/exports/ATExporter.java: New.
@@ -7571,7 +18666,7 @@
 
 	* src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java:
 	  Checks for right class now.
-	
+
 2011-06-21  Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
 	Fix for flys/issue154
@@ -7722,7 +18817,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java: New.
 	  Specialized facet to access the duration data stored in WQDay data structures.
-	  
+
 	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Facets are
 	  now generated dynamically from the current available ones stored with
 	  the artifact.
@@ -7739,7 +18834,7 @@
 	  states overwrites the computeAdvance() and computeFeed() methods to do
 	  the corresponding WINFO calculations.
 
-	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Calls 
+	* src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: Calls
 	  computeAdvance() and computeFeed() if artifact is fed or advanced. Centralized
 	  the caching mechanism.
 
@@ -7852,7 +18947,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
 	  Loop errors through for q->w interpolations.
-	  
+
 	* src/main/java/de/intevation/flys/artifacts/model/WQDay.java:
 	  Added constructor to directly create with calculated results.
 
@@ -8214,7 +19309,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: Re-enabled
 	  calculation of the back jump correction. Fixed more flow direction issues.
-	  
+
 2011-05-27  Ingo Weinzierl <ingo@intevation.de>
 
 	* src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java:
@@ -8413,13 +19508,13 @@
 
 	* src/main/java/de/intevation/flys/artifacts/model/WstFactory.java:
 	  Forget to select wst kind.
-	  
+
 2011-05-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
 	flys/issue81
 
 	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
-	  weights for kms were swapped. 
+	  weights for kms were swapped.
 
 2011-05-20  Ingo Weinzierl <ingo@intevation.de>
 
@@ -8511,7 +19606,7 @@
 	  Made getExplodedValues static.
 
 	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
-	  Use new logic to calculate "W für ungleichwertige Abfluesse".
+	  Use new logic to calculate "W fuer ungleichwertige Abfluesse".
 	  Not working, yet.
 
 	* ChangeLog: Fixed former entry.
@@ -8540,7 +19635,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
 	  Use new logic to calculate "Wasserstand/Wasserspiegellage".
-	  Compared to desktop FLYS are the results are structurally right 
+	  Compared to desktop FLYS are the results are structurally right
 	  but a bit off in the positions after the decimal points.
 	  Maybe a result of the interpolation? Need to debug this.
 
@@ -8634,9 +19729,9 @@
 	* src/main/java/de/intevation/flys/artifacts/math/LinearRemap.java:
 	  New. Remaps "gleichwertige" Q values to the corresponding
 	  "ungleichwertige" Q values depending on km.
-	  
+
 	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
-	  Remap the Q values "ungleichwertig" depending on the 
+	  Remap the Q values "ungleichwertig" depending on the
 	  "gleichwertige" ones.
 
 2011-05-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
@@ -8745,7 +19840,7 @@
 2011-05-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
 	* src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java:
-	  Fetches river name from incoming XML document. If no river is given all 
+	  Fetches river name from incoming XML document. If no river is given all
 	  infos about all rivers are listed.
 
 	* src/main/resources/metadata/template.xml: Templates honors the 'river'
@@ -8757,7 +19852,7 @@
 
 	* src/main/java/de/intevation/flys/artifacts/services/meta/StackFrames.java:
 	  Take parameters as an initial stack frame.
-	  
+
 	* src/main/java/de/intevation/flys/artifacts/services/meta/TypeConverter.java:
 	  New. Converts types off stacked variables.
 
@@ -9161,7 +20256,7 @@
 	* src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java:
 	  Use the cache for the wst value table if configured.
 
-	* doc/conf/cache.xml: Choose a more precise name for the 
+	* doc/conf/cache.xml: Choose a more precise name for the
 	  wst value table cache.
 
 2011-04-29	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
@@ -9356,7 +20451,7 @@
 
 2011-04-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
-	* contrib/visualize-transitions.xsl: Added to create a 
+	* contrib/visualize-transitions.xsl: Added to create a
 	  Graphviz digraph out of the config.xml. Usage:
 
 	  $ xsltproc --stringparam base-dir ../doc/conf/ \
@@ -9585,7 +20680,7 @@
 	* src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java:
 	  Added static method getWForQ() to interpolate a w value for
 	  a given q value based on a given discharge table.
-	
+
 2011-04-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
 	* src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java:
@@ -9755,10 +20850,10 @@
 
 	* src/main/java/de/intevation/flys/artifacts/context/SessionCallContextListener.java:
 	  Interacts with SessionHolder now.
-	
+
 	* src/main/java/de/intevation/flys/exports/ChartExportHelper.java:
 	  Removed superfluous import.
-	
+
 2011-04-14  Ingo Weinzierl <ingo@intevation.de>
 
 	* src/main/java/de/intevation/flys/artifacts/context/SessionCallContextListener.java:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/contrib/add-i18n-numbers.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+
+""" Add unique numbers in front of properties values
+    to identfy the key without knowing the real key.
+"""
+
+import sys
+import re
+import os
+
+BLACK_LISTED_KEYS = [
+    re.compile(r".*\.file$")
+]
+
+BLACK_LISTED_VALUES = [
+    re.compile(r"^http.*$")
+]
+
+NUMBERED  = re.compile(r"^\s*([^\s]+)\s*=\s*\[([0-9a-zA-Z]+)\]\s*(.+)$")
+UNUMBERED = re.compile(r"^\s*([^\s]+)\s*=\s*(.+)$")
+
+ALPHA = "0123456789" \
+        "abcdefghijklmnopqrstuvwxyz" \
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+def decode_ibase62(s):
+    t, c = 0, 1
+    for x in s[::-1]:
+        i = ALPHA.find(x)
+        t += i*c
+        c *= len(ALPHA)
+    return t
+
+def ibase62(i):
+    if i == 0:
+        return "0"
+    out = []
+    if i < 0:
+        out.append("-")
+        i = -1
+    while i > 0:
+        out.append(ALPHA[i % len(ALPHA)])
+        i //= len(ALPHA)
+    out.reverse()
+    return ''.join(out)
+
+def is_blacklisted(key, value):
+
+    for bl in BLACK_LISTED_KEYS:
+        if bl.match(key):
+            return True
+
+    for bl in BLACK_LISTED_VALUES:
+        if bl.match(value):
+            return True
+
+    return False
+
+def find_key(already_numbered, value):
+    for k, v in already_numbered.iteritems():
+        if v == value:
+            return k
+    return None
+
+def decorated_content(infile, outfile, already_numbered):
+
+    for line in infile:
+        line = line.strip()
+        m = NUMBERED.match(line)
+        if m:
+            key, num, value = m.groups()
+            decoded_num = decode_ibase62(num)
+            last = find_key(already_numbered, decoded_num)
+            if last is None:
+                already_numbered[key] = decoded_num
+            elif last != key:
+                print >> sys.stderr,  "WARN: Number clash: " \
+                    "%s leeds to '%s' and '%s'" % (num, key, last)
+            print >> outfile, line
+            continue
+
+        m = UNUMBERED.match(line)
+        if m:
+            key, value = m.groups(1)
+            if is_blacklisted(key, value):
+                print >> outfile, line
+            else:
+                num = already_numbered.setdefault(key, len(already_numbered))
+                print >> outfile, "%s=[%s] %s" % (key, ibase62(num), m.group(2))
+            continue
+        print >> outfile, line
+
+def tmp_fname(fname):
+    name = fname + ".tmp"
+    i = 0
+    while os.path.exists(name):
+        name = "%s.tmp%d" % (fname, i)
+        i += 1
+    return name
+
+def decorate_file(fname, already_numbered):
+
+    tmp = tmp_fname(fname)
+
+    with open(fname, "r") as infile:
+        with open(tmp, "w") as outfile:
+            decorated_content(infile, outfile, already_numbered)
+
+    os.rename(tmp, fname)
+
+def main():
+    already_numbered = {}
+    for fname in sys.argv[1:]:
+        print >> sys.stderr, "checking %s" % fname
+        decorate_file(fname, already_numbered)
+
+if __name__ == "__main__":
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/contrib/check-i18n-properties.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+import sys
+import re
+
+SPLIT_RE = re.compile(r"^\s*([^=]+)=\s*(.*)\s*")
+
+def load_properties_file(filename):
+    props = {}
+    with open(filename, "r") as f:
+        while True:
+            line = f.readline()
+            if not line: break
+            m = SPLIT_RE.match(line)
+            if not m: continue
+            k = m.group(1).strip()
+            v = m.group(2).strip()
+            if k in props:
+                print >> sys.stderr, "'%s' found more than once in '%s'." % (
+                    k, filename)
+            else:
+                props[k] = v
+    return props
+
+def main():
+
+    props = [(arg, load_properties_file(arg)) for arg in sys.argv[1:]]
+
+    l = len(props)
+
+    for i in range(0, l):
+        a = props[i][1]
+        for j in range(i+1, l):
+            b = props[j][1]
+            for k in a.iterkeys():
+                if k not in b:
+                    print >> sys.stderr, "'%s' found in '%s' but not in '%s'." % (
+                        k, props[i][0], props[j][0])
+            for k in b.iterkeys():
+                if k not in a:
+                    print >> sys.stderr, "'%s' found in '%s' but not in '%s'." % (
+                        k, props[j][0], props[i][0])
+        
+if __name__ == '__main__':
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/contrib/fixoverview2html.xsl	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,397 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet
+  version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="xml" encoding="UTF-8"
+    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
+    doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" indent="yes"/>
+
+  <xsl:param name="project-uuid">de3f3307-3429-4ff9-8f43-3fb2fcf21b27</xsl:param>
+  <xsl:param name="render-checkboxes" select="true()"/>
+  <xsl:param name="callback"/>
+
+  <xsl:param name="locale">de</xsl:param>
+
+  <xsl:decimal-format name="de" decimal-separator=',' grouping-separator='.'/>
+  <xsl:decimal-format name="en" decimal-separator='.' grouping-separator=','/>
+
+  <!-- XXX: This kind of i18n is cheesy.
+            It should be better done in an external resource. -->
+
+  <xsl:variable name="km-pattern">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">0,##</xsl:when>
+      <xsl:otherwise>0.##</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-event">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">Ereignis</xsl:when>
+      <xsl:otherwise>Event</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-legend">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">Legende</xsl:when>
+      <xsl:otherwise>Caption</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-color">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">Farbe</xsl:when>
+      <xsl:otherwise>Color</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-meaning">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">Bedeutung</xsl:when>
+      <xsl:otherwise>Meaning</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-around-mnq">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">um MNQ</xsl:when>
+      <xsl:otherwise>around MNQ</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-around-mq">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">um MQ</xsl:when>
+      <xsl:otherwise>around MQ</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-around-mhq">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">um MHQ</xsl:when>
+      <xsl:otherwise>around MHQ</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-above-hq5">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">über HQ5</xsl:when>
+      <xsl:otherwise>above HQ5</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <!-- TODO: Format dates according locale. -->
+
+  <xsl:template match="@*" mode="min">
+    <xsl:if test="position() = 1">
+      <xsl:value-of select="number(.)"/>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="@*" mode="max">
+    <xsl:if test="position() = last()">
+      <xsl:value-of select="number(.)"/>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:variable name="global-min">
+    <xsl:choose>
+      <xsl:when test="count(/fixings/events/event/sector) &gt; 0">
+        <xsl:apply-templates mode="min" select="/fixings/events/event/sector/@from">
+          <xsl:sort data-type="number" select="."/>
+        </xsl:apply-templates>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="number(/fixings/river/@from)"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="global-max">
+    <xsl:choose>
+      <xsl:when test="count(/fixings/events/event/sector) &gt; 0">
+        <xsl:apply-templates mode="max" select="/fixings/events/event/sector/@to">
+          <xsl:sort data-type="number" select="."/>
+        </xsl:apply-templates>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="number(/fixings/river/@to)"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:template name="percent">
+    <xsl:param name="sector"/>
+
+    <xsl:variable name="start">
+      <xsl:choose>
+        <xsl:when test="number($sector/@from) &lt; $global-min">
+          <xsl:value-of select="$global-min"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="number($sector/@from)"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:variable name="end">
+      <xsl:choose>
+        <xsl:when test="number($sector/@to) &gt; $global-max">
+          <xsl:value-of select="$global-max"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="number($sector/@to)"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:choose>
+      <xsl:when test="$end &lt; $start">
+        <xsl:value-of select="number(0)"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="100.0 * (($end - $start) div ($global-max - $global-min))"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="emit-gap-gauge">
+    <xsl:param name="gauge"/>
+    <xsl:call-template name="internal-emit-gap">
+      <xsl:with-param name="sector" select="$gauge"/>
+      <xsl:with-param name="preds" select="$gauge/preceding-sibling::gauge"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="emit-gap">
+    <xsl:param name="sector"/>
+    <xsl:call-template name="internal-emit-gap">
+      <xsl:with-param name="sector" select="$sector"/>
+      <xsl:with-param name="preds" select="$sector/preceding-sibling::sector"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="internal-emit-gap">
+    <xsl:param name="sector"/>
+    <xsl:param name="preds"/>
+
+    <xsl:variable name="start">
+      <xsl:choose>
+        <xsl:when test="number($sector/@from) &lt; $global-min">
+          <xsl:value-of select="$global-min"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="$sector/@from"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:if test="$start &lt; $global-max">
+      <xsl:variable name="num-preds" select="count($preds)"/>
+      <xsl:variable name="prev-end">
+        <xsl:choose>
+          <xsl:when test="count($preds) &lt; 1">
+            <xsl:value-of select="$global-min"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="number($preds[last()]/@to)"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+
+      <xsl:if test="$prev-end &lt; $global-max">
+        <xsl:variable name="gap-len" select="$start - $prev-end"/>
+        <xsl:if test="$gap-len &gt; 0.005">
+          <div>
+            <xsl:attribute name="style">
+              <xsl:text>width:</xsl:text>
+                <xsl:value-of select="100.0 * ($gap-len div ($global-max - $global-min))"/>
+              <xsl:text>%;float:left</xsl:text>
+            </xsl:attribute>
+            <xsl:text disable-output-escaping="yes"><![CDATA[&nbsp;]]></xsl:text>
+          </div>
+        </xsl:if>
+      </xsl:if>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="sector" mode="sectors">
+    <xsl:call-template name="emit-gap">
+      <xsl:with-param name="sector" select="."/>
+    </xsl:call-template>
+    <div>
+      <xsl:attribute name="style">
+        <xsl:text>background:</xsl:text>
+        <xsl:choose>
+          <xsl:when test="@class = '0'">green</xsl:when>
+          <xsl:when test="@class = '1'">blue</xsl:when>
+          <xsl:when test="@class = '2'">magenta</xsl:when>
+          <xsl:when test="@class = '3'">red</xsl:when>
+          <xsl:otherwise>black</xsl:otherwise>
+        </xsl:choose>
+        <xsl:text>;width:</xsl:text>
+        <xsl:call-template name="percent">
+          <xsl:with-param name="sector" select="."/>
+        </xsl:call-template>
+        <xsl:text>%</xsl:text>
+        <xsl:text>;float:left</xsl:text>
+      </xsl:attribute>
+      <xsl:attribute name="title">
+        <xsl:text>km </xsl:text>
+        <xsl:value-of select="format-number(@from, $km-pattern, $locale)"/>
+        <xsl:text> - </xsl:text>
+        <xsl:value-of select="format-number(@to, $km-pattern, $locale)"/>
+        <xsl:choose>
+          <xsl:when test="@class = '0'"> / Q <xsl:value-of select="$i18n-around-mnq"/></xsl:when>
+          <xsl:when test="@class = '1'"> / Q <xsl:value-of select="$i18n-around-mq"/></xsl:when>
+          <xsl:when test="@class = '2'"> / Q <xsl:value-of select="$i18n-around-mhq"/></xsl:when>
+          <xsl:when test="@class = '3'"> / Q <xsl:value-of select="$i18n-above-hq5"/></xsl:when>
+        </xsl:choose>
+      </xsl:attribute>
+      <xsl:text disable-output-escaping="yes"><![CDATA[&nbsp;]]></xsl:text>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="event">
+    <tr id="{@cid}">
+      <xsl:if test="$render-checkboxes">
+        <td>
+          <input type="checkbox" name="{$project-uuid}:{@cid}" checked="true" onclick="{$callback}"/>
+        </td>
+      </xsl:if>
+      <td>
+        <xsl:apply-templates mode="sectors"/>
+      </td>
+      <td align="center">
+        <xsl:attribute name="title"><xsl:value-of select="@description"/></xsl:attribute>
+        <xsl:value-of select="@date"/>
+      </td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="gauge" mode="gauges">
+    <xsl:call-template name="emit-gap-gauge">
+      <xsl:with-param name="gauge" select="."/>
+    </xsl:call-template>
+    <div>
+      <xsl:variable name="start">
+        <xsl:choose>
+          <xsl:when test="number(@from) &lt; $global-min">
+            <xsl:value-of select="$global-min"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="number(@from)"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+
+      <xsl:variable name="end">
+        <xsl:choose>
+          <xsl:when test="number(@to) &gt; $global-max">
+            <xsl:value-of select="$global-max"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="number(@to)"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+
+      <xsl:attribute name="style">
+        <xsl:text>overflow:hidden;background:</xsl:text>
+        <xsl:choose>
+          <xsl:when test="(count(preceding::*) mod 2) = 0">#ada96e</xsl:when>
+          <xsl:otherwise>silver</xsl:otherwise>
+        </xsl:choose>
+        <xsl:text>;width:</xsl:text>
+        <xsl:call-template name="percent">
+          <xsl:with-param name="sector" select="."/>
+        </xsl:call-template>
+        <xsl:text>%</xsl:text>
+        <xsl:text>;float:left</xsl:text>
+      </xsl:attribute>
+      <xsl:attribute name="title">
+        <xsl:value-of select="@name"/>
+        <xsl:text>: km </xsl:text>
+        <xsl:value-of select="format-number($start, $km-pattern, $locale)"/>
+        <xsl:text> - </xsl:text>
+        <xsl:value-of select="format-number($end, $km-pattern, $locale)"/>
+      </xsl:attribute>
+      <nobr><xsl:value-of select="@name"/></nobr>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="events">
+    <table width="97%" border="1" cellspacing="0" cellpadding="0"
+           style="font-size: 10pt;font-family:Arial;Verdana,sans-serif">
+      <colgroup>
+        <xsl:if test="$render-checkboxes">
+            <col width="20px"/>
+        </xsl:if>
+        <col width="*"/>
+        <col width="75px"/>
+      </colgroup>
+      <tr>
+        <xsl:if test="$render-checkboxes">
+          <th>&#160;</th>
+        </xsl:if>
+        <th><xsl:apply-templates mode="gauges" select="/fixings/gauges"/></th>
+        <th><xsl:value-of select="$i18n-event"/></th>
+      </tr>
+      <xsl:apply-templates/>
+    </table>
+  </xsl:template>
+
+  <xsl:template match="/">
+    <html>
+      <head>
+        <title>Fixierungen:</title>
+      </head>
+      <body>
+        <xsl:apply-templates/>
+        <hr/>
+        <table border="1" cellspacing="0" cellpadding="0">
+          <caption><xsl:value-of select="$i18n-legend"/></caption>
+          <tr>
+            <th><xsl:value-of select="$i18n-color"/></th>
+            <th colspan="2"><xsl:value-of select="$i18n-meaning"/></th>
+          </tr>
+          <xsl:if test="count(/fixings/events/event/sector[@class = '0']) &gt; 0">
+          <tr>
+            <td style="background: green">&#160;</td>
+            <td><xsl:value-of select="$i18n-around-mnq"/></td>
+            <td>Q &#8712; [0, (MNQ+MQ)/2)</td>
+          </tr>
+          </xsl:if>
+          <xsl:if test="count(/fixings/events/event/sector[@class = '1']) &gt; 0">
+          <tr>
+            <td style="background: blue">&#160;</td>
+            <td><xsl:value-of select="$i18n-around-mq"/></td>
+            <td>Q &#8712; [(MNQ+MQ)/2, (MQ+MHQ)/2)</td>
+          </tr>
+          </xsl:if>
+          <xsl:if test="count(/fixings/events/event/sector[@class = '2']) &gt; 0">
+          <tr>
+            <td style="background: magenta">&#160;</td>
+            <td><xsl:value-of select="$i18n-around-mhq"/></td>
+            <td>Q &#8712; [(MQ+MHQ)/2, HQ5)</td>
+          </tr>
+          </xsl:if>
+          <xsl:if test="count(/fixings/events/event/sector[@class = '3']) &gt; 0">
+          <tr>
+            <td style="background: red">&#160;</td>
+            <td><xsl:value-of select="$i18n-above-hq5"/></td>
+            <td>Q &#8712; [HQ5, &#8734;)</td>
+          </tr>
+          </xsl:if>
+        </table>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template match="text()"/>
+  <xsl:template match="text()" mode="sectors"/>
+  <xsl:template match="text()" mode="gauges"/>
+
+</xsl:stylesheet>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/contrib/themes2html.xsl	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet
+  version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="xml" encoding="UTF-8"
+    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
+    doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" indent="yes"/>
+
+
+  <xsl:template match="/themes/themegroup" mode="header">
+    <li><a href="#tg-{@name}"><xsl:value-of select="@name"/></a> (<xsl:value-of select="count(theme)"/> themes)</li>
+  </xsl:template>
+
+  <xsl:template match="field" mode="theme-inherits">
+    <tr>
+        <td><i><xsl:value-of select="@name"/></i> (<a
+            href="#theme-{../../../@name}-{../../@name}"><xsl:value-of select="../../@name"/></a>)</td>
+        <td><xsl:value-of select="@display"/></td>
+        <td><xsl:value-of select="@type"/></td>
+        <td><xsl:value-of select="@default"/></td>
+        <td><xsl:value-of select="@hints"/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="field" mode="theme-fields">
+    <tr>
+        <td><xsl:value-of select="@name"/></td>
+        <td><xsl:value-of select="@display"/></td>
+        <td><xsl:value-of select="@type"/></td>
+        <td><xsl:value-of select="@default"/></td>
+        <td><xsl:value-of select="@hints"/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="inherit" mode="theme-inherits">
+    <xsl:variable name="target" select="@from"/>
+    <xsl:apply-templates
+        select="../../../theme[@name = $target]/inherits/inherit | /themes/themegroup/theme[@type='virtual' and @name=$target]/inherits/inherit"
+        mode="theme-inherits"/>
+    <xsl:apply-templates
+        select="../../../theme[@name = $target]/fields/field | /themes/themegroup/theme[@type='virtual' and @name=$target]/fields/field"
+        mode="theme-inherits"/>
+  </xsl:template>
+
+  <xsl:template match="theme" mode="sub-themes">
+    <xsl:variable name="tname" select="../@name"/>
+    <xsl:variable name="name" select="@name"/>
+    <li><a href="#theme-{$tname}-{$name}"><xsl:value-of select="$tname"/>/<xsl:value-of select="$name"/></a></li>
+  </xsl:template>
+
+  <xsl:template match="theme" mode="theme-groups">
+    <div>
+      <h4>[<a href="#theme-groups">Groups</a>] [<a href="#tg-{../@name}"><xsl:value-of select="../@name"/></a>] <a 
+          name="theme-{../@name}-{@name}">Theme '<xsl:value-of select="@name"/>'<xsl:if
+        test="@type = 'virtual'"> (virtual)</xsl:if></a></h4>
+
+      <xsl:variable name="tname" select="../@name"/>
+      <xsl:variable name="is-virtual" select="$tname = 'virtual'"/>
+      <xsl:variable name="name" select="@name"/>
+
+      <xsl:if
+        test="count(/themes/themegroup[$is-virtual or @name=$tname or @name='virtual']/theme[inherits/inherit/@from=$name]) &gt; 0">
+      <strong>Sub themes</strong>
+      <ul>
+        <xsl:apply-templates
+            select="/themes/themegroup[$is-virtual or @name=$tname or @name='virtual']/theme[inherits/inherit/@from=$name]"
+            mode="sub-themes"/>
+      </ul>
+      </xsl:if>
+
+      <table border="1" cellspacing="0" width="80%" summary="Definition of theme {@name}">
+        <tr>
+          <th>Name</th>
+          <th>Display</th>
+          <th>Type</th>
+          <th>Default</th>
+          <th>Hints</th>
+        </tr>
+        <xsl:apply-templates mode="theme-inherits" select="inherits/inherit"/>
+        <xsl:apply-templates mode="theme-fields" select="fields/field"/>
+      </table>
+    </div>
+    <hr/>
+  </xsl:template>
+
+  <xsl:template match="theme" mode="theme-list">
+    <li><a href="#theme-{../@name}-{@name}"><xsl:value-of select="@name"/></a></li>
+  </xsl:template>
+
+  <xsl:template match="/themes/themegroup" mode="theme-groups">
+    <div>
+        <h2><a name="tg-{@name}">Theme group '<xsl:value-of select="@name"/>'</a></h2>
+        <div>
+          <h3>Theme List</h3>
+          <ul>
+            <xsl:apply-templates mode="theme-list" select="theme"/>
+          </ul>
+        </div>
+        <div>
+          <h3>Theme Definitions</h3>
+          <xsl:apply-templates mode="theme-groups" select="theme"/>
+        </div>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="mapping" mode="mappings">
+    <xsl:variable name="target" select="@to"/>
+    <tr>
+      <td><xsl:value-of select="@from"/></td>
+      <td><a 
+        href="#theme-{/themes/themegroup/theme[@name = $target][1]/../@name}-{$target}"
+      ><xsl:value-of select="@to"/></a></td>
+      <td><xsl:if test="@pattern"><pre><xsl:value-of select="@pattern"/></pre></xsl:if></td>
+      <td><xsl:if test="@masterAttr"><pre><xsl:value-of select="@masterAttr"/></pre></xsl:if></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="mappings" mode="mappings">
+    <div>
+      <h3><a name="mappings">Mappings</a></h3>
+      <table width="80%" border="1" cellspacing="0" summary="Mappings from facets to themes">
+      <tr>
+        <th>From</th>
+        <th>To</th>
+        <th>Pattern</th>
+        <th>Condition</th>
+      </tr>
+      <xsl:apply-templates select="mapping" mode="mappings"/>
+      </table>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="/">
+    <html>
+    <head>
+        <title>FLYS3 - Themes</title>
+    </head>
+    <body>
+      <h1>FLYS3 - Themes</h1>
+      <div>
+      <h2><a name="theme-groups">Theme groups</a> (<xsl:value-of select="count(/themes/themegroup)"/> groups)</h2>
+      <ul>
+        <xsl:apply-templates mode="header" select="/themes/themegroup[@name != 'virtual']"/>
+        <xsl:apply-templates mode="header" select="/themes/themegroup[@name = 'virtual']"/>
+      </ul>
+      </div>
+      <div>
+        <h2><a href="#mappings">Mappings</a> (<xsl:value-of select="count(/themes/mappings/mapping)"/> mappings)</h2>
+      </div>
+      <hr/>
+      <div>
+        <xsl:apply-templates mode="theme-groups" select="/themes/themegroup[@name != 'virtual']"/>
+        <xsl:apply-templates mode="theme-groups" select="/themes/themegroup[@name = 'virtual']"/>
+      </div>
+      <xsl:apply-templates mode="mappings" select="/themes/mappings"/>
+    </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template match="text()"/>
+  <xsl:template match="text()" mode="header"/>
+  <xsl:template match="text()" mode="theme-groups"/>
+  <xsl:template match="text()" mode="theme-list"/>
+  <xsl:template match="text()" mode="sub-themes"/>
+  <xsl:template match="text()" mode="theme-fields"/>
+  <xsl:template match="text()" mode="theme-inherits"/>
+  <xsl:template match="text()" mode="mappings"/>
+
+</xsl:stylesheet>
--- a/flys-artifacts/contrib/visualize-transitions.xsl	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/contrib/visualize-transitions.xsl	Fri Sep 28 12:15:52 2012 +0200
@@ -92,9 +92,11 @@
 
     <xsl:template match="condition" mode="inside-artifact">
         <xsl:text> [ label="</xsl:text>
-        <xsl:value-of select="@inputvalue"/>
+        <xsl:value-of select="@data"/>
         <xsl:text> </xsl:text>
-        <xsl:value-of select="@operator"/>
+        <xsl:call-template name="readable-operator">
+            <xsl:with-param name="operator" select="@operator"/>
+        </xsl:call-template>
         <xsl:text> </xsl:text>
         <xsl:value-of select="@value"/>
         <xsl:text>" ]</xsl:text>
@@ -103,6 +105,15 @@
     <xsl:template match="text()" mode="inside-artifact"/>
     <xsl:template match="text()"/>
 
+    <xsl:template name="readable-operator">
+        <xsl:param name="operator" />
+        <xsl:choose>
+            <xsl:when test='$operator = "equal"'>=</xsl:when>
+            <xsl:when test='$operator = "notequal"'>!=</xsl:when>
+            <xsl:otherwise><xsl:value-of select="$operator"/></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
      <xsl:template name="string-replace-all">
         <xsl:param name="text" />
         <xsl:param name="replace" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifact-db.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<database>
+    <!-- This Section configures the Settings for connecting to the
+         Artifact-Database instance. e.g. SQLite -->
+    <user>SA</user>
+    <password></password>
+    <!-- For use with a postgresql database use the appropriate driver-->
+    <!--driver>org.postgresql.Driver</driver-->
+    <url>jdbc:h2:${artifacts.config.dir}/../artifactdb/artifacts.db</url>
+</database>
--- a/flys-artifacts/doc/conf/artifacts/annotation.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/artifacts/annotation.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -1,16 +1,16 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <artifact name="annotation">
-    <states>
-        <state id="state.annotation.river"
+  <states>
+    <state id="state.annotation.river"
                description="state.annotation.river"
                state="de.intevation.flys.artifacts.states.AnnotationRiverState">
-           <outputmodes>
-             <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart">
-                  <facets>
-                     <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations" />
-                  </facets>
-              </outputmode>
-           </outputmodes>
-        </state>
-    </states>
+      <outputmodes>
+        <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart">
+          <facets>
+            <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations" />
+          </facets>
+        </outputmode>
+      </outputmodes>
+    </state>
+  </states>
 </artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifacts/chart.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<artifact name="new_chart">
+    <states>
+         <state id="state.chart.river" description="state.winfo.river" state="de.intevation.flys.artifacts.states.RiverSelect">
+            <data name="river" type="String" />
+         </state>
+
+         <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+             <from state="state.chart.river"/>
+             <to state="state.chart.type"/>
+         </transition>
+
+         <state id="state.chart.type" description="state.chart.type" state="de.intevation.flys.artifacts.ChartArtifact$ChartState">
+            <data name="chart_type" type="String" />
+         </state>
+
+         <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+             <from state="state.chart.type"/>
+             <to state="state.chart.w_differences"/>
+             <condition data="chart_type" value="chart.new.w_differences" operator="equal"/>
+         </transition>
+
+         <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+             <from state="state.chart.type"/>
+             <to state="state.chart.km"/>
+             <condition data="chart_type" value="chart.new.durationcurve" operator="equal"/>
+         </transition>
+
+         <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+             <from state="state.chart.type"/>
+             <to state="state.chart.km"/>
+             <condition data="chart_type" value="chart.new.computeddischargecurve" operator="equal"/>
+         </transition>
+
+         <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+             <from state="state.chart.type"/>
+             <to state="state.chart.crosssection"/>
+             <condition data="chart_type" value="chart.new.crosssection" operator="equal"/>
+         </transition>
+
+         <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+             <from state="state.chart.type"/>
+             <to state="state.chart.longitudinal_section"/>
+             <condition data="chart_type" value="chart.new.longitudinal_section" operator="equal"/>
+         </transition>
+
+         <state id="state.chart.km" description="state.chart.km" state="de.intevation.flys.artifacts.states.LocationSelect">
+             <data name="ld_locations" type="Double[]"/>
+         </state>
+
+         <state id="state.chart.w_differences" description="state.chart.w_differences" state="de.intevation.flys.artifacts.states.WDifferencesState">
+            <outputmodes>
+                <outputmode name="w_differences" description="output.w_differences" mime-type="image/png" type="chart">
+                    <facets>
+                        <facet name="empty.facet" description="Empty"/>
+                        <facet name="longitudinal_section.q" description="facet.longitudinal_section.q"/>
+                        <facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/>
+                        <facet name="w_differences" description="facet.w_differences"/>
+                        <facet name="other.wkms" description="facet.other.wkms"/>
+                        <facet name="other.wqkms" description="facet.other.wqkms"/>
+                        <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/>
+                        <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <state id="state.chart.longitudinal_section" description="state.chart.logitudinal_section" state="de.intevation.flys.artifacts.states.DischargeLongitudinalSection">
+            <outputmodes>
+                <outputmode name="longitudinal_section" description="output.discharge_longitudinal_section" mime-type="image/png" type="chart">
+                    <facets>
+                        <facet name="empty.facet" decription= "Empty"/>
+                        <facet name="discharge_longitudinal_section.w"/>
+                        <facet name="discharge_longitudinal_section.q"/>
+                        <facet name="discharge_longitudinal_section.c"/>
+                        <facet name="other.wqkms"/>
+                        <facet name="other.wkms"/>
+                        <facet name="heightmarks_points"/>
+                        <facet name="longitudinal_section.area"        description="an area"/>
+                        <facet name="longitudinal_section.annotations"/>
+                        <facet name="longitudinal_section.w"/>
+                        <facet name="longitudinal_section.manualpoints"/>
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <state id="state.chart.crosssection" description="state.chart.crosssection" state="de.intevation.flys.artifacts.states.WaterlevelState">
+            <outputmodes>
+                <outputmode name="cross_section" description="output.cross_section" mime-type="image/png" type="chart">
+                  <facets>
+                    <facet name="empty.facet" description="Empty"/>
+                    <facet name="cross_section_water_line" description="facet.cross_section_water_line"/>
+                    <facet name="cross_section"            description="facet.cross_section"/>
+                    <facet name="area"                     description="an area"/>
+                    <facet name="cross_section.area"         description="an area"/>
+                    <facet name="cross_section.manualpoints" description="points"/>
+                    <facet name="hyk"                      description="hyks"/>
+                  </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.chart.km"/>
+            <to state="state.chart.computeddischargecurve"/>
+            <condition data="chart_type" value="chart.new.computeddischargecurve" operator="equal"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.chart.km"/>
+            <to state="state.chart.durationcurve"/>
+            <condition data="chart_type" value="chart.new.durationcurve" operator="equal"/>
+        </transition>
+
+        <state id="state.chart.computeddischargecurve" description="state.chart.computeddischargecurve" state="de.intevation.flys.artifacts.states.ComputedDischargeCurveState">
+            <outputmodes>
+                <outputmode name="computed_discharge_curve" description="output.computed_discharge_curve" mime-type="image/png" type="chart">
+                    <facets>
+                        <facet name="empty.facet" description="Empty"/>
+                        <facet name="computed_discharge_curve.manualpoints"/>
+                        <facet name="computed_discharge_curve.q" description="facet.computed_discharge_curve.q"/>
+                        <facet name="computed_discharge_curve.mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/>
+                        <facet name="computed_discharge_curve.mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/>
+                        <facet name="other.wqkms" description="facet.other.wqkms"/>
+                        <facet name="other.wq" description="Point-like data like fixations"/>
+                        <facet name="other.wq" description="Point-like data like fixations"/>
+                        <facet name="other.wkms.interpol" description="Height over km, like flood protections."/>
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <state id="state.chart.durationcurve" description="state.chart.durationcurve" state="de.intevation.flys.artifacts.states.DurationCurveState">
+            <outputmodes>
+                <outputmode name="duration_curve" description="output.duration_curve" mime-type="image/png" type="chart">
+                    <facets>
+                        <facet name="empty.facet" description="Empty"/>
+                        <facet name="duration_curve.manualpoints"/>
+                        <facet name="duration_curve.w" description="facet.duration_curve.w"/>
+                        <facet name="duration_curve.q" description="facet.duration_curve.q"/>
+                        <facet name="computed_discharge_curve.mainvalues.q" description="Q Main Values"/>
+                        <facet name="computed_discharge_curve.mainvalues.w" description="W Main Values"/>
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+    </states>
+</artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifacts/fixanalysis.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,290 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<artifact name="fixanalysis">
+    <states>
+        <state id="state.fix.river" description="state.fix.river"
+            state="de.intevation.flys.artifacts.states.RiverSelect">
+            <data name="river" type="String" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.river"/>
+            <to state="state.fix.calculation.mode"/>
+        </transition>
+
+        <state id="state.fix.calculation.mode"
+            description="state.fix.calcuation.mode"
+            state="de.intevation.flys.artifacts.states.fixation.FixationSelect">
+            <data name="calculation.mode" type="String"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.calculation.mode"/>
+            <to state="state.fix.location"/>
+        </transition>
+
+        <state id="state.fix.location" description="state.fix.location"
+            state="de.intevation.flys.artifacts.states.fixation.LocationSelect">
+            <data name="from" type="Double"/>
+            <data name="to" type="Double"/>
+            <data name="step" type="Double"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.location"/>
+            <to state="state.fix.period"/>
+        </transition>
+
+        <state id="state.fix.period" description="state.fix.period"
+            state="de.intevation.flys.artifacts.states.fixation.FixationPeriod">
+            <data name="start" type="Long"/>
+            <data name="end" type="Long"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.period"/>
+            <to state="state.fix.gaugerange"/>
+        </transition>
+
+        <state id="state.fix.gaugerange" description="state.fix.gaugerange"
+            state="de.intevation.flys.artifacts.states.fixation.GaugeRange">
+            <data name="q1" type="Integer"/>
+            <data name="q2" type="Integer"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.gaugerange"/>
+            <to state="state.fix.eventselect"/>
+        </transition>
+
+        <state id="state.fix.eventselect" description="state.fix.eventselect"
+            state="de.intevation.flys.artifacts.states.fixation.EventSelect">
+            <data name="events" type="intarray"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.fix.eventselect"/>
+            <to state="state.fix.analysis.referenceperiod"/>
+            <condition data="calculation.mode" value="calculation.analysis"
+                operator="equal"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.fix.eventselect"/>
+            <to state="state.fix.vollmer.function"/>
+            <condition data="calculation.mode" value="calculation.vollmer"
+                operator="equal"/>
+        </transition>
+
+        <state id="state.fix.analysis.referenceperiod"
+            description="state.fix.analysis.referenceperiod"
+            state="de.intevation.flys.artifacts.states.fixation.ReferencePeriod">
+            <data name="ref_start" type="Long"/>
+            <data name="ref_end" type="Long"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.analysis.referenceperiod"/>
+            <to state="state.fix.analysis.analysisperiods"/>
+        </transition>
+
+        <state id="state.fix.analysis.analysisperiods"
+            description="state.fix.analysis.analysisperiods"
+            state="de.intevation.flys.artifacts.states.fixation.AnalysisPeriods">
+            <data name="ana_data" type="String"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.analysis.analysisperiods"/>
+            <to state="state.fix.analysis.function"/>
+        </transition>
+
+        <state id="state.fix.analysis.function"
+            description="state.fix.analysis.function"
+            state="de.intevation.flys.artifacts.states.fixation.FunctionSelect">
+            <data name="function" type="String"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.analysis.function"/>
+            <to state="state.fix.analysis.preprocessing"/>
+        </transition>
+
+        <state id="state.fix.analysis.preprocessing"
+            description="state.fix.analysis.preprocessing"
+            state="de.intevation.flys.artifacts.states.fixation.PreprocessingSelect">
+            <data name="preprocessing" type="Boolean"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.analysis.preprocessing"/>
+            <to state="state.fix.analysis.compute"/>
+        </transition>
+
+        <state id="state.fix.analysis.compute"
+            description="state.fix.analysis.compute"
+            state="de.intevation.flys.artifacts.states.fixation.FixAnalysisCompute">
+            <outputmodes>
+                <outputmode name="fix_deltawt_export" description="output.fix_deltawt_export" mine-type="text/plain" type="export">
+                    <facets>
+                        <facet name="csv" description="facet.fix_deltawt.csv" />
+                    </facets>
+                </outputmode>
+                <outputmode name="fix_parameters_export" description="output.fix_parameters_export" mine-type="text/plain" type="export">
+                    <facets>
+                        <facet name="fix_parameters" description="facet.fix_parameters.csv" />
+                    </facets>
+                </outputmode>
+                <outputmode name="fix_wq_curve_at_export" description="output.fix_wq_curve_at_export" mime-type="text/plain" type="export">
+                    <facets>
+                        <facet name="at" description="facet.fix_wq_curve_export.at"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="fix_wq_curve" description="output.fix_wq_curve" mine-type="image/png" type="chart">
+                    <facets>
+                        <facet name="fix_sector_average_wq_0" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_wq_1" description="Average values for Ws in Q sectors."/>
+                        <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="qsectors" description="qsectors."/>
+                        <facet name="fix_outlier" description="The outliers"/>
+                        <facet name="other.wqkms.q"          description="W-Type of data" />
+                        <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"/>
+                        <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"/>
+                        <facet name="fix_wq_curve.manualpoints" description="Manual points"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="fix_deltawt_curve" description="output.fix_deltawt_curve" mine-type="image/png" type="chart">
+                    <facets>
+                        <facet name="fix_sector_average_dwt_0" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_dwt_1" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_dwt_2" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_dwt_3" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_analysis_events_dwt" description="Raw event values used in the calculation"/>
+                        <facet name="fix_reference_events_dwt" description="Raw event values used in the calculation"/>
+                        <facet name="fix_analysis_periods_dwt" description="Dateranges of analysis periods."/>
+                        <facet name="fix_deviation_dwt" description="The standard variance"/>
+                        <facet name="fix_deltawt_curve.manualpoints" description="Manual points"/>
+                        <facet name="fix_reference_period_dwt" description="Reference period"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="fix_longitudinal_section_curve" description="output.fix_longitudinal_section_curve" mine-type="image/png" type="chart">
+                    <facets>
+                        <facet name="fix_sector_average_ls_0" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_ls_1" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_ls_2" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_ls_3" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_ls_deviation_0" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_ls_deviation_1" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_ls_deviation_2" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_ls_deviation_3" description="Average values for Ws in Q sectors."/>
+                        <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
+                        <facet name="fix_deviation_ls" description="The standard variance"/>
+                        <facet name="fix_analysis_events_ls" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_reference_events_ls" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_longitudinal_section_curve.manualpoints" description="Manual points"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="fix_derivate_curve" description="output.fix_derivate_curve" mine-type="image/png" type="chart">
+                    <facets>
+                        <facet name="fix_derivate_curve" description="Derivate curve"/>
+                        <facet name="fix_derivate_curve.manualpoints" description="Manual points"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="fix_report" description="output.fix_report.report" mime-type="text/plain" type="report">
+                    <facets>
+                        <facet name="report" description="facet.fix.report" />
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <state id="state.fix.vollmer.function"
+            description="state.fix.vollmer.function"
+            state="de.intevation.flys.artifacts.states.fixation.FunctionSelect">
+            <data name="function" type="String"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.vollmer.function"/>
+            <to state="state.fix.vollmer.preprocessing"/>
+        </transition>
+
+        <state id="state.fix.vollmer.preprocessing"
+            description="state.fix.vollmer.preprocessing"
+            state="de.intevation.flys.artifacts.states.fixation.PreprocessingSelect">
+            <data name="preprocessing" type="Boolean"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.vollmer.preprocessing"/>
+            <to state="state.fix.vollmer.qs"/>
+        </transition>
+
+        <state id="state.fix.vollmer.qs" description="state.fix.vollmer.qs"
+            state="de.intevation.flys.artifacts.states.WQAdapted">
+            <data name="wq_isq"   type="String" />
+            <data name="wq_values" type="WQTriple" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.fix.vollmer.qs"/>
+            <to state="state.fix.vollmer.compute"/>
+        </transition>
+
+        <state id="state.fix.vollmer.compute"
+            description="state.fix.vollmer.compute"
+            state="de.intevation.flys.artifacts.states.fixation.FixRealizingCompute">
+            <outputmodes>
+                <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart">
+                    <facets>
+                    	<facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/>
+                    	<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.wqkms" description="facet.other.wqkms"/>
+                        <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"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="fix_wq_curve" description="output.fix_wq_curve" mine-type="image/png" type="chart">
+                    <facets>
+                        <facet name="fix_sector_average_wq_0" description="Average values for Ws in Q sectors."/>
+                        <facet name="fix_sector_average_wq_1" description="Average values for Ws in Q sectors."/>
+                        <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_outlier" description="The outliers"/>
+                        <facet name="qsectors" description="qsectors."/>
+                        <facet name="other.wqkms.q"          description="W-Type of data" />
+                        <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"/>
+                        <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"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="fix_waterlevel_export" description="output.fix_waterlevel_export" mine-type="text/plain" type="export">
+                    <facets>
+                        <facet name="csv" description="facet.waterlevel_export.csv" />
+                        <facet name="wst" description="facet.waterlevel_export.wst" />
+                        <facet name="pdf" description="facet.waterlevel_export.pdf" />
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+    </states>
+</artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifacts/gaugedischarge.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<artifact name="gaugedischarge">
+  <states>
+    <state id="state.gaugedischarge.init"
+               description="state.gaugedischarge.init"
+               state="de.intevation.flys.artifacts.states.GaugeDischargeState">
+      <outputmodes>
+        <outputmode name="computed_discharge_curve" description="computed_discharge_curve" mime-type="image/png" type="chart">
+          <facets>
+            <facet name="discharge_curve.curve" description="facet.discharge_curve.curve" />
+          </facets>
+        </outputmode>
+      </outputmodes>
+    </state>
+  </states>
+</artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifacts/hyk.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<artifact name="hyk">
+  <states>
+    <state id="state.hyk.static"
+               description="state.hyk.static"
+               state="de.intevation.flys.artifacts.states.StaticHYKState">
+      <outputmodes>
+        <outputmode name="cross_section" description="output.cross_section" mime-type="image/png" type="chart">
+          <facets>
+            <facet name="hyk" description="hyk data" />
+          </facets>
+        </outputmode>
+      </outputmodes>
+    </state>
+  </states>
+</artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifacts/manualpoints.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<artifact name="manualpoints">
+  <states>
+    <state id="state.manualpoints.static"
+               description="state.manualpoints.static"
+               state="de.intevation.flys.artifacts.states.ManualPointsSingleState">
+      <outputmodes>
+        <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart">
+          <facets>
+            <facet name="longitudinal_section.manualpoints" description="Points provided by user." />
+            <facet name="discharge_longitudinal_section.manualpoints" description="Points provided by user." />
+            <facet name="discharge_curve.manualpoints" description="Points provided by user." />
+            <facet name="w_differences.manualpoints" description="Points provided by user." />
+            <facet name="duration_curve.manualpoints" description="Points provided by user." />
+            <facet name="computed_discharge_curve.manualpoints" description="Points provided by user." />
+            <facet name="cross_section.manualpoints" description="Points provided by user." />
+            <facet name="reference_curve.manualpoints" description="User-provided points *yawn*"/>
+            <facet name="reference_curve_normalized.manualpoints" description="points"/>
+            <facet name="historical_discharge.manualpoints" description="Points provided by user." />
+            <facet name="cross_section.manualline" description="Lines provided by user." />
+            <facet name="fix_wq_curve.manualpoints" description="Points provided by user." />
+            <facet name="fix_deltawt_curve.manualpoints" description="Points provided by user." />
+            <facet name="fix_longitudinal_section_curve.manualpoints" description="Points provided by user." />
+            <facet name="fix_derivate_curve.manualpoints" description="Points provided by user." />
+          </facets>
+        </outputmode>
+      </outputmodes>
+    </state>
+  </states>
+</artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifacts/map.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<artifact name="new_map">
+    <states>
+         <state id="state.map.river" description="state.winfo.river" state="de.intevation.flys.artifacts.states.RiverSelect">
+            <data name="river" type="String" />
+         </state>
+
+         <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+             <from state="state.map.river"/>
+             <to state="state.map.new"/>
+         </transition>
+
+         <state id="state.map.new" description="state.map.new" state="de.intevation.flys.artifacts.MapArtifact$MapState">
+            <outputmodes>
+                <outputmode name="map" description="output.uesk.map.description" type="map">
+                    <facets>
+                        <facet name="floodmap.wsplgen"/>
+                        <facet name="floodmap.barriers"/>
+                        <facet name="floodmap.riveraxis"/>
+                        <facet name="floodmap.wmsbackground"/>
+                        <facet name="floodmap.kms"/>
+                        <facet name="floodmap.qps"/>
+                        <facet name="floodmap.hws"/>
+                        <facet name="floodmap.hydr_boundaries"/>
+                        <facet name="floodmap.hydr_boundaries_poly"/>
+                        <facet name="floodmap.catchment"/>
+                        <facet name="floodmap.floodplain"/>
+                        <facet name="floodmap.lines"/>
+                        <facet name="floodmap.buildings"/>
+                        <facet name="floodmap.fixpoints"/>
+                        <facet name="floodmap.floodmaps"/>
+                        <facet name="floodmap.gauge_location"/>
+                        <facet name="floodmap.externalwms"/>
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+    </states>
+</artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifacts/minfo.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<artifact name="minfo">
+
+    <states>
+        <state id="state.minfo.river" description="state.minfo.river" state="de.intevation.flys.artifacts.states.RiverSelect" helpText="help.index">
+            <data name="river" type="String" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+                <from state="state.minfo.river"/>
+                <to state="state.minfo.calculation_mode"/>
+        </transition>
+
+        <state id="state.minfo.calculation_mode" description="state.minfo.calculation_mode" state="de.intevation.flys.artifacts.states.CalculationSelectMinfo" helpText="help.minfo">
+            <data name="calculation_mode" type="String"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.minfo.calculation_mode"/>
+            <to state="state.minfo.distance_only"/>
+            <condition data="calculation_mode" value="calc.flow.velocity" operator="equal"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.minfo.calculation_mode"/>
+            <to state="state.minfo.distance_only"/>
+            <condition data="calculation_mode" value="calc.bed.middle" operator="equal"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.minfo.calculation_mode"/>
+            <to state="state.minfo.sq.location"/>
+            <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>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.minfo.calculation_mode"/>
+            <to state="state.minfo.bed.location"/>
+            <condition data="calculation_mode" value="calc.bed.quality" 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>
+
+        <state id="state.minfo.bed.location" description="state.minfo.bed.location" state="de.intevation.flys.artifacts.states.DistanceOnlySelect" helpText="help.minfo.bed.loaction">
+            <data name="ld_from" type="Double" />
+            <data name="ld_to" type="Double" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.minfo.distance_only"/>
+            <to state="state.minfo.dischargestate"/>
+            <condition data="calculation_mode" value="calc.flow.velocity" operator="equal"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.minfo.distance_only"/>
+            <to state="state.minfo.soundings"/>
+            <condition data="calculation_mode" value="calc.bed.middle" operator="equal"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.sq.location"/>
+            <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>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.bed.location"/>
+            <to state="state.minfo.bed.periods"/>
+        </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"/>
+        </state>
+
+        <state id="state.minfo.soundings" description="state.minfo.soundingsstate" state="de.intevation.flys.artifacts.states.SoundingsSelect" helpText="help.minfo.soundingsstate">
+            <data name="soundings" type="options"/>
+        </state>
+
+        <state id="state.minfo.sq.period" description="state.minfo.sq.period" state="de.intevation.flys.artifacts.states.sq.SQPeriodSelect">
+            <data name="start" type="Long"/>
+            <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>
+
+        <state id="state.minfo.bed.periods" description="state.minfo.bed.periods" state="de.intevation.flys.artifacts.states.minfo.BedQualityPeriodsSelect">
+            <data name="periods" type="String"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.dischargestate"/>
+            <to state="state.minfo.flow_velocity"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.soundings"/>
+            <to state="state.minfo.bedheight_middle"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.sq.period"/>
+            <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>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.bed.periods"/>
+            <to state="state.minfo.bed.char_diameter"/>
+        </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">
+                    <facets>
+                        <facet name="flow_velocity.totalchannel" description="A facet for total channels"/>
+                        <facet name="flow_velocity.mainchannel" description="A facet for main channels"/>
+                        <facet name="flow_velocity.tau" description="A facet for tau"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="flow_velocity_export" description="output.flow_velocity_export" mime-type="text/plain" type="export">
+                    <facets>
+                        <facet name="csv" description="facet.flow_velocity_export.csv" />
+                        <!--
+                        <facet name="pdf" description="facet.historical_discharge.pdf" />
+                        -->
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <state id="state.minfo.bedheight_middle" description="state.minfo.bedheight_middle" state="de.intevation.flys.artifacts.states.MiddleBedHeight" helpText="help.minfo.bedheight_middle">
+            <outputmodes>
+                <outputmode name="bedheight_middle" description="output.bedheight_middle" mime-type="image/png" type="chart">
+                    <facets>
+                        <facet name="bedheight_middle.single" description="A facet for total channels"/>
+                        <facet name="bedheight_middle.epoch" description="A facet for total channels"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="bedheight_middle_export" description="output.bedheight_middle_export" mime-type="text/plain" type="export">
+                    <facets>
+                        <facet name="csv" description="facet.bedheight_middle_export.csv" />
+                        <!--
+                        <facet name="pdf" description="facet.historical_discharge.pdf" />
+                        -->
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <state id="state.minfo.sq.outliers" description="state.minfo.sq.outliers" state="de.intevation.flys.artifacts.states.OutliersInput" helpText="help.minfo.sq.outliers">
+            <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="bed_difference_height_year" description="output.absolute_height" mime-type="image/png" type="chart">
+                    <facets>
+                        <facet name="bedheight_difference.height_year" description="A facet for absolute heights"/>
+                        <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="bed_difference_year" description="output.difference_year" mime-type="img/png" type="chart">
+                    <facets>
+                        <facet name="bedheight_difference.year" description="A facet for bed height differences"/>
+                        <facet name="bedheight_difference.morph_width" description="A facet for morphologic width"/>
+                        <facet name="bedheight_difference.year.height1" description="A facet for raw heights."/>
+                        <facet name="bedheight_difference.year.height2" description="A facet for raw heights."/>
+                        <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="bed_difference_epoch" description="output.difference_epoch" mime-type="img/png" type="chart">
+                    <facets>
+                        <facet name="bedheight_difference.epoch" description="A facet for bed height differences"/>
+                        <facet name="bedheight_difference.epoch.height1" description="A facet for raw heights."/>
+                        <facet name="bedheight_difference.epoch.height2" description="A facet for raw heights."/>
+                        <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <state id="state.minfo.bed.char_diameter" description="state.minfo.bed.char_diameter" state="de.intevation.flys.artifacts.states.minfo.CharDiameter">
+            <data name="bed_diameter" type="options"/>
+            <data name="load_diameter" type="options"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.sq.outliers"/>
+            <to state="state.minfo.sq.relation"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.minfo.bed.char_diameter"/>
+            <to state="state.minfo.bed.bed_quality"/>
+        </transition>
+
+        <state id="state.minfo.sq.relation" description="state.minfo.sq.relation" state="de.intevation.flys.artifacts.states.SQRelation">
+            <outputmodes>
+                <outputmode name="sq_relation_a" description="output.sq_relation" type="chart">
+                    <facets>
+                        <facet name="sq_a_measurement" description="A facet for sq measurements"/>
+                        <facet name="sq_a_outlier" description="A facet fo sq outliers"/>
+                        <facet name="sq_a_curve" description="A facet for sq curve"/>
+                        <facet name="sq_a_outlier_curve" description="A facet for sq outlier curve"/>
+                        <facet name="sq_a_outlier_measurement" description="A facet for sq outlier measurement"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="sq_relation_b" description="output.sq_relation" type="chart">
+                    <facets>
+                        <facet name="sq_b_measurement" description="A facet for sq measurements"/>
+                        <facet name="sq_b_outlier" description="A facet fo sq outliers"/>
+                        <facet name="sq_b_curve" description="A facet for sq curve"/>
+                        <facet name="sq_b_outlier_curve" description="A facet for sq outlier curve"/>
+                        <facet name="sq_b_outlier_measurement" description="A facet for sq outlier measurement"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="sq_relation_c" description="output.sq_relation" type="chart">
+                    <facets>
+                        <facet name="sq_c_measurement" description="A facet for sq measurements"/>
+                        <facet name="sq_c_outlier" description="A facet fo sq outliers"/>
+                        <facet name="sq_c_curve" description="A facet for sq curve"/>
+                        <facet name="sq_c_outlier_curve" description="A facet for sq outlier curve"/>
+                        <facet name="sq_c_outlier_measurement" description="A facet for sq outlier measurement"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="sq_relation_d" description="output.sq_relation" type="chart">
+                    <facets>
+                        <facet name="sq_d_measurement" description="A facet for sq measurements"/>
+                        <facet name="sq_d_outlier" description="A facet fo sq outliers"/>
+                        <facet name="sq_d_curve" description="A facet for sq curve"/>
+                        <facet name="sq_d_outlier_curve" description="A facet for sq outlier curve"/>
+                        <facet name="sq_d_outlier_measurement" description="A facet for sq outlier measurement"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="sq_relation_e" description="output.sq_relation" type="chart">
+                    <facets>
+                        <facet name="sq_e_measurement" description="A facet for sq measurements"/>
+                        <facet name="sq_e_outlier" description="A facet fo sq outliers"/>
+                        <facet name="sq_e_curve" description="A facet for sq curve"/>
+                        <facet name="sq_e_outlier_curve" description="A facet for sq outlier curve"/>
+                        <facet name="sq_e_outlier_measurement" description="A facet for sq outlier measurement"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="sq_relation_f" description="output.sq_relation" type="chart">
+                    <facets>
+                        <facet name="sq_f_measurement" description="A facet for sq measurements"/>
+                        <facet name="sq_f_outlier" description="A facet fo sq outliers"/>
+                        <facet name="sq_f_curve" description="A facet for sq curve"/>
+                        <facet name="sq_f_outlier_curve" description="A facet for sq outlier curve"/>
+                        <facet name="sq_f_outlier_measurement" description="A facet for sq outlier measurement"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="sq_overview" description="output.sq_overview" type="overview">
+                    <facets>
+                        <facet name="sq_chart_overview" description="A facet for sq chart overview"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="sq_relation_export" description="output.sq_relation_export" type="export">
+                    <facets>
+                        <facet name="csv" description="facet.sq_export.csv" />
+                        <facet name="pdf" description="facet.sq_export.pdf" />
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <state id="state.minfo.bed.bed_quality" description="state.minfo.bed.bed_quality" state="de.intevation.flys.artifacts.states.minfo.BedQualityState" helpText="help.minfo.bed.bed_quality">
+            <outputmodes>
+                <outputmode name="bed_longitudinal_section" description="output.bed_longitudinal_section" mime-type="image/png" type="chart">
+                    <facets>
+                    	<facet name="bed_longitudinal_section.porosity_toplayer"/>
+                    	<facet name="bed_longitudinal_section.porosity_sublayer"/>
+                    	<facet name="bed_longitudinal_section.sediment_density_toplayer"/>
+                    	<facet name="bed_longitudinal_section.sediment_density_sublayer"/>
+                    	<facet name="bed_longitudinal_section.bed_diameter_toplayer"/>
+                    	<facet name="bed_longitudinal_section.bed_diameter_sublayer"/>
+                    	<facet name="bed_longitudinal_section.bedload_diameter"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="bed_quality_export" description="output.bed_quality_export" type="export">
+                    <facets>
+                        <facet name="csv" description="facet.bed_quality_export.csv" />
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+    </states>
+
+</artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifacts/qsector.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<artifact name="qsector">
+  <states>
+    <state id="state.qsector.static"
+               description="state.qsector.static"
+               state="de.intevation.flys.artifacts.states.QSectorSingleState">
+      <outputmodes>
+        <outputmode name="fix_wq_curve" description="output.fix_wq_curve" mime-type="image/png" type="chart">
+          <facets>
+            <facet name="qsectors" description="qsectors."/>
+          </facets>
+        </outputmode>
+      </outputmodes>
+    </state>
+  </states>
+</artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/artifacts/staticwqkms.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<artifact name="staticwqkms">
+  <states>
+    <state id="state.staticwqkms.static"
+               description="state.staticwqkms.state"
+               state="de.intevation.flys.artifacts.states.StaticWQKmsState">
+      <outputmodes>
+        <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart">
+          <facets>
+            <facet name="other.wqkms.w" description="W-type data" />
+            <facet name="other.wqkms.q" description="Q-type data" />
+          </facets>
+        </outputmode>
+      </outputmodes>
+    </state>
+  </states>
+</artifact>
--- a/flys-artifacts/doc/conf/artifacts/waterlevel.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/artifacts/waterlevel.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -8,6 +8,7 @@
              <outputmode name="w_differences" description="output.w_differences" mime-type="image/png" type="chart">
                   <facets>
                      <facet name="longitudinal_section.w" description="facet.longitudinal_section.w" />
+                     <facet name="longitudinal_section.q" description="facet.longitudinal_section.q" />
                   </facets>
               </outputmode>
            </outputmodes>
--- a/flys-artifacts/doc/conf/artifacts/winfo.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/artifacts/winfo.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -2,16 +2,16 @@
 <artifact name="winfo">
     <states>
 
-        <state id="state.winfo.river" description="state.winfo.river" state="de.intevation.flys.artifacts.states.RiverSelect">
+        <state id="state.winfo.river" description="state.winfo.river" state="de.intevation.flys.artifacts.states.RiverSelect" helpText="help.index">
             <data name="river" type="String" />
         </state>
 
-        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition" helpText="https://flys-intern.intevation.de/Flys-3.0">
             <from state="state.winfo.river"/>
             <to state="state.winfo.calculation_mode"/>
         </transition>
 
-        <state id="state.winfo.calculation_mode" description="state.winfo.calculation_mode" state="de.intevation.flys.artifacts.states.CalculationSelect">
+        <state id="state.winfo.calculation_mode" description="state.winfo.calculation_mode" state="de.intevation.flys.artifacts.states.CalculationSelect" helpText="help.winfo">
             <data name="calculation_mode" type="String" />
         </state>
 
@@ -52,70 +52,87 @@
         </transition>
 
         <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.winfo.calculation_mode"/>
+            <to state="state.winfo.historicalq.reference_gauge"/>
+            <condition data="calculation_mode" value="calc.historical.discharge.curve" operator="equal"/>
+        </transition>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
             <from state="state.winfo.waterlevel_pair_select"/>
             <to state="state.winfo.w_differences"/>
-            <condition data="calculation_mode" value="calc.w.differences" operator="equal"/>
         </transition>
 
-        <state id="state.winfo.location" description="state.winfo.location" state="de.intevation.flys.artifacts.states.LocationSelect">
+        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+            <from state="state.winfo.calculation_mode"/>
+            <to state="state.winfo.reference.curve.input.start"/>
+            <condition data="calculation_mode" value="calc.reference.curve" operator="equal"/>
+        </transition>
+
+        <state id="state.winfo.location" description="state.winfo.location" state="de.intevation.flys.artifacts.states.LocationSelect" helpText="help.winfo.duration.locations">
             <data name="ld_locations" type="Double[]" />
 
+            <!--
             <outputmodes>
                 <outputmode name="discharge_curve" description="output.discharge_curve" mime-type="image/png" type="chart">
                     <facets>
                         <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/>
                         <facet name="mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/>
+                        <facet name="discharge_curve.manualpoints" description="Manuelle Punkte"/>
                         <facet name="mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/>
                     </facets>
                 </outputmode>
-                <!-- TODO: Do we want an error report? -->
             </outputmodes>
+            -->
         </state>
 
-        <state id="state.winfo.distance_only" description="state.winfo.distance_only" state="de.intevation.flys.artifacts.states.DistanceOnlySelect">
+        <state id="state.winfo.distance_only" description="state.winfo.distance_only" state="de.intevation.flys.artifacts.states.DistanceOnlySelect" helpText="help.winfo.uesk.distance">
             <data name="ld_from" type="Double" />
             <data name="ld_to"   type="Double" />
         </state>
 
-        <state id="state.winfo.distance" description="state.winfo.distance" state="de.intevation.flys.artifacts.states.DistanceSelect">
+        <state id="state.winfo.distance" description="state.winfo.distance" state="de.intevation.flys.artifacts.states.DistanceSelect" helpText="help.winfo.discharge.longitudinal.distance">
             <data name="ld_from" type="Double" />
             <data name="ld_to"   type="Double" />
             <data name="ld_step" type="Double" />
 
+            <!--
             <outputmodes>
                 <outputmode name="discharge_curve" description="output.discharge_curve" mime-type="image/png" type="chart">
                     <facets>
                         <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/>
                         <facet name="mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/>
+                        <facet name="discharge_curve.manualpoints" description="Manuelle Punkte"/>
                         <facet name="mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/>
                     </facets>
                 </outputmode>
             </outputmodes>
+            -->
         </state>
 
-        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
             <from state="state.winfo.distance_only"/>
             <to state="state.winfo.uesk.wsp"/>
-            <condition data="calculation_mode" value="calc.flood.map" operator="equal"/>
         </transition>
 
-        <state id="state.winfo.location_distance" description="state.winfo.location_distance" state="de.intevation.flys.artifacts.states.LocationDistanceSelect">
+        <state id="state.winfo.location_distance" description="state.winfo.location_distance" state="de.intevation.flys.artifacts.states.LocationDistanceSelect" helpText="help.winfo.wsp.location_distance">
             <data name="ld_mode" type="String" />
             <data name="ld_locations" type="Double[]" />
             <data name="ld_from" type="Double" />
             <data name="ld_to" type="Double" />
             <data name="ld_step" type="Double" />
 
+            <!--
             <outputmodes>
                 <outputmode name="discharge_curve" description="output.discharge_curve" mime-type="image/png" type="chart">
                     <facets>
                         <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/>
                         <facet name="mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/>
+                        <facet name="discharge_curve.manualpoints" description="Manuelle Punkte"/>
                         <facet name="mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/>
                     </facets>
                 </outputmode>
-                <!-- TODO: Do we want an error report? -->
             </outputmodes>
+            -->
         </state>
 
         <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
@@ -123,10 +140,9 @@
             <to state="state.winfo.wq_adapted"/>
         </transition>
 
-        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
             <from state="state.winfo.location_distance"/>
             <to state="state.winfo.wq"/>
-            <condition data="calculation_mode" value="calc.surface.curve" operator="equal"/>
         </transition>
 
         <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
@@ -141,27 +157,76 @@
             <condition data="calculation_mode" value="calc.discharge.curve" operator="equal"/>
         </transition>
 
-        <state id="state.winfo.wq" description="state.winfo.wq" state="de.intevation.flys.artifacts.states.WQSelect">
-            <data name="wq_mode" type="String" />
-            <data name="wq_free" type="Boolean" />
-            <data name="wq_selection" type="String" />
+        <state id="state.winfo.wq" description="state.winfo.wq" state="de.intevation.flys.artifacts.states.WQSelect" helpText="help.winfo.wsp.wq">
+            <data name="wq_isq" type="Boolean" />
+            <data name="wq_isfree" type="Boolean" />
+            <data name="wq_isrange" type="Boolean" />
             <data name="wq_from" type="Double" />
             <data name="wq_to" type="Double" />
             <data name="wq_step" type="Double" />
             <data name="wq_single" type="Double[]" />
         </state>
 
-        <state id="state.winfo.wq_adapted" description="state.winfo.wq_adapted" state="de.intevation.flys.artifacts.states.WQAdapted">
+        <state id="state.winfo.wq_adapted" description="state.winfo.wq_adapted"
+               state="de.intevation.flys.artifacts.states.WQAdapted" helpText="help.winfo.discharge.longitudinal.wq">
             <!-- TODO Add data objects -->
-            <data name="wq_mode" type="String" />
+            <data name="wq_isq"   type="String" />
             <data name="wq_values" type="WQTriple" />
         </state>
 
-        <state id="state.winfo.waterlevel_pair_select" description="state.winfo.waterlevel_pair_select" state="de.intevation.flys.artifacts.states.WaterlevelPairSelectState">
+        <state id="state.winfo.waterlevel_pair_select" description="state.winfo.waterlevel_pair_select" state="de.intevation.flys.artifacts.states.WaterlevelPairSelectState" helpText="help.winfo.diff.diffs">
             <data name="diffids" type="String" />
         </state>
 
-        <state id="state.winfo.w_differences" description="state.winfo.w_differences" state="de.intevation.flys.artifacts.states.WDifferencesState">
+        <state id="state.winfo.reference.curve.input.start" description="state.winfo.reference.curve.input (start)" state="de.intevation.flys.artifacts.states.EnterLocationState" helpText="help.winfo.reference.curve.start">
+            <data name="reference_startpoint" type="Double[]"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.reference.curve.input.start"/>
+            <to   state="state.winfo.reference.curve.input.end"/>
+        </transition>
+
+        <state id="state.winfo.reference.curve.input.end" description="state.winfo.reference.curve.input (end)" state="de.intevation.flys.artifacts.states.EnterMultipleLocationsState" helpText="help.winfo.reference.curve.end">
+            <data name="reference_endpoint" type="Double[]"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.reference.curve.input.end"/>
+            <to state="state.winfo.reference.curve"/>
+        </transition>
+
+        <state id="state.winfo.reference.curve" description="state.winfo.reference.curve" state="de.intevation.flys.artifacts.states.ReferenceCurveState" helpText="">
+            <outputmodes>
+                <outputmode name="reference_curve_normalized" mime-type="image/png" type="chart">
+                    <facets>
+                        <facet name="reference_curve_normalized" description="A normalized reference curve!"/>
+                        <facet name="reference_curve_normalized.manualpoints" description="points"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="reference_curve" mime-type="image/png" type="chart">
+                    <facets>
+                        <facet name="reference_curve" description="A ... reference curve!"/>
+                        <facet name="reference_curve.manualpoints" description="points"/>
+                        <facet name="relativepoint"    description="Points at curve"/>
+                        <facet name="mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="reference_curve_export" mime-type="text/plain" type="export">
+                    <facets>
+                        <facet name="csv" description="facet.reference_curve_export.csv" />
+                        <facet name="pdf" description="facet.reference_curve_export.pdf" />
+                    </facets>
+                </outputmode>
+                <outputmode name="reference_curve_report" description="output.reference_curve_report" mime-type="text/xml" type="report">
+                    <facets>
+                        <facet name="report" description="facet.reference_curve_export.report" />
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
+        <state id="state.winfo.w_differences" description="state.winfo.w_differences" state="de.intevation.flys.artifacts.states.WDifferencesState" helpText="https://flys-intern.intevation.de/Flys-3.0">
 
             <outputmodes>
                 <outputmode name="w_differences" description="output.w_differences" mime-type="image/png" type="chart">
@@ -172,30 +237,36 @@
                         <facet name="other.wkms" description="facet.other.wkms"/>
                         <facet name="other.wqkms" description="facet.other.wqkms"/>
                         <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/>
+                        <facet name="w_differences.manualpoints" description="Manuelle Punkte"/>
                         <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
                     </facets>
                 </outputmode>
                 <outputmode name="w_differences_export" description="output.w_differences.export" mime-type="text/plain" type="export">
                     <facets>
                         <facet name="csv" description="facet.w_differences.csv" />
+                        <facet name="pdf" description="facet.w_differences.pdf" />
                     </facets>
                 </outputmode>
             </outputmodes>
         </state>
 
-        <state id="state.winfo.durationcurve" description="state.winfo.durationcurve" state="de.intevation.flys.artifacts.states.DurationCurveState">
+        <state id="state.winfo.durationcurve" description="state.winfo.durationcurve" state="de.intevation.flys.artifacts.states.DurationCurveState" helpText="https://flys-intern.intevation.de/Flys-3.0">
             <outputmodes>
                 <outputmode name="duration_curve" description="output.duration_curve" mime-type="image/png" type="chart">
                     <facets>
                         <facet name="duration_curve.w" description="facet.duration_curve.w"/>
                         <facet name="duration_curve.q" description="facet.duration_curve.q"/>
-                        <facet name="computed_discharge_curve.mainvalues.q" description="Q Main Values"/>
+                        <facet name="other.wq"         description="Point-like data like fixations"/>
+                        <facet name="duration_curve.mainvalues.q" description="Q Main Values at optional second axis"/>
                         <facet name="computed_discharge_curve.mainvalues.w" description="W Main Values"/>
+                        <facet name="duration_curve.manualpoints" description="Manuelle Punkte"/>
+                        <facet name="relativepoint"    description="Points at curve"/>
                     </facets>
                 </outputmode>
                 <outputmode name="durationcurve_export" description="output.durationcurve_export" mime-type="text/plain" type="export">
                     <facets>
                         <facet name="csv" description="facet.durationcurve_export.csv" />
+                        <facet name="pdf" description="facet.durationcurve_export.pdf" />
                     </facets>
                 </outputmode>
                 <outputmode name="durationcurve_report" description="output.durationcurve_report" mime-type="text/xml" type="report">
@@ -206,22 +277,26 @@
             </outputmodes>
         </state>
 
-        <state id="state.winfo.computeddischargecurve" description="state.winfo.computeddischargecurve" state="de.intevation.flys.artifacts.states.ComputedDischargeCurveState">
+        <state id="state.winfo.computeddischargecurve" description="state.winfo.computeddischargecurve" state="de.intevation.flys.artifacts.states.ComputedDischargeCurveState" helpText="https://flys-intern.intevation.de/Flys-3.0">
             <outputmodes>
                 <outputmode name="computed_discharge_curve" description="output.computed_discharge_curve" mime-type="image/png" type="chart">
                     <facets>
                         <facet name="computed_discharge_curve.q" description="facet.computed_discharge_curve.q"/>
                         <facet name="computed_discharge_curve.mainvalues.q" description="facet.computed_discharge_curve.mainvalues.q"/>
                         <facet name="computed_discharge_curve.mainvalues.w" description="facet.computed_discharge_curve.mainvalues.w"/>
+                        <facet name="discharge_curve.curve" description="facet.discharge_curve.curve"/>
+                        <facet name="heightmarks_points" description="facet.other.wqkms"/>
                         <facet name="other.wqkms" description="facet.other.wqkms"/>
                         <facet name="other.wq"    description="Point-like data like fixations"/>
-                        <facet name="other.wq"    description="Point-like data like fixations"/>
+                        <facet name="other.wkms"  description="Point-like data like fixations"/>
                         <facet name="other.wkms.interpol" description="Height over km, like flood protections."/>
+                        <facet name="computed_discharge_curve.manualpoints" description="Manuelle Punkte"/>
                     </facets>
                 </outputmode>
                 <outputmode name="computed_dischargecurve_export" description="output.computed_dischargecurve_export" mime-type="text/plain" type="export">
                     <facets>
                         <facet name="csv" description="facet.computed_dischargecurve_export.csv" />
+                        <facet name="pdf" description="facet.computed_dischargecurve_export.pdf" />
                     </facets>
                 </outputmode>
                 <outputmode name="computed_dischargecurve_report" description="output.computed_dischargecurve_report" mime-type="text/xml" type="report">
@@ -237,10 +312,9 @@
             </outputmodes>
         </state>
 
-        <transition transition="de.intevation.flys.artifacts.transitions.ValueCompareTransition">
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
             <from state="state.winfo.wq"/>
             <to state="state.winfo.waterlevel"/>
-            <condition data="calculation_mode" value="calc.surface.curve" operator="equal"/>
         </transition>
 
         <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
@@ -248,16 +322,20 @@
             <to state="state.winfo.discharge_longitudinal_section"/>
         </transition>
 
-        <state id="state.winfo.waterlevel" description="state.winfo.waterlevel" state="de.intevation.flys.artifacts.states.WaterlevelState">
+        <state id="state.winfo.waterlevel" description="state.winfo.waterlevel" state="de.intevation.flys.artifacts.states.WaterlevelState" helpText="https://flys-intern.intevation.de/Flys-3.0">
             <outputmodes>
                 <outputmode name="longitudinal_section" description="output.longitudinal_section" mime-type="image/png" type="chart">
                   <facets>
                     <facet name="longitudinal_section.w" description="facet.longitudinal_section.w"/>
                     <facet name="longitudinal_section.q" description="facet.longitudinal_section.q"/>
                     <facet name="w_differences"          description="facet.w_differences"/>
+                    <facet name="other.wqkms.w"          description="W-Type of data" />
+                    <facet name="other.wq"               description="WQ-Type of data" />
+                    <facet name="other.wqkms.q"          description="Q-Type of data" />
                     <facet name="other.wkms"             description="facet.other.wkms"/>
-                    <facet name="other.wqkms"             description="facet.other.wqkms"/>
-                    <facet name="heightmarks_points" description="facet.other.wkms.heightmarks_points"/>
+                    <facet name="longitudinal_section.manualpoints" description="Manuelle Punkte"/>
+                    <facet name="other.wqkms"            description="facet.other.wqkms"/>
+                    <facet name="heightmarks_points"     description="facet.other.wkms.heightmarks_points"/>
                     <facet name="longitudinal_section.area"        description="an area"/>
                     <facet name="longitudinal_section.annotations" description="facet.longitudinal_section.annotations"/>
                   </facets>
@@ -266,6 +344,7 @@
                   <facets>
                     <facet name="csv" description="facet.waterlevel_export.csv" />
                     <facet name="wst" description="facet.waterlevel_export.wst" />
+                    <facet name="pdf" description="facet.waterlevel_export.pdf" />
                   </facets>
                 </outputmode>
                 <outputmode name="waterlevel_report" description="output.waterlevel_report" mime-type="text/xml" type="report">
@@ -275,27 +354,35 @@
                 </outputmode>
                 <outputmode name="cross_section" description="output.cross_section" mime-type="image/png" type="chart">
                   <facets>
-                    <facet name="cross_section_water_line" description="facet.cross_section_water_line"/>
-                    <facet name="cross_section"            description="facet.cross_section"/>
-                    <facet name="area"                     description="an area"/>
-                    <facet name="cross_section.area"                     description="an area"/>
+                    <facet name="cross_section_water_line"   description="facet.cross_section_water_line"/>
+                    <facet name="cross_section"              description="facet.cross_section"/>
+                    <facet name="area"                       description="an area"/>
+                    <facet name="cross_section.area"         description="an area"/>
+                    <facet name="cross_section.manualpoints" description="points"/>
+                    <facet name="cross_section.manualline"   description="line"/>
+                    <facet name="hyk"                        description="hyks"/>
                   </facets>
                 </outputmode>
             </outputmodes>
         </state>
 
-        <state id="state.winfo.discharge_longitudinal_section" description="state.winfo.discharge_longitudinal_section" state="de.intevation.flys.artifacts.states.DischargeLongitudinalSection">
+        <state id="state.winfo.discharge_longitudinal_section" description="state.winfo.discharge_longitudinal_section" state="de.intevation.flys.artifacts.states.DischargeLongitudinalSection" helpText="https://flys-intern.intevation.de/Flys-3.0">
             <outputmodes>
                 <outputmode name="discharge_longitudinal_section" description="output.discharge_longitudinal_section" mime-type="image/png" type="chart">
                     <facets>
                         <facet name="discharge_longitudinal_section.w"/>
                         <facet name="discharge_longitudinal_section.q"/>
                         <facet name="discharge_longitudinal_section.c"/>
+                        <facet name="discharge_longitudinal_section.manualpoints" description="Manuelle Punkte"/>
+                        <facet name="other.wqkms.w"/>
+                        <facet name="other.wq"/>
+                        <facet name="other.wqkms.q"/>
                         <facet name="other.wqkms"/>
                         <facet name="other.wkms"/>
                         <facet name="heightmarks_points"/>
                         <facet name="longitudinal_section.annotations"/>
                         <facet name="longitudinal_section.w"/>
+                        <facet name="longitudinal_section.q"/>
                     </facets>
                 </outputmode>
                 <outputmode name="discharge_longitudinal_section_export" description="output.discharge_longitudinal_section_export" mime-type="text/plain" type="export">
@@ -309,6 +396,17 @@
                         <facet name="report" description="facet.discharge_longitudinal_section_export.report"/>
                     </facets>
                 </outputmode>
+                <outputmode name="cross_section" description="output.cross_section" mime-type="image/png" type="chart">
+                  <facets>
+                    <facet name="cross_section_water_line" description="facet.cross_section_water_line"/>
+                    <facet name="cross_section"            description="facet.cross_section"/>
+                    <facet name="area"                     description="an area"/>
+                    <facet name="cross_section.area"                     description="an area"/>
+                    <facet name="cross_section.manualpoints" description="points"/>
+                    <facet name="cross_section.manualline" description="line"/>
+                    <facet name="hyk"                      description="hyks"/>
+                  </facets>
+                </outputmode>
             </outputmodes>
         </state>
 
@@ -317,7 +415,7 @@
             <to state="state.winfo.uesk.dgm"/>
         </transition>
 
-        <state id="state.winfo.uesk.wsp" description="state.winfo.uesk.wsp" state="de.intevation.flys.artifacts.states.WaterlevelSelectState">
+        <state id="state.winfo.uesk.wsp" description="state.winfo.uesk.wsp" state="de.intevation.flys.artifacts.states.WaterlevelSelectState" helpText="help.winfo.uesk.wsp">
             <data name="wsp" type="String" />
         </state>
 
@@ -326,7 +424,7 @@
             <to state="state.winfo.uesk.dgm"/>
         </transition>
 
-        <state id="state.winfo.uesk.dgm" description="state.winfo.uesk.dgm" state="de.intevation.flys.artifacts.states.DGMSelect">
+        <state id="state.winfo.uesk.dgm" description="state.winfo.uesk.dgm" state="de.intevation.flys.artifacts.states.DGMSelect" helpText="help.winfo.uesk.dem">
             <data name="dgm" type="String" />
         </state>
 
@@ -335,7 +433,7 @@
             <to state="state.winfo.uesk.profiles"/>
         </transition>
 
-        <state id="state.winfo.uesk.profiles" description="state.winfo.uesk.profiles" state="de.intevation.flys.artifacts.states.ProfileDistanceSelect">
+        <state id="state.winfo.uesk.profiles" description="state.winfo.uesk.profiles" state="de.intevation.flys.artifacts.states.ProfileDistanceSelect" helpText="help.winfo.uesk.profiles">
             <data name="profile_distance" type="String" />
         </state>
 
@@ -344,7 +442,7 @@
             <to state="state.winfo.uesk.floodplain"/>
         </transition>
 
-        <state id="state.winfo.uesk.floodplain" description="state.winfo.uesk.floodplain.description" state="de.intevation.flys.artifacts.states.FloodplainChoice">
+        <state id="state.winfo.uesk.floodplain" description="state.winfo.uesk.floodplain.description" state="de.intevation.flys.artifacts.states.FloodplainChoice" helpText="help.winfo.uesk.floodplain">
             <data name="use_floodplain" type="Boolean" />
         </state>
 
@@ -353,7 +451,7 @@
             <to state="state.winfo.uesk.differences"/>
         </transition>
 
-        <state id="state.winfo.uesk.differences" description="state.winfo.uesk.differences" state="de.intevation.flys.artifacts.states.WaterlevelGroundDifferences">
+        <state id="state.winfo.uesk.differences" description="state.winfo.uesk.differences" state="de.intevation.flys.artifacts.states.WaterlevelGroundDifferences" helpText="help.winfo.uesk.differences">
             <data name="diff_from" type="Double" />
             <data name="diff_to"   type="Double" />
             <data name="diff_diff" type="Double" />
@@ -364,7 +462,7 @@
             <to state="state.winfo.uesk.scenario"/>
         </transition>
 
-        <state id="state.winfo.uesk.scenario" description="state.winfo.uesk.scenario" state="de.intevation.flys.artifacts.states.ScenarioSelect">
+        <state id="state.winfo.uesk.scenario" description="state.winfo.uesk.scenario" state="de.intevation.flys.artifacts.states.ScenarioSelect" helpText="help.winfo.uesk.scenario">
             <data name="scenario" type="String" />
             <data name="uesk.barriers" type="String" />
         </state>
@@ -374,22 +472,27 @@
             <to state="state.winfo.uesk.uesk"/>
         </transition>
 
-        <state id="state.winfo.uesk.uesk" description="state.winfo.uesk.uesk" state="de.intevation.flys.artifacts.states.FloodMapState">
+        <state id="state.winfo.uesk.uesk" description="state.winfo.uesk.uesk" state="de.intevation.flys.artifacts.states.FloodMapState" helpText="https://flys-intern.intevation.de/Flys-3.0">
             <outputmodes>
                 <outputmode name="floodmap" description="output.uesk.map.description" type="map">
                     <facets>
                         <facet name="floodmap.wsplgen"/>
                         <facet name="floodmap.barriers"/>
+                        <facet name="floodmap.usershape"/>
                         <facet name="floodmap.riveraxis"/>
                         <facet name="floodmap.wmsbackground"/>
                         <facet name="floodmap.kms"/>
                         <facet name="floodmap.qps"/>
                         <facet name="floodmap.hws"/>
+                        <facet name="floodmap.hydr_boundaries"/>
+                        <facet name="floodmap.hydr_boundaries_poly"/>
                         <facet name="floodmap.catchment"/>
                         <facet name="floodmap.floodplain"/>
                         <facet name="floodmap.lines"/>
                         <facet name="floodmap.buildings"/>
                         <facet name="floodmap.fixpoints"/>
+                        <facet name="floodmap.floodmaps"/>
+                        <facet name="floodmap.gauge_location"/>
                         <facet name="floodmap.externalwms"/>
                     </facets>
                 </outputmode>
@@ -401,5 +504,58 @@
             </outputmodes>
         </state>
 
+
+        <!-- path for historical discharge curves -->
+        <state id="state.winfo.historicalq.reference_gauge" description="state.winfo.historicalq.reference_gauge" state="de.intevation.flys.artifacts.states.ReferenceGaugeState" helpText="help.winfo.historical.discharge.reference_gauge">
+            <data name="reference_gauge" type="Integer" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.historicalq.reference_gauge"/>
+            <to state="state.winfo.historicalq.timerange"/>
+        </transition>
+
+        <state id="state.winfo.historicalq.timerange" description="state.winfo.historicalq.timerange" state="de.intevation.flys.artifacts.states.GaugeTimerangeState" helpText="help.winfo.historical.discharge.timerange">
+            <data name="year_range" type="longrange"/>
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.historicalq.timerange"/>
+            <to state="state.winfo.historicalq.mode"/>
+        </transition>
+
+        <state id="state.winfo.historicalq.mode" description="state.winfo.historicalq.mode" state="de.intevation.flys.artifacts.states.HistoricalDischargeState" helpText="help.winfo.historical.discharge.mode">
+            <data name="historical_mode" type="intoptions" />
+            <data name="historical_values" type="doublearray" />
+        </state>
+
+        <transition transition="de.intevation.flys.artifacts.transitions.DefaultTransition">
+            <from state="state.winfo.historicalq.mode"/>
+            <to state="state.winfo.historicalq.compute"/>
+        </transition>
+
+        <state id="state.winfo.historicalq.compute" description="state.winfo.historicalq.compute" state="de.intevation.flys.artifacts.states.HistoricalDischargeComputeState" helpText="https://flys-intern.intevation.de/Flys-3.0">
+            <outputmodes>
+                <outputmode name="historical_discharge" description="output.historical_discharge.description" mime-type="image/png" type="chart">
+                    <facets>
+                        <facet name="historical_discharge.historicalq"/>
+                        <facet name="historical_discharge.historicalq.diff"/>
+                        <facet name="historical_discharge.manualpoints"/>
+                    </facets>
+                </outputmode>
+                <outputmode name="historical_discharge_export" description="output.historical_discharge.export" mime-type="text/plain" type="export">
+                    <facets>
+                        <facet name="csv" description="facet.historical_discharge.csv" />
+                        <facet name="pdf" description="facet.historical_discharge.pdf" />
+                    </facets>
+                </outputmode>
+                <outputmode name="historical_discharge_report" description="output.historical_discharge_report" mime-type="text/xml" type="report">
+                    <facets>
+                        <facet name="report" description="facet.historical_discharge.report"/>
+                    </facets>
+                </outputmode>
+            </outputmodes>
+        </state>
+
     </states>
 </artifact>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/backend-db.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<backend-database>
+    <!-- This is the default backend db configuration. -->
+    <user>flys</user>
+    <password>flys</password>
+    <dialect>org.hibernate.dialect.PostgreSQLDialect</dialect>
+    <driver>org.postgresql.Driver</driver>
+    <url>jdbc:postgresql://localhost:5432/flys</url>
+</backend-database>
--- a/flys-artifacts/doc/conf/cache.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/cache.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -28,18 +28,9 @@
            memoryStoreEvictionPolicy="LRU"
            />
 
-    <!-- This one is used to cache the distance infos per river as Documents -->
-    <cache name="service-distanceinfo"
+    <cache name="location-provider"
            maxElementsInMemory="20"
            eternal="false"
-           timeToIdleSeconds="360"
-           timeToLiveSeconds="86400"
-           memoryStoreEvictionPolicy="LFU"
-           />
-
-    <cache name="location-provider"
-           maxElementsInMemory="5000"
-           eternal="false"
            diskPersistent="true"
            overflowToDisk="true"
            timeToIdleSeconds="360"
@@ -47,15 +38,6 @@
            memoryStoreEvictionPolicy="LFU"
            />
 
-    <!-- This one is used to cache the distance infos per river as Lists -->
-    <cache name="annotations"
-           maxElementsInMemory="2000"
-           eternal="false"
-           timeToIdleSeconds="360"
-           timeToLiveSeconds="86400"
-           memoryStoreEvictionPolicy="LFU"
-           />
-
     <!-- This one is used to cache the computed values.-->
     <cache name="computed.values"
            maxElementsInMemory="200"
@@ -76,6 +58,16 @@
            memoryStoreEvictionPolicy="LRU"
            />
 
+    <!-- This one is used to cache the non-computed wst-values.-->
+    <cache name="wst-wq-value-table-static"
+           maxElementsInMemory="200"
+           eternal="false"
+           timeToLiveSeconds="172800"
+           overflowToDisk="true"
+           diskPersistent="true"
+           memoryStoreEvictionPolicy="LRU"
+           />
+
     <!-- This one is used for the SQL statements used by the static datacage -->
     <cache name="datacage.db"
            maxElementsInMemory="2000"
@@ -92,11 +84,74 @@
            memoryStoreEvictionPolicy="LRU"
            />
 
-    <!-- This one is used for the cross section lookup -->
+    <!-- This one is used to load chunks of the cross section lines  -->
+    <cache name="fast-cross-section-lines"
+           maxElementsInMemory="500"
+           eternal="false"
+           timeToLiveSeconds="7200"
+           memoryStoreEvictionPolicy="LRU"
+           overflowToDisk="true"
+           diskPersistent="true"
+           />
+
+    <!-- This one is used to hold the S/Q overviews. -->
+    <cache name="sq-overviews"
+           maxElementsInMemory="15"
+           eternal="false"
+           timeToLiveSeconds="7200"
+           memoryStoreEvictionPolicy="LFU"
+           overflowToDisk="true"
+           diskPersistent="true"
+           />
+
+    <!-- This one is used to hold the fixings overviews. -->
+    <cache name="fixings-overviews"
+           maxElementsInMemory="15"
+           eternal="false"
+           timeToLiveSeconds="7200"
+           memoryStoreEvictionPolicy="LFU"
+           overflowToDisk="true"
+           diskPersistent="true"
+           />
+
+    <!-- This one is used to hold the data columns of fixings. -->
+    <cache name="fixings-columns"
+           maxElementsInMemory="70"
+           eternal="false"
+           timeToLiveSeconds="7200"
+           memoryStoreEvictionPolicy="LFU"
+           overflowToDisk="true"
+           diskPersistent="true"
+           />
+
+    <!-- This one is used to load single HYK Zones  -->
+    <cache name="hykache"
+           maxElementsInMemory="500"
+           eternal="false"
+           timeToLiveSeconds="14400"
+           memoryStoreEvictionPolicy="LRU"
+           overflowToDisk="true"
+           diskPersistent="true"
+           />
+
+    <!-- This one is used to load gauge finders -->
+    <cache name="gauge-finders"
+           maxElementsInMemory="15"
+           eternal="false"
+           timeToLiveSeconds="14400"
+           memoryStoreEvictionPolicy="LRU"
+           overflowToDisk="true"
+           diskPersistent="true"
+           />
+
+    <!-- This one is used for the cross section lookup
+         Because of lazy fetching and relatively big amount of data, disabled
+         cache for now.
     <cache name="cross_sections"
            maxElementsInMemory="50"
            eternal="false"
            timeToLiveSeconds="86400"
            memoryStoreEvictionPolicy="LRU"
            />
+    -->
 </ehcache>
--- a/flys-artifacts/doc/conf/conf.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/conf.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -1,3 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE artifact-database [
+    <!ENTITY artifact-db SYSTEM "artifact-db.xml">
+    <!ENTITY datacage-db SYSTEM "datacage-db.xml">
+    <!ENTITY backend-db  SYSTEM "backend-db.xml">
+    <!ENTITY seddb-db    SYSTEM "seddb-db.xml">
+    <!ENTITY rest-server SYSTEM "rest-server.xml">
+    <!ENTITY floodmap    SYSTEM "floodmap.xml">
+]>
 <artifact-database>
     <export-secret>YOUR_SECRET</export-secret>
     <factories>
@@ -17,6 +26,12 @@
             <artifact-factory name="riveraxis" description="Factory to create an artifact to be used in WINFO"
                 ttl="3600000"
                 artifact="de.intevation.flys.artifacts.RiverAxisArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="hyk" description="Factory to create an artifact to be used for hyks"
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.HYKArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="new_map" description="Factory to create an artifact to be used for new map"
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.MapArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
             <artifact-factory name="wmskmfactory" description="Factory to create an artifact that generates WMS facets for KMs."
                 ttl="3600000"
                 artifact="de.intevation.flys.artifacts.WMSKmArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
@@ -26,6 +41,12 @@
             <artifact-factory name="wmshwsfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks."
                 ttl="3600000"
                 artifact="de.intevation.flys.artifacts.WMSHwsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="wmshydrboundariesfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks."
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.WMSHydrBoundaryArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="wmshydrboundariespolyfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks."
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.WMSHydrBoundaryPolyArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
             <artifact-factory name="wmscatchmentfactory" description="Factory to create an artifact that generates WMS facets for CrossSectionTracks."
                 ttl="3600000"
                 artifact="de.intevation.flys.artifacts.WMSCatchmentArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
@@ -41,6 +62,12 @@
             <artifact-factory name="wmsfixpointsfactory" description="Factory to create an artifact to be used in WINFO"
                 ttl="3600000"
                 artifact="de.intevation.flys.artifacts.WMSFixpointsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="wmsfloodmapsfactory" description="Factory to create an artifact to be used in WINFO"
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.WMSFloodmapsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="wmsgaugelocationfactory" description="Factory to create an artifact to be used in WINFO"
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.WMSGaugeLocationArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
             <artifact-factory name="wmsbackground" description="Factory to create an artifact to be used in WINFO"
                 ttl="3600000"
                 artifact="de.intevation.flys.artifacts.WMSBackgroundArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
@@ -65,9 +92,39 @@
             <artifact-factory name="area" description="Factory to create an artifact to draw (wkms) area data"
                 ttl="3600000"
                 artifact="de.intevation.flys.artifacts.AreaArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="staticwqkms" description="Factory to create an artifact to access 'other' WKms data"
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.StaticWQKmsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
             <artifact-factory name="wqinterpol" description="Factory to create an artifact to access 'other' WQ (at km) data"
                 ttl="3600000"
                 artifact="de.intevation.flys.artifacts.WQKmsInterpolArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="new_chart" description="Factory to create an artifact to be used for new chart"
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.ChartArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="manualpoints" description="Factory to create an artifact for storing and editing points added by the user."
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.ManualPointsArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="fixanalysis" description="Factory to create an artifact to be used in fixation analysis."
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.FixationArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="gaugedischarge" description="Factory to create an artifact to host historical qs."
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.GaugeDischargeArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+            <artifact-factory name="qsectors" description="Factory to create an artifact to host qsectors."
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.QSectorArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
+
+            <!-- MINFO specific Artifacts -->
+            <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-factory name="gaugedischargecurve" description="Factory to create an artifact to show a discharge curve for a gauge."
+                ttl="3600000"
+                artifact="de.intevation.flys.artifacts.GaugeDischargeCurveArtifact">de.intevation.artifactdatabase.DefaultArtifactFactory</artifact-factory>
         </artifact-factories>
 
         <user-factory name="default" description="Factory to create new users">de.intevation.artifactdatabase.DefaultUserFactory</user-factory>
@@ -97,6 +154,54 @@
                 name="cross-section-km"
                 service="de.intevation.flys.artifacts.services.CrossSectionKMService"
                 description="The service provides the N next neighbored kms and ids of cross section lines for given cross section id, km and N.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="cache-invalidation"
+                service="de.intevation.flys.artifacts.services.CacheInvalidationService"
+                description="The service invalidates caches.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="dischargeinfo"
+                service="de.intevation.flys.artifacts.services.DischargeInfoService"
+                description="Returns description, start year and end year of discharges at a specific gauge.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="fixings-overview"
+                service="de.intevation.flys.artifacts.services.FixingsOverviewService"
+                description="Returns an overview of the fixings of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="fixings-km-chart"
+                service="de.intevation.flys.artifacts.services.FixingsKMChartService"
+                description="Returns a chart of fixings of given river and km.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="gaugeinfo"
+                service="de.intevation.flys.artifacts.services.GaugeInfoService"
+                description="Returns an overview of the fixings of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="fileupload"
+                service="de.intevation.flys.artifacts.services.FileUploadService"
+                description="Takes base64 coded files embedded in XML.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="themelisting"
+                service="de.intevation.flys.artifacts.services.ThemeListingService"
+                description="Returns a list of Themes filtered by theme name.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="sq-km-chart"
+                service="de.intevation.flys.artifacts.services.SQKMChartService"
+                description="Returns a chart of km and date of meassuring points of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="modules"
+                service="de.intevation.flys.artifacts.services.ModuleService"
+                description="Returns a list of available modules.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="bed-km-chart"
+                service="de.intevation.flys.artifacts.services.BedKMChartService"
+                description="Returns a chart of km and date of meassuring points of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="bedload-km-chart"
+                service="de.intevation.flys.artifacts.services.BedloadKMChartService"
+                description="Returns a chart of km and date of meassuring points of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
+                name="gaugeoverviewinfo"
+                service="de.intevation.flys.artifacts.services.GaugeOverviewInfoService"
+                description="Returns an overview of the fixings of a given river.">de.intevation.artifactdatabase.DefaultServiceFactory</service-factory>
         </service-factories>
 
     </factories>
@@ -115,12 +220,28 @@
         description="A CallContext.Listener to open and close Hibernatesessions">de.intevation.flys.artifacts.context.SessionCallContextListener</callcontext-listener>
 
     <artifacts>
+        <artifact name="manualpoints" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/manualpoints.xml" />
         <artifact name="winfo" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/winfo.xml" />
+        <artifact name="minfo" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/minfo.xml" />
         <artifact name="waterlevel" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/waterlevel.xml" />
         <artifact name="annotation" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/annotation.xml" />
+        <artifact name="hyk" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/hyk.xml" />
         <artifact name="wmsbackground" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/wmsbackground.xml" />
+        <artifact name="new_map" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/map.xml" />
+        <artifact name="new_chart" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/chart.xml" />
+        <artifact name="staticwqkms" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/staticwqkms.xml" />
+        <artifact name="fixanalysis" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/fixanalysis.xml" />
+        <artifact name="gaugedischarge" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/gaugedischarge.xml" />
+        <artifact name="qsector" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="${artifacts.config.dir}/artifacts/qsector.xml" />
     </artifacts>
 
+    <modules>
+        <module name="winfo" selected="true"/>
+        <module name="minfo"/>
+        <module name="new_map"/>
+        <module name="new_chart"/>
+        <module name="fixanalysis"/>
+    </modules>
 
     <hooks>
         <hook
@@ -145,6 +266,8 @@
         <output-generator name="discharge_longitudinal_section">de.intevation.flys.exports.DischargeLongitudinalSectionGenerator</output-generator>
         <output-generator name="discharge_longitudinal_section_chartinfo">de.intevation.flys.exports.DischargeLongitudinalSectionInfoGenerator</output-generator>
         <output-generator name="waterlevel_export">de.intevation.flys.exports.WaterlevelExporter</output-generator>
+        <output-generator name="fix_wq_curve">de.intevation.flys.exports.fixings.FixWQCurveGenerator</output-generator>
+        <output-generator name="fix_wq_curve_chartinfo">de.intevation.flys.exports.fixings.FixWQCurveInfoGenerator</output-generator>
         <output-generator name="durationcurve_export">de.intevation.flys.exports.DurationCurveExporter</output-generator>
         <output-generator name="computed_dischargecurve_export">de.intevation.flys.exports.ComputedDischargeCurveExporter</output-generator>
         <output-generator name="discharge_longitudinal_section_export">de.intevation.flys.exports.DischargeLongitudinalSectionExporter</output-generator>
@@ -152,14 +275,67 @@
         <output-generator name="w_differences_chartinfo">de.intevation.flys.exports.WDifferencesCurveInfoGenerator</output-generator>
         <output-generator name="w_differences_export">de.intevation.flys.exports.WDifferencesExporter</output-generator>
         <output-generator name="floodmap">de.intevation.flys.exports.MapGenerator</output-generator>
+        <output-generator name="map">de.intevation.flys.exports.MapGenerator</output-generator>
+        <output-generator name="reference_curve">de.intevation.flys.exports.ReferenceCurveGenerator</output-generator>
+        <output-generator name="reference_curve_normalized">de.intevation.flys.exports.NormalizedReferenceCurveGenerator</output-generator>
+        <output-generator name="reference_curve_normalized_chartinfo">de.intevation.flys.exports.NormalizedReferenceCurveInfoGenerator</output-generator>
+        <output-generator name="reference_curve_chartinfo">de.intevation.flys.exports.ReferenceCurveInfoGenerator</output-generator>
+        <output-generator name="reference_curve_export">de.intevation.flys.exports.ReferenceCurveExporter</output-generator>
+        <output-generator name="historical_discharge">de.intevation.flys.exports.HistoricalDischargeCurveGenerator</output-generator>
+        <output-generator name="historical_discharge_chartinfo">de.intevation.flys.exports.HistoricalDischargeCurveInfoGenerator</output-generator>
+        <output-generator name="historical_discharge_export">de.intevation.flys.exports.HistoricalDischargeCurveExporter</output-generator>
+        <output-generator name="flow_velocity">de.intevation.flys.exports.FlowVelocityGenerator</output-generator>
+        <output-generator name="flow_velocity_chartinfo">de.intevation.flys.exports.FlowVelocityInfoGenerator</output-generator>
+        <output-generator name="flow_velocity_export">de.intevation.flys.exports.FlowVelocityExporter</output-generator>
+        <output-generator name="bedheight_middle">de.intevation.flys.exports.MiddleBedHeightGenerator</output-generator>
+        <output-generator name="bedheight_middle_chartinfo">de.intevation.flys.exports.MiddleBedHeightInfoGenerator</output-generator>
+        <output-generator name="bedheight_middle_export">de.intevation.flys.exports.MiddleBedHeightExporter</output-generator>
+        <output-generator name="bed_longitudinal_section">de.intevation.flys.exports.minfo.BedQualityGenerator</output-generator>
+        <output-generator name="bed_longitudinal_section_chartinfo">de.intevation.flys.exports.minfo.BedQualityInfoGenerator</output-generator>
+        <output-generator name="bed_quality_export">de.intevation.flys.exports.minfo.BedQualityExporter</output-generator>
+        <output-generator name="bed_difference_year">de.intevation.flys.exports.minfo.BedDifferenceYearGenerator</output-generator>
+        <output-generator name="bed_difference_year_chartinfo">de.intevation.flys.exports.minfo.BedDiffYearInfoGenerator</output-generator>
+        <output-generator name="bed_difference_epoch">de.intevation.flys.exports.minfo.BedDifferenceEpochGenerator</output-generator>
+        <output-generator name="bed_difference_epoch_chartinfo">de.intevation.flys.exports.minfo.BedDiffEpochInfoGenerator</output-generator>
+        <output-generator name="bed_difference_height_year">de.intevation.flys.exports.minfo.BedDiffHeightYearGenerator</output-generator>
+        <output-generator name="bed_difference_height_year_chartinfo">de.intevation.flys.exports.minfo.BedDiffHeightYearInfoGenerator</output-generator>
+        <output-generator name="sq_relation_a">de.intevation.flys.exports.sq.SQRelationGeneratorA</output-generator>
+        <output-generator name="sq_relation_b">de.intevation.flys.exports.sq.SQRelationGeneratorB</output-generator>
+        <output-generator name="sq_relation_c">de.intevation.flys.exports.sq.SQRelationGeneratorC</output-generator>
+        <output-generator name="sq_relation_d">de.intevation.flys.exports.sq.SQRelationGeneratorD</output-generator>
+        <output-generator name="sq_relation_e">de.intevation.flys.exports.sq.SQRelationGeneratorE</output-generator>
+        <output-generator name="sq_relation_f">de.intevation.flys.exports.sq.SQRelationGeneratorF</output-generator>
+        <output-generator name="sq_relation_a_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator>
+        <output-generator name="sq_relation_b_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator>
+        <output-generator name="sq_relation_c_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator>
+        <output-generator name="sq_relation_d_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator>
+        <output-generator name="sq_relation_e_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator>
+        <output-generator name="sq_relation_f_chartinfo">de.intevation.flys.exports.sq.SQRelationInfoGenerator</output-generator>
+        <output-generator name="sq_relation_export">de.intevation.flys.exports.sq.SQRelationExporter</output-generator>
+        <output-generator name="sq_overview">de.intevation.flys.exports.sq.SQOverviewGenerator</output-generator>
+        <output-generator name="fix_parameters_export">de.intevation.flys.exports.fixings.ParametersExporter</output-generator>
+        <output-generator name="fix_deltawt_export">de.intevation.flys.exports.fixings.DeltaWtExporter</output-generator>
+        <output-generator name="fix_deltawt_curve">de.intevation.flys.exports.fixings.FixDeltaWtGenerator</output-generator>
+        <output-generator name="fix_deltawt_curve_chartinfo">de.intevation.flys.exports.fixings.FixDeltaWtInfoGenerator</output-generator>
+        <output-generator name="fix_longitudinal_section_curve">de.intevation.flys.exports.fixings.FixLongitudinalSectionGenerator</output-generator>
+        <output-generator name="fix_longitudinal_section_curve_chartinfo">de.intevation.flys.exports.fixings.FixLongitudinalSectionInfoGenerator</output-generator>
+        <output-generator name="fix_derivate_curve">de.intevation.flys.exports.fixings.FixDerivedCurveGenerator</output-generator>
+        <output-generator name="fix_derivate_curve_chartinfo">de.intevation.flys.exports.fixings.FixDerivedCurveInfoGenerator</output-generator>
+        <output-generator name="fix_waterlevel_export">de.intevation.flys.exports.WaterlevelExporter</output-generator>
+        <output-generator name="fix_vollmer_wq_curve">de.intevation.flys.exports.fixings.FixWQCurveGenerator</output-generator>
+        <output-generator name="fix_vollmer_wq_curve_chartinfo">de.intevation.flys.exports.fixings.FixWQCurveInfoGenerator</output-generator>
         <!-- Error report generators. -->
         <output-generator name="discharge_longitudinal_section_report">de.intevation.flys.exports.ReportGenerator</output-generator>
         <output-generator name="waterlevel_report">de.intevation.flys.exports.ReportGenerator</output-generator>
         <output-generator name="computed_dischargecurve_report">de.intevation.flys.exports.ReportGenerator</output-generator>
         <output-generator name="durationcurve_report">de.intevation.flys.exports.ReportGenerator</output-generator>
         <output-generator name="wsplgen_report">de.intevation.flys.exports.ReportGenerator</output-generator>
+        <output-generator name="historical_discharge_report">de.intevation.flys.exports.ReportGenerator</output-generator>
+        <output-generator name="reference_curve_report">de.intevation.flys.exports.ReportGenerator</output-generator>
+        <output-generator name="fix_report">de.intevation.flys.exports.ReportGenerator</output-generator>
         <!-- AT exporter. -->
         <output-generator name="computed_dischargecurve_at_export">de.intevation.flys.exports.ATExporter</output-generator>
+        <output-generator name="fix_wq_curve_at_export">de.intevation.flys.exports.fixings.FixATExport</output-generator>
     </output-generators>
 
     <!-- Path to the template file of the meta data. -->
@@ -167,44 +343,10 @@
         <template>${artifacts.config.dir}/meta-data.xml</template>
     </metadata>
 
-    <!-- The floodmap configuration for each supported river. Each element
-         requires a srid, wms and background-wms. Those information are used for
-         creating a Map view.-->
-    <floodmap>
-        <shapefile-path value="${artifacts.config.dir}/../shapefiles"/>
-        <mapserver>
-            <server path="http://flys-devel.intevation.de/cgi-bin/"/>
-            <mapfile path="${artifacts.config.dir}/../flys.map"/>
-            <templates path="${artifacts.config.dir}/mapserver/"/>
-            <map-template path="mapfile.vm"/>
-        </mapserver>
-
-        <velocity>
-            <logfile path="${artifacts.config.dir}/../velocity_log.log"/>
-        </velocity>
+    &floodmap;
 
-        <river name="Saar">
-            <srid value="31466"/>
-            <river-wms url="http://flys-devel.intevation.de/cgi-bin/saar-wms"/>
-            <background-wms url="http://vmap0.tiles.osgeo.org/wms/vmap0" layers="basic"/>
-        </river>
-        <river name="Mosel">
-            <srid value="31466"/>
-            <river-wms url="http://flys-devel.intevation.de/cgi-bin/mosel-wms"/>
-            <background-wms url="http://vmap0.tiles.osgeo.org/wms/vmap0" layers="basic"/>
-        </river>
-        <river name="Elbe">
-            <srid value="31466"/>
-            <river-wms url="http://flys-devel.intevation.de/cgi-bin/elbe-wms"/>
-            <background-wms url="http://vmap0.tiles.osgeo.org/wms/vmap0" layers="basic"/>
-        </river>
-    </floodmap>
+    &rest-server;
 
-    <rest-server>
-        <!--  The port which the ArtifactDatabase (ArtifactServer) will bind to. -->
-        <port>8181</port>
-        <listen>localhost</listen>
-    </rest-server>
     <!-- Garbage collection of outdated artifacts. -->
     <cleaner>
         <sleep-time>60000</sleep-time>
@@ -214,34 +356,11 @@
         <config-file>${artifacts.config.dir}/cache.xml</config-file>
     </cache>
 
-    <!-- This is the default configuration of the datacage db:
-    <datacage>
-        <user/>
-        <password/>
-        <driver>org.h2.Driver</driver>
-        <url>jdbc:h2:mem:datacage;INIT=RUNSCRIPT FROM '${artifacts.config.dir}/datacage.sql'</url>
-    </datacage>
-    -->
-
-    <database>
-        <!-- This Section configures the Settings for connecting to the 
-             Artifact-Database instance. e.g. SQLite -->
-        <user>SA</user>
-        <password></password>
-        <!-- For use with a postgresql database use the appropriate driver-->
-        <!--driver>org.postgresql.Driver</driver-->
-        <url>jdbc:h2:${artifacts.config.dir}/../artifactdb/artifacts.db</url>
-    </database>
-    <!-- This is the default backend db configuration. -->
-    <!--
-    <backend-database>
-        <user>flys</user>
-        <password>flys</password>
-        <dialect>org.hibernate.dialect.PostgreSQLDialect</dialect>
-        <driver>org.postgresql.Driver</driver>
-        <url>jdbc:postgresql://localhost:5432/flys</url>
-    </backend-database>
-    -->
+    <!-- Configuration of used databases. -->
+    &artifact-db;
+    &datacage-db;
+    &backend-db;
+    &seddb-db;
 
     <flys>
         <themes>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/datacage-db.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<datacage>
+    <user>SA</user>
+    <password/>
+    <driver>org.h2.Driver</driver>
+    <url>jdbc:h2:${artifacts.config.dir}/../h2/datacage</url>
+</datacage>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/default-themes.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,1637 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<themegroup name="default">
+    <theme name="DischargeCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 153" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="2" hints="h" />
+        </fields>
+    </theme>
+
+    <!-- concrete theme for historical discharge curves -->
+    <theme name="HistoricalDischargeCurveQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 153" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="2" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="HistoricalDischargeCurveQDiff">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="2" hints="h" />
+        </fields>
+    </theme>
+
+
+    <!-- Discharge Longitudinal Section -->
+    <theme name="LongitudinalSectionW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="bandwidth" type="double" display="Bandbreite"
+                default="0"/>
+            <field name="fillcolor" type="Color" display="Bandbreitenfarbe"
+                default="104, 104, 104"/> 
+    	    <field name="transparency" type="int" default="20" display="Transparenz"/>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ1">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ2">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ5">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 153, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ10">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ20">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 153, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ25">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 51, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ50">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 153, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ100">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ200">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ500">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ1000">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQRZ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HSQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="253, 153, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MHQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 255, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MNQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 255, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 51, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_NQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 204, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQExtrem">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionPoints">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="false" />
+            <field name="showpoints" type="boolean" display="Punkte anzeigen"
+                default="true" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ1_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ2_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ5_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 153, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ10_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ20_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 153, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ25_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 51, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ50_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 153, 153" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ100_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ200_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ500_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ1000_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQRZ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HSQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="253, 153, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MHQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 255, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MNQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 255, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 51, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_NQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 204, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQExtrem_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+
+    <!-- Longitudinal Section Q's -->
+
+    <theme name="LongitudinalSectionQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ1">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ2">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ5">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 153, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ10">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ20">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 153, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ25">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 51, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ50">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 153, 153" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ100">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ200">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ500">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ1000">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQRZ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HSQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="253, 153, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_MHQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 255, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_MNQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 255, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_MQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 51, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_NQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 204, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQExtrem">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+
+    <!-- Main Values -->
+    <theme name="MainValuesQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Farbe"
+                default="200, 0, 15" />
+            <field name="textcolor" type="Color" display="Farbe"
+                default="200, 0, 15" />
+            <field name="showhorizontalline" type="boolean"
+                display="Horizontale Linie" default="true" />
+            <field name="showverticalline" type="boolean" display="Vertikale Linie"
+                default="true" />
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+        </fields>
+    </theme>
+
+    <theme name="MainValuesW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Farbe"
+                default="0, 215, 0" />
+            <field name="textcolor" type="Color" display="Farbe"
+                default="0, 215, 0" />
+            <field name="showhorizontalline" type="boolean"
+                display="Horizontale Linie" default="true" />
+            <field name="showverticalline" type="boolean" display="Vertikale Linie"
+                default="true" />
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+        </fields>
+    </theme>
+
+    <!-- Computed Discharge Curves -->
+    <theme name="ComputedDischargeCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 153" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="2" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="ComputedDischargeCurveQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Farbe"
+                default="200, 0, 15" />
+            <field name="textcolor" type="Color" display="Farbe"
+                default="200, 0, 15" />
+        </fields>
+    </theme>
+
+    <theme name="ComputedDischargeCurveW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Farbe"
+                default="0, 215, 0" />
+            <field name="textcolor" type="Color" display="Farbe"
+                default="0, 215, 0" />
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+        </fields>
+    </theme>
+
+    <!-- Cross Sections -->
+    <theme name="CrossSection">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0,0,0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="CrossSectionWaterLine">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0,0,153" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+            <field name="showwidth" type="boolean" display="Breite anzeigen"
+                default="false" />
+            <field name="showlevel" type="boolean" display="Wasserstand anzeigen"
+                default="true" />
+            <field name="showlinelabel" type="boolean" default="true"
+                display="Beschriftung anzeigen" />
+            <field name="showmiddleheight" type="boolean"
+                display="Wasserstand anzeigen" default="false" />
+        </fields>
+    </theme>
+
+    <theme name="Hyk">
+        <inherits>
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+        </fields>
+    </theme>
+
+    <!-- Relative Points -->
+    <theme name="RelativePoint">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <!--fields> <field name="linecolor" type="Color" display="Linienfarbe"
+            default="0, 0, 0"/> </fields -->
+    </theme>
+
+    <!-- Duration Curves -->
+    <theme name="DurationCurveW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0,51,204" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="2" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="DurationCurveQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0,204,0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="2" hints="h" />
+        </fields>
+    </theme>
+
+    <!-- Differences -->
+    <theme name="Differences">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+    <!-- Reference Curves -->
+    <theme name="ReferenceCurveNormalized">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="ReferenceCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+    <!-- General -->
+    <theme name="WKms">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="WQKms">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="WQPoints">
+        <inherits>
+            <inherit from="Points" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="false" />
+            <field name="showpoints" type="boolean" display="Punkte anzeigen"
+                default="true" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 0" />
+        </fields>
+    </theme>
+
+    <!-- Discharge Longitudinal Section -->
+    <theme name="DischargeLongitudinalSectionW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+
+    <theme name="DischargeLongitudinalSectionC">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0 , 0" />
+        </fields>
+    </theme>
+
+    <theme name="DischargeLongitudinalSectionQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+
+    <!-- Annotations -->
+    <theme name="Annotations">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="Text" />
+            <inherit from="AnnotationText" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+
+    <!-- Manual Points -->
+    <theme name="ManualPoints">
+        <inherits>
+            <inherit from="Points" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="250, 0, 0" />
+            <field name="font" type="Font" display="Schriftart"
+                default="arial" />
+            <field name="textcolor" type="Color" display="Schriftfarbe"
+                default="0, 0, 0" />
+            <field name="textsize" type="int" display="Schriftgröße"
+                default="10" />
+            <field name="textstyle" type="Style" display="Schriftstil"
+                default="standard" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" hints="h" />
+            <field name="backgroundcolor" type="Color" display="Texthintergrund"
+                default="255, 255, 255" />
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+            <field name="showbackground" type="boolean"
+                display="Hintergrund anzeigen" default="false" />
+        </fields>
+    </theme>
+
+    <!-- Height Marks -->
+    <theme name="heightmarks_points">
+        <inherits>
+            <inherit from="Points" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+
+    <!-- Areas -->
+    <theme name="Area">
+        <inherits>
+            <inherit from="Areas" />
+         </inherits>
+         <fields>
+            <field name="showarea" type="boolean" display="Show Area"
+                default="true"/>
+         </fields>
+    </theme>
+
+    <!-- Map -->
+    <theme name="Floodmaps">
+        <inherits>
+            <inherit from="Floodmap" />
+        </inherits>
+    </theme>
+
+    <theme name="Floodplains">
+        <inherits>
+            <inherit from="Floodplain" />
+        </inherits>
+    </theme>
+
+    <theme name="WSPLGEN">
+        <inherits>
+            <inherit from="WSPLGENS" />
+        </inherits>
+    </theme>
+
+    <theme name="RiverAxis">
+        <inherits>
+            <inherit from="RiverAxes" />
+        </inherits>
+    </theme>
+
+    <theme name="Kms">
+        <inherits>
+            <inherit from="Km" />
+        </inherits>
+    </theme>
+
+
+    <theme name="Fixpoints">
+        <inherits>
+            <inherit from="Fixpoint" />
+        </inherits>
+    </theme>
+
+
+    <theme name="GaugeLocation">
+        <inherits>
+            <inherit from="GaugeLocations" />
+        </inherits>
+    </theme>
+
+
+    <theme name="Qps">
+        <inherits>
+            <inherit from="Qp" />
+        </inherits>
+    </theme>
+
+    <theme name="Hws">
+        <inherits>
+            <inherit from="Hw" />
+        </inherits>
+    </theme>
+
+    <theme name="Catchment">
+        <inherits>
+            <inherit from="Catchments" />
+        </inherits>
+    </theme>
+
+    <theme name="FloodmapLines">
+        <inherits>
+            <inherit from="FloodmapLine" />
+        </inherits>
+    </theme>
+
+    <theme name="Buildings">
+        <inherits>
+            <inherit from="Building" />
+        </inherits>
+    </theme>
+
+    <theme name="HydrBoundariesLines">
+        <inherits>
+            <inherit from="HydrBoundariesLine" />
+        </inherits>
+    </theme>
+
+    <theme name="HydrBoundariesPolys">
+        <inherits>
+            <inherit from="HydrBoundariesPoly" />
+        </inherits>
+    </theme>
+
+    <!-- MIDDLE BED HEIGHT -->
+    <theme name="MiddleBedHeightSingle">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="MiddleBedHeightEpoch">
+        <inherits>
+            <inherit from="FlowVelocityVMainChannel" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 102" />
+        </fields>
+    </theme>
+    
+    <!-- Bed Quality -->
+    <theme name="PorosityTopLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+    
+    <theme name="PorositySubLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+        </fields>
+    </theme>
+    
+    <theme name="DensityTopLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#996366" />
+        </fields>
+    </theme>
+    
+    <theme name="DensitySubLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#996366" />
+        </fields>
+    </theme>
+    
+    <theme name="BedDiameterTopLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#FF0000" />
+        </fields>
+    </theme>
+    
+    <theme name="BedDiameterSubLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#FF0000" />
+        </fields>
+    </theme>
+    
+    <theme name="BedLoadDiameter">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#00FF00" />
+        </fields>
+    </theme>
+
+    <!-- Bedheight differences -->
+    <theme name="BedheightDiffYear">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffMorphWidth">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 0" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffEpoch">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffAbsHeight1">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffAbsHeight2">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 100, 100" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffHeightYear">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 0" />
+        </fields>
+    </theme>
+
+
+    <!-- FLOW VELOCITY -->
+    <theme name="FlowVelocityVMainChannel">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="FlowVelocityVTotalChannel">
+        <inherits>
+            <inherit from="FlowVelocityVMainChannel" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="FlowVelocityTau">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 204, 204" />
+        </fields>
+    </theme>
+
+
+    <!-- SQ Relation -->
+    <theme name="SQMeasurements">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="false" hidden="true" />
+            <field name="pointcolor" type="Color" default="#0099FF" />
+        </fields>
+    </theme>
+
+    <theme name="SQOutliers">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="false" hidden="true" />
+            <field name="pointcolor" type="Color" default="#CC0000" />
+        </fields>
+    </theme>
+
+    <theme name="SQCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="#000000" />
+        </fields>
+    </theme>
+
+    <theme name="FixingWQCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="227, 27, 162" />
+        </fields>
+    </theme>
+
+    <theme name="FixingDerivedCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="227, 27, 162" />
+            <field name="showpoints" type="boolean" display="Datenpunkte anzeigen"
+                default="false" hints="h" hidden="true" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="5" hints="h" hidden="true" />
+        </fields>
+    </theme>
+
+    <theme name="FixingSectorAverageWQ0">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" default="true" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 128, 0" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="true"/>
+        </fields>
+    </theme>
+    <theme name="FixingSectorAverageWQ1">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="showlines" type="boolean" default="true" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 0, 255" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="true"/>
+        </fields>
+    </theme>
+    <theme name="FixingSectorAverageWQ2">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="showlines" type="boolean" default="true" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="255, 0, 255" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="true"/>
+        </fields>
+    </theme>
+    <theme name="FixingSectorAverageWQ3">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="showlines" type="boolean" default="true" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="255, 0, 0" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="true"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingAnalysisEventsWQ">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" default="false" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 255, 0" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="true"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingReferenceEvents">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" default="false"
+                hidden="true" />
+            <field name="showlinelabel" type="boolean" default="false"
+                hidden="true" />
+            <field name="linetype" type="Dash" display="Linienart"
+                default="10" hidden="true" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hidden="true" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 80, 160" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="true"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingOutliers">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="false"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingDeltaWtAverage0">
+        <inherits>
+            <inherit from="ColorLines" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="true" hints="h" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 128, 0" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+    <theme name="FixingDeltaWtAverage1">
+        <inherits>
+            <inherit from="ColorLines" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="true" hints="h" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 255" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+    <theme name="FixingDeltaWtAverage2">
+        <inherits>
+            <inherit from="ColorLines" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="true" hints="h" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 255" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+    <theme name="FixingDeltaWtAverage3">
+        <inherits>
+            <inherit from="ColorLines" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="true" hints="h" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 0" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingDeltaWtAnalysis">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="true"/>
+            <field name="showlines" type="boolean" default="false" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 255, 0" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingLSAverage0">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="0, 128, 0" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixingLSAverage1">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="0, 0, 255" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixingLSAverage2">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="255, 0, 255" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixingLSAverage3">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="255, 0, 0" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="FixingSectorDeviationLS0">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Fuellfarbe"
+                default="0, 128, 0" />
+        </fields>
+    </theme>
+    <theme name="FixingSectorDeviationLS1">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Fuellfarbe"
+                default="0, 0, 255" />
+        </fields>
+    </theme>
+    <theme name="FixingSectorDeviationLS2">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Fuellfarbe"
+                default="255, 0, 255" />
+        </fields>
+    </theme>
+    <theme name="FixingSectorDeviationLS3">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Fuellfarbe"
+                default="255, 0, 0" />
+        </fields>
+    </theme>
+    <theme name="FixLSDeviation">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Fuellfarbe"
+                default="100, 100, 100" />
+        </fields>
+    </theme>
+    <theme name="FixLSAnalysis">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="0, 255, 0" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixLSReference">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="0, 80, 160" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixDeltaWtDeviation">
+    	<inherits>
+    		<inherit from="Areas"/>
+    	</inherits>
+    	<fields>
+    		<field name="transparency" type="int" default="80" display="Transparenz"/>
+    		<field name="backgroundcolor" type="Color" default="0, 0, 0" display="Füllfarbe"/>
+    	</fields>
+    </theme>
+    <theme name="FixingDeltaWtAnalysisPeriods">
+        <inherits>
+    		<inherit from="Areas"/>
+    	</inherits>
+    	<fields>
+    		<field name="transparency" type="int" default="80" display="Transparenz"/>
+            <field name="backgroundcolor" type="Color" default="255, 0, 0" display="Füllfarbe" />
+    	</fields>
+    </theme>
+    
+    <theme name="FixingReferencePeriod">
+        <inherits>
+    		<inherit from="Areas"/>
+    	</inherits>
+    	<fields>
+    		<field name="transparency" type="int" default="80" display="Transparenz"/>
+            <field name="backgroundcolor" type="Color" default="0, 0, 255" display="Füllfarbe" />
+    	</fields>
+    </theme>
+
+    <theme name="QSectors">
+        <fields>
+            <field name="linecolor" type="Color" default="0, 0, 0" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="true" hints="h" />
+            <field name="linetype" type="Dash" display="Linienart"
+                default="10" hidden="true" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hidden="true" />
+            <field name="labelfontface" type="Font"
+                display="Beschriftung: Schriftart" default="arial" />
+            <field name="labelfontcolor" type="Color"
+                display="Beschriftung: Schriftfarbe" default="0, 0, 0" />
+            <field name="labelfontsize" type="int"
+                display="Beschriftung: Schriftgröße" default="10" />
+            <field name="labelfontstyle" type="Style"
+                display="Beschriftung: Schriftstil" default="standard" />
+        </fields>
+    </theme>
+
+</themegroup>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/floodmap.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<floodmap>
+    <shapefile-path value="${artifacts.config.dir}/../shapefiles"/>
+    <mapserver>
+        <server path="http://flys-devel.intevation.de/cgi-bin/"/>
+        <mapfile path="${artifacts.config.dir}/../flys.map"/>
+        <templates path="${artifacts.config.dir}/mapserver/"/>
+        <map-template path="mapfile.vm"/>
+    </mapserver>
+
+    <velocity>
+        <logfile path="${artifacts.config.dir}/../velocity_log.log"/>
+    </velocity>
+
+    <river name="Saar">
+        <srid value="31466"/>
+        <river-wms url="http://flys-devel.intevation.de/cgi-bin/saar-wms"/>
+        <background-wms url="http://vmap0.tiles.osgeo.org/wms/vmap0" layers="basic"/>
+    </river>
+    <river name="Mosel">
+        <srid value="31466"/>
+        <river-wms url="http://flys-devel.intevation.de/cgi-bin/mosel-wms"/>
+        <background-wms url="http://vmap0.tiles.osgeo.org/wms/vmap0" layers="basic"/>
+    </river>
+    <river name="Elbe">
+        <srid value="31466"/>
+        <river-wms url="http://flys-devel.intevation.de/cgi-bin/elbe-wms"/>
+        <background-wms url="http://vmap0.tiles.osgeo.org/wms/vmap0" layers="basic"/>
+    </river>
+</floodmap>
Binary file flys-artifacts/doc/conf/jasper/computed-discharge.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/computed-discharge_en.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/duration.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/duration_en.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/historical-discharge.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/historical-discharge_en.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/reference.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/reference_en.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/reference_en_gauge.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/reference_en_gauge_end.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/reference_en_gauge_start_end.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/reference_gauge.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/reference_gauge_end.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/reference_gauge_start_end.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/waterlevel.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/waterlevel_en.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/wdifferences.jasper has changed
Binary file flys-artifacts/doc/conf/jasper/wdifferences_en.jasper has changed
--- a/flys-artifacts/doc/conf/mapserver/db_layer.vm	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/mapserver/db_layer.vm	Fri Sep 28 12:15:52 2012 +0200
@@ -6,7 +6,7 @@
     CONNECTION "$LAYER.getConnection()"
 
     DATA    "$LAYER.getData()"
-    FILTER  '$LAYER.getFilter()'
+    FILTER  "$LAYER.getFilter()"
     EXTENT  $LAYER.getExtent()
 
     STATUS    ON
@@ -21,6 +21,10 @@
         LABELITEM $LAYER.getLabelItem()
     #end
 
+    PROJECTION
+        "init=epsg:31467"
+    END
+
     METADATA
         "wms_title" "$LAYER.getTitle()"
         "gml_include_items" "all"
--- a/flys-artifacts/doc/conf/mapserver/layer.vm	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/mapserver/layer.vm	Fri Sep 28 12:15:52 2012 +0200
@@ -18,6 +18,10 @@
         #end
     END
 
+    PROJECTION
+        "init=epsg:$LAYER.getSrid()"
+    END
+
     #if ( !$LAYER.getStyle() )
         #if ( $LAYER.getGroupTitle() )
             #if ( $LAYER.getType() == "POLYGON" )
--- a/flys-artifacts/doc/conf/mapserver/mapfile.vm	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/mapserver/mapfile.vm	Fri Sep 28 12:15:52 2012 +0200
@@ -3,14 +3,14 @@
     STATUS ON
     SIZE 600 400
     MAXSIZE 4000
-    EXTENT -90 -180 90 180
+    EXTENT 3233232.55407617 5303455.37850183 3421524.44644752 5585825.50888523
     UNITS DD
     SHAPEPATH "$SHAPEFILEPATH"
     FONTSET "$CONFIGDIR/mapserver/fontset.txt"
     SYMBOLSET "$CONFIGDIR/mapserver/symbols.sym"
     IMAGECOLOR 255 255 255
     PROJECTION
-        "init=epsg:31466"
+        "init=epsg:31467"
     END
 
     DEBUG 5
--- a/flys-artifacts/doc/conf/mapserver/shapefile_layer.vm	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/mapserver/shapefile_layer.vm	Fri Sep 28 12:15:52 2012 +0200
@@ -10,6 +10,10 @@
         GROUP "$LAYER.getGroup()"
     #end
 
+    PROJECTION
+        "init=epsg:$LAYER.getSrid()"
+    END
+
     METADATA
         "wms_title" "$LAYER.getTitle()"
         "gml_include_items" "all"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/mapserver/wsplgen_layer.vm	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,40 @@
+LAYER
+    NAME      "$LAYER.getName()"
+    TYPE      $LAYER.getType()
+    DATA      "$LAYER.getDirectory()/$LAYER.getData()"
+    STATUS    ON
+    TEMPLATE  map.html
+    TOLERANCE 10
+    DUMP      TRUE
+    #if( $LAYER.getGroup() )
+        GROUP "$LAYER.getGroup()"
+    #end
+
+    PROJECTION
+        "init=epsg:$LAYER.getSrid()"
+    END
+
+    METADATA
+        "wms_title" "$LAYER.getTitle()"
+        "gml_include_items" "all"
+        "ows_enable_request" "GetFeatureInfo"
+        "wms_feature_info_mime_type" "gml"
+        #if ( $LAYER.getGroupTitle() )
+            "wms_group_title" "$LAYER.getGroupTitle()"
+        #end
+    END
+
+    #if ( !$LAYER.getStyle() )
+        #if ( $LAYER.getGroupTitle() )
+            #if ( $LAYER.getType() == "POLYGON" )
+                #include("barrier_polygons_class.vm")
+            #else
+                #include("barrier_lines_class.vm")
+            #end
+        #else
+            #include("wsplgen_class.vm")
+        #end
+    #else
+        $LAYER.getStyle()
+    #end
+END
--- a/flys-artifacts/doc/conf/meta-data.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/meta-data.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -27,7 +27,8 @@
                       <dc:statement>
                         SELECT id       AS prot_column_id,
                                name     AS prot_column_name,
-                               position AS prot_rel_pos
+                               position AS prot_rel_pos,
+                               description AS info
                         FROM wst_columns WHERE wst_id = ${prot_id}
                         ORDER by position
                       </dc:statement>
@@ -36,6 +37,7 @@
                           <dc:attribute name="name" value="${prot_column_name}"/>
                           <dc:attribute name="ids" value="base_data-wstv-${prot_rel_pos}-${prot_id}"/>
                           <dc:attribute name="factory" value="staticwkms"/>
+                          <dc:attribute name="info" value="${info}"/>
                         </column>
                       </dc:elements>
                     </dc:context>
@@ -60,7 +62,8 @@
                       <dc:statement>
                         SELECT id       AS prot_column_id,
                                name     AS prot_column_name,
-                               position AS prot_rel_pos
+                               position AS prot_rel_pos,
+                               description AS info
                         FROM wst_columns WHERE wst_id = ${prot_id}
                         ORDER by position
                       </dc:statement>
@@ -69,6 +72,7 @@
                           <dc:attribute name="name" value="${prot_column_name}"/>
                           <dc:attribute name="ids" value="base_data-wstv-${prot_rel_pos}-${prot_id}"/>
                           <dc:attribute name="factory" value="wqinterpol"/>
+                          <dc:attribute name="info" value="${info}"/>
                         </column>
                       </dc:elements>
                     </dc:context>
@@ -80,7 +84,7 @@
 
         <dc:macro name="basedata_1_additionals">
             <dc:comment comment=".ZUS -------------------------------"/>
-            <addtionals>
+            <additionals>
               <dc:context>
                 <dc:statement>
                   SELECT id          AS prot_id,
@@ -94,7 +98,8 @@
                       <dc:statement>
                         SELECT id       AS prot_column_id,
                                name     AS prot_column_name,
-                               position AS prot_rel_pos
+                               position AS prot_rel_pos,
+                               description AS info
                         FROM wst_columns WHERE wst_id = ${prot_id}
                         ORDER by position
                       </dc:statement>
@@ -103,13 +108,50 @@
                           <dc:attribute name="name" value="${prot_column_name}"/>
                           <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/>
                           <dc:attribute name="factory" value="staticwkms"/>
+                          <dc:attribute name="info" value="${info}"/>
                         </column>
                       </dc:elements>
                     </dc:context>
                   </additional>
                 </dc:elements>
               </dc:context>
-            </addtionals>
+            </additionals>
+        </dc:macro>
+
+        <dc:macro name="basedata_1_additionals-relative_point">
+            <dc:comment comment=".ZUS -------------------------------"/>
+            <additionals>
+              <dc:context>
+                <dc:statement>
+                  SELECT id          AS prot_id,
+                         description AS prot_description
+                  FROM wsts WHERE kind = 1 AND river_id = ${river_id}
+                </dc:statement>
+                <dc:elements>
+                  <relativepoint>
+                    <dc:attribute name="name" value="${prot_description}"/>
+                    <dc:context>
+                      <dc:statement>
+                        SELECT id       AS prot_column_id,
+                               name     AS prot_column_name,
+                               position AS prot_rel_pos,
+                               description AS info
+                        FROM wst_columns WHERE wst_id = ${prot_id}
+                        ORDER by position
+                      </dc:statement>
+                      <dc:elements>
+                        <column>
+                          <dc:attribute name="name" value="${prot_column_name}"/>
+                          <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/>
+                          <dc:attribute name="factory" value="staticwkms"/>
+                          <dc:attribute name="info" value="${info}"/>
+                        </column>
+                      </dc:elements>
+                    </dc:context>
+                  </relativepoint>
+                </dc:elements>
+              </dc:context>
+            </additionals>
         </dc:macro>
 
         <dc:macro name="basedata_2_fixations_wst">
@@ -122,9 +164,26 @@
               </dc:statement>
               <dc:elements>
                 <fixation>
-                    <dc:attribute name="name" value="${prot_description}"/>
-                    <dc:attribute name="ids" value="fixations-wstv-A-${prot_id}"/>
-                    <dc:attribute name="factory" value="wqinterpol"/>
+                  <dc:attribute name="name" value="${prot_description}"/>
+                  <!--dc:attribute name="ids" value="fixations-wstv-A-${prot_id}"/-->
+                  <dc:context>
+                    <dc:statement>
+                      SELECT id       AS prot_column_id,
+                             name     AS prot_column_name,
+                             position AS prot_rel_pos,
+                             description AS info
+                      FROM wst_columns WHERE wst_id = ${prot_id}
+                      ORDER by position
+                    </dc:statement>
+                    <dc:elements>
+                      <column>
+                        <dc:attribute name="name" value="${prot_column_name}"/>
+                        <dc:attribute name="ids" value="fixations-wstv-${prot_rel_pos}-${prot_id}"/>
+                        <dc:attribute name="factory" value="wqinterpol"/>
+                        <dc:attribute name="info" value="${info}"/>
+                      </column>
+                    </dc:elements>
+                  </dc:context>
                 </fixation>
               </dc:elements>
             </dc:context>
@@ -146,7 +205,8 @@
                     <dc:statement>
                       SELECT id       AS prot_column_id,
                              name     AS prot_column_name,
-                             position AS prot_rel_pos
+                             position AS prot_rel_pos,
+                             desciption AS info
                       FROM wst_columns WHERE wst_id = ${prot_id}
                       ORDER by position
                     </dc:statement>
@@ -155,6 +215,7 @@
                         <dc:attribute name="name" value="${prot_column_name}"/>
                         <dc:attribute name="ids" value="fixations-wstv-${prot_rel_pos}-${prot_id}"/>
                         <dc:attribute name="factory" value="wqinterpol"/>
+                        <dc:attribute name="info" value="${info}"/>
                       </column>
                     </dc:elements>
                   </dc:context>
@@ -179,7 +240,8 @@
                     <dc:statement>
                       SELECT id       AS prot_column_id,
                              name     AS prot_column_name,
-                             position AS prot_rel_pos
+                             position AS prot_rel_pos,
+                             description AS info
                       FROM wst_columns WHERE wst_id = ${prot_id}
                       ORDER by position
                     </dc:statement>
@@ -188,6 +250,7 @@
                         <dc:attribute name="name" value="${prot_column_name}"/>
                         <dc:attribute name="ids" value="fixations-wstv-${prot_rel_pos}-${prot_id}"/>
                         <dc:attribute name="factory" value="staticwkms"/>
+                        <dc:attribute name="info" value="${info}"/>
                       </column>
                     </dc:elements>
                   </dc:context>
@@ -197,6 +260,112 @@
           </fixations>
         </dc:macro>
 
+        <dc:macro name="basedata_2_fixations_relative_point">
+          <fixations>
+            <dc:context>
+              <dc:statement>
+                SELECT id          AS prot_id,
+                       description AS prot_description
+                FROM wsts WHERE kind = 2 AND river_id = ${river_id}
+              </dc:statement>
+              <dc:elements>
+                <relativepoint>
+                  <dc:attribute name="name" value="${prot_description}"/>
+                  <dc:context>
+                    <dc:statement>
+                      SELECT id       AS prot_column_id,
+                             name     AS prot_column_name,
+                             position AS prot_rel_pos,
+                             description AS info
+                      FROM wst_columns WHERE wst_id = ${prot_id}
+                      ORDER by position
+                    </dc:statement>
+                    <dc:elements>
+                      <column>
+                        <dc:attribute name="name" value="${prot_column_name}"/>
+                        <dc:attribute name="ids" value="fixations-wstv-${prot_rel_pos}-${prot_id}"/>
+                        <dc:attribute name="factory" value="staticwkms"/>
+                        <dc:attribute name="info" value="${info}"/>
+                      </column>
+                    </dc:elements>
+                  </dc:context>
+                </relativepoint>
+              </dc:elements>
+            </dc:context>
+          </fixations>
+        </dc:macro>
+
+        <dc:macro name="basedata_3_officials">
+            <dc:comment comment=".wst -------------------------------"/>
+            <officiallines>
+              <dc:context>
+                <dc:statement>
+                  SELECT id          AS prot_id,
+                         description AS prot_description
+                  FROM wsts WHERE kind = 3 AND river_id = ${river_id}
+                </dc:statement>
+                <dc:elements>
+                  <official>
+                    <dc:attribute name="name" value="${prot_description}"/>
+                    <dc:context>
+                      <dc:statement>
+                        SELECT id       AS prot_column_id,
+                               name     AS prot_column_name,
+                               position AS prot_rel_pos,
+                               description AS info
+                        FROM wst_columns WHERE wst_id = ${prot_id}
+                        ORDER by position
+                      </dc:statement>
+                      <dc:elements>
+                        <column>
+                          <dc:attribute name="name" value="${prot_column_name}"/>
+                          <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/>
+                          <dc:attribute name="factory" value="staticwkms"/>
+                          <dc:attribute name="info" value="${info}"/>
+                        </column>
+                      </dc:elements>
+                    </dc:context>
+                  </official>
+                </dc:elements>
+              </dc:context>
+            </officiallines>
+        </dc:macro>
+
+        <dc:macro name="basedata_4_heightmarks-points-relative_points">
+          <heightmarks>
+            <dc:context>
+              <dc:statement>
+                SELECT id          AS prot_id,
+                       description AS prot_description
+                FROM wsts WHERE kind = 4 AND river_id = ${river_id}
+              </dc:statement>
+              <dc:elements>
+                <relativepoint>
+                  <dc:attribute name="name" value="${prot_description}"/>
+                  <dc:context>
+                    <dc:statement>
+                      SELECT id       AS prot_column_id,
+                             name     AS prot_column_name,
+                             position AS prot_rel_pos,
+                             description AS info
+                      FROM wst_columns WHERE wst_id = ${prot_id}
+                      ORDER by position
+                    </dc:statement>
+                    <dc:elements>
+                      <column>
+                        <dc:attribute name="name" value="${prot_column_name}"/>
+                        <dc:attribute name="ids" value="heightmarks_points-wstv-${prot_rel_pos}-${prot_id}"/>
+                        <dc:attribute name="factory" value="staticwkms"/>
+                        <dc:attribute name="info" value="${info}"/>
+                      </column>
+                    </dc:elements>
+                  </dc:context>
+                </relativepoint>
+              </dc:elements>
+            </dc:context>
+          </heightmarks>
+        </dc:macro>
+
         <dc:macro name="basedata_4_heightmarks-points">
           <heightmarks>
             <dc:context>
@@ -212,7 +381,8 @@
                     <dc:statement>
                       SELECT id       AS prot_column_id,
                              name     AS prot_column_name,
-                             position AS prot_rel_pos
+                             position AS prot_rel_pos,
+                             description AS info
                       FROM wst_columns WHERE wst_id = ${prot_id}
                       ORDER by position
                     </dc:statement>
@@ -221,6 +391,7 @@
                         <dc:attribute name="name" value="${prot_column_name}"/>
                         <dc:attribute name="ids" value="heightmarks_points-wstv-${prot_rel_pos}-${prot_id}"/>
                         <dc:attribute name="factory" value="staticwkms"/>
+                        <dc:attribute name="info" value="${info}"/>
                       </column>
                     </dc:elements>
                   </dc:context>
@@ -245,7 +416,8 @@
                     <dc:statement>
                       SELECT id       AS prot_column_id,
                              name     AS prot_column_name,
-                             position AS prot_rel_pos
+                             position AS prot_rel_pos,
+                             description AS info
                       FROM wst_columns WHERE wst_id = ${prot_id}
                       ORDER by position
                     </dc:statement>
@@ -254,6 +426,7 @@
                         <dc:attribute name="name" value="${prot_column_name}"/>
                         <dc:attribute name="ids" value="heightmarks_annotations-wstv-${prot_rel_pos}-${prot_id}"/>
                         <dc:attribute name="factory" value="wqinterpol"/>
+                        <dc:attribute name="info" value="${info}"/>
                       </column>
                     </dc:elements>
                   </dc:context>
@@ -263,8 +436,8 @@
           </heightmarks>
         </dc:macro>
 
-        <dc:macro name="basedata_5_flood-protections">
-          <flood-protections>
+        <dc:macro name="basedata_5_flood-protections_relative_points">
+          <flood_protections>
             <dc:attribute name="id" value="flood-protections-${river_id}"/>
             <dc:context>
               <dc:statement>
@@ -273,7 +446,47 @@
                 FROM wsts WHERE kind = 5 AND river_id = ${river_id}
               </dc:statement>
               <dc:elements>
-                <flood-protection>
+                <relativepoint>
+                  <dc:attribute name="name" value="${prot_description}"/>
+                  <dc:attribute name="db-id" value="${prot_id}"/>
+                  <dc:attribute name="factory" value="staticwkms"/>
+                  <columns>
+                    <dc:context>
+                      <dc:statement>
+                        SELECT id       AS prot_column_id,
+                               name     AS prot_column_name,
+                               position AS prot_rel_pos,
+                               description AS info
+                        FROM wst_columns WHERE wst_id = ${prot_id}
+                        ORDER by position
+                      </dc:statement>
+                      <dc:elements>
+                        <column>
+                          <dc:attribute name="name" value="${prot_column_name}"/>
+                          <dc:attribute name="ids" value="flood_protection-wstv-${prot_rel_pos}-${prot_id}"/>
+                          <dc:attribute name="factory" value="staticwkms"/>
+                          <dc:attribute name="info" value="${info}"/>
+                        </column>
+                      </dc:elements>
+                    </dc:context>
+                  </columns>
+                </relativepoint>
+              </dc:elements>
+            </dc:context>
+          </flood_protections>
+        </dc:macro>
+
+        <dc:macro name="basedata_5_flood-protections">
+          <flood_protections>
+            <dc:attribute name="id" value="flood-protections-${river_id}"/>
+            <dc:context>
+              <dc:statement>
+                SELECT id          AS prot_id,
+                       description AS prot_description
+                FROM wsts WHERE kind = 5 AND river_id = ${river_id}
+              </dc:statement>
+              <dc:elements>
+                <flood_protection>
                   <dc:attribute name="name" value="${prot_description}"/>
                   <dc:attribute name="db-id" value="${prot_id}"/>
                   <dc:attribute name="factory" value="staticwkms"/>
@@ -295,10 +508,10 @@
                       </dc:elements>
                     </dc:context>
                   </columns>
-                </flood-protection>
+                </flood_protection>
               </dc:elements>
             </dc:context>
-          </flood-protections>
+          </flood_protections>
         </dc:macro>
 
         <dc:macro name="mainvalues">
@@ -308,6 +521,13 @@
           </mainvalue>
         </dc:macro>
 
+        <dc:macro name="qsectors">
+          <qsector>
+            <dc:attribute name="factory" value="qsectors"/>
+            <dc:attribute name="ids"     value="${river_id}"/>
+          </qsector>
+        </dc:macro>
+
         <dc:macro name="annotations">
           <annotation>
             <dc:attribute name="factory" value="annotations"/>
@@ -316,7 +536,7 @@
         </dc:macro>
 
         <dc:macro name="cross_sections">
-          <cross-sections>
+          <cross_sections>
             <dc:attribute name="id" value="flood-protections-${river_id}"/>
             <dc:context>
               <dc:statement>
@@ -325,16 +545,35 @@
                 FROM cross_sections WHERE river_id = ${river_id}
               </dc:statement>
               <dc:elements>
-                <cross-section>
+                <cross_section>
                   <dc:attribute name="name" value="${prot_description}"/>
                   <dc:attribute name="ids" value="${prot_id}"/>
                   <dc:attribute name="factory" value="crosssections"/>
-                </cross-section>
+                </cross_section>
               </dc:elements>
             </dc:context>
-          </cross-sections>
+          </cross_sections>
         </dc:macro>
 
+        <dc:macro name="hyks">
+          <hyks>
+            <dc:attribute name="id" value="hyk-${river_id}"/>
+            <dc:context>
+              <dc:statement>
+                SELECT id          AS hyk_id,
+                       description AS hyk_description
+                FROM hyks WHERE river_id = ${river_id}
+              </dc:statement>
+              <dc:elements>
+                <hyk>
+                  <dc:attribute name="name" value="${hyk_description}"/>
+                  <dc:attribute name="ids" value="${hyk_id}"/>
+                  <dc:attribute name="factory" value="hyk"/>
+                </hyk>
+              </dc:elements>
+            </dc:context>
+          </hyks>
+        </dc:macro>
 
         <dc:comment>
 
@@ -348,13 +587,33 @@
           <dc:choose>
             <dc:when test="dc:contains($parameters, 'recommended')">
                <dc:comment>
-                  Recommendations.
+                  Recommendations (client shall load immediately).
                </dc:comment>
                <dc:if test="dc:contains($artifact-outs, 'w_differences') or (dc:contains($artifact-outs, 'discharge_longitudinal_section'))">
-                  <dc:call-macro name="annotations"/>
+                 <dc:call-macro name="annotations"/>
                </dc:if>
                <dc:if test="dc:contains($artifact-outs, 'cross_section')">
                  <dc:call-macro name="cross_sections"/>
+                 <dc:call-macro name="hyks"/>
+               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'reference_curve')">
+                 <dc:call-macro name="annotations"/>
+                 <dc:call-macro name="mainvalues"/>
+               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'fix_wq_curve')">
+                 <dc:call-macro name="qsectors"/>
+               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'fix_longitudinal_section_curve')">
+                 <dc:call-macro name="annotations"/>
+               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'bed_difference_epoch')">
+                 <dc:call-macro name="annotations"/>
+               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'bed_difference_year')">
+                 <dc:call-macro name="annotations"/>
+               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'bed_difference_height_year')">
+                 <dc:call-macro name="annotations"/>
                </dc:if>
             </dc:when>
             <dc:otherwise>
@@ -362,17 +621,26 @@
                  Non - Recommendations.
               </dc:comment>
               <dc:if test="dc:contains($artifact-outs, 'cross_section')">
-                  <dc:call-macro name="basedata_0"/>
-                  <dc:call-macro name="basedata_1_additionals"/>
+                 <dc:call-macro name="basedata_0"/>
+                 <dc:call-macro name="basedata_1_additionals"/>
+                 <dc:call-macro name="basedata_2_fixations"/>
+                 <dc:call-macro name="basedata_3_officials"/>
+                 <dc:call-macro name="basedata_4_heightmarks-points"/>
+                 <dc:call-macro name="cross_sections"/>
+                 <dc:call-macro name="hyks"/>
               </dc:if>
               <dc:if test="dc:contains($artifact-outs, 'discharge_longitudinal_section')">
                  <dc:call-macro name="basedata_0"/>
+                 <dc:call-macro name="basedata_1_additionals"/>
+                 <dc:call-macro name="basedata_2_fixations"/>
+                 <dc:call-macro name="basedata_3_officials"/>
                  <dc:call-macro name="basedata_4_heightmarks-points"/>
+                 <dc:call-macro name="basedata_5_flood-protections"/>
               </dc:if>
-              <dc:if test="dc:contains($artifact-outs, 'computed_discharge_curve')">
+              <!--dc:if test="dc:contains($artifact-outs, 'computed_discharge_curve')">
                  <dc:call-macro name="basedata_0_wq"/>
                  <dc:call-macro name="basedata_4_heightmarks-wq"/>
-              </dc:if>
+              </dc:if-->
               <dc:if test="dc:contains($artifact-outs, 'longitudinal_section') or (dc:contains($artifact-outs, 'w_differences'))">
                  <dc:call-macro name="basedata_0"/>
                  <dc:call-macro name="basedata_1_additionals"/>
@@ -380,7 +648,32 @@
                  <dc:call-macro name="basedata_2_fixations"/>
                  <dc:comment comment=" HOEHENMARKEN ---------------------------"/>
                  <dc:call-macro name="basedata_4_heightmarks-points"/>
+                 <dc:comment comment=" AMTL LINIEN  ---------------------------"/>
+                 <dc:call-macro name="basedata_3_officials"/>
               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'reference_curve')">
+                 <dc:call-macro name="annotations"/>
+                 <!--dc:call-macro name="basedata_0"/-->
+                 <dc:call-macro name="basedata_1_additionals-relative_point"/>
+                 <dc:comment comment=" FIXATIONS ---------------------------"/>
+                 <dc:call-macro name="basedata_2_fixations_relative_point"/>
+                 <dc:comment comment=" HOEHENMARKEN ---------------------------"/>
+                 <dc:call-macro name="basedata_4_heightmarks-points-relative_points"/>
+                 <dc:call-macro name="basedata_5_flood-protections_relative_points"/>
+               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'fix_wq_curve')">
+                 <dc:call-macro name="basedata_0_wq"/>
+                 <dc:call-macro name="basedata_1_additionals"/>
+                 <dc:call-macro name="basedata_2_fixations"/>
+                 <dc:call-macro name="basedata_3_officials"/>
+                 <dc:call-macro name="basedata_4_heightmarks-points"/>
+                 <dc:call-macro name="basedata_5_flood-protections_relative_points"/>
+               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'fix_deltawt_curve')">
+               </dc:if>
+               <dc:if test="dc:contains($artifact-outs, 'fix_longitudinal_section_curve')">
+                 <dc:call-macro name="annotations"/>
+               </dc:if>
              <dc:comment comment="--- non-recommendations---"/>
             </dc:otherwise>
           </dc:choose>
@@ -409,8 +702,8 @@
           </dc:if>
 
           <dc:if test="dc:contains($artifact-outs, 'computed_discharge_curve') and not (dc:contains($parameters, 'recommended'))">
-              <discharge-table-nn>
-                <discharge-table-gauge>
+              <discharge_table_nn>
+                <discharge_table_gauge>
                   <dc:context>
                     <dc:statement>
                       SELECT id   AS gauge_id,
@@ -421,30 +714,42 @@
                       <gauge>
                         <dc:attribute name="name" value="${gauge_name}"/>
                         <dc:attribute name="db-id" value="${gauge_id}"/>
+                        <dc:attribute name="factory" value="gaugedischarge"/>
+                        <dc:attribute name="from" value="${g_start}"/>
+                        <dc:attribute name="to" value="${g_stop}"/>
+                        <dc:attribute name="ids" value="${gauge_name}"/>
+                      </gauge>
+                      <!--
+                      <gauge>
+                        <dc:attribute name="name" value="${gauge_name}"/>
+                        <dc:attribute name="db-id" value="${gauge_id}"/>
                         <dc:context>
                           <dc:statement>
-                            SELECT description   AS gauge_desc, 
+                            SELECT description   AS gauge_desc,
                                    d.id          AS discharge_id,
-                                   ti.start_time AS g_start, 
+                                   ti.start_time AS g_start,
                                    ti.stop_time  AS g_stop
-                            FROM discharge_tables d JOIN time_intervals ti 
+                            FROM discharge_tables d JOIN time_intervals ti
                             ON d.time_interval_id = ti.id
                             WHERE d.gauge_id = ${gauge_id} AND d.kind = 1
                           </dc:statement>
                           <dc:elements>
                             <historical>
                               <dc:attribute name="name" value="${gauge_desc}"/>
+                              <dc:attribute name="factory" value="gaugedischarge"/>
                               <dc:attribute name="from" value="${g_start}"/>
                               <dc:attribute name="to" value="${g_stop}"/>
-                              <dc:attribute name="db-id" value="${discharge_id}"/></historical>
+                              <dc:attribute name="ids" value="${discharge_id}-${g_start}-${g_stop}"/>
+                            </historical>
                           </dc:elements>
                         </dc:context>
                       </gauge>
+                      -->
                     </dc:elements>
                   </dc:context>
-                </discharge-table-gauge>
+                </discharge_table_gauge>
 
-              </discharge-table-nn>
+              </discharge_table_nn>
 
             <dc:call-macro name="basedata_2_fixations_wst"/>
 
@@ -457,23 +762,66 @@
 
             <!-- former flood-water-marks -->
             <dc:call-macro name="basedata_4_heightmarks-points"/>
-          </dc:if>
-          <dc:if test="dc:contains($artifact-outs, 'computed_discharge_curve')"><!-- or (dc:contains($artifact-outs, 'discharge_curve'))"-->
-              <!-- && parameter contains recommended/ation -->
-              <computed-discharge-curve>
+              <computed_discharge_curve>
                 <dc:call-macro name="mainvalues"/>
-              </computed-discharge-curve>
-              <dc:call-macro name="basedata_2_fixations_wst"/>
+              </computed_discharge_curve>
           </dc:if>
 
           <dc:if test="dc:contains($artifact-outs, 'duration_curve')">
-            <dc:call-macro name="mainvalues"/>
+            <dc:choose>
+                <dc:when test="dc:contains($parameters, 'recommended')">
+                  <dc:call-macro name="mainvalues"/>
+                </dc:when>
+                <dc:otherwise>
+                  <dc:call-macro name="mainvalues"/>
+                  <dc:call-macro name="basedata_2_fixations_relative_point"/>
+                  <dc:call-macro name="basedata_4_heightmarks-points-relative_points"/>
+                  <dc:call-macro name="basedata_5_flood-protections_relative_points"/>
+                </dc:otherwise>
+            </dc:choose>
           </dc:if>
 
-          <dc:if test="dc:contains($artifact-outs, 'longitudinal_section')">
-              <longitudinal-section>
-                <dc:call-macro name="annotations"/>
-              </longitudinal-section>
+          <dc:if test="dc:contains($artifact-outs, 'fix_wq_curve') and not (dc:contains($parameters, 'recommended'))">
+              <discharge_table_nn>
+                <discharge_table_gauge>
+                  <dc:context>
+                    <dc:statement>
+                      SELECT id   AS gauge_id,
+                             name AS gauge_name
+                      FROM gauges WHERE river_id = ${river_id}
+                    </dc:statement>
+                    <dc:elements>
+                      <gauge>
+                        <dc:attribute name="name" value="${gauge_name}"/>
+                        <dc:attribute name="db-id" value="${gauge_id}"/>
+                        <dc:attribute name="factory" value="gaugedischarge"/>
+                        <dc:attribute name="from" value="${g_start}"/>
+                        <dc:attribute name="to" value="${g_stop}"/>
+                        <dc:attribute name="ids" value="${gauge_name}"/>
+                      </gauge>
+                    </dc:elements>
+                  </dc:context>
+                </discharge_table_gauge>
+              </discharge_table_nn>
+          </dc:if>
+
+          <dc:if test="dc:contains($artifact-outs, 'longitudinal_section')">
+
+              <longitudinal_section>
+                <dc:call-macro name="annotations"/>
+              </longitudinal_section>
+          </dc:if>
+
+          <dc:if test="dc:contains($artifact-outs, 'map')">
+              <map>
+              <dc:choose>
+                  <dc:when test="dc:contains($parameters, 'recommended')">
+                  </dc:when>
+                  <dc:otherwise>
+                      <dc:call-macro name="flood-map-complete"/>
+                  </dc:otherwise>
+              </dc:choose>
+              </map>
           </dc:if>
           <dc:if test="dc:contains($artifact-outs, 'floodmap')">
               <floodmap>
@@ -512,14 +860,17 @@
                     <dc:statement>
                       SELECT id    AS dem_id,
                              lower AS dem_lower,
-                             upper AS dem_upper
+                             upper AS dem_upper,
+                             name AS name,
+                             projection || ' | ' || year_from || ' - ' || year_to AS info
                       FROM dem WHERE river_id = ${river_id}
                     </dc:statement>
                     <dc:elements>
                         <dem>
                           <dc:attribute name="factory" value="demfactory"/>
                           <dc:attribute name="ids" value="${dem_id}"/>
-                          <dc:attribute name="description" value="${dem_lower}-${dem_upper}"/>
+                          <dc:attribute name="name" value="${name}"/>
+                          <dc:attribute name="info" value="${info}"/>
                         </dem>
                     </dc:elements>
                   </dc:context>
@@ -560,31 +911,113 @@
               <dc:macro name="flood-map-hws">
                 <dc:context>
                   <dc:statement>
-                    SELECT count(*) as km_exists
-                    FROM hws WHERE river_id = ${river_id}
+                    SELECT count(*) as km_exists, name as name
+                    FROM hws WHERE river_id = ${river_id} GROUP BY name
                   </dc:statement>
                    <dc:elements>
                     <dc:if test="$km_exists>0">
                       <hws>
                         <dc:attribute name="factory" value="wmshwsfactory"/>
-                        <dc:attribute name="ids" value="${river_id}"/>
+                        <dc:attribute name="ids" value="${river_id};${name}"/>
+                        <dc:attribute name="name" value="${name}"/>
                       </hws>
                     </dc:if>
                   </dc:elements>
                 </dc:context>
               </dc:macro>
+              <dc:macro name="flood-map-hydr-boundaries">
+                <hydr_boundaries_lines>
+                  <dc:call-macro name="flood-map-hydr-boundaries-lines"/>
+                </hydr_boundaries_lines>
+                <hydr_boundaries_polygons>
+                  <dc:call-macro name="flood-map-hydr-boundaries-poly"/>
+                </hydr_boundaries_polygons>
+              </dc:macro>
+              <dc:macro name="flood-map-hydr-boundaries-lines">
+                <bfg>
+                  <dc:context>
+                    <dc:statement>
+                      SELECT count(*) as km_exists, name as name
+                      FROM hydr_boundaries WHERE river_id = ${river_id} AND kind = 1 GROUP BY name
+                    </dc:statement>
+                     <dc:elements>
+                      <dc:if test="$km_exists>0">
+                        <hydrboundary>
+                          <dc:attribute name="factory" value="wmshydrboundariesfactory"/>
+                          <dc:attribute name="ids" value="${river_id};${name}"/>
+                          <dc:attribute name="name" value="${name}"/>
+                        </hydrboundary>
+                      </dc:if>
+                    </dc:elements>
+                  </dc:context>
+                </bfg>
+                <land>
+                  <dc:context>
+                    <dc:statement>
+                      SELECT count(*) as km_exists, name as name
+                      FROM hydr_boundaries WHERE river_id = ${river_id} AND kind = 2 GROUP BY name
+                    </dc:statement>
+                     <dc:elements>
+                      <dc:if test="$km_exists>0">
+                        <hydrboundary>
+                          <dc:attribute name="factory" value="wmshydrboundariesfactory"/>
+                          <dc:attribute name="ids" value="${river_id};${name}"/>
+                          <dc:attribute name="name" value="${name}"/>
+                        </hydrboundary>
+                      </dc:if>
+                    </dc:elements>
+                  </dc:context>
+                </land>
+              </dc:macro>
+              <dc:macro name="flood-map-hydr-boundaries-poly">
+                <bfg>
+                  <dc:context>
+                    <dc:statement>
+                      SELECT count(*) as km_exists, name as name
+                      FROM hydr_boundaries_poly WHERE river_id = ${river_id} AND kind = 1 GROUP BY name
+                    </dc:statement>
+                     <dc:elements>
+                      <dc:if test="$km_exists>0">
+                        <hws>
+                          <dc:attribute name="factory" value="wmshydrboundariespolyfactory"/>
+                          <dc:attribute name="ids" value="${river_id};${name}"/>
+                          <dc:attribute name="name" value="${name}"/>
+                        </hws>
+                      </dc:if>
+                    </dc:elements>
+                  </dc:context>
+                </bfg>
+                <land>
+                  <dc:context>
+                    <dc:statement>
+                      SELECT count(*) as km_exists, name as name
+                      FROM hydr_boundaries_poly WHERE river_id = ${river_id} AND kind = 2 GROUP BY name
+                    </dc:statement>
+                     <dc:elements>
+                      <dc:if test="$km_exists>0">
+                        <hws>
+                          <dc:attribute name="factory" value="wmshydrboundariespolyfactory"/>
+                          <dc:attribute name="ids" value="${river_id};${name}"/>
+                          <dc:attribute name="name" value="${name}"/>
+                        </hws>
+                      </dc:if>
+                    </dc:elements>
+                  </dc:context>
+                </land>
+              </dc:macro>
               <dc:macro name="flood-map-catchments">
                 <dc:context>
                   <dc:statement>
-                    SELECT count(*) as km_exists
-                    FROM catchment WHERE river_id = ${river_id}
+                    SELECT count(*) as km_exists, name as name
+                    FROM catchment WHERE river_id = ${river_id} GROUP BY name
                   </dc:statement>
                    <dc:elements>
                     <dc:if test="$km_exists>0">
-                      <catchments>
+                      <catchment>
                         <dc:attribute name="factory" value="wmscatchmentfactory"/>
-                        <dc:attribute name="ids" value="${river_id}"/>
-                      </catchments>
+                        <dc:attribute name="ids" value="${river_id};${name}"/>
+                        <dc:attribute name="name" value="${name}"/>
+                      </catchment>
                     </dc:if>
                   </dc:elements>
                 </dc:context>
@@ -608,15 +1041,16 @@
               <dc:macro name="flood-map-lines">
                 <dc:context>
                   <dc:statement>
-                    SELECT count(*) as km_exists
-                    FROM lines WHERE river_id = ${river_id}
+                    SELECT count(*) as km_exists, name as name
+                    FROM lines WHERE river_id = ${river_id} GROUP BY name
                   </dc:statement>
                    <dc:elements>
                     <dc:if test="$km_exists>0">
-                      <lines>
+                      <line>
                         <dc:attribute name="factory" value="wmslinefactory"/>
-                        <dc:attribute name="ids" value="${river_id}"/>
-                      </lines>
+                        <dc:attribute name="ids" value="${river_id};${name}"/>
+                        <dc:attribute name="name" value="${name}"/>
+                      </line>
                     </dc:if>
                   </dc:elements>
                 </dc:context>
@@ -624,15 +1058,16 @@
               <dc:macro name="flood-map-buildings">
                 <dc:context>
                   <dc:statement>
-                    SELECT count(*) as km_exists
-                    FROM buildings WHERE river_id = ${river_id}
+                    SELECT count(*) as km_exists, name as name
+                    FROM buildings WHERE river_id = ${river_id} GROUP BY name
                   </dc:statement>
                    <dc:elements>
                     <dc:if test="$km_exists>0">
-                      <buildings>
+                      <building>
                         <dc:attribute name="factory" value="wmsbuildingsfactory"/>
-                        <dc:attribute name="ids" value="${river_id}"/>
-                      </buildings>
+                        <dc:attribute name="ids" value="${river_id};${name}"/>
+                        <dc:attribute name="name" value="${name}"/>
+                      </building>
                     </dc:if>
                   </dc:elements>
                 </dc:context>
@@ -640,20 +1075,140 @@
               <dc:macro name="flood-map-fixpoints">
                 <dc:context>
                   <dc:statement>
-                    SELECT count(*) as km_exists
-                    FROM fixpoints WHERE river_id = ${river_id}
+                    SELECT count(*) as km_exists, name as name
+                    FROM fixpoints WHERE river_id = ${river_id} GROUP BY name
                   </dc:statement>
                    <dc:elements>
                     <dc:if test="$km_exists>0">
-                      <fixpoints>
+                      <fixpoint>
                         <dc:attribute name="factory" value="wmsfixpointsfactory"/>
-                        <dc:attribute name="ids" value="${river_id}"/>
-                      </fixpoints>
+                        <dc:attribute name="ids" value="${river_id};${name}"/>
+                        <dc:attribute name="name"  value="${name}"/>
+                      </fixpoint>
                     </dc:if>
                   </dc:elements>
                 </dc:context>
               </dc:macro>
+              <dc:macro name="flood-map-gaugelocations">
+                <dc:context>
+                  <dc:statement>
+                    SELECT count(*) as km_exists, name as name
+                    FROM gauge_location WHERE river_id = ${river_id} GROUP BY name
+                  </dc:statement>
+                   <dc:elements>
+                    <dc:if test="$km_exists>0">
+                      <gaugelocation>
+                        <dc:attribute name="factory" value="wmsgaugelocationfactory"/>
+                        <dc:attribute name="ids" value="${river_id};${name}"/>
+                        <dc:attribute name="name"  value="${name}"/>
+                      </gaugelocation>
+                    </dc:if>
+                  </dc:elements>
+                </dc:context>
+              </dc:macro>
+              <dc:macro name="flood-map-uesk">
+                <uesk>
+                  <calculations>
+                    <current>
+                      <bfg>
+                        <dc:context>
+                          <dc:statement>
+                              SELECT count(*) as uesg_exist, name as name
+                              FROM floodmaps
+                              WHERE river_id = ${river_id} AND kind = 111
+                              GROUP BY name, kind
+                          </dc:statement>
+                          <dc:elements>
+                            <dc:if test="$uesg_exist>0">
+                              <floodmaps>
+                                <dc:attribute name="factory" value="wmsfloodmapsfactory"/>
+                                <dc:attribute name="ids" value="${river_id};${name}"/>
+                                <dc:attribute name="name" value="${name}"/>
+                              </floodmaps>
+                            </dc:if>
+                          </dc:elements>
+                        </dc:context>
+                      </bfg>
+                      <land>
+                        <dc:context>
+                          <dc:statement>
+                              SELECT count(*) as uesg_exist, name as name
+                              FROM floodmaps
+                              WHERE river_id = ${river_id} AND kind = 112
+                              GROUP BY name, kind
+                          </dc:statement>
+                          <dc:elements>
+                            <dc:if test="$uesg_exist>0">
+                              <floodmaps>
+                                <dc:attribute name="factory" value="wmsfloodmapsfactory"/>
+                                <dc:attribute name="ids" value="${river_id};${name}"/>
+                                <dc:attribute name="name" value="${name}"/>
+                              </floodmaps>
+                            </dc:if>
+                          </dc:elements>
+                        </dc:context>
+                      </land>
+                    </current>
+                    <potentiel>
+                      <bfg>
+                        <dc:context>
+                          <dc:statement>
+                              SELECT count(*) as uesg_exist, name as name
+                              FROM floodmaps
+                              WHERE river_id = ${river_id} AND kind = 121
+                              GROUP BY name, kind
+                          </dc:statement>
+                          <dc:elements>
+                            <dc:if test="$uesg_exist>0">
+                              <floodmaps>
+                                <dc:attribute name="factory" value="wmsfloodmapsfactory"/>
+                                <dc:attribute name="ids" value="${river_id};${name}"/>
+                                <dc:attribute name="name" value="${name}"/>
+                              </floodmaps>
+                            </dc:if>
+                          </dc:elements>
+                        </dc:context>
+                      </bfg>
+                      <land>
+                        <dc:context>
+                          <dc:statement>
+                              SELECT count(*) as uesg_exist, name as name
+                              FROM floodmaps
+                              WHERE river_id = ${river_id} AND kind = 122
+                              GROUP BY name, kind
+                          </dc:statement>
+                          <dc:elements>
+                            <dc:if test="$uesg_exist>0">
+                              <floodmaps>
+                                <dc:attribute name="factory" value="wmsfloodmapsfactory"/>
+                                <dc:attribute name="ids" value="${river_id};${name}"/>
+                                <dc:attribute name="name" value="${name}"/>
+                              </floodmaps>
+                            </dc:if>
+                          </dc:elements>
+                        </dc:context>
+                      </land>
+                    </potentiel>
+                  </calculations>
+                </uesk>
+              </dc:macro>
               <dc:macro name="flood-map-complete">
+                  <buildings>
+                    <dc:call-macro name="flood-map-buildings"/>
+                  </buildings>
+                  <catchments>
+                    <dc:call-macro name="flood-map-catchments"/>
+                  </catchments>
+                  <fixpoints>
+                    <dc:call-macro name="flood-map-fixpoints"/>
+                  </fixpoints>
+                  <hws>
+                    <dc:call-macro name="flood-map-hws"/>
+                  </hws>
+                  <hydrboundaries>
+                    <dc:call-macro name="flood-map-hydr-boundaries"/>
+                    <dc:call-macro name="flood-map-floodplain"/>
+                  </hydrboundaries>
                   <kilometrage>
                       <riveraxis>
                           <dc:attribute name="factory" value="riveraxis"/>
@@ -661,13 +1216,14 @@
                       </riveraxis>
                     <dc:call-macro name="flood-map-km"/>
                     <dc:call-macro name="flood-map-qps"/>
-                    <dc:call-macro name="flood-map-hws"/>
-                    <dc:call-macro name="flood-map-catchments"/>
-                    <dc:call-macro name="flood-map-floodplain"/>
+                  </kilometrage>
+                  <lines>
                     <dc:call-macro name="flood-map-lines"/>
-                    <dc:call-macro name="flood-map-buildings"/>
-                    <dc:call-macro name="flood-map-fixpoints"/>
-                  </kilometrage>
+                  </lines>
+                  <dc:call-macro name="flood-map-uesk"/>
+                  <gaugelocations>
+                    <dc:call-macro name="flood-map-gaugelocations"/>
+                  </gaugelocations>
                   <rastermap>
                       <background>
                           <dc:attribute name="factory" value="wmsbackground"/>
@@ -676,6 +1232,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>
@@ -701,6 +1309,40 @@
             ORDER BY c.creation DESC
         </dc:statement>
 
+        <!-- OFFICIAL LINES -->
+        <dc:if test="dc:contains($artifact-outs, 'longitudinal_section')">
+          <dc:comment comment=".wst -------------------------------"/>
+          <officiallines>
+            <dc:elements>
+                <dc:context>
+                  <dc:statement>
+                    SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation, ardg.v as gaugy, arv.v as wqsingle
+                    FROM   master_artifacts m, artifact_data ardg, artifact_data arv
+                    WHERE  m.collection_id = ${collection_id} AND m.gid = CAST(${artifact-id} AS uuid) AND ardg.artifact_id = m.id AND ardg.k = 'ld_gaugename' AND arv.artifact_id = m.id AND arv.k = 'wq_single'
+                    AND EXISTS (
+                        SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river})
+                  </dc:statement>
+                  <dc:elements>
+                      <dc:context connection="system">
+                        <dc:statement>
+                          SELECT ol.wst_id AS wstid, ol.wst_column_pos AS wstcolpos, ol.name AS olname, ol.value AS oval
+                          FROM official_q_values ol
+                          WHERE ol.value = CAST(${wqsingle} AS NUMERIC(10,2)) AND ol.gauge_name = ${gaugy}
+                        </dc:statement>
+                        <dc:elements>
+                          <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:element>
+                        </dc:elements>
+                      </dc:context>
+                  </dc:elements>
+                </dc:context>
+          </dc:elements>
+          </officiallines>
+        </dc:if>
+        <!-- END OFFICIAL LINES -->
 
         <dc:comment>
           SHOW W-DIFFERENCES
@@ -740,6 +1382,48 @@
           </differences>
         </dc:if>
 
+        <dc:comment>
+          SHOW REFERENCE CURVE
+        </dc:comment>
+
+        <dc:if test="dc:contains($artifact-outs, 'reference_curve')">
+          <reference_curves>
+            <dc:elements>
+                <dc:context>
+                  <dc:statement>
+                    SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation
+                    FROM   master_artifacts m
+                    WHERE  m.collection_id = ${collection_id} AND m.gid &lt;&gt; CAST(${artifact-id} AS uuid)
+                    AND EXISTS (
+                        SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river})
+                  </dc:statement>
+                  <dc:elements>
+                      <dc:context>
+                        <dc:statement>
+                          SELECT a.gid as aid, f.id AS fid, f.name AS facet_name, f.num AS facet_num, f.description as facet_description
+                          FROM outs as o, facets as f, artifacts as a
+                          WHERE f.name = 'reference_curve' and f.out_id = o.id and o.artifact_id = ${a_id} and a.id = ${a_id}
+                        </dc:statement>
+                        <dc:elements>
+                          <dc:element name="${facet_name}">
+                            <dc:attribute name="description" value="${facet_description}"/>
+                            <dc:attribute name="factory"     value="winfo"/>
+                            <dc:attribute name="artifact-id" value="${aid}"/>
+                            <dc:attribute name="ids"         value="${aid}"/>
+                            <dc:attribute name="out"         value="reference_curve"/>
+                          </dc:element>
+                        </dc:elements>
+                      </dc:context>
+                  </dc:elements>
+                </dc:context>
+            </dc:elements>
+          </reference_curves>
+        </dc:if>
+
+        <dc:comment>
+          SHOW COMPUTED DISCHARGE CURVES
+        </dc:comment>
+
         <dc:if test="dc:contains($artifact-outs, 'computed_discharge_curve')">
           <computed_discharge_curves>
             <dc:elements>
@@ -774,6 +1458,57 @@
           </computed_discharge_curves>
         </dc:if>
 
+        <dc:comment>
+          CROSS SECTION
+        </dc:comment>
+
+        <dc:if test="dc:contains($artifact-outs, 'cross_section')">
+          <waterlevels>
+            <dc:elements>
+              <dc:context>
+                 <dc:statement>
+                   SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation
+                   FROM   master_artifacts m
+                   WHERE  m.collection_id = ${collection_id} AND m.gid &lt;&gt; CAST(${artifact-id} AS uuid)
+                   AND EXISTS (
+                       SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river})
+                 </dc:statement>
+                 <dc:elements>
+                   <dc:context>
+                     <dc:statement>
+                       SELECT id AS out_id
+                       FROM outs
+                       WHERE artifact_id = ${a_id} AND name = 'cross_section'
+                     </dc:statement>
+                     <dc:elements>
+                       <dc:context>
+                         <dc:statement>
+                           SELECT name AS facet_name, num as facet_num, description AS facet_description
+                           FROM facets
+                           WHERE out_id = ${out_id}
+                           ORDER BY num ASC, name DESC
+                         </dc:statement>
+                         <longitudinal_section_columns>
+                             <dc:attribute name="description" value="${river} ${a_creation}"/>
+                             <dc:elements>
+                               <dc:element name="${facet_name}">
+                                 <dc:attribute name="description" value="${facet_description}"/>
+                                 <dc:attribute name="ids" value="${facet_num}"/>
+                                 <dc:attribute name="factory" value="winfo"/>
+                                 <dc:attribute name="artifact-id" value="${a_gid}"/>
+                                 <dc:attribute name="out" value="cross_section"/>
+                               </dc:element>
+                             </dc:elements>
+                         </longitudinal_section_columns>
+                       </dc:context>
+                     </dc:elements>
+                   </dc:context>
+                 </dc:elements>
+               </dc:context>
+             </dc:elements>
+          </waterlevels>
+        </dc:if>
+
 
         <dc:if test="dc:contains($artifact-outs, 'longitudinal_section') or (dc:contains($artifact-outs, 'discharge_longitudinal_section') or (dc:contains($artifact-outs, 'w_differences')))">
           <waterlevels>
@@ -822,11 +1557,238 @@
           </waterlevels>
         </dc:if>
 
+        <dc:if test="dc:contains($artifact-outs, 'fix_longitudinal_section_curve')">
+          <waterlevels>
+            <dc:elements>
+              <dc:context>
+                 <dc:statement>
+                   SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation
+                   FROM   master_artifacts m
+                   WHERE  m.collection_id = ${collection_id} AND m.gid &lt;&gt; CAST(${artifact-id} AS uuid)
+                   AND EXISTS (
+                       SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river})
+                 </dc:statement>
+                 <dc:elements>
+
+                   <dc:context>
+                   <dc:statement>
+                     SELECT id AS out_id
+                     FROM outs
+                     WHERE artifact_id = ${a_id} AND name = 'fix_longitudinal_section_curve'
+                   </dc:statement>
+                   <dc:elements>
+                     <dc:context>
+                     <!-- average und deviation ls_0 . ls_1 ...-->
+                       <dc:statement>
+                         SELECT name AS facet_name, num as facet_num, description AS facet_description
+                         FROM facets
+                         WHERE out_id = ${out_id} AND ( name LIKE 'fix_deviation_ls%' OR name LIKE 'fix_sector_average_ls%' OR name LIKE 'fix_analysis_events_ls%' OR name LIKE 'fix_reference_events_ls%' )
+                         ORDER BY num ASC, name DESC
+                       </dc:statement>
+                       <waterlevels>
+                         <dc:attribute name="description" value="${river} ${a_creation} ${collection_name}"/>
+                         <dc:elements>
+                           <dc:element name="${facet_name}">
+                             <dc:attribute name="description" value="${facet_description}"/>
+                             <dc:attribute name="ids"         value="${facet_num}"/>
+                             <dc:attribute name="factory"     value="fixanalysis"/>
+                             <dc:attribute name="artifact-id" value="${a_gid}"/>
+                             <dc:attribute name="out"         value="fix_longitudinal_section_curve"/>
+                           </dc:element>
+                         </dc:elements>
+                       </waterlevels>
+                     </dc:context>
+                   </dc:elements>
+                  </dc:context>
+                 </dc:elements>
+                </dc:context>
+             </dc:elements>
+          </waterlevels>
+        </dc:if>
+
+        <dc:if test="dc:contains($artifact-outs, 'fix_deltawt_curve')">
+          <waterlevels>
+            <dc:elements>
+              <dc:context>
+                 <dc:statement>
+                   SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation
+                   FROM   master_artifacts m
+                   WHERE  m.collection_id = ${collection_id} AND m.gid &lt;&gt; CAST(${artifact-id} AS uuid)
+                   AND EXISTS (
+                       SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river})
+                 </dc:statement>
+                 <dc:elements>
+
+                   <dc:context>
+                   <dc:statement>
+                     SELECT id AS out_id
+                     FROM outs
+                     WHERE artifact_id = ${a_id} AND name = 'fix_deltawt_curve'
+                   </dc:statement>
+                   <dc:elements>
+                     <dc:context>
+                       <dc:statement>
+                         SELECT name AS facet_name, num as facet_num, description AS facet_description
+                         FROM facets
+                         WHERE out_id = ${out_id} and ( name LIKE 'fix_sector_average_dwt%' OR name LIKE 'fix_deviation_dwt%' OR name = 'fix_analysis_events_dwt' OR name = 'fix_reference_events_dwt' OR name = 'fix_analysis_periods_dwt' )
+                         ORDER BY num ASC, name DESC
+                       </dc:statement>
+                       <waterlevels>
+                         <dc:attribute name="description" value="${river} ${a_creation} ${collection_name}"/>
+                         <dc:elements>
+                           <dc:element name="${facet_name}">
+                             <dc:attribute name="description" value="${facet_description}"/>
+                             <dc:attribute name="ids"         value="${facet_num}"/>
+                             <dc:attribute name="factory"     value="fixanalysis"/>
+                             <dc:attribute name="artifact-id" value="${a_gid}"/>
+                             <dc:attribute name="out"         value="fix_deltawt_curve"/>
+                           </dc:element>
+                         </dc:elements>
+                       </waterlevels>
+                     </dc:context>
+                   </dc:elements>
+                  </dc:context>
+                 </dc:elements>
+                </dc:context>
+             </dc:elements>
+          </waterlevels>
+        </dc:if>
+
+        <dc:if test="dc:contains($artifact-outs, 'fix_derivate_curve')">
+          <waterlevels>
+            <dc:elements>
+              <dc:context>
+                 <dc:statement>
+                   SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation
+                   FROM   master_artifacts m
+                   WHERE  m.collection_id = ${collection_id} AND m.gid &lt;&gt; CAST(${artifact-id} AS uuid)
+                   AND EXISTS (
+                       SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river})
+                 </dc:statement>
+                 <dc:elements>
+
+                   <dc:context>
+                   <dc:statement>
+                     SELECT id AS out_id
+                     FROM outs
+                     WHERE artifact_id = ${a_id} AND name = 'fix_derivate_curve'
+                   </dc:statement>
+                   <dc:elements>
+                     <dc:context>
+                       <dc:statement>
+                         SELECT name AS facet_name, num as facet_num, description AS facet_description
+                         FROM facets
+                         WHERE out_id = ${out_id} and name = 'fix_derivate'
+                         ORDER BY num ASC, name DESC
+                       </dc:statement>
+                       <waterlevels>
+                         <dc:attribute name="description" value="${river} ${a_creation} ${collection_name}"/>
+                         <dc:elements>
+                           <dc:element name="${facet_name}">
+                             <dc:attribute name="description" value="${facet_description}"/>
+                             <dc:attribute name="ids"         value="${facet_num}"/>
+                             <dc:attribute name="factory"     value="fixanalysis"/>
+                             <dc:attribute name="artifact-id" value="${a_gid}"/>
+                             <dc:attribute name="out"         value="fix_derivate_curve"/>
+                           </dc:element>
+                         </dc:elements>
+                       </waterlevels>
+                     </dc:context>
+                   </dc:elements>
+                  </dc:context>
+                 </dc:elements>
+                </dc:context>
+             </dc:elements>
+          </waterlevels>
+        </dc:if>
+
+        <dc:if test="dc:contains($artifact-outs, 'fix_wq_curve')">
+          <waterlevels>
+            <dc:elements>
+              <dc:context>
+                 <dc:statement>
+                   SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation
+                   FROM   master_artifacts m
+                   WHERE  m.collection_id = ${collection_id} AND m.gid &lt;&gt; CAST(${artifact-id} AS uuid)
+                   AND EXISTS (
+                       SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river})
+                 </dc:statement>
+                 <dc:elements>
+
+                   <dc:context>
+                   <dc:statement>
+                     SELECT id AS out_id
+                     FROM outs
+                     WHERE artifact_id = ${a_id} AND name = 'fix_wq_curve'
+                   </dc:statement>
+                   <dc:elements>
+                     <dc:context>
+                       <dc:statement>
+                         SELECT name AS facet_name, num as facet_num, description AS facet_description
+                         FROM facets
+                         WHERE out_id = ${out_id} and ( name LIKE 'fix_sector_average_wq%' OR name = 'fix_wq_curve' OR name LIKE 'fix_analysis_events_wq%' OR name LIKE 'fix_reference_events_wq%' )
+                         ORDER BY num ASC, name DESC
+                       </dc:statement>
+                       <waterlevels>
+                         <dc:attribute name="description" value="${river} ${a_creation} ${collection_name}"/>
+                         <dc:elements>
+                           <dc:element name="${facet_name}">
+                             <dc:attribute name="description" value="${facet_description}"/>
+                             <dc:attribute name="ids"         value="${facet_num}"/>
+                             <dc:attribute name="factory"     value="fixanalysis"/>
+                             <dc:attribute name="artifact-id" value="${a_gid}"/>
+                             <dc:attribute name="out"         value="fix_wq_curve"/>
+                           </dc:element>
+                         </dc:elements>
+                       </waterlevels>
+                     </dc:context>
+                   </dc:elements>
+                  </dc:context>
+                 </dc:elements>
+                </dc:context>
+             </dc:elements>
+          </waterlevels>
+        </dc:if>
+
+        <dc:if test="dc:contains($artifact-outs, 'duration_curve')">
+          <computed_discharge_curves>
+            <dc:elements>
+                <dc:context>
+                  <dc:statement>
+                    SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation
+                    FROM   master_artifacts m
+                    WHERE  m.collection_id = ${collection_id} AND m.gid &lt;&gt; CAST(${artifact-id} AS uuid)
+                    AND EXISTS (
+                        SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river})
+                  </dc:statement>
+                  <dc:elements>
+                      <dc:context>
+                        <dc:statement>
+                          SELECT a.gid as aid, f.id AS fid, f.name AS facet_name, f.num AS facet_num, f.description as facet_description
+                          FROM outs as o, facets as f, artifacts as a
+                          WHERE (f.name = 'duration_curve.q' or f.name = 'duration_curve.w') and f.out_id = o.id and o.artifact_id = ${a_id} and a.id = ${a_id}
+                        </dc:statement>
+                        <dc:elements>
+                          <dc:element name="${facet_name}">
+                            <dc:attribute name="description" value="${facet_description}"/>
+                            <dc:attribute name="factory"     value="winfo"/>
+                            <dc:attribute name="artifact-id" value="${aid}"/>
+                            <dc:attribute name="ids"         value="${aid}"/>
+                            <dc:attribute name="out"         value="duration_curve"/>
+                          </dc:element>
+                        </dc:elements>
+                      </dc:context>
+                  </dc:elements>
+                </dc:context>
+            </dc:elements>
+          </computed_discharge_curves>
+        </dc:if>
         <dc:comment>
            WATERLEVELS - ONLY SHOW Ws
         </dc:comment>
 
-        <dc:if test="dc:contains($artifact-outs, 'waterlevels')">
+        <!-- TODO doesnt work nicely for fix/wq-diags. -->
+        <dc:if test="dc:contains($artifact-outs, 'waterlevels') or (dc:contains($artifact-outs, 'fix_wq_curve'))"> 
           <waterlevels>
             <dc:elements>
               <dc:context>
@@ -874,6 +1836,44 @@
           </waterlevels>
         </dc:if>
 
+        <dc:comment>
+          SHOW FLOODMAPS
+        </dc:comment>
+
+        <dc:if test="dc:contains($artifact-outs, 'floodmap') or dc:contains($artifact-outs, 'map')">
+          <floodmap>
+            <dc:elements>
+                <dc:context>
+                  <dc:statement>
+                    SELECT m.id AS a_id, m.state AS a_state, m.gid AS a_gid, m.creation AS a_creation
+                    FROM   master_artifacts m
+                    WHERE  m.collection_id = ${collection_id} AND m.gid &lt;&gt; CAST(${artifact-id} AS uuid)
+                    AND EXISTS (
+                        SELECT id FROM artifact_data ad WHERE ad.artifact_id = m.id AND k = 'river' AND v = ${river})
+                  </dc:statement>
+                  <dc:elements>
+                      <dc:context>
+                        <dc:statement>
+                          SELECT a.gid as aid, f.id AS fid, f.name AS facet_name, f.num AS facet_num, f.description as facet_description
+                          FROM outs as o, facets as f, artifacts as a
+                          WHERE f.name = 'floodmap.wsplgen' and f.out_id = o.id and o.artifact_id = ${a_id} and a.id = ${a_id}
+                        </dc:statement>
+                        <dc:elements>
+                          <dc:element name="${facet_name}">
+                            <dc:attribute name="description" value="${facet_description}"/>
+                            <dc:attribute name="factory"     value="winfo"/>
+                            <dc:attribute name="artifact-id" value="${aid}"/>
+                            <dc:attribute name="ids"         value="${aid}"/>
+                            <dc:attribute name="out"         value="floodmap"/>
+                          </dc:element>
+                        </dc:elements>
+                      </dc:context>
+                  </dc:elements>
+                </dc:context>
+            </dc:elements>
+          </floodmap>
+        </dc:if>
+
       </dc:context>
       </old_calculations>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/rest-server.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<rest-server>
+    <!--  The port which the ArtifactDatabase (ArtifactServer) will bind to. -->
+    <port>8181</port>
+    <listen>localhost</listen>
+</rest-server>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/second-themes.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,1649 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<themegroup name="second">
+    <theme name="DischargeCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 0, 153" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+        </fields>
+    </theme>
+
+    <!-- concrete theme for historical discharge curves -->
+    <theme name="HistoricalDischargeCurveQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 0, 153" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="HistoricalDischargeCurveQDiff">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 204, 204" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+        </fields>
+    </theme>
+
+
+    <!-- Discharge Longitudinal Section -->
+    <theme name="LongitudinalSectionW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="bandwidth" type="double" display="Bandbreite"
+                default="0"/>
+            <field name="fillcolor" type="Color" display="Bandbreitenfarbe"
+                default="104, 104, 104"/> 
+    	    <field name="transparency" type="int" default="30" display="Transparenz"/>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ1">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ2">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ5">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="51, 153, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ10">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ20">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 0, 153" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ25">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ50">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 153, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ100">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 128, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ200">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 128, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ500">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 128, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ1000">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 128, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQRZ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 128, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HSQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="253, 153, 128" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MHQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MNQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 51, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_NQ">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 204, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQExtrem">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 255, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionPoints">
+        <inherits>
+            <inherit from="LongitudinalSectionW" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="false" />
+            <field name="showpoints" type="boolean" display="Punkte anzeigen"
+                default="true" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ1_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="64, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ2_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="64, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ5_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="64, 153, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ10_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="64, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ20_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 153, 64" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ25_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 51, 64" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ50_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 153" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ100_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 10, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ200_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 64, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ500_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 64, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQ1000_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQRZ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 64, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HSQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="253, 153, 64" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MHQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 128, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MNQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 255, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_MQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="64, 51, 178" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_NQ_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 0, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionW_HQExtrem_Points">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 64, 0" />
+        </fields>
+    </theme>
+
+    <!-- Longitudinal Section Q's -->
+
+    <theme name="LongitudinalSectionQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 64, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ1">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ2">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ5">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 153, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ10">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ20">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 0, 153" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ25">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 51, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ50">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 153" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ100">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 50, 51" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ200">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 255, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ500">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 102, 64" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQ1000">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 102, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQRZ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 102, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HSQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="253, 153, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_MHQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="102, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_MNQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 255" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_MQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="55, 51, 204" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_NQ">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="153, 204, 0" />
+        </fields>
+    </theme>
+
+    <theme name="LongitudinalSectionQ_HQExtrem">
+        <inherits>
+            <inherit from="LongitudinalSectionQ" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 128, 0" />
+        </fields>
+    </theme>
+
+    <!-- Main Values -->
+    <theme name="MainValuesQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Farbe"
+                default="200, 64, 0" />
+            <field name="textcolor" type="Color" display="Farbe"
+                default="200, 0, 15" />
+            <field name="showhorizontalline" type="boolean"
+                display="Horizontale Linie" default="true" />
+            <field name="showverticalline" type="boolean" display="Vertikale Linie"
+                default="true" />
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+        </fields>
+    </theme>
+
+    <theme name="MainValuesW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Farbe"
+                default="0, 0, 215" />
+            <field name="textcolor" type="Color" display="Farbe"
+                default="0, 215, 0" />
+            <field name="showhorizontalline" type="boolean"
+                display="Horizontale Linie" default="true" />
+            <field name="showverticalline" type="boolean" display="Vertikale Linie"
+                default="true" />
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+        </fields>
+    </theme>
+
+    <!-- Computed Discharge Curves -->
+    <theme name="ComputedDischargeCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 153" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="4" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="ComputedDischargeCurveQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Farbe"
+                default="200, 255, 15" />
+            <field name="textcolor" type="Color" display="Farbe"
+                default="200, 0, 15" />
+        </fields>
+    </theme>
+
+    <theme name="ComputedDischargeCurveW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Farbe"
+                default="0, 215, 128" />
+            <field name="textcolor" type="Color" display="Farbe"
+                default="0, 215, 0" />
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+        </fields>
+    </theme>
+
+    <!-- Cross Sections -->
+    <theme name="CrossSection">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0,0,0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="CrossSectionWaterLine">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255,0,153" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+            <field name="showwidth" type="boolean" display="Breite anzeigen"
+                default="false" />
+            <field name="showlevel" type="boolean" display="Wasserstand anzeigen"
+                default="true" />
+            <field name="showlinelabel" type="boolean" default="true"
+                display="Beschriftung anzeigen" />
+            <field name="showmiddleheight" type="boolean"
+                display="Wasserstand anzeigen" default="false" />
+        </fields>
+    </theme>
+
+    <theme name="Hyk">
+        <inherits>
+            <inherit from="Text" />
+        </inherits>
+        <fields>
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+        </fields>
+    </theme>
+
+    <!-- Relative Points -->
+    <theme name="RelativePoint">
+        <inherits>
+            <inherit from="LongitudinalSectionPoints" />
+        </inherits>
+        <!--fields> <field name="linecolor" type="Color" display="Linienfarbe"
+            default="0, 0, 0"/> </fields -->
+    </theme>
+
+    <!-- Duration Curves -->
+    <theme name="DurationCurveW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0,51,204" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="DurationCurveQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0,204,0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+        </fields>
+    </theme>
+
+    <!-- Differences -->
+    <theme name="Differences">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <!-- Reference Curves -->
+    <theme name="ReferenceCurveNormalized">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <theme name="ReferenceCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <!-- General -->
+    <theme name="WKms">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <theme name="WQKms">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <theme name="WQPoints">
+        <inherits>
+            <inherit from="Points" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="false" />
+            <field name="showpoints" type="boolean" display="Punkte anzeigen"
+                default="true" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 200" />
+        </fields>
+    </theme>
+
+    <!-- Discharge Longitudinal Section -->
+    <theme name="DischargeLongitudinalSectionW">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+
+    <theme name="DischargeLongitudinalSectionC">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0 , 255" />
+        </fields>
+    </theme>
+
+    <theme name="DischargeLongitudinalSectionQ">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+
+    <!-- Annotations -->
+    <theme name="Annotations">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="Text" />
+            <inherit from="AnnotationText" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="99, 99, 99" />
+        </fields>
+    </theme>
+
+    <!-- Manual Points -->
+    <theme name="ManualPoints">
+        <inherits>
+            <inherit from="Points" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="250, 255, 0" />
+            <field name="font" type="Font" display="Schriftart"
+                default="arial" />
+            <field name="textcolor" type="Color" display="Schriftfarbe"
+                default="0, 0, 0" />
+            <field name="textsize" type="int" display="Schriftgröße"
+                default="10" />
+            <field name="textstyle" type="Style" display="Schriftstil"
+                default="standard" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="2" hints="h" />
+            <field name="backgroundcolor" type="Color" display="Texthintergrund"
+                default="55, 55, 55" />
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="true" />
+            <field name="showbackground" type="boolean"
+                display="Hintergrund anzeigen" default="false" />
+        </fields>
+    </theme>
+
+    <!-- Height Marks -->
+    <theme name="heightmarks_points">
+        <inherits>
+            <inherit from="Points" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="330, 33, 33" />
+        </fields>
+    </theme>
+
+    <!-- Areas -->
+    <theme name="Area">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="showarea" type="boolean" display="Show Area"
+                default="true"/>
+        </fields>
+    </theme>
+
+    <!-- Map -->
+    <theme name="Floodmaps">
+        <inherits>
+            <inherit from="Floodmap" />
+        </inherits>
+    </theme>
+
+    <theme name="Floodplains">
+        <inherits>
+            <inherit from="Floodplain" />
+        </inherits>
+    </theme>
+
+    <theme name="WSPLGEN">
+        <inherits>
+            <inherit from="WSPLGENS" />
+        </inherits>
+    </theme>
+
+    <theme name="RiverAxis">
+        <inherits>
+            <inherit from="RiverAxes" />
+        </inherits>
+    </theme>
+
+    <theme name="Kms">
+        <inherits>
+            <inherit from="Km" />
+        </inherits>
+    </theme>
+
+
+    <theme name="Fixpoints">
+        <inherits>
+            <inherit from="Fixpoint" />
+        </inherits>
+    </theme>
+
+
+    <theme name="GaugeLocation">
+        <inherits>
+            <inherit from="GaugeLocations" />
+        </inherits>
+    </theme>
+
+
+    <theme name="Qps">
+        <inherits>
+            <inherit from="Qp" />
+        </inherits>
+    </theme>
+
+    <theme name="Hws">
+        <inherits>
+            <inherit from="Hw" />
+        </inherits>
+    </theme>
+
+    <theme name="Catchment">
+        <inherits>
+            <inherit from="Catchments" />
+        </inherits>
+    </theme>
+
+    <theme name="FloodmapLines">
+        <inherits>
+            <inherit from="FloodmapLine" />
+        </inherits>
+    </theme>
+
+    <theme name="Buildings">
+        <inherits>
+            <inherit from="Building" />
+        </inherits>
+    </theme>
+
+    <theme name="HydrBoundariesLines">
+        <inherits>
+            <inherit from="HydrBoundariesLine" />
+        </inherits>
+    </theme>
+
+    <theme name="HydrBoundariesPolys">
+        <inherits>
+            <inherit from="HydrBoundariesPoly" />
+        </inherits>
+    </theme>
+
+    <!-- MIDDLE BED HEIGHT -->
+    <theme name="MiddleBedHeightSingle">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="128, 128, 128" />
+        </fields>
+    </theme>
+
+    <theme name="MiddleBedHeightEpoch">
+        <inherits>
+            <inherit from="FlowVelocityVMainChannel" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="64, 0, 102" />
+        </fields>
+    </theme>
+    
+    <!-- Bedheight differences -->
+    <theme name="BedheightDiffYear">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 204, 204" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffMorphWidth">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 204, 0" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffEpoch">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 0" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffAbsHeight1">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 0" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffAbsHeight2">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="100, 255, 100" />
+        </fields>
+    </theme>
+
+    <theme name="BedheightDiffHeightYear">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 100" />
+        </fields>
+    </theme>
+
+
+    <!-- Bed Quality -->
+    <theme name="PorosityTopLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="100, 100, 100" />
+        </fields>
+    </theme>
+    
+    <theme name="PorositySubLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="100, 100, 100" />
+        </fields>
+    </theme>
+    
+    <theme name="DensityTopLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#990000" />
+        </fields>
+    </theme>
+    
+    <theme name="DensitySubLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#990000" />
+        </fields>
+    </theme>
+    
+    <theme name="BedDiameterTopLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#FF4444" />
+        </fields>
+    </theme>
+    
+    <theme name="BedDiameterSubLayer">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#FF4444" />
+        </fields>
+    </theme>
+    
+    <theme name="BedLoadDiameter">
+    	<inherits>
+    		<inherit from="HiddenColorLines" />
+    		<inherit from="MinMaxPoints" />
+    	</inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="#33FF11" />
+        </fields>
+    </theme>
+
+
+    <!-- FLOW VELOCITY -->
+    <theme name="FlowVelocityVMainChannel">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="204, 0, 204" />
+        </fields>
+    </theme>
+
+    <theme name="FlowVelocityVTotalChannel">
+        <inherits>
+            <inherit from="FlowVelocityVMainChannel" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="64, 0, 102" />
+        </fields>
+    </theme>
+
+    <theme name="FlowVelocityTau">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+            <inherit from="MinMaxPoints" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 204, 0" />
+        </fields>
+    </theme>
+
+
+    <!-- SQ Relation -->
+    <theme name="SQMeasurements">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="false" hidden="true" />
+            <field name="pointcolor" type="Color" default="0, 99, 255" />
+        </fields>
+    </theme>
+
+    <theme name="SQOutliers">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="false" hidden="true" />
+            <field name="pointcolor" type="Color" default="0, 99, 0" />
+        </fields>
+    </theme>
+
+    <theme name="SQCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="#000000" />
+            <field name="linesize" type="int" default="3" />
+        </fields>
+    </theme>
+
+    <theme name="FixingWQCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="0, 27, 162" />
+        </fields>
+    </theme>
+
+    <theme name="FixingDerivedCurve">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="0, 27, 162" />
+            <field name="showpoints" type="boolean" display="Datenpunkte anzeigen"
+                default="false" hints="h" hidden="true" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="5" hints="h" hidden="true" />
+        </fields>
+    </theme>
+
+    <theme name="FixingSectorAverageWQ0">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" default="false" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 128, 128" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="false"/>
+        </fields>
+    </theme>
+    <theme name="FixingSectorAverageWQ1">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="showlines" type="boolean" default="false" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 64, 255" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="false"/>
+        </fields>
+    </theme>
+    <theme name="FixingSectorAverageWQ2">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="showlines" type="boolean" default="false" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="2" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="255, 0, 255" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="false"/>
+        </fields>
+    </theme>
+    <theme name="FixingSectorAverageWQ3">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="showlines" type="boolean" default="false" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="255, 0, 255" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="false"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingAnalysisEventsWQ">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" default="false" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 255, 255" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="false"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingReferenceEvents">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" default="false"
+                hidden="true" />
+            <field name="showlinelabel" type="boolean" default="false"
+                hidden="true" />
+            <field name="linetype" type="Dash" display="Linienart"
+                default="10" hidden="true" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="2" hidden="true" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="4" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 80, 255" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="true"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingOutliers">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="false"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingDeltaWtAverage0">
+        <inherits>
+            <inherit from="ColorLines" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="true" hints="h" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 128, 128" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+    <theme name="FixingDeltaWtAverage1">
+        <inherits>
+            <inherit from="ColorLines" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="true" hints="h" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="128, 0, 255" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+    <theme name="FixingDeltaWtAverage2">
+        <inherits>
+            <inherit from="ColorLines" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="true" hints="h" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 128, 255" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+    <theme name="FixingDeltaWtAverage3">
+        <inherits>
+            <inherit from="ColorLines" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="true" hints="h" />
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+
+
+    <theme name="FixingDeltaWtAnalysis">
+        <inherits>
+            <inherit from="ColorPoints" />
+        </inherits>
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="true" />
+            <field name="showlines" type="boolean" default="false" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="3" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="0, 255, 0" />
+            <field name="textorientation" type="boolean" default="true" display="Text horizontal"/>
+        </fields>
+    </theme>
+
+    <theme name="FixingLSAverage0">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="0, 128, 64" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixingLSAverage1">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="0, 64, 255" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixingLSAverage2">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="255, 64, 255" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixingLSAverage3">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="255, 0, 64" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="FixingSectorDeviationLS0">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Fuellfarbe"
+                default="0, 128, 64" />
+        </fields>
+    </theme>
+    <theme name="FixingSectorDeviationLS1">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Fuellfarbe"
+                default="64, 0, 255" />
+        </fields>
+    </theme>
+    <theme name="FixingSectorDeviationLS2">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Fuellfarbe"
+                default="255, 64, 255" />
+        </fields>
+    </theme>
+    <theme name="FixingSectorDeviationLS3">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Fuellfarbe"
+                default="255, 64, 0" />
+        </fields>
+    </theme>
+    <theme name="FixLSDeviation">
+        <inherits>
+            <inherit from="Areas" />
+        </inherits>
+        <fields>
+            <field name="fillcolor" type="Color" display="Fuellfarbe"
+                default="200, 200, 200" />
+            <field name="transparent" type="boolean" display="Transparenz"
+                default="true" />
+        </fields>
+    </theme>
+    <theme name="FixLSAnalysis">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="0, 0, 255" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixLSReference">
+        <inherits>
+            <inherit from="HiddenColorLines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" default="160, 80, 160" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+        </fields>
+    </theme>
+    <theme name="FixDeltaWtDeviation">
+    	<inherits>
+    		<inherit from="Areas"/>
+    	</inherits>
+    	<fields>
+    		<field name="transparency" type="int" default="30" display="Transparenz"/>
+    		<field name="backgroundcolor" type="Color" default="0, 0, 0" display="Füllfarbe"/>
+    	</fields>
+    </theme>
+    <theme name="FixingDeltaWtAnalysisPeriods">
+        <inherits>
+    		<inherit from="Areas"/>
+    	</inherits>
+    	<fields>
+    		<field name="transparency" type="int" default="90" display="Transparenz"/>
+    	</fields>
+    </theme>
+    
+    <theme name="FixingReferencePeriod">
+        <inherits>
+    		<inherit from="Areas"/>
+    	</inherits>
+    	<fields>
+    		<field name="transparency" type="int" default="70" display="Transparenz"/>
+            <field name="backgroundcolor" type="Color" default="0, 128, 200" display="Füllfarbe" />
+    	</fields>
+    </theme>
+
+    <theme name="QSectors">
+        <fields>
+            <field name="linecolor" type="Color" default="32, 27, 162" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="linetype" type="Dash" display="Linienart"
+                default="10" hidden="true" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="2" hidden="true" />
+            <field name="labelfontface" type="Font"
+                display="Beschriftung: Schriftart" default="arial" />
+            <field name="labelfontcolor" type="Color"
+                display="Beschriftung: Schriftfarbe" default="0, 0, 0" />
+            <field name="labelfontsize" type="int"
+                display="Beschriftung: Schriftgröße" default="9" />
+            <field name="labelfontstyle" type="Style"
+                display="Beschriftung: Schriftstil" default="standard" />
+        </fields>
+    </theme>
+
+</themegroup>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/seddb-db.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<seddb-database>
+    <!-- This is the default SedDB db configuration. -->
+    <user>sedb</user>
+    <password>sedb</password>
+    <dialect>org.hibernate.dialect.PostgreSQLDialect</dialect>
+    <driver>org.postgresql.Driver</driver>
+    <url>jdbc:postgresql://localhost:5432/seddb</url>
+</seddb-database>
--- a/flys-artifacts/doc/conf/themes.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/doc/conf/themes.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -1,908 +1,270 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE themes [
+    <!ENTITY default-themes SYSTEM "conf/default-themes.xml">
+    <!ENTITY second-themes SYSTEM "conf/second-themes.xml">
+    <!ENTITY virtual-themes  SYSTEM "conf/virtual-themes.xml">
+]>
 <themes>
-
-    <!-- Concrete themes are following now! -->
-    <theme name="DischargeCurve">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 153"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="2" hints="h"/>
-        </fields>
-    </theme>
-
-    <!--
-        Discharge Longitudinal Section
-    -->
-    <theme name="LongitudinalSectionW">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="204, 204, 204"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ1">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ2">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ5">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 153, 51"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ10">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 204, 204"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ20">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="153, 153, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ25">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 51, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ50">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 153, 153"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ100">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 51"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ200">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 255"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ500">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ1000">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQRZ">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HSQ">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="253, 153, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_MHQ">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 255, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_MNQ">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 255, 255"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_MQ">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 51, 204"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_NQ">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="153, 204, 255"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQExtrem">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionPoints">
-        <inherits>
-            <inherit from="LongitudinalSectionW"/>
-        </inherits>
-        <fields>
-            <field name="showlines"  type="boolean" display="Linie anzeigen"  default="false"/>
-            <field name="showpoints" type="boolean" display="Punkte anzeigen" default="true"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ1_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ2_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ5_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 153, 51"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ10_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 204, 204"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ20_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="153, 153, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ25_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 51, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ50_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 153, 153"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ100_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 51"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ200_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 255"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ500_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQ1000_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQRZ_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HSQ_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="253, 153, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_MHQ_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 255, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_MNQ_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 255, 255"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_MQ_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 51, 204"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_NQ_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="153, 204, 255"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionW_HQExtrem_Points">
-        <inherits><inherit from="LongitudinalSectionPoints"/></inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-        </fields>
-    </theme>
-
-    <!--
-      Longitudinal Section Q's
-    -->
-
-    <theme name="LongitudinalSectionQ">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="204, 204, 204"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ1">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ2">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ5">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 153, 51"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ10">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 204, 204"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ20">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="153, 153, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ25">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 51, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ50">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 153, 153"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ100">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 51"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ200">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 255"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ500">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQ1000">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQRZ">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 0, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HSQ">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="253, 153, 0"/>
-        </fields>
-    </theme>
+    &default-themes;
+    &second-themes;
+    &virtual-themes;
 
-    <theme name="LongitudinalSectionQ_MHQ">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="102, 255, 102"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_MNQ">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 255, 255"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_MQ">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 51, 204"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_NQ">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="153, 204, 255"/>
-        </fields>
-    </theme>
-
-    <theme name="LongitudinalSectionQ_HQExtrem">
-        <inherits>
-            <inherit from="LongitudinalSectionQ"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-        </fields>
-    </theme>
-
-
-    <!--
-        Computed Discharge Curves
-    -->
-    <theme name="ComputedDischargeCurve">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 153"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="2" hints="h"/>
-        </fields>
-    </theme>
-
-    <theme name="ComputedDischargeCurveQ">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-            <inherit from="Text"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Farbe" default="200, 0, 15"/>
-        </fields>
-    </theme>
-
-    <theme name="ComputedDischargeCurveW">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-            <inherit from="Text"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Farbe" default="0, 215, 0"/>
-        </fields>
-    </theme>
-
-    <!--
-        Cross Sections
-    -->
-    <theme name="CrossSection">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0,0,0"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="1" hints="h"/>
-        </fields>
-    </theme>
-
-    <theme name="CrossSectionWaterLine">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0,0,153"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="1" hints="h"/>
-        </fields>
-    </theme>
-
-
-    <!--
-        Duration Curves
-    -->
-    <theme name="DurationCurveW">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0,51,204"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="2" hints="h"/>
-        </fields>
-    </theme>
-
-    <theme name="DurationCurveQ">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0,204,0"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="2" hints="h"/>
-        </fields>
-    </theme>
-
-    <!-- Differences -->
-    <theme name="Differences">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="204, 204, 204"/>
-        </fields>
-    </theme>
-
-
-    <!-- General -->
-    <theme name="WKms">
-       <inherits><inherit from="HiddenColorLines"/></inherits>
-       <fields>
-         <field name="linecolor" type="Color" display="Linienfarbe" default="204, 204, 204"/>
-       </fields>
-    </theme>
-
-    <theme name="WQKms">
-       <inherits><inherit from="HiddenColorLines"/></inherits>
-       <fields>
-         <field name="linecolor" type="Color" display="Linienfarbe" default="204, 204, 204"/>
-       </fields>
-    </theme>
-
-    <theme name="WQPoints">
-      <inherits><inherit from="Points"/></inherits>
-      <fields>
-        <field name="showlines"  type="boolean" display="Linie anzeigen"  default="false"/>
-        <field name="showpoints" type="boolean" display="Punkte anzeigen" default="true"/>
-        <field name="linecolor" type="Color" display="Linienfarbe" default="204, 0, 0"/>
-      </fields>
-    </theme>
-
-    <!--
-        Discharge Longitudinal Section
-    -->
-    <theme name="DischargeLongitudinalSectionW">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="204, 204, 204"/>
-        </fields>
-    </theme>
-
-
-    <theme name="DischargeLongitudinalSectionC">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0 , 0"/>
-        </fields>
-    </theme>
-
-    <theme name="DischargeLongitudinalSectionQ">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="204, 204, 204"/>
-        </fields>
-    </theme>
-
-
-    <!-- Annotations -->
-    <theme name="Annotations">
-        <inherits>
-            <inherit from="HiddenColorLines"/>
-            <inherit from="Text"/>
-            <inherit from="AnnotationText"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-        </fields>
-    </theme>
-
-    <!-- Height Marks -->
-    <theme name="heightmarks_points">
-        <inherits>
-            <inherit from="Points"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-        </fields>
-    </theme>
-
-
-    <!-- Virtual themes are following now! -->
-    <theme name="Lines" type="virtual">
-        <fields>
-            <field name="showlines" type="boolean" display="Linie anzeigen" default="true"/>
-            <field name="linesize"  type="int"     display="Liniendicke"    default="1"/>
-            <field name="linetype"  type="Dash"    display="Linienart"      default="10"/>
-        </fields>
-    </theme>
+	<!-- Mappings are following now. A mapping maps between a name of a facet 
+		and a theme. Always the first matching mapping is taken, so consider putting 
+		most specific mappings on top of the list. -->
+	<mappings>
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ1)(\D.*)*" to="LongitudinalSectionW_HQ1_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ2)(\D.*)*" to="LongitudinalSectionW_HQ2_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ5)(\D.*)*" to="LongitudinalSectionW_HQ5_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ10)(\D.*)*" to="LongitudinalSectionW_HQ10_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ20)(\D.*)*" to="LongitudinalSectionW_HQ20_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ25)(\D.*)*" to="LongitudinalSectionW_HQ25_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ50)(\D.*)*" to="LongitudinalSectionW_HQ50_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ100)(\D.*)*" to="LongitudinalSectionW_HQ100_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ200)(\D.*)*" to="LongitudinalSectionW_HQ200_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ500)(\D.*)*" to="LongitudinalSectionW_HQ500_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQ1000)(\D.*)*" to="LongitudinalSectionW_HQ1000_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQExtrem)(\D.*)*" to="LongitudinalSectionW_HQExtrem_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HQRZ)(\D.*)*" to="LongitudinalSectionW_HQRZ_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(HSQ)(\D.*)*" to="LongitudinalSectionW_HSQ_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(MHQ)(\D.*)*" to="LongitudinalSectionW_MHQ_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(MNQ)(\D.*)*" to="LongitudinalSectionW_MNQ_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(MQ)(\D.*)*" to="LongitudinalSectionW_MQ_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			pattern=".*(NQ)(\D.*)*" to="LongitudinalSectionW_NQ_Points" />
+		<mapping from="longitudinal_section.w" masterAttr="ld_mode==location"
+			to="LongitudinalSectionPoints" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ1)(\D.*)*"
+			to="LongitudinalSectionW_HQ1" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ2)(\D.*)*"
+			to="LongitudinalSectionW_HQ2" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ5)(\D.*)*"
+			to="LongitudinalSectionW_HQ5" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ10)(\D.*)*"
+			to="LongitudinalSectionW_HQ10" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ20)(\D.*)*"
+			to="LongitudinalSectionW_HQ20" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ25)(\D.*)*"
+			to="LongitudinalSectionW_HQ25" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ50)(\D.*)*"
+			to="LongitudinalSectionW_HQ50" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ100)(\D.*)*"
+			to="LongitudinalSectionW_HQ100" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ200)(\D.*)*"
+			to="LongitudinalSectionW_HQ200" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ500)(\D.*)*"
+			to="LongitudinalSectionW_HQ500" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQ1000)(\D.*)*"
+			to="LongitudinalSectionW_HQ1000" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQExtrem)(\D.*)*"
+			to="LongitudinalSectionW_HQExtrem" />
+		<mapping from="longitudinal_section.w" pattern=".*(HQRZ)(\D.*)*"
+			to="LongitudinalSectionW_HQRZ" />
+		<mapping from="longitudinal_section.w" pattern=".*(HSQ)(\D.*)*"
+			to="LongitudinalSectionW_HSQ" />
+		<mapping from="longitudinal_section.w" pattern=".*(MHQ)(\D.*)*"
+			to="LongitudinalSectionW_MHQ" />
+		<mapping from="longitudinal_section.w" pattern=".*(MNQ)(\D.*)*"
+			to="LongitudinalSectionW_MNQ" />
+		<mapping from="longitudinal_section.w" pattern=".*(MQ)(\D.*)*"
+			to="LongitudinalSectionW_MQ" />
+		<mapping from="longitudinal_section.w" pattern=".*(NQ)(\D.*)*"
+			to="LongitudinalSectionW_NQ" />
+		<mapping from="longitudinal_section.w" to="LongitudinalSectionW" />
 
-    <theme name="Points" type="virtual">
-        <fields>
-            <field name="showlines"  type="boolean" display="Linie anzeigen"  default="false"/>
-            <field name="linesize"   type="int"     display="Liniendicke"     default="1"/>
-            <field name="linetype"   type="Dash"    display="Linienart"       default="10"/>
-            <field name="showpoints" type="boolean" display="Punkte anzeigen" default="true"/>
-        </fields>
-    </theme>
-
-    <theme name="ColorLines" type="virtual">
-        <inherits>
-            <inherit from="Lines"/>
-        </inherits>
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="Color.BLACK"/>
-        </fields>
-    </theme>
-
-    <theme name="HiddenColorLines" type="virtual">
-        <inherits>
-            <inherit from="ColorLines"/>
-        </inherits>
-        <fields>
-            <field name="showlines"  type="boolean" display="Linie anzeigen"       default="true"        hints="h"/>
-            <field name="linesize"   type="int"     display="Liniendicke"          default="1"           hints="h"/>
-            <field name="linetype"   type="Dash"    display="Linienart"            default="10"          hints="h"/>
-            <field name="showpoints" type="boolean" display="Datenpunkte anzeigen" default="false" hints="h"/>
-        </fields>
-    </theme>
-
-    <theme name="Text" type="virtual">
-        <fields>
-            <field name="font"      type="Font"  display="Schriftart"      default="arial"/>
-            <field name="textcolor" type="Color" display="Schriftfarbe"    default="0, 0, 0"/>
-            <field name="textsize"  type="int"   display="Schriftgröße" default="10"/>
-            <field name="textstyle" type="Style" display="Schriftstil"     default="standard"/>
-        </fields>
-    </theme>
-
-    <theme name="AnnotationText" type="virtual">
-        <fields>
-            <field name="backgroundcolor"  type="Color"   display="Texthintergrund"      default="255, 255, 255"/>
-            <field name="textorientation"  type="boolean" display="Textausrichtung"      default="false"/>
-            <field name="showbackground"   type="boolean" display="Hintergrund anzeigen" default="false"/>
-        </fields>
-    </theme>
-
-    <!-- Area relevant theme(s) -->
-    <theme name="Area">
-        <inherits>
-            <inherit from="Text"/>
-            <inherit from="ColorLines"/>
-        </inherits>
-        <fields>
-            <field name="fillcolor" type="Color" display="Fuellfarbe" default="0, 100, 0"/>
-            <field name="showarea" type="boolean" display="Flaeche beschriften" default="false"/>
-            <field name="showborder" type="boolean" display="Flaechebegrenzungslinie anzeigen" default="false"/>
-            <field name="transparent" type="boolean" display="Transparenz" default="false"/>
-        </fields>
-    </theme>
-
-
-    <!-- MAP relevant themes -->
-    <theme name="RiverAxis">
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 205"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="3" hints="h"/>
-        </fields>
-    </theme>
-
-    <theme name="Kms">
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 0"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="5" hints="h"/>
-            <field name="textcolor" type="Color" display="Schriftfarbe"    default="0, 0, 0"/>
-            <field name="textsize"  type="int"   display="Schriftgröße" default="10"/>
-            <field name="symbol"    type="Symbol" display="Symbol"     default="square"/>
-        </fields>
-    </theme>
-
-    <theme name="Fixpoints">
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 0"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="3" hints="h"/>
-            <field name="symbol"    type="Symbol" display="Symbol"     default="point"/>
-        </fields>
-    </theme>
-
-    <theme name="Qps">
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 255"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="3" hints="h"/>
-        </fields>
-    </theme>
-
-    <theme name="Hws">
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 0"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="3" hints="h"/>
-        </fields>
-    </theme>
-
-    <theme name="Catchment">
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="1" hints="h"/>
-            <field name="backgroundcolor" type="Color" display="Hintergrund" default="140, 200, 130"/>
-        </fields>
-    </theme>
+		<mapping from="longitudinal_section.q" pattern="(HQ1)(\D.*)*"
+			to="LongitudinalSectionQ_HQ1" />
+		<mapping from="longitudinal_section.q" pattern="(HQ2)(\D.*)*"
+			to="LongitudinalSectionQ_HQ2" />
+		<mapping from="longitudinal_section.q" pattern="(HQ5)(\D.*)*"
+			to="LongitudinalSectionQ_HQ5" />
+		<mapping from="longitudinal_section.q" pattern="(HQ10)(\D.*)*"
+			to="LongitudinalSectionQ_HQ10" />
+		<mapping from="longitudinal_section.q" pattern="(HQ20)(\D.*)*"
+			to="LongitudinalSectionQ_HQ20" />
+		<mapping from="longitudinal_section.q" pattern="(HQ25)(\D.*)*"
+			to="LongitudinalSectionQ_HQ25" />
+		<mapping from="longitudinal_section.q" pattern="(HQ50)(\D.*)*"
+			to="LongitudinalSectionQ_HQ50" />
+		<mapping from="longitudinal_section.q" pattern="(HQ100)(\D.*)*"
+			to="LongitudinalSectionQ_HQ100" />
+		<mapping from="longitudinal_section.q" pattern="(HQ200)(\D.*)*"
+			to="LongitudinalSectionQ_HQ200" />
+		<mapping from="longitudinal_section.q" pattern="(HQ500)(\D.*)*"
+			to="LongitudinalSectionQ_HQ500" />
+		<mapping from="longitudinal_section.q" pattern="(HQ1000)(\D.*)*"
+			to="LongitudinalSectionQ_HQ1000" />
+		<mapping from="longitudinal_section.q" pattern="(HQExtrem)(\D.*)*"
+			to="LongitudinalSectionQ_HQExtrem" />
+		<mapping from="longitudinal_section.q" pattern="(HQRZ)(\D.*)*"
+			to="LongitudinalSectionQ_HQRZ" />
+		<mapping from="longitudinal_section.q" pattern="(HSQ)(\D.*)*"
+			to="LongitudinalSectionQ_HSQ" />
+		<mapping from="longitudinal_section.q" pattern="(MHQ)(\D.*)*"
+			to="LongitudinalSectionQ_MHQ" />
+		<mapping from="longitudinal_section.q" pattern="(MNQ)(\D.*)*"
+			to="LongitudinalSectionQ_MNQ" />
+		<mapping from="longitudinal_section.q" pattern="(MQ)(\D.*)*"
+			to="LongitudinalSectionQ_MQ" />
+		<mapping from="longitudinal_section.q" pattern="(NQ)(\D.*)*"
+			to="LongitudinalSectionQ_NQ" />
+		<mapping from="longitudinal_section.q" to="LongitudinalSectionQ" />
 
-    <theme name="Floodplain">
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="0, 0, 0"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="1" hints="h"/>
-            <field name="backgroundcolor" type="Color" display="Hintergrund" default="140, 200, 130"/>
-        </fields>
-    </theme>
-
-    <theme name="Lines">
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="140, 200, 130"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="3" hints="h"/>
-        </fields>
-    </theme>
-
-    <theme name="Buildings">
-        <fields>
-            <field name="linecolor" type="Color" display="Linienfarbe" default="255, 0, 0"/>
-            <field name="linesize"  type="int"   display="Liniendicke" default="5" hints="h"/>
-        </fields>
-    </theme>
-
-
-    <!--
-      Mappings are following now. A mapping maps between a name of a facet
-      and a theme.
-      Always the first matching mapping is taken, so consider putting most
-      specific mappings on top of the list.
-    -->
-    <mappings>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ1)(\D.*)*" to="LongitudinalSectionW_HQ1_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ2)(\D.*)*" to="LongitudinalSectionW_HQ2_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ5)(\D.*)*" to="LongitudinalSectionW_HQ5_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ10)(\D.*)*" to="LongitudinalSectionW_HQ10_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ20)(\D.*)*" to="LongitudinalSectionW_HQ20_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ25)(\D.*)*" to="LongitudinalSectionW_HQ25_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ50)(\D.*)*" to="LongitudinalSectionW_HQ50_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ100)(\D.*)*" to="LongitudinalSectionW_HQ100_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ200)(\D.*)*" to="LongitudinalSectionW_HQ200_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ500)(\D.*)*" to="LongitudinalSectionW_HQ500_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQ1000)(\D.*)*" to="LongitudinalSectionW_HQ1000_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQExtrem)(\D.*)*" to="LongitudinalSectionW_HQExtrem_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HQRZ)(\D.*)*" to="LongitudinalSectionW_HQRZ_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(HSQ)(\D.*)*" to="LongitudinalSectionW_HSQ_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(MHQ)(\D.*)*" to="LongitudinalSectionW_MHQ_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(MNQ)(\D.*)*" to="LongitudinalSectionW_MNQ_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(MQ)(\D.*)*" to="LongitudinalSectionW_MQ_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" pattern=".*(NQ)(\D.*)*" to="LongitudinalSectionW_NQ_Points"/>
-        <mapping from="longitudinal_section.w" masterAttr="ld_mode==location" to="LongitudinalSectionPoints"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ1)(\D.*)*" to="LongitudinalSectionW_HQ1"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ2)(\D.*)*" to="LongitudinalSectionW_HQ2"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ5)(\D.*)*" to="LongitudinalSectionW_HQ5"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ10)(\D.*)*" to="LongitudinalSectionW_HQ10"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ20)(\D.*)*" to="LongitudinalSectionW_HQ20"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ25)(\D.*)*" to="LongitudinalSectionW_HQ25"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ50)(\D.*)*" to="LongitudinalSectionW_HQ50"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ100)(\D.*)*" to="LongitudinalSectionW_HQ100"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ200)(\D.*)*" to="LongitudinalSectionW_HQ200"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ500)(\D.*)*" to="LongitudinalSectionW_HQ500"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQ1000)(\D.*)*" to="LongitudinalSectionW_HQ1000"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQExtrem)(\D.*)*" to="LongitudinalSectionW_HQExtrem"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HQRZ)(\D.*)*" to="LongitudinalSectionW_HQRZ"/>
-        <mapping from="longitudinal_section.w" pattern=".*(HSQ)(\D.*)*" to="LongitudinalSectionW_HSQ"/>
-        <mapping from="longitudinal_section.w" pattern=".*(MHQ)(\D.*)*" to="LongitudinalSectionW_MHQ"/>
-        <mapping from="longitudinal_section.w" pattern=".*(MNQ)(\D.*)*" to="LongitudinalSectionW_MNQ"/>
-        <mapping from="longitudinal_section.w" pattern=".*(MQ)(\D.*)*" to="LongitudinalSectionW_MQ"/>
-        <mapping from="longitudinal_section.w" pattern=".*(NQ)(\D.*)*" to="LongitudinalSectionW_NQ"/>
-        <mapping from="longitudinal_section.w" to="LongitudinalSectionW"/>
-
-        <mapping from="longitudinal_section.q" pattern="(HQ1)(\D.*)*" to="LongitudinalSectionQ_HQ1"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ2)(\D.*)*" to="LongitudinalSectionQ_HQ2"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ5)(\D.*)*" to="LongitudinalSectionQ_HQ5"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ10)(\D.*)*" to="LongitudinalSectionQ_HQ10"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ20)(\D.*)*" to="LongitudinalSectionQ_HQ20"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ25)(\D.*)*" to="LongitudinalSectionQ_HQ25"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ50)(\D.*)*" to="LongitudinalSectionQ_HQ50"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ100)(\D.*)*" to="LongitudinalSectionQ_HQ100"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ200)(\D.*)*" to="LongitudinalSectionQ_HQ200"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ500)(\D.*)*" to="LongitudinalSectionQ_HQ500"/>
-        <mapping from="longitudinal_section.q" pattern="(HQ1000)(\D.*)*" to="LongitudinalSectionQ_HQ1000"/>
-        <mapping from="longitudinal_section.q" pattern="(HQExtrem)(\D.*)*" to="LongitudinalSectionQ_HQExtrem"/>
-        <mapping from="longitudinal_section.q" pattern="(HQRZ)(\D.*)*" to="LongitudinalSectionQ_HQRZ"/>
-        <mapping from="longitudinal_section.q" pattern="(HSQ)(\D.*)*" to="LongitudinalSectionQ_HSQ"/>
-        <mapping from="longitudinal_section.q" pattern="(MHQ)(\D.*)*" to="LongitudinalSectionQ_MHQ"/>
-        <mapping from="longitudinal_section.q" pattern="(MNQ)(\D.*)*" to="LongitudinalSectionQ_MNQ"/>
-        <mapping from="longitudinal_section.q" pattern="(MQ)(\D.*)*" to="LongitudinalSectionQ_MQ"/>
-        <mapping from="longitudinal_section.q" pattern="(NQ)(\D.*)*" to="LongitudinalSectionQ_NQ"/>
-        <mapping from="longitudinal_section.q" to="LongitudinalSectionQ"/>
-
-        <mapping from="discharge_curve.curve" to="DischargeCurve"/>
-        <mapping from="cross_section" to="CrossSection"/>
-        <mapping from="cross_section_water_line" to="CrossSectionWaterLine"/>
-        <mapping from="computed_discharge_curve.q" to="ComputedDischargeCurve"/>
-        <mapping from="duration_curve.w" to="DurationCurveW"/>
-        <mapping from="duration_curve.q" to="DurationCurveQ"/>
-        <mapping from="discharge_longitudinal_section.w" to="DischargeLongitudinalSectionW"/>
-        <mapping from="discharge_longitudinal_section.c" to="DischargeLongitudinalSectionC"/>
-        <mapping from="discharge_longitudinal_section.q" to="DischargeLongitudinalSectionQ"/>
-        <mapping from="computed_discharge_curve.mainvalues.q" to="ComputedDischargeCurveQ"/>
-        <mapping from="computed_discharge_curve.mainvalues.w" to="ComputedDischargeCurveW"/>
-        <mapping from="longitudinal_section.annotations" to="Annotations"/>
-        <mapping from="w_differences" to="Differences"/>
-        <mapping from="floodmap.riveraxis" to="RiverAxis"/>
-        <mapping from="floodmap.kms" to="Kms"/>
-        <mapping from="floodmap.qps" to="Qps"/>
-        <mapping from="floodmap.hws" to="Hws"/>
-        <mapping from="floodmap.catchment" to="Catchment"/>
-        <mapping from="floodmap.floodplain" to="Floodplain"/>
-        <mapping from="floodmap.lines" to="Lines"/>
-        <mapping from="floodmap.buildings" to="Buildings"/>
-        <mapping from="floodmap.fixpoints" to="Fixpoints"/>
-        <mapping from="other.wq" to="WQPoints"/>
-        <mapping from="other.wkms" to="WKms"/>
-        <mapping from="other.wqkms" to="WQKms"/>
-        <mapping from="heightmarks_points" to="heightmarks_points"/>
-        <mapping from="area" to="Area"/>
-        <mapping from="cross_section.area" to="Area"/>
-        <mapping from="longitudinal_section.area" to="Area"/>
-    </mappings>
+		<mapping from="discharge_curve.curve" to="DischargeCurve" />
+		<mapping from="historical_discharge.historicalq" to="HistoricalDischargeCurveQ" />
+		<mapping from="historical_discharge.historicalq.diff" to="HistoricalDischargeCurveQDiff" />
+		<mapping from="cross_section" to="CrossSection" />
+		<mapping from="cross_section_water_line" to="CrossSectionWaterLine" />
+		<mapping from="computed_discharge_curve.q" to="ComputedDischargeCurve" />
+		<mapping from="duration_curve.w" to="DurationCurveW" />
+		<mapping from="duration_curve.q" to="DurationCurveQ" />
+		<mapping from="discharge_longitudinal_section.w" to="DischargeLongitudinalSectionW" />
+		<mapping from="discharge_longitudinal_section.c" to="DischargeLongitudinalSectionC" />
+		<mapping from="discharge_longitudinal_section.q" to="DischargeLongitudinalSectionQ" />
+		<mapping from="computed_discharge_curve.mainvalues.q" to="MainValuesQ" />
+		<mapping from="computed_discharge_curve.mainvalues.w" to="MainValuesW" />
+		<mapping from="duration_curve.mainvalues.q" to="MainValuesQ" />
+		<mapping from="mainvalues.q" to="MainValuesQ" />
+		<mapping from="mainvalues.w" to="MainValuesW" />
+		<mapping from="longitudinal_section.annotations" to="Annotations" />
+		<mapping from="w_differences" to="Differences" />
+		<mapping from="floodmap.wsplgen" to="WSPLGEN" />
+		<mapping from="floodmap.riveraxis" to="RiverAxis" />
+		<mapping from="floodmap.kms" to="Kms" />
+		<mapping from="floodmap.qps" to="Qps" />
+		<mapping from="floodmap.hws" to="Hws" />
+		<mapping from="floodmap.hydr_boundaries" to="HydrBoundariesLines" />
+		<mapping from="floodmap.hydr_boundaries_poly" to="HydrBoundariesPolys" />
+		<mapping from="floodmap.catchment" to="Catchment" />
+		<mapping from="floodmap.floodplain" to="Floodplains" />
+		<mapping from="floodmap.lines" to="FloodmapLines" />
+		<mapping from="floodmap.buildings" to="Buildings" />
+		<mapping from="floodmap.fixpoints" to="Fixpoints" />
+		<mapping from="floodmap.floodmaps" to="Floodmaps" />
+		<mapping from="floodmap.gauge_location" to="GaugeLocation" />
+		<mapping from="other.wq" to="WQPoints" />
+		<mapping from="other.wkms" to="WKms" />
+		<mapping from="other.wqkms" to="WQKms" />
+		<mapping from="other.wqkms.w" to="WQKms" />
+		<mapping from="other.wqkms.q" to="WQKms" />
+		<mapping from="heightmarks_points" to="heightmarks_points" />
+		<mapping from="area" to="Area" />
+		<mapping from="cross_section.area" to="Area" />
+		<mapping from="hyk" to="Hyk" />
+		<mapping from="longitudinal_section.area" to="Area" />
+		<mapping from="longitudinal_section.manualpoints" to="ManualPoints" />
+		<mapping from="cross_section.manualpoints" to="ManualPoints" />
+		<mapping from="cross_section.manualline" to="CrossSectionWaterLine" />
+		<mapping from="computed_discharge_curve.manualpoints" to="ManualPoints" />
+		<mapping from="duration_curve.manualpoints" to="ManualPoints" />
+		<mapping from="wdifferences.manualpoints" to="ManualPoints" />
+		<mapping from="discharge_longitudinal_section.manualpoints"
+			to="ManualPoints" />
+		<mapping from="discharge_curve.manualpoints" to="ManualPoints" />
+		<mapping from="reference_curve.manualpoints" to="ManualPoints" />
+		<mapping from="reference_curve_normalized.manualpoints" to="ManualPoints" />
+		<mapping from="historical_discharge.manualpoints" to="ManualPoints" />
+		<mapping from="manualpoints" to="ManualPoints" />
+		<mapping from="reference_curve" to="ReferenceCurve" />
+		<mapping from="reference_curve_normalized" to="ReferenceCurveNormalized" />
+		<mapping from="flow_velocity.totalchannel" to="FlowVelocityVTotalChannel" />
+		<mapping from="flow_velocity.mainchannel" to="FlowVelocityVMainChannel" />
+		<mapping from="flow_velocity.tau" to="FlowVelocityTau" />
+		<mapping from="bedheight_middle.single" to="MiddleBedHeightSingle" />
+		<mapping from="bedheight_middle.epoch" to="MiddleBedHeightEpoch" />
+		<mapping from="bed_longitudinal_section.porosity_toplayer" to="PorosityTopLayer" />
+		<mapping from="bed_longitudinal_section.porosity_sublayer" to="PorositySubLayer" />
+		<mapping from="bed_longitudinal_section.sediment_density_toplayer" to="DensityTopLayer" />
+		<mapping from="bed_longitudinal_section.sediment_density_sublayer" to="DensitySublayer" />
+		<mapping from="bed_longitudinal_section.bed_diameter_toplayer" to="BedDiameterTopLayer" />
+		<mapping from="bed_longitudinal_section.bed_diameter_sublayer" to="BedDiameterSubLayer" />
+		<mapping from="bed_longitudinal_section.bedload_diameter" to="BedLoadDiameter" />
+		<mapping from="bedheight_difference.year" to="BedheightDiffYear"/>
+		<mapping from="bedheight_difference.morph_width" to="BedheightDiffMorphWidth"/>
+		<mapping from="bedheight_difference.epoch" to="BedheightDiffEpoch"/>
+		<mapping from="bedheight_difference.year.height1" to="BedheightDiffAbsHeight1"/>
+		<mapping from="bedheight_difference.year.height2" to="BedheightDiffAbsHeight2"/>
+		<mapping from="bedheight_difference.epoch.height1" to="BedheightDiffAbsHeight1"/>
+		<mapping from="bedheight_difference.epoch.height2" to="BedheightDiffAbsHeight2"/>
+		<mapping from="bedheight_difference.height_year" to="BedheightDiffHeightYear"/>
+		<mapping from="relativepoint" to="RelativePoint" />
+		<mapping from="sq_a_measurement" to="SQMeasurements" />
+		<mapping from="sq_a_outlier" to="SQOutliers" />
+		<mapping from="sq_a_curve" to="SQCurve" />
+		<mapping from="sq_a_outlier_curve" to="SQCurve" />
+		<mapping from="sq_a_outlier_measurement" to="SQMeasurements" />
+		<mapping from="sq_b_measurement" to="SQMeasurements" />
+		<mapping from="sq_b_outlier" to="SQOutliers" />
+		<mapping from="sq_b_curve" to="SQCurve" />
+		<mapping from="sq_b_outlier_curve" to="SQCurve" />
+		<mapping from="sq_b_outlier_measurement" to="SQMeasurements" />
+		<mapping from="sq_c_measurement" to="SQMeasurements" />
+		<mapping from="sq_c_outlier" to="SQOutliers" />
+		<mapping from="sq_c_curve" to="SQCurve" />
+		<mapping from="sq_c_outlier_curve" to="SQCurve" />
+		<mapping from="sq_c_outlier_measurement" to="SQMeasurements" />
+		<mapping from="sq_d_measurement" to="SQMeasurements" />
+		<mapping from="sq_d_outlier" to="SQOutliers" />
+		<mapping from="sq_d_curve" to="SQCurve" />
+		<mapping from="sq_d_outlier_curve" to="SQCurve" />
+		<mapping from="sq_d_outlier_measurement" to="SQMeasurements" />
+		<mapping from="sq_e_measurement" to="SQMeasurements" />
+		<mapping from="sq_e_outlier" to="SQOutliers" />
+		<mapping from="sq_e_curve" to="SQCurve" />
+		<mapping from="sq_e_outlier_curve" to="SQCurve" />
+		<mapping from="sq_e_outlier_measurement" to="SQMeasurements" />
+		<mapping from="sq_f_measurement" to="SQMeasurements" />
+		<mapping from="sq_f_outlier" to="SQOutliers" />
+		<mapping from="sq_f_curve" to="SQCurve" />
+		<mapping from="sq_f_outlier_curve" to="SQCurve" />
+		<mapping from="sq_f_outlier_measurement" to="SQMeasurements" />
+		<mapping from="fix_sector_average_wq_0" to="FixingSectorAverageWQ0" />
+		<mapping from="fix_sector_average_wq_1" to="FixingSectorAverageWQ1" />
+		<mapping from="fix_sector_average_wq_2" to="FixingSectorAverageWQ2" />
+		<mapping from="fix_sector_average_wq_3" to="FixingSectorAverageWQ3" />
+		<mapping from="fix_analysis_events_wq" to="FixingAnalysisEventsWQ" />
+		<mapping from="fix_outlier" to="FixingOutlier" />
+		<mapping from="fix_wq_curve" to="FixingWQCurve" />
+		<mapping from="fix_reference_events_wq" to="FixingReferenceEvents" />
+		<mapping from="fix_sector_average_dwt_0" to="FixingDeltaWtAverage0" />
+		<mapping from="fix_sector_average_dwt_1" to="FixingDeltaWtAverage1" />
+		<mapping from="fix_sector_average_dwt_2" to="FixingDeltaWtAverage2" />
+		<mapping from="fix_sector_average_dwt_3" to="FixingDeltaWtAverage3" />
+		<mapping from="fix_analysis_events_dwt" to="FixingDeltaWtAnalysis" />
+		<mapping from="fix_analysis_periods_dwt" to="FixingDeltaWtAnalysisPeriods" />
+		<mapping from="fix_reference_events_dwt" to="FixingReferenceEvents" />
+        <mapping from="fix_reference_period_dwt" to="FixingReferencePeriod" />
+		<mapping from="fix_sector_average_ls_deviation_0" to="FixingSectorDeviationLS0" />
+		<mapping from="fix_sector_average_ls_deviation_1" to="FixingSectorDeviationLS1" />
+		<mapping from="fix_sector_average_ls_deviation_2" to="FixingSectorDeviationLS2" />
+		<mapping from="fix_sector_average_ls_deviation_3" to="FixingSectorDeviationLS3" />
+		<mapping from="fix_sector_average_ls_0" to="FixingLSAverage0" />
+		<mapping from="fix_sector_average_ls_1" to="FixingLSAverage1" />
+		<mapping from="fix_sector_average_ls_2" to="FixingLSAverage2" />
+		<mapping from="fix_sector_average_ls_3" to="FixingLSAverage3" />
+		<mapping from="fix_deviation_ls" to="FixLSDeviation" />
+		<mapping from="fix_deviation_dwt" to="FixDeltaWtDeviation" />
+		<mapping from="fix_analysis_events_ls" to="FixLSAnalysis" />
+		<mapping from="fix_reference_events_ls" to="FixLSReference" />
+		<mapping from="fix_derivate_curve" to="FixingDerivedCurve" />
+		<mapping from="fix_derivate_curve.manualpoints" to="ManualPoints" />
+		<mapping from="qsectors" to="QSectors" />
+	</mappings>
 </themes>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/conf/virtual-themes.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<themegroup name="virtual">
+    <!-- Virtual themes are following now! DO NOT USE VIRTUAL THEMES FOR
+        FACETS! Please implement concrete themes! -->
+    <theme name="Lines" type="virtual">
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="true" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" />
+            <field name="linetype" type="Dash" display="Linienart"
+                default="10" />
+            <field name="showlinelabel" type="boolean"
+                display="Beschriftung anzeigen" default="false" hints="h" />
+            <field name="labelfontface" type="Font"
+                display="Beschriftung: Schriftart" default="arial" />
+            <field name="labelfontcolor" type="Color"
+                display="Beschriftung: Schriftfarbe" default="0, 0, 0" />
+            <field name="labelfontsize" type="int"
+                display="Beschriftung: Schriftgröße" default="10" />
+            <field name="labelfontstyle" type="Style"
+                display="Beschriftung: Schriftstil" default="standard" />
+            <field name="labelbgcolor" type="Color"
+                display="Beschriftung: Hintergrundfarbe" default="0, 0, 0" />
+            <field name="labelshowbg" type="boolean"
+                display="Beschriftung: Hintergrund füllen" default="false" />
+            <!--orientation? -->
+        </fields>
+    </theme>
+
+    <theme name="Points" type="virtual">
+        <fields>
+            <field name="showlinelabel" type="boolean"
+                display="Linienbeschriftung anzeigen" default="false" />
+            <field name="showpointlabel" type="boolean"
+                display="Punktbeschriftung anzeigen" default="false"/>
+            <field name="showlines" type="boolean" default="false" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" />
+            <field name="linetype" type="Dash" display="Linienart"
+                default="10" />
+            <field name="showpoints" type="boolean" display="Punkte anzeigen"
+                default="true" />
+            <field name="textorientation" type="boolean" display="Text horizontal"
+                default="true"/>
+            <field name="labelfontface" type="Font" default="Arial"
+                display="Beschriftung: Schriftart" />
+            <field name="labelfontcolor" type="Color" default="Color.BLACK"
+                display="Beschriftung: Schriftfarbe" />
+            <field name="labelfontsize" type="int"
+                display="Beschriftung: Schriftgröße" default="10" />
+            <field name="labelshowbg" type="boolean" default="false"
+                display="Beschriftung: Hintergrund anzeigen" />
+            <field name="labelbgcolor" type="Color" default="Color.WHITE"
+                display="Beschriftung: Hintergrundfarbe" />
+        </fields>
+    </theme>
+
+    <theme name="ColorLines" type="virtual">
+        <inherits>
+            <inherit from="Lines" />
+        </inherits>
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="Color.BLACK" />
+        </fields>
+    </theme>
+
+    <theme name="HiddenColorLines" type="virtual">
+        <inherits>
+            <inherit from="ColorLines" />
+        </inherits>
+        <fields>
+            <field name="showlines" type="boolean" display="Linie anzeigen"
+                default="true" hints="h" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+            <field name="linetype" type="Dash" display="Linienart"
+                default="10" hints="h" />
+            <field name="showpoints" type="boolean" display="Datenpunkte anzeigen"
+                default="false" hints="h" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="5" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="ColorPoints" type="virtual">
+        <inherits>
+            <inherit from="Points" />
+        </inherits>
+        <fields>
+            <field name="showpoints" type="boolean" display="Datenpunkte anzeigen"
+                default="true" />
+            <field name="pointsize" type="int" display="Punktdicke"
+                default="5" />
+            <field name="pointcolor" type="Color" display="Punktfarbe"
+                default="Color.BLACK" />
+        </fields>
+    </theme>
+
+    <theme name="MinMaxPoints" type="virtual">
+        <fields>
+            <field name="showminimum" type="boolean" display="Minimum anzeigen"
+                default="false" hints="h" />
+            <field name="showmaximum" type="boolean" display="Minimum anzeigen"
+                default="false" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="Text" type="virtual">
+        <fields>
+            <field name="font" type="Font" display="Schriftart"
+                default="arial" />
+            <field name="textcolor" type="Color" display="Schriftfarbe"
+                default="0, 0, 0" />
+            <field name="textsize" type="int" display="Schriftgröße"
+                default="10" />
+            <field name="textstyle" type="Style" display="Schriftstil"
+                default="standard" />
+        </fields>
+    </theme>
+
+    <theme name="AnnotationText" type="virtual">
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Texthintergrund"
+                default="255, 255, 255" />
+            <field name="textorientation" type="boolean" display="Textausrichtung"
+                default="false" />
+            <field name="showbackground" type="boolean"
+                display="Hintergrund anzeigen" default="false" />
+        </fields>
+    </theme>
+
+    <!-- Area relevant theme(s) -->
+    <theme name="Areas">
+        <fields>
+            <field name="backgroundcolor" type="Color" display="Füllfarbe"
+                default="0, 100, 0" />
+            <!-- <field name="showbackground" type="boolean"
+                display="Hintergrund anzeigen" default="true" hidden="true" /> //-->
+            <!-- <field name="showborder" type="boolean"
+                display="Flaechebegrenzungslinie anzeigen" default="false" /> //-->
+            <field name="transparency" type="int" default="50" display="Transparenz" />
+        </fields>
+    </theme>
+
+
+    <!-- MAP relevant themes -->
+    <theme name="WSPLGENS" type="virtual">
+        <fields>
+            <field name="wsplgen_cat1" type="Color" display="Hintergrund"
+                default="178, 201, 215" />
+            <field name="wsplgen_cat2" type="Color" display="Hintergrund"
+                default="111, 147, 170" />
+            <field name="wsplgen_cat3" type="Color" display="Hintergrund"
+                default="66, 111, 139" />
+            <field name="wsplgen_cat4" type="Color" display="Hintergrund"
+                default="33, 79, 108" />
+            <field name="wsplgen_cat5" type="Color" display="Hintergrund"
+                default="2, 27, 42" />
+        </fields>
+    </theme>
+
+    <theme name="RiverAxes" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 205" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="Km" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="5" hints="h" />
+            <field name="textcolor" type="Color" display="Schriftfarbe"
+                default="0, 0, 0" />
+            <field name="textsize" type="int" display="Schriftgröße"
+                default="10" />
+            <field name="symbol" type="Symbol" display="Symbol"
+                default="square" />
+        </fields>
+    </theme>
+
+    <theme name="Fixpoint" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" hints="h" />
+            <field name="symbol" type="Symbol" display="Symbol"
+                default="point" />
+        </fields>
+    </theme>
+
+    <theme name="Floodmap" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+            <field name="backgroundcolor" type="Color" display="Hintergrund"
+                default="140, 200, 130" />
+        </fields>
+    </theme>
+
+    <theme name="GaugeLocations" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+            <field name="symbol" type="Symbol" display="Symbol"
+                default="point" />
+        </fields>
+    </theme>
+
+    <theme name="Qp" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 255" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="Hw" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="Catchments" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+            <field name="backgroundcolor" type="Color" display="Hintergrund"
+                default="140, 200, 130" />
+        </fields>
+    </theme>
+
+    <theme name="Floodplain" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="0, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="1" hints="h" />
+            <field name="backgroundcolor" type="Color" display="Hintergrund"
+                default="140, 200, 130" />
+        </fields>
+    </theme>
+
+    <theme name="FloodmapLine" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="140, 200, 130" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="3" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="Building" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="5" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="HydrBoundariesLine" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="5" hints="h" />
+        </fields>
+    </theme>
+
+    <theme name="HydrBoundariesPoly" type="virtual">
+        <fields>
+            <field name="linecolor" type="Color" display="Linienfarbe"
+                default="255, 0, 0" />
+            <field name="linesize" type="int" display="Liniendicke"
+                default="5" hints="h" />
+            <field name="backgroundcolor" type="Color" display="Hintergrund"
+                default="140, 200, 130" />
+        </fields>
+    </theme>
+
+</themegroup>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/datacage-config-manual/Makefile	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,3492 @@
+# Copyright 2004 Chris Monson (shiblon@gmail.com)
+# Latest version available at http://www.bouncingchairs.net/oss
+#
+#    This file is part of ``Chris Monson's Free Software''.
+#
+#    ``Chris Monson's Free Software'' is free software; you can redistribute it
+#    and/or modify it under the terms of the GNU General Public License as
+#    published by the Free Software Foundation, Version 2.
+#
+#    ``Chris Monson's Free Software'' is distributed in the hope that it will
+#    be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+#    Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License along
+#    with ``Chris Monson's Free Software''; if not, write to the Free Software
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+#    It is also available on the web at http://www.gnu.org/copyleft/gpl.html
+#
+#    Note that using this makefile to build your documents does NOT place them
+#    under the GPL unless you, the author, specifically do so.  In other words,
+#    I, Chris Monson, the copyright holder and author of this makefile,
+#    consider it impossible to ``link'' to this makefile in any way covered by
+#    the GPL.
+#
+# TO OBTAIN INSTRUCTIONS FOR USING THIS FILE, RUN:
+#    make help
+#
+fileinfo	:= LaTeX Makefile
+author		:= Chris Monson
+version		:= 2.2.0-rc1
+#
+# Note that the user-global version is imported *after* the source directory,
+# so that you can use stuff like ?= to get proper override behavior.
+.PHONY: Makefile GNUmakefile Makefile.ini $(HOME)/.latex-makefile/Makefile.ini
+-include Makefile.ini
+-include $(HOME)/.latex-makefile/Makefile.ini
+#
+# This can be pdflatex or latex - you can change this by adding the following line to your Makefile.ini:
+# BUILD_STRATEGY := latex
+BUILD_STRATEGY		?= pdflatex
+#
+# Sets LC_ALL=C, by default, so that the locale-aware tools, like sort, be
+# # immune to changes to the locale in the user environment.
+export LC_ALL		?= C
+#
+#
+# If you specify sources here, all other files with the same suffix
+# will be treated as if they were _include_ files.
+#onlysources.tex	?= main.tex
+#onlysources.tex.sh	?=
+#onlysources.tex.pl	?=
+#onlysources.tex.py	?=
+#onlysources.rst	?=
+#onlysources.fig	?=
+#onlysources.gpi	?=
+#onlysources.dot	?=
+#onlysources.xvg	?=
+#onlysources.svg	?=
+#onlysources.eps.gz	?=
+#onlysources.eps	?=
+#
+# If you list files here, they will be treated as _include_ files
+#includes.tex		?= file1.tex file2.tex
+#includes.tex.sh	?=
+#includes.tex.pl	?=
+#includes.tex.py	?=
+#includes.rst		?=
+#includes.fig		?=
+#includes.gpi		?=
+#includes.dot		?=
+#includes.xvg		?=
+#includes.svg		?=
+#includes.eps.gz	?=
+#includes.eps		?=
+#
+# If you list files or wildcards here, they will *not* be cleaned - default is
+# to allow everything to be cleaned.
+#neverclean		?= *.pdf
+#
+# Alternatively (recommended), you can add those lines to a Makefile.ini file
+# and it will get picked up automatically without your having to edit this
+# Makefile.
+#
+# KNOWN ISSUES:
+#	* The following occurs:
+#		file with: \usepackage{named}\bibliographystyle{named}
+#		Compile
+#		change to: \usepackage{apalike}\bibliographystyle{apalike}
+#		Compile again -- BARF!
+#
+#		The workaround: make clean-nographics; make
+#
+#		Note that we may not be able to fix this.  LaTeX itself barfs
+#		on this, not the makefile.  The very first invocation of LaTeX
+#		(when something like this has happened) reads the existing .aux
+#		file and discovers invalid commands like \citeauthoryear that
+#		are only valid in the package that was just removed.  It then
+#		tries to parse them and explodes.  It's not at all clear to me
+#		how to fix this.  I tried removing the .aux files on the first
+#		run of LaTeX, but that necessarily requires more subsequent
+#		rebuilds on common edits.  There does not appear to be a
+#		graceful solution to this issue.
+#
+# CHANGES:
+# Chris Monson (2010-04-08):
+# 	* Bumped version to 2.2.0-rc1
+# 	* Added back in the rst_style_file stuff that got broken when switching
+# 		rst -> tex to use the script mechanism
+# Chris Monson (2010-03-23):
+#	* Bumped version to 2.2.0-beta8
+#	* Work on issue 76: bad backtick escape for some sed versions, failure
+#		to clear out the hold buffer when outputting MISSING comment.
+#		- Backed out 2>&1 to &> (doesn't work in sh)
+#		- Backed out using . to source variables
+# Chris Monson (2010-03-22):
+# 	* Bumped version to 2.2.0-beta7
+# 	* Issue 72: Fix latex/bibtex invocation order for annotated bib styles
+# 	* Fixed informational output to reflect which LaTeX run we're on
+# 	* Fixed graphic detection to include graphics that are already there in
+# 		.d files
+# 	* Tightened up the .d file output to only make .d depend on graphic
+# 		*source* files.  This means that building foo.d no longer
+# 		builds all of the graphics files on which foo.tex depends.
+# 		Had to use .SECONDEXPANSION trickery to make it work.
+# 	* Changed get-graphics to only accept a stem.
+# 	* Fixed build-once logic for scripted .tex to work better
+# 	* Made get-inputs sed script more maintainable.
+# 	* Moved Makefile.ini import up higher.
+# 	* Changed bare stems to not recursively invoke make
+# 	* Updated diff output to be more silent everywhere
+# 	* Added a MISSING comment to the .d file if stuff isn't found - forces
+# 		removal of .1st.make file, which often forces it to try again.
+# 	* Fixed broken graphics-target function
+# 	* Added sleep to .d file generation when stuff is missing - if it
+# 		builds too fast, make doesn't realize it needs to be reloaded,
+# 		and thus never discovers some deeper dependencies (especially
+# 		evident when graphics are included from scripted include
+# 		files).
+# Chris Monson (2010-03-17):
+# 	* Bumped version to 2.2.0-beta6
+# 	* Fixed bareword builds to actually work (requires static patterns)
+# 	* Fixed colorization to work with new paragraph stuff
+# Chris Monson (2010-03-17):
+# 	* Bumped version to 2.2.0-beta5
+# 	* Fixed graphic detection to be much more focused - splits log file
+# 		into paragraphs before doing pattern matching.
+# 	* Fixed make foo to work properly (recursively calls make foo.pdf)
+# 	* Fixed gpi -> pdf generation to not waste time building .eps *after*
+# 		the pdf already exists.
+# 	* Changed log copies to include MAKE_RESTARTS as part of the name.
+# 	* Fixed missing include file detection (also makes use of the paragraph
+# 		stuff) to detect missing scripted include files.
+# Chris Monson (2010-03-16):
+# 	* Bumped version to 2.2.0-beta4
+# 	* issue 70: .pdf not moved out of the way properly on first
+# 		compilation, resulting in early error detection failure.
+# 	* issue 74: fixed broken error on missing .aux files: the
+# 		implementation was masking real errors.
+# Chris Monson (2010-03-15):
+# 	* Bumped version to 2.2.0-beta3
+# 	* issue 71: Made the tput dependency optional
+# 	* issue 73: Made .tex targets not pull in .d files (building them from
+# 		scripts should not require a .d)
+# 	* issue 74: Output a much saner error when a .aux file is not produced
+# 		(e.g., when you are typing "make" without arguments in a
+# 		directory with included .tex files that are not named with
+# 		._include_.)
+# Chris Monson (2010-03-11):
+# 	* Bumped version to 2.2.0-beta2
+# 	* Fixed clean-graphics to get rid of intermediate .eps files that may
+# 		be hanging around
+# 	* Added an automatic setting to use eps terminals in pdflatex mode for
+# 		gnuplot if it doesn't understand pdf.
+# 	* issue 66: Removed grayscale generation via magic suffix.  Grayscale
+# 		generation is now only available via GRAY=1
+# 	* issue 68: Added explicit handling of LC_ALL for locale-aware tools
+# 		like "sort"
+# Chris Monson (2010-03-10):
+# 	* Bumped version to 2.2.0-beta1
+# 	* Fixed success message to handle output message in different places
+# 	* Added name of produced file to success message
+# Chris Monson (2010-03-10):
+# 	* Bumped version to 2.2.0-alpha3
+# 	* Added meaningful error message for wrong hyperref options
+# 	* Added meaningful error message for incorrect graphics extensions
+# Chris Monson (2010-03-09):
+# 	* Bumped version to 2.2.0-alpha2
+# 	* Updated graphics handling (gnuplot and fig generate pdf natively)
+# 	* Changed xmgrace to output monochrome natively
+# Chris Monson (2010-03-09):
+# 	* Bumped version to 2.2.0-alpha1 - major change!
+# 	* Support pdflatex natively and by default (issue 6 - a long time coming)
+# 	* Add ability to have a single $HOME/.latex-makefile/Makefile.ini for
+# 		all invocations
+# 	* Reworked graphic inclusion detection so that extensions need not be
+# 		specified for either build strategy (e.g.,
+# 		\includegraphics{test1.eps} -> \includegrahpics{test1})
+# 	* Changed log format to include filenames and line numbers
+# Chris Monson (2010-02-04):
+# 	* Bumped version to 2.1.43
+# 	* All of the following are for issue 63 (thanks to mojoh81):
+# 	* Added documentation about fixing Makefile.ini default target
+# 	* Added perl and python script targets
+# 	* Fixed run logic to allow included .tex files to be scripted (the
+# 		run-again logic now detects missing .tex files, and the MV
+# 		command has been switched out for a command that only invokes
+# 		MV if the files exist)
+# 	* Changed scripted generation to only run once per make invocation
+# 	* Added dependency on expr
+# Chris Monson (2010-01-19):
+# 	* Bumped version to 2.1.42
+# 	* issue 62: Added .brf extension to cleanable files (backrefs)
+# Chris Monson (2010-01-07):
+# 	* Bumped version to 2.1.41
+# 	* issue 60: bad makeindex runs now error out on subsequent tries
+# Chris Monson (2009-12-01):
+# 	* Bumped version to 2.1.40
+# 	* issue 36: build all indices (for e.g., splitidx usage)
+# 	* issue 59: clean up all generated files (including indices)
+# Chris Monson (2009-11-23):
+# 	* Bumped version to 2.1.39
+# 	* issue 57: change ps2pdf invocations to just use gs directly
+# Chris Monson (2009-11-19):
+# 	* Bumped version to 2.1.38
+# 	* issue 57: Added some limited support for Cygwin (spaces in filenames)
+# Chris Monson (2009-11-15):
+# 	* Bumped version to 2.1.37
+# 	* Removed svninfo, since this is now managed by mercurial
+# 	* Fixed typo in changelist
+# 	* Issue 52: added jpg->eps conversion (thanks to brubakee)
+# 	* Issue 54: fix missing Overfull colorization due to lack of a blank
+# 		line preceding the first error.
+#	* Issue 51: remove head.tmp and body.tmp in make clean invocation
+#	* Issue 56: maintain multiple versions of log files (for debugging)
+# Chris Monson (2009-11-14):
+# 	* Bumped version to 2.1.36
+# 	* Issues 53 and 49: added .brf, .mtc, and .maf to the cleanables
+# Chris Monson (2009-11-05):
+# 	* Bumped version to 2.1.35
+# 	* Added nomenclature support (see issue 48)
+# Chris Monson (2009-10-29):
+# 	* Bumped version to 2.1.34
+# 	* Fixed _out_ creation bug introduced in 2.1.33 (it was always created)
+# 	* Fixed erroneous help output for $HOME in BINARY_TARGET_DIR
+# 	* Changed contact email address - bring on the spam!
+# Chris Monson (2009-10-21):
+# 	* Bumped version to 2.1.33
+# 	* Fixed issue 46, adding support for dot2tex (thanks to fdemesmay)
+# 	* Made all_files.* settable in Makefile.ini (using ?= instead of :=)
+# 	* Fixed issue 47, thanks to fdemesmay: add binary copy directory, copy
+# 		dvi, pdf, and ps if it exists
+# Chris Monson (2009-09-25):
+# 	* Bumped version to 2.1.32
+# 	* Fixed so that a changed lol file will cause a rebuild
+# 	* Added .lol files to the cleanable list
+# Chris Monson (2009-09-08):
+# 	* Bumped version to 2.1.31
+# 	* Closed issue 43: evince doesn't notice pdf change w/out touch
+# Chris Monson (2009-08-28):
+# 	* Bumped version to 2.1.30
+# 	* Closed issue 39: Capture multi-line log warnings/errors to output
+# Chris Monson (2009-08-26):
+# 	* Bumped version to 2.1.29
+# 	* Closed issue 42: add svg support using inkscape
+# Chris Monson (2009-08-17):
+# 	* Bumped version to 2.1.28
+# 	* Patch from paul.biggar for issue 38: package warnings are overlooked
+# Chris Monson (2009-08-07):
+# 	* Bumped version to 2.1.27
+# 	* Included patch for issue 37 - removes pdf/ps files before copying,
+# 		allowing some broken viewers to see changes properly.
+# Chris Monson (2009-05-15):
+# 	* Bumped version to 2.1.26
+# 	* Included patch for issue 9 from favonia - detects .fig changes for
+# 		pstex files during regular compilation, so long as the pstex
+# 		has been built at least once with make all-pstex.
+# Chris Monson (2009-03-27):
+# 	* Bumped version to 2.1.25
+# 	* Cleaned up a bunch of variable setting stuff - more stuff is now
+# 		settable from Makefile.ini
+# 	* Cleaned up documentation for various features, especially settable
+# 		variables.
+# 	* issue 28: support for png -> eps conversion (it even looks good!)
+# 	* issue 29: support for "neverclean" files in Makefile.ini
+# 	* issue 30: make ps2pdf14 the default - fall back when not there
+# Chris Monson (2009-03-09):
+# 	* Bumped version to 2.1.24
+# 	* issue 27: xmgrace support (thanks to rolandschulzhd)
+# Chris Monson (2008-10-23):
+# 	* Bumped version to 2.1.23
+# 	* issue 23: fixed _check_programs to not use bash string subs
+# Chris Monson (2008-09-02):
+# 	* Bumped version to 2.1.22
+# 	* Appled patch from Holger <yllohy@googlemail.com> to add include
+# 		sources and some documentation updates.
+# 	* Updated backup_patterns to be a bit more aggressive (also thanks to
+# 		Holger)
+# Chris Monson (2008-08-30):
+# 	* Bumped version to 2.1.21
+# 	* Added ability to specify onlysources.* variables to indicate the only
+# 		files that should *not* be considered includes.  Thanks to Holger
+# 		<yllohy@googlemail.com> for this patch.
+# 	* Added an automatic include of Makefile.ini if it exists.  Allows
+# 		settings to be made outside of this makefile.
+# Chris Monson (2008-05-21):
+# 	* Bumped version to 2.1.20
+# 	* Added manual pstex compilation support (run make all-pstex first)
+# 	* Removed all automatic pstex support.  It was totally breaking
+# 		everything and is very hard to incorporate into the makefile
+# 		concept because it requires LaTeX to *fail* before it can
+# 		determine that it needs the files.
+# Chris Monson (2008-04-17):
+# 	* Bumped version to 2.1.19
+# 	* Changed the pstex build hack to be on by default
+# Chris Monson (2008-04-09):
+# 	* Bumped version to 2.1.18
+# 	* issue 16: fixed pstex build problems, seems nondeterministic.  Added
+# 		gratuitious hack for testing: set PSTEX_BUILD_ALL_HACK=1.
+# Chris Monson (2008-04-09):
+# 	* Bumped version to 2.1.17
+# 	* issue 20: fixed accumulation of <pid>*.make files - wildcard was
+#		refusing to work on files that are very recently created.
+# Chris Monson (2008-04-02):
+# 	* Bumped version to 2.1.16
+# 	* issue 19: Removed the use of "type" to fix broken "echo" settings
+# Chris Monson (2008-03-27):
+# 	* Bumped version to 2.1.15
+# 	* issue 18: Favors binary echo over builtin, as binary understands -n
+# 	* issue 16: Fixed handling of missing pstex_t files in the log
+# 	* issue 9: Added .SECONDARY target for .pstex files
+# Chris Monson (2008-03-21):
+# 	* Bumped version to 2.1.14
+# 	* Fixed broken aux file flattening, which caused included bibs to be
+# 		missed.
+# Chris Monson (2008-03-20):
+# 	* Bumped version to 2.1.13
+# 	* Changed error output colorization to show errors for missing files
+# 		that are not graphics files.
+# Chris Monson (2008-03-20):
+# 	* Bumped version to 2.1.12
+# 	* Fixed a regression introduced in r28 that makes bibtex fail when
+# 		there is no index file present
+# Chris Monson (2008-03-03):
+# 	* Bumped version to 2.1.11
+# 	* Fixed issue 11 (handle index files, reported by abachn)
+# 	* Cleaned up some comments and help text
+# Chris Monson (2008-01-24):
+# 	* Bumped version to 2.1.10
+#	* Fixed to work when 'sh' is a POSIX shell like 'dash'
+# Chris Monson (2007-12-12):
+# 	* Bumped version to 2.1.9
+# 	* Fixed documentation and dependency graph for pstex files
+# Chris Monson (2007-12-12):
+# 	* Bumped version to 2.1.8
+# 	* Added basic pstex_t support for fig files (Issue 9 by favonia)
+# 		I still suggest that psfrag be used instead.
+# Chris Monson (2007-10-16):
+# 	* Bumped version to 2.1.7
+# 	* Removed todo item: allow other comment directives for rst conversion
+# 	* Added ability to use global rst style file _rststyle_._include_.tex
+# 	* Added help text to that effect
+# Chris Monson (2007-05-20):
+# 	* Bumped version to 2.1.6
+# 	* Changed default paper size for rst files
+# 	* Added todo item: fix paper size for rst files
+# 	* Added todo item: allow other comment directives for rst conversion
+# Chris Monson (2007-04-02):
+# 	* Bumped version to 2.1.5
+# 	* Addressed Issue 7, incorrect .gpi.d generation in subdirectories
+# Chris Monson (2007-03-28):
+# 	* Bumped version to 2.1.4
+# 	* Fixed syntax error in dot output
+# Chris Monson (2007-03-01):
+# 	* Bumped version to 2.1.3
+# 	* Added reST to the included documentation
+# 	* Fixed graphics and script generation to be settable in the
+# 		environment.
+# Chris Monson (2007-02-23):
+# 	* Bumped version to 2.1.2
+# 	* Added the ability to generate .tex files from .rst files
+# Chris Monson (2006-10-17):
+# 	* Bumped version to 2.1.1
+# 	* Fixed includes from subdirectories (sed-to-sed slash escape problem)
+# Chris Monson (2006-10-05):
+# 	* Bumped version to 2.1.0 (pretty serious new feature added)
+# 	* New feature: bib files can now be anywhere on the BIBINPUTS path
+# 	* New programs: kpsewhich (with tetex) and xargs (BSD)
+# Chris Monson (2006-09-28):
+# 	* Bumped version to 2.0.9
+# 	* Added ability to parse more than one bibliography
+# Chris Monson (2006-06-01):
+# 	* Bumped version to 2.0.8
+# 	* Added .vrb to the list of cleaned files
+# Chris Monson (2006-04-26):
+# 	* Bumped version to 2.0.7
+# 	* Fixed so that clean-nographics does not remove .gpi.d files
+# 	* Removed jpg -> eps hack (not working properly -- just pre-convert)
+# 	* Fixed so that postscript grayscale can be done with BSD sed
+# Chris Monson (2006-04-25):
+# 	* Bumped version to 2.0.6
+# 	* Fixed so that changed toc, lot, lof, or out causes a rebuild
+# Chris Monson (2006-04-17):
+# 	* Bumped version to 2.0.5
+# 	* Added jpg -> eps conversion target
+# Chris Monson (2006-04-12):
+# 	* Bumped version to 2.0.4
+# 	* Fixed BSD sed invocation to not use \| as a branch delimiter
+# 	* Added a comment section on what is and is not allowed in BSD sed
+# 	* Made paper size handling more robust while I was at it
+# 	* Fixed postscript RGB grayscale to use a weighted average
+# 	* Fixed postscript HSB grayscale to convert to RGB first
+# 	* Fixed a problem with rebuilding .bbl files
+# Chris Monson (2006-04-11):
+# 	* Bumped version to 2.0.3
+# 	* Fixed some BSD sed problems: can't use \n in substitutions
+# Chris Monson (2006-04-10):
+# 	* Bumped version to 2.0.2
+# 	* Once again removed ability to create .tex files from scripts
+# 	* \includeonly works again
+# Chris Monson (2006-04-09):
+# 	* Bumped version to 2.0.1
+# 	* Fixed grayscale postscript handling to be more robust
+# 	* Added ability to generate ._gray_. files from eps and eps.gz
+# 	* Added ability to clean ._gray_.eps files created from .eps files
+# Chris Monson (2006-04-07):
+# 	* Bumped version to 2.0.0
+# 	* Removed clunky ability to create included .tex files from scripts
+# 	* Added note in the help about included tex scripting not working
+# 	* Fixed the .eps generation to delete %.gpihead.make when finished
+# 	* Abandoned designs to use shell variables to create sed scripts
+# 	* Abandoned __default__.tex.sh idea: it causes recursion with %: .
+# 	* Removed web page to-do.  All items are now complete.
+# 	* Added better grayscale conversion for dot figures (direct ps fixup).
+# 	* Include files can now be scripted (at the expense of \includeonly).
+# 	* Updated dependency graph to contain better node names.
+# Chris Monson (2006-04-06):
+# 	* Bumped version to 2.0b3
+# 	* Top level includes now fail if there is no rule to build them
+# 	* A helpful message is printed when they do fail
+# 	* Grayscale has been changed to be ._gray_, other phonies use _ now, too
+# 	* Grayscale handling has been completed
+# 	* Changed _include_stems target to _includes target.
+# 	* Fixed _includes target to be useful by itself.
+# 	* Removed the ability to specify clean and build targets at once
+# 	* Verified that epsfig works fine with current code
+# 	* Fixed included scripts so that they are added to the dep files
+# 	* Fixed so that graphics includes don't happen if they aren't for gpi
+# 	* Fixed dot output to allow grayscale.
+# Chris Monson (2006-04-05):
+#	* Bumped version to 2.0b2
+#	* Removed automatic -gray output.  It needs fixing in a bad way.
+#	* Revamped dependency creation completely.
+#	* Fixed conditional inclusion to actually work (test.nobuild.d, test.d).
+#	* Fixed clean target to remove log targets
+#	* Added the 'monochrome' word for gray gpi output
+#	* Added a _check_gpi_files target that checks for common problems
+#	* Changed the _version target into the version target (no _)
+#	* Added better handling of grayscale files.  Use the .gray.pdf target.
+#	* Fixed testing for rebuilds
+# Chris Monson (2006-04-04):
+#	* Bumped version to 2.0b1
+#	* Changed colorization of output
+#	* Made .auxbbl and .auxtex .make files secondary targets
+#	* Shortened and simplified the final latex invocation loop
+#	* Added version-specific output ($$i vs. $$$$i) in latex loop
+#	* Added a build message for the first .dvi run (Building .dvi (0))
+#	* Removed some build messages that most people don't care about.
+#	* Simplified procedure for user-set colors -- simple text specification
+#	* Fixed diff output to...not output.
+#	* Fixed rerun bug -- detect not only when preceded with LaTeX Warning
+#	* Sped up gpi plotting
+#	* Added error handling and colorized output for gpi failure
+#	* Documented color changing stuff.
+#	* Now sort the flattened aux file to avoid false recompilation needs
+#	* Added clean-nographics target
+#	* Don't remove self.dvi file if self.aux is missing in the log
+#	* Clarified some code.  Did some very minor adjusting.
+# Chris Monson (2006-04-03):
+#	* Bumped version to 2.0a7
+#	* Added .dvi and .ps files as secondary files.
+#	* Fixed handling of multiple run detection when includeonly is in use.
+#	* Added code to flatten .aux files.
+#	* Added more files as .SECONDARY prerequisites to avoid recompilation.
+#	* Fixed the inputs generation to be much simpler and to use pipes.
+#	* Added the dependency graph directly into the makefile.
+#	* Changed flatten-aux to remove \@writefile \relax \newlabel, etc.
+#	* Undid pipe changes with sed usage (BSD sed doesn't know -f-).
+#	* Added a _check_programs target that tells you what your system has.
+#	* Fixed an error in colorization that made unnecessary errors appear
+#	* Added view targets.
+#	* Updated help text.
+#	* Augmented cookies so that .aux can trigger .bbl and .dvi rebuilds
+#	* Added more informative error handling for dvips and ps2pdf
+# Chris Monson (2006-04-02):
+#	* Bumped version to 2.0a6
+#	* Added indirection to .bbl dependencies to avoid rebuilding .bbl files
+#	* Streamlined the diff invocation to eliminate an existence test
+#	* Removed special shell quote escape variables
+#	* Moved includes to a more prominent location
+#	* Fixed .inputs.make to not contain .aux files
+#	* Fixed embedding to use a file instead of always grepping.
+#	* Added *.make.temp to the list of cleanable files
+#	* Fixed Ruby.  It should now be supported properly.
+#	* Now differentiate between all, default, and buildable files.
+#	* Fixed to bail out on serious errors.
+#	* Revised the handling of includable files.  Still working on it.
+# Chris Monson (2006-03-31):
+#	* Bumped version to 2.0a5
+#	* Fixed a bug with LaTeX error detection (there can be spaces)
+#	* Added .bbl support, simplifying everything and making it more correct
+#	* Refactored some tests that muddy the code
+#	* Did a little cleanup of some shell loops that can safely be make loops
+#	* Added support for graphviz .dot files
+#	* Made _all_programs output easier to read
+#	* Added the ruby support that has long been advertised
+#	* Font embedding was screwed up for PostScript -- now implicit
+#	* Changed the generation of -gray.gpi files to a single command
+#	* Changed any make-generated file that is not included from .d to .make
+# Chris Monson (2006-03-30):
+#	* Bumped version to 2.0a4
+#	* Fixed a bug with very long graphics file names
+#	* Added a todo entry for epsfig support
+#	* Fixed a bug paper size bug: sometimes more than one entry appears
+#	* Fixed DVI build echoing to display the number instead of process ID
+#	* DVI files are now removed on first invocation if ANY file is missing
+#	* Added a simple grayscale approach: if a file ends with -gray.gpi, it
+#		is created from the corresponding .gpi file with a special
+#		comment ##GRAY in its header, which causes coloring to be
+#		turned off.
+#	* Fixed a bug in the handling of .tex.sh files.  For some reason I had
+#		neglected to define file stems for scripted output.
+#	* Removed a trailing ; from the %.graphics dependencies
+#	* Added dvips embedding (I think it works, anyway)
+# Chris Monson (2006-03-29):
+#	* Bumped version to 2.0a3
+#	* Fixed error in make 3.79 with MAKEFILE_LIST usage
+#	* Added the presumed filename to the _version output
+#	* Added a vim macro for converting sed scripts to make commands
+#	* Added gpi dependency support (plotting external files and loading gpi)
+#	* Allow .gpi files to be ignored if called .include.gpi or .nobuild.gpi
+#	* Fixed sed invocations where \+ was used.  BSD sed uses \{1,\}.
+# Chris Monson (2006-03-28):
+#	* Bumped version to 2.0a2
+#	* Added SHELL_DEBUG and VERBOSE options
+#	* Changed the default shell back to /bin/sh (unset, in other words)
+#	* Moved .PHONY declarations closer to their targets
+#	* Moved help text into its own define block to obtain better formatting
+#	* Removed need for double-entry when adding a new program invocation
+#	* Moved .SECONDARY declaration closer to its relevant occurrence
+#	* Commented things more heavily
+#	* Added help text about setting terminal and output in gnuplot
+#	* Created more fine-grained clean targets
+#	* Added a %.graphics target that generates all of %'s graphics
+#	* Killed backward-compatible graphics generation (e.g., eps.gpi=gpi.eps)
+#	* For now, we're just GPL 2, not 3.  Maybe it will change later
+#	* Made the version and svninfo into variables
+# Chris Monson (2006-03-27):
+#	* Bumped version to 2.0a1
+#	* Huge, sweeping changes -- automatic dependencies
+
+# IMPORTANT!
+#
+# When adding to the following list, do not introduce any blank lines.  The
+# list is extracted for documentation using sed and is terminated by a blank
+# line.
+#
+# EXTERNAL PROGRAMS:
+# = ESSENTIAL PROGRAMS =
+# == Basic Shell Utilities ==
+CAT		?= cat
+CP		?= cp -f
+DIFF		?= diff
+ECHO		?= echo
+EGREP		?= egrep
+ENV		?= env
+EXPR		?= expr
+MV		?= mv -f
+SED		?= sed
+SORT		?= sort
+TOUCH		?= touch
+UNIQ		?= uniq
+WHICH		?= which
+XARGS		?= xargs
+SLEEP		?= sleep
+# == LaTeX (tetex-provided) ==
+BIBTEX		?= bibtex
+DVIPS		?= dvips
+LATEX		?= latex
+PDFLATEX	?= pdflatex
+EPSTOPDF	?= epstopdf
+MAKEINDEX	?= makeindex
+KPSEWHICH	?= kpsewhich
+GS		?= gs
+# = OPTIONAL PROGRAMS =
+# == Makefile Color Output ==
+TPUT		?= tput
+# == TeX Generation ==
+PERL		?= perl
+PYTHON		?= python
+RST2LATEX	?= rst2latex.py
+# == EPS Generation ==
+CONVERT		?= convert	# ImageMagick
+DOT		?= dot		# GraphViz
+DOT2TEX		?= dot2tex	# dot2tex - add options (not -o) as needed
+FIG2DEV		?= fig2dev	# XFig
+GNUPLOT		?= gnuplot	# GNUplot
+INKSCAPE	?= inkscape	# Inkscape (svg support)
+XMGRACE		?= xmgrace	# XMgrace
+PNGTOPNM	?= pngtopnm	# From NetPBM - step 1 for png -> eps
+PPMTOPGM	?= ppmtopgm	# From NetPBM - (gray) step 2 for png -> eps
+PNMTOPS		?= pnmtops	# From NetPBM - step 3 for png -> eps
+GUNZIP		?= gunzip	# GZipped EPS
+# == Beamer Enlarged Output ==
+PSNUP		?= psnup
+# == Viewing Stuff ==
+VIEW_POSTSCRIPT	?= gv
+VIEW_PDF	?= xpdf
+VIEW_GRAPHICS	?= display
+
+# Command options for embedding fonts and postscript->pdf conversion
+PS_EMBED_OPTIONS	?= -dPDFSETTINGS=/printer -dEmbedAllFonts=true -dSubsetFonts=true -dMaxSubsetPct=100
+PS_COMPATIBILITY	?= 1.4
+
+# Defaults for GPI
+DEFAULT_GPI_EPS_FONTSIZE	?= 22
+DEFAULT_GPI_PDF_FONTSIZE	?= 12
+
+# Style file for ReST
+RST_STYLE_FILE			?= $(wildcard _rststyle_._include_.tex)
+
+# This ensures that even when echo is a shell builtin, we still use the binary
+# (the builtin doesn't always understand -n)
+FIXED_ECHO	:= $(if $(findstring -n,$(shell $(ECHO) -n)),$(shell which echo),$(ECHO))
+ECHO		:= $(if $(FIXED_ECHO),$(FIXED_ECHO),$(ECHO))
+
+define determine-gnuplot-output-extension
+$(if $(shell $(WHICH) $(GNUPLOT)),
+     $(if $(findstring unknown or ambiguous, $(shell $(GNUPLOT) -e "set terminal pdf" 2>&1)),
+	  eps, pdf),
+     none)
+endef
+
+GNUPLOT_OUTPUT_EXTENSION	?= $(strip $(call determine-gnuplot-output-extension))
+
+# Directory into which we place "binaries" if it exists.
+# Note that this can be changed on the commandline or in Makefile.ini:
+#
+# Command line:
+#   make BINARY_TARGET_DIR=$HOME/pdfs myfile.pdf
+#
+# Also, you can specify a relative directory (relative to the Makefile):
+#   make BINARY_TARGET_DIR=pdfs myfile.pdf
+#
+# Or, you can use Makefile.ini:
+#
+#   BINARY_TARGET_DIR := $(HOME)/bin_out
+#
+BINARY_TARGET_DIR	?= _out_
+
+RESTARTS		:= $(if $(MAKE_RESTARTS),$(MAKE_RESTARTS),0)
+# SH NOTES
+#
+# On some systems, /bin/sh, which is the default shell, is not linked to
+# /bin/bash.  While bash is supposed to be sh-compatible when invoked as sh, it
+# just isn't.  This section details some of the things you have to stay away
+# from to remain sh-compatible.
+#
+#	* File pattern expansion does not work for {}
+#	* [ "$x" = "$y" ] has to be [ x"$x" x"$y" ]
+#	* &> for stderr redirection doesn't work, use 2>&1 instead
+#
+# BSD SED NOTES
+#
+# BSD SED is not very nice compared to GNU sed, but it is the most
+# commonly-invoked sed on Macs (being based on BSD), so we have to cater to
+# it or require people to install GNU sed.  It seems like the GNU
+# requirement isn't too bad since this makefile is really a GNU makefile,
+# but apparently GNU sed is much less common than GNU make in general, so
+# I'm supporting it here.
+#
+# Sad experience has taught me the following about BSD sed:
+#
+# 	* \+ is not understood to mean \{1,\}
+# 	* \| is meaningless (does not branch)
+# 	* \n cannot be used as a substitution character
+# 	* ? does not mean \{0,1\}, but is literal
+# 	* a\ works, but only reliably for a single line if subsequent lines
+# 		have forward slashes in them (as is the case in postscript)
+#
+# For more info (on the Mac) you can consult
+#
+# man -M /usr/share/man re_format
+#
+# And look for the word "Obsolete" near the bottom.
+
+#
+# EXTERNAL PROGRAM DOCUMENTATION SCRIPT
+#
+
+# $(call output-all-programs,[<output file>])
+define output-all-programs
+	[ -f '$(this_file)' ] && \
+	$(SED) \
+		-e '/^[[:space:]]*#[[:space:]]*EXTERNAL PROGRAMS:/,/^$$/!d' \
+		-e '/EXTERNAL PROGRAMS/d' \
+		-e '/^$$/d' \
+		-e '/^[[:space:]]*#/i\ '\
+		-e 's/^[[:space:]]*#[[:space:]][^=]*//' \
+		$(this_file) $(if $1,> '$1',) || \
+	$(ECHO) "Cannot determine the name of this makefile."
+endef
+
+# If they misspell gray, it should still work.
+GRAY	?= $(call get-default,$(GREY),)
+
+#
+# Utility Functions and Definitions
+#
+
+# While not exactly a make function, this vim macro is useful.  It takes a
+# verbatim sed script and converts each line to something suitable in a command
+# context.  Just paste the script's contents into the editor, yank this into a
+# register (starting at '0') and run the macro once for each line of the
+# original script:
+#
+# 0i	-e :s/\$/$$/eg
:s/'/'"'"'/eg
^Ela'A' \:noh
j
+
+# don't call this directly - it is here to avoid calling wildcard more than
+# once in remove-files.
+remove-files-helper	= $(if $1,$(RM) $1,$(sh_true))
+
+# $(call remove-files,file1 file2)
+remove-files		= $(call remove-files-helper,$(wildcard $1))
+
+# Removes all cleanable files in the given list
+# $(call clean-files,file1 file2 file3 ...)
+# Works exactly like remove-files, but filters out files in $(neverclean)
+clean-files		= \
+	$(call remove-files-helper,$(call cleanable-files,$(wildcard $1)))
+
+# Outputs all generated files to STDOUT, along with some others that are
+# created by these (e.g., .idx files end up producing .ilg and .ind files).
+# Discovered by reading *.fls OUTPUT lines and producing corresponding .ind
+# filenames as needed.
+#
+# $(call get-generated-names,<source recorder file (*.fls)>)
+define get-generated-names
+[ -f '$1' ] && \
+$(SED) \
+	-e '/^OUTPUT /{' \
+	-e '  s///' \
+	-e '  p' \
+	-e '  s/\.idx/\.ind/p' \
+	-e '  s/\.ind/\.ilg/p' \
+	-e '}' \
+	-e 'd' \
+	'$1' \
+| $(SORT) | $(UNIQ)
+endef
+
+# This removes files without checking whether they are there or not.  This
+# sometimes has to be used when the file is created by a series of shell
+# commands, but there ends up being a race condition: make doesn't know about
+# the file generation as quickly as the system does, so $(wildcard ...) doesn't
+# work right.  Blech.
+# $(call remove-temporary-files,filenames)
+remove-temporary-files	= $(if $1,$(RM) $1,:)
+
+# Create an identifier from a file name
+# $(call cleanse-filename,filename)
+cleanse-filename	= $(subst .,_,$(subst /,__,$1))
+
+# Escape dots
+# $(call escape-dots,str)
+escape-dots		= $(subst .,\\.,$1)
+
+# Test that a file exists
+# $(call test-exists,file)
+test-exists		= [ -e '$1' ]
+
+# $(call move-files,source,destination)
+move-if-exists		= $(call test-exists,$1) && $(MV) '$1' '$2'
+
+# Copy file1 to file2 only if file2 doesn't exist or they are different
+# $(call copy-if-different,sfile,dfile)
+copy-if-different	= $(call test-different,$1,$2) && $(CP) '$1' '$2'
+copy-if-exists		= $(call test-exists,$1) && $(CP) '$1' '$2'
+move-if-different	= $(call test-different,$1,$2) && $(MV) '$1' '$2'
+replace-if-different-and-remove	= \
+	$(call test-different,$1,$2) \
+	&& $(MV) '$1' '$2' \
+	|| $(call remove-files,'$1')
+
+# Note that $(DIFF) returns success when the files are the SAME....
+# $(call test-different,sfile,dfile)
+test-different		= ! $(DIFF) -q '$1' '$2' >/dev/null 2>&1
+test-exists-and-different	= \
+	$(call test-exists,$2) && $(call test-different,$1,$2)
+
+# Return value 1, or value 2 if value 1 is empty
+# $(call get-default,<possibly empty arg>,<default value if empty>)
+get-default	= $(if $1,$1,$2)
+
+# Copy a file and log what's going on
+# $(call copy-with-logging,<source>,<target>)
+define copy-with-logging
+if [ -d '$2/' ]; then \
+	if $(CP) '$1' '$2/'; then \
+		$(ECHO) "$(C_INFO)Copied '$1' to '$2/'$(C_RESET)"; \
+	else \
+		$(ECHO) "$(C_ERROR)Failed to copy '$1' to '$2/'$(C_RESET)"; \
+	fi; \
+fi
+endef
+
+# Gives a reassuring message about the failure to find include files
+# $(call include-message,<list of include files>)
+define include-message
+$(strip \
+$(if $(filter-out $(wildcard $1),$1),\
+	$(shell $(ECHO) \
+	"$(C_INFO)NOTE: You may ignore warnings about the"\
+	"following files:" >&2;\
+	$(ECHO) >&2; \
+	$(foreach s,$(filter-out $(wildcard $1),$1),$(ECHO) '     $s' >&2;)\
+	$(ECHO) "$(C_RESET)" >&2)
+))
+endef
+# Characters that are hard to specify in certain places
+space		:= $(empty) $(empty)
+colon		:= \:
+comma		:= ,
+
+# Useful shell definitions
+sh_true		:= :
+sh_false	:= ! :
+
+# Clear out the standard interfering make suffixes
+.SUFFIXES:
+
+# Turn off forceful rm (RM is usually mapped to rm -f)
+ifdef SAFE_RM
+RM	:= rm
+endif
+
+# Turn command echoing back on with VERBOSE=1
+ifndef VERBOSE
+QUIET	:= @
+endif
+
+# Turn on shell debugging with SHELL_DEBUG=1
+# (EVERYTHING is echoed, even $(shell ...) invocations)
+ifdef SHELL_DEBUG
+SHELL	+= -x
+endif
+
+# Get the name of this makefile (always right in 3.80, often right in 3.79)
+# This is only really used for documentation, so it isn't too serious.
+ifdef MAKEFILE_LIST
+this_file	:= $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
+else
+this_file	:= $(wildcard GNUmakefile makefile Makefile)
+endif
+
+# Terminal color definitions
+
+REAL_TPUT 	:= $(if $(NO_COLOR),,$(shell $(WHICH) $(TPUT)))
+
+# $(call get-term-code,codeinfo)
+# e.g.,
+# $(call get-term-code,setaf 0)
+get-term-code = $(if $(REAL_TPUT),$(shell $(REAL_TPUT) $1),)
+
+black	:= $(call get-term-code,setaf 0)
+red	:= $(call get-term-code,setaf 1)
+green	:= $(call get-term-code,setaf 2)
+yellow	:= $(call get-term-code,setaf 3)
+blue	:= $(call get-term-code,setaf 4)
+magenta	:= $(call get-term-code,setaf 5)
+cyan	:= $(call get-term-code,setaf 6)
+white	:= $(call get-term-code,setaf 7)
+bold	:= $(call get-term-code,bold)
+uline	:= $(call get-term-code,smul)
+reset	:= $(call get-term-code,sgr0)
+
+#
+# User-settable definitions
+#
+LATEX_COLOR_WARNING	?= magenta
+LATEX_COLOR_ERROR	?= red
+LATEX_COLOR_INFO	?= green
+LATEX_COLOR_UNDERFULL	?= magenta
+LATEX_COLOR_OVERFULL	?= red bold
+LATEX_COLOR_PAGES	?= bold
+LATEX_COLOR_BUILD	?= cyan
+LATEX_COLOR_GRAPHIC	?= yellow
+LATEX_COLOR_DEP		?= green
+LATEX_COLOR_SUCCESS	?= green bold
+LATEX_COLOR_FAILURE	?= red bold
+
+# Gets the real color from a simple textual definition like those above
+# $(call get-color,ALL_CAPS_COLOR_NAME)
+# e.g., $(call get-color,WARNING)
+get-color	= $(subst $(space),,$(foreach c,$(LATEX_COLOR_$1),$($c)))
+
+#
+# STANDARD COLORS
+#
+C_WARNING	:= $(call get-color,WARNING)
+C_ERROR		:= $(call get-color,ERROR)
+C_INFO		:= $(call get-color,INFO)
+C_UNDERFULL	:= $(call get-color,UNDERFULL)
+C_OVERFULL	:= $(call get-color,OVERFULL)
+C_PAGES		:= $(call get-color,PAGES)
+C_BUILD		:= $(call get-color,BUILD)
+C_GRAPHIC	:= $(call get-color,GRAPHIC)
+C_DEP		:= $(call get-color,DEP)
+C_SUCCESS	:= $(call get-color,SUCCESS)
+C_FAILURE	:= $(call get-color,FAILURE)
+C_RESET		:= $(reset)
+
+#
+# PRE-BUILD TESTS
+#
+
+# Check that clean targets are not combined with other targets (weird things
+# happen, and it's not easy to fix them)
+hascleangoals	:= $(if $(sort $(filter clean clean-%,$(MAKECMDGOALS))),1)
+hasbuildgoals	:= $(if $(sort $(filter-out clean clean-%,$(MAKECMDGOALS))),1)
+ifneq "$(hasbuildgoals)" ""
+ifneq "$(hascleangoals)" ""
+$(error $(C_ERROR)Clean and build targets specified together$(C_RESET)))
+endif
+endif
+
+#
+# VARIABLE DECLARATIONS
+#
+
+# Names of sed scripts that morph gnuplot files -- only the first found is used
+GNUPLOT_SED	:= global-gpi.sed gnuplot.sed
+GNUPLOT_GLOBAL	:= global._include_.gpi gnuplot.global
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+default_graphic_extension	?= eps
+latex_build_program		?= $(LATEX)
+build_target_extension		?= dvi
+hyperref_driver_pattern		?= hdvips
+hyperref_driver_error		?= Using dvips: specify ps2pdf in the hyperref options.
+else
+default_graphic_extension	?= pdf
+latex_build_program		?= $(PDFLATEX)
+build_target_extension		?= pdf
+hyperref_driver_pattern		?= hpdf.*
+hyperref_driver_error		?= Using pdflatex: specify pdftex in the hyperref options (or leave it blank).
+endif
+
+# Files of interest
+all_files.tex		?= $(wildcard *.tex)
+all_files.tex.sh	?= $(wildcard *.tex.sh)
+all_files.tex.pl	?= $(wildcard *.tex.pl)
+all_files.tex.py	?= $(wildcard *.tex.py)
+all_files.rst		?= $(wildcard *.rst)
+all_files.fig		?= $(wildcard *.fig)
+all_files.gpi		?= $(wildcard *.gpi)
+all_files.dot		?= $(wildcard *.dot)
+all_files.xvg		?= $(wildcard *.xvg)
+all_files.svg		?= $(wildcard *.svg)
+all_files.png		?= $(wildcard *.png)
+all_files.jpg		?= $(wildcard *.jpg)
+all_files.eps.gz	?= $(wildcard *.eps.gz)
+all_files.eps		?= $(wildcard *.eps)
+
+# Utility function for obtaining all files not specified in $(neverclean)
+# $(call cleanable-files,file1 file2 file3 ...)
+# Returns the list of files that is not in $(wildcard $(neverclean))
+cleanable-files = $(filter-out $(wildcard $(neverclean)), $1)
+
+# Utility function for getting all .$1 files that are to be ignored
+#  * files listed in $(includes.$1)
+#  * files not listed in $(onlysources.$1) if it is defined
+ignore_files = \
+  $(includes.$1) \
+  $(if $(onlysources.$1),$(filter-out $(onlysources.$1), $(all_files.$1)))
+
+# Patterns to never be allowed as source targets
+ignore_patterns	:= %._include_
+
+# Patterns allowed as source targets but not included in 'all' builds
+nodefault_patterns := %._nobuild_ $(ignore_patterns)
+
+# Utility function for getting targets suitable building
+# $(call filter-buildable,suffix)
+filter-buildable	= \
+	$(filter-out $(call ignore_files,$1) \
+		$(addsuffix .$1,$(ignore_patterns)),$(all_files.$1))
+
+# Utility function for getting targets suitable for 'all' builds
+# $(call filter-default,suffix)
+filter-default		= \
+	$(filter-out $(call ignore_files,$1) \
+		$(addsuffix .$1,$(nodefault_patterns)),$(all_files.$1))
+
+# Top level sources that can be built even when they are not by default
+files.tex	:= $(call filter-buildable,tex)
+files.tex.sh	:= $(call filter-buildable,tex.sh)
+files.tex.pl	:= $(call filter-buildable,tex.pl)
+files.tex.py	:= $(call filter-buildable,tex.py)
+files.rst	:= $(call filter-buildable,rst)
+files.gpi	:= $(call filter-buildable,gpi)
+files.dot	:= $(call filter-buildable,dot)
+files.fig	:= $(call filter-buildable,fig)
+files.xvg	:= $(call filter-buildable,xvg)
+files.svg	:= $(call filter-buildable,svg)
+files.png	:= $(call filter-buildable,png)
+files.jpg	:= $(call filter-buildable,jpg)
+files.eps.gz	:= $(call filter-buildable,eps.gz)
+
+# Make all pstex targets secondary.  The pstex_t target requires the pstex
+# target, and nothing else really depends on it, so it often gets deleted.
+# This avoids that by allowing *all* fig files to be pstex targets, which is
+# perfectly valid and causes no problems even if they're going to become eps
+# files in the end.
+.SECONDARY:	$(patsubst %.fig,%.pstex,$(files.fig))
+
+# Top level sources that are built by default targets
+default_files.tex	:= $(call filter-default,tex)
+default_files.tex.sh	:= $(call filter-default,tex.sh)
+default_files.tex.pl	:= $(call filter-default,tex.pl)
+default_files.tex.py	:= $(call filter-default,tex.py)
+default_files.rst	:= $(call filter-default,rst)
+default_files.gpi	:= $(call filter-default,gpi)
+default_files.dot	:= $(call filter-default,dot)
+default_files.fig	:= $(call filter-default,fig)
+default_files.xvg	:= $(call filter-default,xvg)
+default_files.svg	:= $(call filter-default,svg)
+default_files.png	:= $(call filter-default,png)
+default_files.jpg	:= $(call filter-default,jpg)
+default_files.eps.gz	:= $(call filter-default,eps.gz)
+
+# Utility function for creating larger lists of files
+# $(call concat-files,suffixes,[prefix])
+concat-files	= $(foreach s,$1,$($(if $2,$2_,)files.$s))
+
+# Useful file groupings
+all_files_source	:= $(call concat-files,tex,all)
+all_files_scripts	:= $(call concat-files,tex.sh tex.pl tex.py rst,all)
+
+.PHONY: $(all_files_scripts)
+
+default_files_source	:= $(call concat-files,tex,default)
+default_files_scripts	:= $(call concat-files,tex.sh tex.pl tex.py rst,default)
+
+files_source	:= $(call concat-files,tex)
+files_scripts	:= $(call concat-files,tex.sh tex.pl tex.py rst)
+
+# Utility function for obtaining stems
+# $(call get-stems,suffix,[prefix])
+get-stems	= $(sort $($(if $2,$2_,)files.$1:%.$1=%))
+
+# List of all stems (including ._include_ and ._nobuild_ file stems)
+all_stems.tex		:= $(call get-stems,tex,all)
+all_stems.tex.sh	:= $(call get-stems,tex.sh,all)
+all_stems.tex.pl	:= $(call get-stems,tex.pl,all)
+all_stems.tex.py	:= $(call get-stems,tex.py,all)
+all_stems.rst		:= $(call get-stems,rst,all)
+all_stems.fig		:= $(call get-stems,fig,all)
+all_stems.gpi		:= $(call get-stems,gpi,all)
+all_stems.dot		:= $(call get-stems,dot,all)
+all_stems.xvg		:= $(call get-stems,xvg,all)
+all_stems.svg		:= $(call get-stems,svg,all)
+all_stems.png		:= $(call get-stems,png,all)
+all_stems.jpg		:= $(call get-stems,jpg,all)
+all_stems.eps.gz	:= $(call get-stems,eps.gz,all)
+all_stems.eps		:= $(call get-stems,eps,all)
+
+# List of all default stems (all default PDF targets):
+default_stems.tex		:= $(call get-stems,tex,default)
+default_stems.tex.sh		:= $(call get-stems,tex.sh,default)
+default_stems.tex.pl		:= $(call get-stems,tex.pl,default)
+default_stems.tex.py		:= $(call get-stems,tex.py,default)
+default_stems.rst		:= $(call get-stems,rst,default)
+default_stems.fig		:= $(call get-stems,fig,default)
+default_stems.gpi		:= $(call get-stems,gpi,default)
+default_stems.dot		:= $(call get-stems,dot,default)
+default_stems.xvg		:= $(call get-stems,xvg,default)
+default_stems.svg		:= $(call get-stems,svg,default)
+default_stems.png		:= $(call get-stems,png,default)
+default_stems.jpg		:= $(call get-stems,jpg,default)
+default_stems.eps.gz		:= $(call get-stems,eps.gz,default)
+
+# List of all stems (all possible bare PDF targets created here):
+stems.tex		:= $(call get-stems,tex)
+stems.tex.sh		:= $(call get-stems,tex.sh)
+stems.tex.pl		:= $(call get-stems,tex.pl)
+stems.tex.py		:= $(call get-stems,tex.py)
+stems.rst		:= $(call get-stems,rst)
+stems.fig		:= $(call get-stems,fig)
+stems.gpi		:= $(call get-stems,gpi)
+stems.dot		:= $(call get-stems,dot)
+stems.xvg		:= $(call get-stems,xvg)
+stems.svg		:= $(call get-stems,svg)
+stems.png		:= $(call get-stems,png)
+stems.jpg		:= $(call get-stems,jpg)
+stems.eps.gz		:= $(call get-stems,eps.gz)
+
+# Utility function for creating larger lists of stems
+# $(call concat-stems,suffixes,[prefix])
+concat-stems	= $(sort $(foreach s,$1,$($(if $2,$2_,)stems.$s)))
+
+# The most likely to be source but not finished product go first
+graphic_source_extensions	:= fig \
+				   gpi \
+				   xvg \
+				   svg \
+				   dot \
+				   eps.gz
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+graphic_source_extensions	+= png jpg
+graphic_target_extensions	:= eps ps
+else
+graphic_source_extensions	+= eps
+graphic_target_extensions	:= pdf png jpg mps tif
+endif
+
+all_stems_source	:= $(call concat-stems,tex,all)
+all_stems_script	:= $(call concat-stems,tex.sh tex.pl tex.py rst,all)
+all_stems_graphic	:= $(call concat-stems,$(graphic_source_extensions),all)
+all_stems_ss		:= $(sort $(all_stems_source) $(all_stems_script))
+all_stems_sg		:= $(sort $(all_stems_script))
+all_stems_ssg		:= $(sort $(all_stems_ss))
+
+default_stems_source	:= $(call concat-stems,tex,default)
+default_stems_script	:= $(call concat-stems,tex.sh tex.pl tex.py rst,default)
+default_stems_ss	:= $(sort $(default_stems_source) $(default_stems_script))
+default_stems_sg	:= $(sort $(default_stems_script))
+default_stems_ssg	:= $(sort $(default_stems_ss))
+
+stems_source		:= $(call concat-stems,tex)
+stems_script		:= $(call concat-stems,tex.sh tex.pl tex.py rst)
+stems_graphic		:= $(call concat-stems,$(graphic_source_extensions))
+stems_gg		:= $(sort $(stems_graphic))
+stems_ss		:= $(sort $(stems_source) $(stems_script))
+stems_sg		:= $(sort $(stems_script))
+stems_ssg		:= $(sort $(stems_ss))
+
+# Calculate names that can generate the need for an include file.  We can't
+# really do this with patterns because it's too easy to screw up, so we create
+# an exhaustive list.
+allowed_source_suffixes	:= \
+	pdf \
+	ps \
+	dvi \
+	ind \
+	nls \
+	bbl \
+	aux \
+	aux.make \
+	d \
+	auxbbl.make \
+	_graphics \
+	_show
+allowed_source_patterns		:= $(addprefix %.,$(allowed_source_suffixes))
+
+allowed_graphic_suffixes	:= \
+	pdf \
+	eps \
+	gpihead.make \
+	gpi.d
+allowed_graphic_patterns	:= $(addprefix %.,$(allowed_graphic_suffixes))
+
+# All targets allowed to build documents
+allowed_source_targets	:= \
+	$(foreach suff,$(allowed_source_suffixes),\
+	$(addsuffix .$(suff),$(stems_ssg)))
+
+# All targets allowed to build graphics
+allowed_graphic_targets	:= \
+	$(foreach suff,$(allowed_graphic_suffixes),\
+	$(addsuffix .$(suff),$(stems_gg)))
+
+# All targets that build multiple documents (like 'all')
+allowed_batch_source_targets	:= \
+	all \
+	all-pdf \
+	all-ps \
+	all-dvi \
+	all-bbl \
+	all-ind \
+	all-gls \
+	all-nls \
+	show
+
+# All targets that build multiple graphics (independent of document)
+allowed_batch_graphic_targets	:= \
+	all-graphics \
+	all-pstex \
+	all-dot2tex \
+	show-graphics
+
+# Now we figure out which stuff is available as a make target for THIS RUN.
+real_goals	:= $(call get-default,$(filter-out _includes,$(MAKECMDGOALS)),\
+			all)
+
+specified_source_targets	:= $(strip \
+	$(filter $(allowed_source_targets) $(stems_ssg),$(real_goals)) \
+	)
+
+specified_batch_source_targets	:= $(strip \
+	$(filter $(allowed_batch_source_targets),$(real_goals)) \
+	)
+
+specified_graphic_targets	:= $(strip \
+	$(filter $(allowed_graphic_targets),$(real_goals)) \
+	)
+
+specified_batch_graphic_targets	:= $(strip \
+	$(filter $(allowed_batch_graphic_targets),$(real_goals)) \
+	)
+
+specified_gpi_targets	:= $(patsubst %.gpi,%.$(default_graphic_extension),\
+	$(filter $(patsubst %.$(default_graphic_extension),%.gpi,$(specified_graphic_targets)),\
+		$(all_files.gpi)) \
+	)
+
+# Determine which .d files need including from the information gained above.
+# This is done by first checking whether a batch target exists.  If it does,
+# then all *default* stems are used to create possible includes (nobuild need
+# not apply for batch status).  If no batch targets exist, then the individual
+# targets are considered and appropriate includes are taken from them.
+source_stems_to_include	:= \
+	$(sort\
+	$(if $(specified_batch_source_targets),\
+		$(default_stems_ss),\
+		$(foreach t,$(specified_source_targets),\
+		$(foreach p,$(allowed_source_patterns),\
+			$(patsubst $p,%,$(filter $p $(stems_ssg),$t)) \
+		)) \
+	))
+
+# Determine which .gpi.d files are needed using the above information.  We
+# first check whether a batch target is specified, then check individual
+# graphics that may have been specified.
+graphic_stems_to_include	:= \
+	$(sort\
+	$(if $(specified_batch_graphic_targets),\
+		$(default_stems.gpi),\
+		$(foreach t,$(specified_gpi_targets),\
+		$(foreach p,$(allowed_graphic_patterns),\
+			$(patsubst $p,%,$(filter $p,$t)) \
+		)) \
+	))
+
+# All dependencies for the 'all' targets
+all_pdf_targets		:= $(addsuffix .pdf,$(stems_ssg))
+all_ps_targets		:= $(addsuffix .ps,$(stems_ssg))
+all_dvi_targets		:= $(addsuffix .dvi,$(stems_ssg))
+all_tex_targets		:= $(addsuffix .tex,$(stems_sg))
+all_d_targets		:= $(addsuffix .d,$(stems_ssg))
+all_graphics_targets	:= $(addsuffix .$(default_graphic_extension),$(stems_gg))
+intermediate_graphics_targets	:= $(if $(filter pdf,$(default_graphic_extension)),$(addsuffix .eps,$(stems_gg)),)
+all_pstex_targets	:= $(addsuffix .pstex_t,$(stems.fig))
+all_dot2tex_targets	:= $(addsuffix .dot_t,$(stems.dot))
+
+all_known_graphics	:= $(sort $(all_graphics_targets) $(wildcard *.$(default_graphic_extension)))
+
+default_pdf_targets	:= $(addsuffix .pdf,$(default_stems_ss))
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+default_ps_targets	:= $(addsuffix .ps,$(default_stems_ss))
+default_dvi_targets	:= $(addsuffix .dvi,$(default_stems_ss))
+pre_pdf_extensions	:= dvi ps
+endif
+
+# Extensions generated by LaTeX invocation that can be removed when complete
+rm_ext		:= \
+	log *.log aux $(pre_pdf_extensions) pdf blg bbl out nav snm toc lof lot lol pfg \
+	fls vrb idx ind ilg glg glo gls lox nls nlo nlg brf mtc maf brf
+backup_patterns	:= *~ *.bak *.backup body.tmp head.tmp
+
+graph_stem	:= _graph
+
+# All LaTeX-generated files that can be safely removed
+
+rm_tex := \
+	$(foreach e,$(rm_ext),$(addsuffix .$e,$(all_stems_source))) \
+	$(foreach e,$(rm_ext) tex,$(addsuffix .$e,$(all_stems_sg))) \
+	$(addsuffix .log,$(all_ps_targets) $(all_pdf_targets)) \
+	$(addsuffix .*.log,$(stems_graphic))
+
+# These are the files that will affect .gpi transformation for all .gpi files.
+#
+# Use only the first one found.  Backward compatible values are at the end.
+# Note that we use foreach, even though wildcard also returns a list, to ensure
+# that the order in the uppercase variables is preserved.  Directory listings
+# provide no such guarantee, so we avoid relying on them.
+gpi_sed		:= $(strip \
+	$(firstword $(foreach f,$(GNUPLOT_SED),$(wildcard $f))))
+gpi_global	:= $(strip \
+	$(firstword $(foreach f,$(GNUPLOT_GLOBAL),$(wildcard $f))))
+
+#
+# Functions used in generating output
+#
+
+# Outputs all source dependencies to stdout.  The first argument is the file to
+# be parsed, the second is a list of files that will show up as dependencies in
+# the new .d file created here.
+#
+# NOTE: BSD sed does not understand \|, so we have to do something more
+# clunky to extract suitable extensions.
+#
+# Also, we do a little bit of funny rewriting up front (TARGETS=) to make sure
+# that we can properly backslash-escape spaces in file names (e.g, on Cygwin
+# for tex distributions that have "Program Files" in their name).
+#
+# $(call get-inputs,<parsed file>,<target files>)
+define get-inputs
+$(SED) \
+-e '/^INPUT/!d' \
+-e 's!^INPUT \(\./\)\{0,1\}!!' \
+-e 's/[[:space:]]/\\ /g' \
+-e 's/\(.*\)\.aux$$/\1.tex/' \
+-e '/\.tex$$/b addtargets' \
+-e '/\.cls$$/b addtargets' \
+-e '/\.sty$$/b addtargets' \
+-e '/\.pstex_t$$/b addtargets' \
+-e '/\.dot_t$$/b addtargets' \
+-e 'd' \
+-e ':addtargets' \
+-e 's/^/$2: /' \
+$1 | $(SORT) | $(UNIQ)
+endef
+
+# $(call get-missing-inputs,<log file>,<target files>)
+define get-missing-inputs
+$(SED) \
+-e '$$ b para' \
+-e '/^$$/b para' \
+-e 'H' \
+-e 'd' \
+-e ':para' \
+-e 'x' \
+-e '/^$$/d' \
+-e 's/^\n*//' \
+-e '/^! LaTeX Error: File /{' \
+-e '  s/^/::DOUBLE_PARAGRAPH::/' \
+-e '  h' \
+-e '  d' \
+-e '}' \
+-e 's/^::DOUBLE_PARAGRAPH:://' \
+-e '/Default extension: /!d' \
+-e 's/[[:space:]]\{1,\}/ /g' \
+-e 's/\n\{1,\}/ /g' \
+-e 's/^.*File `//' \
+-e 's/'"'"' not found\..*//' \
+-e '/\.tex/!s/$$/.tex/' \
+-e 's/[[:space:]]/\\ /g' \
+-e 'h' \
+-e 's/.*/# MISSING input "&" - (presence of comment affects build)/' \
+-e 'p' \
+-e 's/.*//' \
+-e 'x' \
+-e 's/^/$2: /' \
+$1 | $(SORT) | $(UNIQ)
+endef
+
+# Get source file for specified graphics stem.
+#
+# $(call graphics-source,<stem>)
+define graphics-source
+$(strip $(firstword \
+	$(wildcard \
+		$(addprefix $1.,\
+			$(graphic_source_extensions))) \
+	$1 \
+))
+endef
+
+# Get the target file for the specified graphics file/stem
+#
+# $(call graphics-target,<stem>)
+define graphics-target
+$(strip $(if 	$(filter $(addprefix %.,$(graphic_target_extensions)),$1), $1,
+	$(firstword $(patsubst $(addprefix %.,$(graphic_source_extensions) $(graphic_target_extensions)), %, $1).$(default_graphic_extension) $1.$(default_graphic_extension))))
+endef
+
+# Outputs all of the graphical dependencies to stdout.  The first argument is
+# the stem of the source file being built, the second is a list of suffixes
+# that will show up as dependencies in the generated .d file.
+#
+# Note that we try to escape spaces in filenames where possible.  We have to do
+# it with three backslashes so that as the name percolates through the makefile
+# it eventually ends up with the proper escaping when the build rule is found.
+# Ugly, but it appears to work.  Note that graphicx doesn't allow filenames
+# with spaces, so this could in many ways be moot unless you're using something
+# like grffile.
+#
+# For pdflatex, we really need the missing file to be specified without an
+# extension, otherwise compilation barfs on the first missing file.  Truly
+# annoying, but there you have it.
+#
+# It turns out that the graphics errors, although they have lines with empty
+# space, are only made of two paragraphs.  So, we just use some sed magic to
+# get everything into paragraphs, detect when it's a paragraph that interests
+# us, and double it up.  Then we get the filename only if we're missing
+# extensions (a sign that it's graphicx complaining).
+#
+# $(call get-graphics,<target file stem>)
+#.log,$(addprefix $*.,d $(build_target_extension) _graphics)
+define get-graphics
+$(SED) \
+-e '$$ b para' \
+-e '/^$$/b para' \
+-e 'H' \
+-e 'd' \
+-e ':para' \
+-e 'x' \
+-e '/^$$/d' \
+-e 's/^\n*//' \
+-e '/^! LaTeX Error: File `/{' \
+-e '  s/^/::DOUBLE_PARAGRAPH::/' \
+-e '  h' \
+-e '  d' \
+-e '}' \
+-e 's/^::DOUBLE_PARAGRAPH:://' \
+-e '/could not locate the file with any of these extensions:/{' \
+-e '  s/\n\{1,\}/ /g' \
+-e '  s/[[:space:]]\{1,\}/ /g' \
+-e '  s/^.*File `//' \
+-e '  s/'"'"' not found\..*//' \
+-e '  h' \
+-e '  s/.*/# MISSING stem "&" - (presence of comment affects build)/' \
+-e '  p' \
+-e '  g' \
+-e '  b addtargets' \
+-e '}' \
+-e '/.*File: \(.*\) Graphic file (type [^)]*).*/{' \
+-e '  s//\1/' \
+-e '  b addtargets' \
+-e '}' \
+-e 'd' \
+-e ':addtargets' \
+-e 's/[[:space:]]/\\\\\\&/g' \
+-e 'h' \
+-e 's/.*/-include &.gpi.d/' \
+-e 'p' \
+-e 'g' \
+-e 's/.*/$(addprefix $1,.d): $$$$(call graphics-source,&)/' \
+-e 'p' \
+-e 's/.*//' \
+-e 'x' \
+-e 's/.*/$(addprefix $1.,$(build_target_extension) _graphics): $$$$(call graphics-target,&)/' \
+-e 'p' \
+-e 'd' \
+$*.log
+endef
+
+# Checks for build failure due to pstex inclusion, and gives instructions.
+#
+# $(call die-on-pstexs,<parsed file>)
+define die-on-pstexs
+if $(EGREP) -q '^! LaTeX Error: File .*\.pstex.* not found' $1; then \
+	$(ECHO) "$(C_ERROR)Missing pstex_t file(s)$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)Please run$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)  make all-pstex$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)before proceeding.$(C_RESET)"; \
+	exit 1; \
+fi
+endef
+
+# Checks for build failure due to dot2tex, and gives instructions.
+#
+# $(call die-on-dot2tex,<parsed file>)
+define die-on-dot2tex
+if $(EGREP) -q ' LaTeX Error: File .*\.dot_t.* not found' $1; then \
+	$(ECHO) "$(C_ERROR)Missing dot_t file(s)$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)Please run$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)  make all-dot2tex$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)before proceeding.$(C_RESET)"; \
+	exit 1; \
+fi
+endef
+
+# Checks for the existence of a .aux file, and dies with an error message if it
+# isn't there.  Note that we pass the file stem in, not the full filename,
+# e.g., to check for foo.aux, we call it thus: $(call die-on-no-aux,foo)
+#
+# $(call die-on-no-aux,<aux stem>)
+define die-on-no-aux
+if [ ! -e '$1.aux' ]; then \
+	$(call colorize-latex-errors,$1.log); \
+	exit 1; \
+fi
+endef
+
+# Outputs all index files to stdout.  Arg 1 is the source file stem, arg 2 is
+# the list of targets for the discovered dependency.
+#
+# $(call get-log-index,<log file stem>,<target files>)
+define get-log-index
+$(SED) \
+-e 's/^No file \(.*\.ind\)\.$$/TARGETS=\1/' \
+-e 's/^No file \(.*\.[gn]ls\)\.$$/TARGETS=\1/' \
+-e 's/[[:space:]]/\\&/g' \
+-e '/^TARGETS=/{' \
+-e '  h' \
+-e '  s/^TARGETS=/$2: /p' \
+-e '  g' \
+-e '  s/^TARGETS=\(.*\)/\1: $1.tex/p' \
+-e '}' \
+-e 'd' \
+'$1.log' | $(SORT) | $(UNIQ)
+endef
+
+
+# Outputs all bibliography files to stdout.  Arg 1 is the source stem, arg 2 is
+# a list of targets for each dependency found.
+#
+# The script kills all lines that do not contain bibdata.  Remaining lines have
+# the \bibdata macro and delimiters removed to create a dependency list.  A
+# trailing comma is added, then all adjacent commas are collapsed into a single
+# comma.  Then commas are replaced with the string .bib[space], and the
+# trailing space is killed off.  Finally, all filename spaces are escaped.
+# This produces a list of space-delimited .bib filenames, which is what the
+# make dep file expects to see.
+#
+# Note that we give kpsewhich a bogus argument so that a failure of sed to
+# produce output will not cause an error.
+#
+# $(call get-bibs,<aux file>,<targets>)
+define get-bibs
+$(SED) \
+-e '/^\\bibdata/!d' \
+-e 's/\\bibdata{\([^}]*\)}/\1,/' \
+-e 's/,\{2,\}/,/g' \
+-e 's/[[:space:]]/\\&/g' \
+-e 's/,/.bib /g' \
+-e 's/ \{1,\}$$//' \
+$1 | $(XARGS) $(KPSEWHICH) '#######' | \
+$(SED) \
+-e 's/^/$2: /' | \
+\$(SORT) | $(UNIQ)
+endef
+
+# Makes a an aux file that only has stuff relevant to the target in it
+# $(call make-auxtarget-file,<flattened-aux>,<new-aux>)
+define make-auxtarget-file
+$(SED) \
+-e '/^\\newlabel/!d' \
+$1 > $2
+endef
+
+# Makes an aux file that only has stuff relevant to the bbl in it
+# $(call make-auxbbl-file,<flattened-aux>,<new-aux>)
+define make-auxbbl-file
+$(SED) \
+-e '/^\\newlabel/d' \
+$1 > $2
+endef
+
+# Makes a .gpi.d file from a .gpi file
+# $(call make-gpi-d,<.gpi>,<.gpi.d>)
+define make-gpi-d
+$(ECHO) '# vim: ft=make' > $2; \
+$(ECHO) 'ifndef INCLUDED_$(call cleanse-filename,$2)' >> $2; \
+$(ECHO) 'INCLUDED_$(call cleanse-filename,$2) := 1' >> $2; \
+$(call get-gpi-deps,$1,$(addprefix $(2:%.gpi.d=%).,$(GNUPLOT_OUTPUT_EXTENSION) gpi.d)) >> $2; \
+$(ECHO) 'endif' >> $2;
+endef
+
+# Parse .gpi files for data and loaded dependencies, output to stdout
+#
+# The sed script here tries to be clever about obtaining valid
+# filenames from the gpi file.  It assumes that the plot command starts its own
+# line, which is not too difficult a constraint to satisfy.
+#
+# This command script also generates 'include' directives for every 'load'
+# command in the .gpi file.  The load command must appear on a line by itself
+# and the file it loads must have the suffix .gpi.  If you don't want it to be
+# compiled when running make graphics, then give it a suffix of ._include_.gpi.
+#
+# $(call get-gpi-deps,<gpi file>,<targets>)
+define get-gpi-deps
+$(SED) \
+-e '/^[[:space:]]*s\{0,1\}plot/,/[^\\]$$/{' \
+-e ' H' \
+-e ' /[^\\]$$/{' \
+-e '  s/.*//' \
+-e '  x' \
+-e '  s/\\\{0,1\}\n//g' \
+-e '  s/^[[:space:]]*s\{0,1\}plot[[:space:]]*\(\[[^]]*\][[:space:]]*\)*/,/' \
+-e '  s/[[:space:]]*\(['\''"][^'\''"]*['\''"]\)\{0,1\}[^,]*/\1/g' \
+-e '  s/,['\''"]-\{0,1\}['\''"]//g' \
+-e '  s/[,'\''"]\{1,\}/ /g' \
+-e '  s!.*!$2: &!' \
+-e '  p' \
+-e ' }' \
+-e ' d' \
+-e '}' \
+-e 's/^[[:space:]]*load[[:space:]]*['\''"]\([^'\''"]*\.gpi\)['\''"].*$$/-include \1.d/p' \
+-e 'd' \
+$1
+endef
+
+# Colorizes real, honest-to-goodness LaTeX errors that can't be overcome with
+# recompilation.
+#
+# Note that we only ignore file not found errors for things that we know how to
+# build, like graphics files.
+#
+# $(call colorize-latex-errors,<log file>)
+define colorize-latex-errors
+$(SED) \
+-e '$$ b para' \
+-e '/^$$/b para' \
+-e 'H' \
+-e 'd' \
+-e ':para' \
+-e 'x' \
+-e '/^$$/d' \
+-e 's/^\n*//' \
+-e '/^! LaTeX Error: File /{' \
+-e '  s/^/::DOUBLE_PARAGRAPH::/' \
+-e '  h' \
+-e '  d' \
+-e '}' \
+-e 's/^::DOUBLE_PARAGRAPH:://' \
+-e '/could not locate the file with any of these extensions:/d' \
+-e '/Missing .begin.document/{' \
+-e '  h' \
+-e '  s/.*/Are you trying to build an include file?/' \
+-e '  x' \
+-e '  G' \
+-e '}' \
+-e '/ LaTeX Error: Cannot determine size/d' \
+-e 's/.* LaTeX Error .*/$(C_ERROR)&$(C_RESET)/p' \
+-e 's/Error: pdflatex (file .*/$(C_ERROR)& - try specifying it without an extension$(C_RESET)/p' \
+-e '/.*\*hyperref using.*driver \(.*\)\*.*/{' \
+-e '  s//\1/' \
+-e '  /^$(hyperref_driver_pattern)$$/!{' \
+-e '    s/.*//' \
+-e '    p' \
+-e '    s/.*/$(C_ERROR)--- Using incorrect driver for hyperref! ---$(C_RESET)/' \
+-e '    p' \
+-e '    s/.*/$(C_ERROR)$(hyperref_driver_error)$(C_RESET)/' \
+-e '    p' \
+-e '  }' \
+-e '  d' \
+-e '}' \
+-e '/ LaTeX Error: Unknown graphics extension/{' \
+-e '  s/^/     /' \
+-e '  h' \
+-e '  s/.*/--- Graphics extension error:/' \
+-e '  G' \
+-e '  h' \
+-e '  s/.*/--- If you specified the extension explicitly in your .tex file, try removing it./' \
+-e '  H' \
+-e '  g' \
+-e '  s/.*/$(C_ERROR)&$(C_RESET)/' \
+-e '  p' \
+-e '  s/.*//' \
+-e '  h' \
+-e '  b' \
+-e '}' \
+-e 's/.*\(\n\{0,\}! .*\)/$(C_ERROR)\1$(C_RESET)/p' \
+-e 'd' \
+$1
+endef
+
+# Colorize Makeindex errors
+define colorize-makeindex-errors
+$(SED) \
+-e '/^!! /{' \
+-e '  N' \
+-e '  s/^.*$$/$(C_ERROR)&$(C_RESET)/' \
+-e '  p' \
+-e '}' \
+-e 'd' \
+$1
+endef
+
+# Colorize epstopdf errors
+#
+# $(call colorize-epstopdf-errors,<log file>)
+define colorize-epstopdf-errors
+$(SED) \
+-e '/^Error:/,/^Execution stack:/{' \
+-e '  /^Execution stack:/d' \
+-e '  s/.*/$(C_ERROR)&$(C_RESET)/' \
+-e '  p' \
+-e '}' \
+-e 'd' \
+$1
+endef
+
+# Colorize GNUplot errors
+#
+# $(call colorize-gnuplot-errors,<log file>)
+define colorize-gnuplot-errors
+$(SED) \
+-e '/, line [0-9]*:/!{' \
+-e '  H' \
+-e '  x' \
+-e '  s/.*\n\(.*\n.*\)$$/\1/' \
+-e '  x' \
+-e '}' \
+-e '/, line [0-9]*:/{' \
+-e '  H' \
+-e '  /unknown.*terminal type/{' \
+-e '    s/.*/--- Try changing the GNUPLOT_OUTPUT_EXTENSION variable to 'eps'./' \
+-e '	H' \
+-e '  }' \
+-e '  /gpihead/{' \
+-e '    s/.*/--- This could be a Makefile bug - contact the maintainer./' \
+-e '    H' \
+-e '  }' \
+-e '  g' \
+-e '  s/.*/$(C_ERROR)&$(C_RESET)/' \
+-e '  p' \
+-e '}' \
+-e '/^gnuplot>/,/^$$/{' \
+-e '  s/^gnuplot.*/$(C_ERROR)&/' \
+-e '  s/^$$/$(C_RESET)/' \
+-e '  p' \
+-e '}' \
+-e 'd' \
+$1
+endef
+
+# Colorize GraphViz errors
+#
+# $(call colorize-dot-errors,<log file>)
+define colorize-dot-errors
+$(SED) \
+-e '/^Error:/,/context:/s/.*/$(C_ERROR)&$(C_RESET)/p' \
+-e 's/^Warning:.*/$(C_WARNING)&$(C_RESET)/p' \
+-e 'd' \
+'$1'
+endef
+
+# Get all important .aux files from the top-level .aux file and merges them all
+# into a single file, which it outputs to stdout.
+#
+# $(call flatten-aux,<toplevel aux>,<output file>)
+define flatten-aux
+$(SED) \
+-e '/\\@input{\(.*\)}/{' \
+-e     's//\1/' \
+-e     's![.:]!\\&!g' \
+-e     'h' \
+-e     's!.*!\\:\\\\@input{&}:{!' \
+-e     'p' \
+-e     'x' \
+-e     's/\\././g' \
+-e     's/.*/r &/p' \
+-e     's/.*/d/p' \
+-e     's/.*/}/p' \
+-e     'd' \
+-e '}' \
+-e 'd' \
+'$1' > "$1.$$$$.sed.make"; \
+$(SED) -f "$1.$$$$.sed.make" '$1' > "$1.$$$$.make"; \
+$(SED) \
+-e '/^\\relax/d' \
+-e '/^\\bibcite/d' \
+-e 's/^\(\\newlabel{[^}]\{1,\}}\).*/\1/' \
+"$1.$$$$.make" | $(SORT) > '$2'; \
+$(call remove-temporary-files,$1.$$$$.make $1.$$$$.sed.make)
+endef
+
+# Generate pdf from postscript
+#
+# Note that we don't just call ps2pdf, since there are so many versions of that
+# script on various systems.  Instead, we call the postscript interpreter
+# directly.
+#
+# $(call ps2pdf,infile,outfile,[embed fonts])
+define ps2pdf
+	$(GS) \
+		-dSAFER -dCompatibilityLevel=$(PS_COMPATIBILITY) \
+		$(if $3,$(PS_EMBED_OPTIONS)) \
+		-q -dNOPAUSE -dBATCH \
+		-sDEVICE=pdfwrite -sstdout=%stderr \
+		'-sOutputFile=$2' \
+		-dSAFER -dCompatibilityLevel=$(PS_COMPATIBILITY) \
+		$(if $3,$(PS_EMBED_OPTIONS)) \
+		-c .setpdfwrite \
+		-f '$1'
+endef
+
+# Colorize LaTeX output.
+# This uses a neat trick from the Sed & Awk Book from O'Reilly:
+# 1) If a line has a single ending paren, delete it to make a blank line (so
+#	that we catch the first error, which is not always preceded by a blank
+#	line).
+# 2) Ensure that the last line of the file gets appended to the hold buffer,
+# 	and blank it out to trigger end-of-paragraph logic below.
+# 3) When encountering a blank line (LaTeX output helpfully breaks output on
+# 	newlines)
+# 	a) swap the hold buffer (containing the paragraph) into the pattern buffer (putting a blank line into the hold buffer),
+# 	b) remove the newline at the beginning (don't ask),
+# 	c) apply any colorizing substitutions necessary to ensure happiness.
+# 	d) get the newline out of the hold buffer and append it
+# 	e) profit! (print)
+# 4) Anything not colorized is deleted, unless in verbose mode.
+color_tex	:= \
+	$(SED) \
+	-e '$${' \
+	-e '  /^$$/!{' \
+	-e '    H' \
+	-e '    s/.*//' \
+	-e '  }' \
+	-e '}' \
+	-e '/^$$/!{' \
+	-e '  H' \
+	-e '  d' \
+	-e '}' \
+	-e '/^$$/{' \
+	-e '  x' \
+	-e '  s/^\n//' \
+	-e '  /Output written on /{' \
+	-e '    s/.*Output written on \([^(]*\) (\([^)]\{1,\}\)).*/Success!  Wrote \2 to \1/' \
+	-e '    s/[[:digit:]]\{1,\}/$(C_PAGES)&$(C_RESET)/g' \
+	-e '    s/Success!/$(C_SUCCESS)&$(C_RESET)/g' \
+	-e '    s/to \(.*\)$$/to $(C_SUCCESS)\1$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	-e '  / *LaTeX Error:.*/{' \
+	-e '    s/.*\( *LaTeX Error:.*\)/$(C_ERROR)\1$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	-e '  /.*Warning:.*/{' \
+	-e '    s//$(C_WARNING)&$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	-e '  /Underfull.*/{' \
+	-e '    s/.*\(Underfull.*\)/$(C_UNDERFULL)\1$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	-e '  /Overfull.*/{' \
+	-e '    s/.*\(Overfull.*\)/$(C_OVERFULL)\1$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	$(if $(VERBOSE),,-e '  d') \
+	-e '  :end' \
+	-e '  G' \
+	-e '}' \
+
+# Colorize BibTeX output.
+color_bib	:= \
+	$(SED) \
+	-e 's/^Warning--.*/$(C_WARNING)&$(C_RESET)/' -e 't' \
+	-e '/---/,/^.[^:]/{' \
+	-e '  H' \
+	-e '  /^.[^:]/{' \
+	-e '    x' \
+	-e '    s/\n\(.*\)/$(C_ERROR)\1$(C_RESET)/' \
+	-e '	p' \
+	-e '    s/.*//' \
+	-e '    h' \
+	-e '    d' \
+	-e '  }' \
+	-e '  d' \
+	-e '}' \
+	-e '/(.*error.*)/s//$(C_ERROR)&$(C_RESET)/' \
+	$(if $(VERBOSE),,-e 'd')
+
+
+# Make beamer output big enough to print on a full page.  Landscape doesn't
+# seem to work correctly.
+enlarge_beamer	= $(PSNUP) -l -1 -W128mm -H96mm -pletter
+
+# $(call test-run-again,<source stem>)
+test-run-again	= $(EGREP) -q '^(.*Rerun .*|No file $1\.[^.]+\.)$$' $1.log
+
+# This tests whether the build target commands should be run at all, from
+# viewing the log file.
+# $(call test-log-for-need-to-run,<source stem>)
+define test-log-for-need-to-run
+$(SED) \
+-e '/^No file $(call escape-dots,$1)\.aux\./d' \
+$1.log \
+| $(EGREP) -q '^(.*Rerun .*|No file $1\.[^.]+\.|No file .+\.tex\.|LaTeX Warning: File.*)$$'
+endef
+
+# LaTeX invocations
+#
+# $(call latex,<tex file>,[<extra LaTeX args>])
+run-latex	= $(latex_build_program) --interaction=batchmode $(if $2,$2,) $1 > /dev/null
+
+# $(call latex-color-log,<LaTeX stem>)
+latex-color-log	= $(color_tex) $1.log
+
+# $(call run-makeindex,<input>,<output>,<log>,<extra flags>)
+define run-makeindex
+success=1; \
+if ! $(MAKEINDEX) -q $1 -t $3 -o $2 $4 > /dev/null || $(EGREP) -q '^!!' $3; then \
+	$(call colorize-makeindex-errors,$3); \
+	$(RM) -f '$2'; \
+	success=0; \
+fi; \
+[ "$$success" = "1" ] && $(sh_true) || $(sh_false);
+endef
+
+# This runs the given script to generate output, and it uses MAKE_RESTARTS to
+# ensure that it never runs it more than once for a particular root make
+# invocation.
+#
+# $(call run-script,<interpreter>,<input>,<output>)
+define run-script
+[ ! -e '$2.cookie' ] && $(ECHO) "restarts=$(RESTARTS)" > $2.cookie && $(ECHO) "level=$(MAKELEVEL)" >> $2.cookie; \
+restarts=`$(SED) -n -e 's/^restarts=//p' $2.cookie`; \
+level=`$(SED) -n -e 's/^level=//p' $2.cookie`; \
+if $(EXPR) $(MAKELEVEL) '<=' $$level '&' $(RESTARTS) '<=' $$restarts >/dev/null; then \
+	$(call echo-build,$2,$3,$(RESTARTS)-$(MAKELEVEL)); \
+	$1 '$2' '$3'; \
+	$(ECHO) "restarts=$(RESTARTS)" > '$2.cookie'; \
+	$(ECHO) "level=$(MAKELEVEL)" >> '$2.cookie'; \
+fi
+endef
+
+# BibTeX invocations
+#
+# $(call run-bibtex,<tex stem>)
+run-bibtex	= $(BIBTEX) $1 | $(color_bib)
+
+
+# $(call convert-eps-to-pdf,<eps file>,<pdf file>,[gray])
+# Note that we don't use the --filter flag because it has trouble with bounding boxes that way.
+define convert-eps-to-pdf
+$(if $3,$(CAT) '$1' | $(call kill-ps-color) > '$1.cookie',$(CP) '$1' '$1.cookie'); \
+$(EPSTOPDF) '$1.cookie' --outfile='$2' > $1.log; \
+$(call colorize-epstopdf-errors,$1.log);
+endef
+
+# $(call convert-gpi,<gpi file>,<output file>,[gray])
+#
+define convert-gpi
+$(ECHO) 'set terminal $(if $(filter %.pdf,$2),pdf enhanced,postscript enhanced eps)' \
+$(if $(filter %.pdf,$2),fsize ,)$(call get-default,$(strip \
+$(firstword \
+	$(shell \
+		$(SED) \
+			-e 's/^\#\#FONTSIZE=\([[:digit:]]\{1,\}\)/\1/p' \
+			-e 'd' \
+			$1 $(strip $(gpi_global)) \
+	) \
+) \
+),$(if $(filter %.pdf,$2),$(DEFAULT_GPI_PDF_FONTSIZE),$(DEFAULT_GPI_EPS_FONTSIZE))) \
+$(strip $(if $3,monochrome,$(if \
+$(shell $(EGREP) '^\#\#[[:space:]]*GRAY[[:space:]]*$$' $< $(gpi_global)),\
+,color))) > $1head.make; \
+$(ECHO) 'set output "$2"' >> $1head.make; \
+$(if $(gpi_global),$(CAT) $(gpi_global) >> $1head.make;,) \
+fnames='$1head.make $1';\
+$(if $(gpi_sed),\
+	$(SED) -f '$(gpi_sed)' $$fnames > $1.temp.make; \
+	fnames=$1.temp.make;,\
+) \
+success=1; \
+if ! $(GNUPLOT) $$fnames 2>$1.log; then \
+	$(call colorize-gnuplot-errors,$1.log); \
+	success=0; \
+fi; \
+$(if $(gpi_sed),$(call remove-temporary-files,$1.temp.make);,) \
+$(call remove-temporary-files,$1head.make); \
+[ "$$success" = "1" ] && $(sh_true) || $(sh_false);
+endef
+
+# Creation of .eps files from .png files
+#
+# The intermediate step of PNM (using NetPBM) produces much nicer output than
+# ImageMagick's "convert" binary.  I couldn't get the right combination of
+# flags to make it look nice, anyway.
+#
+# To handle gray scale conversion, we pipe things through ppmtopgm in the
+# middle.
+#
+# $(call convert-png,<png file>,<eps file>)
+define convert-png
+$(PNGTOPNM) "$1" \
+	$(if $3,| $(PPMTOPGM),) \
+	| $(PNMTOPS) -noturn \
+	> "$2"
+endef
+
+# Creation of .eps files from .jpg files
+#
+# Thanks to brubakee for this solution.
+#
+# Uses Postscript level 2 to avoid file size bloat
+# $(call convert-jpg,<jpg file>,<eps file>)
+define convert-jpg
+$(CONVERT) $(if $3,-type Grayscale,) '$1' eps2:'$2'
+endef
+
+# Creation of .eps files from .fig files
+# $(call convert-fig,<fig file>,<output file>,[gray])
+convert-fig	= $(FIG2DEV) -L $(if $(filter %.pdf,$2),pdf,eps) $(if $3,-N,) $1 $2
+
+# Creation of .pstex files from .fig files
+# $(call convert-fig-pstex,<fig file>,<pstex file>)
+convert-fig-pstex	= $(FIG2DEV) -L pstex $1 $2 > /dev/null 2>&1
+
+# Creation of .pstex_t files from .fig files
+# $(call convert-fig-pstex-t,<fig file>,<pstex file>,<pstex_t file>)
+convert-fig-pstex-t	= $(FIG2DEV) -L pstex_t -p $3 $1 $2 > /dev/null 2>&1
+
+# Creation of .dot_t files from .dot files
+# #(call convert-dot-tex,<dot file>,<dot_t file>)
+convert-dot-tex		= $(DOT2TEX) '$1' > '$2'
+
+# Converts svg files into .eps files
+#
+# $(call convert-svg,<svg file>,<eps file>,[gray])
+convert-svg	= $(INKSCAPE) --export-eps='$2' '$1'
+
+# Converts xvg files into .eps files
+#
+# $(call convert-xvg,<xvg file>,<eps file>,[gray])
+convert-xvg	= $(XMGRACE) '$1' -printfile - -hardcopy -hdevice $(if $3,-mono,) EPS > '$2'
+
+# Converts .eps.gz files into .eps files
+#
+# $(call convert-epsgz,<eps.gz file>,<eps file>,[gray])
+convert-epsgz	= $(GUNZIP) -c '$1' $(if $3,| $(call kill-ps-color)) > '$2'
+
+# Converts .eps files into .eps files (usually a no-op, but can make grayscale)
+#
+# $(call convert-eps,<in file>,<out file>,[gray])
+convert-eps	= $(if $3,$(call kill-ps-color) $1 > $2)
+
+# The name of the file containing special postscript commands for grayscale
+gray_eps_file	:= gray.eps.make
+
+# Changes sethsbcolor and setrgbcolor calls in postscript to always produce
+# grayscale.  In general, this is accomplished by writing new versions of those
+# functions into the user dictionary space, which is looked up before the
+# global or system dictionaries (userdict is one of the permanent dictionaries
+# in postscript and is not read-only like systemdict).
+#
+# For setrgbcolor, the weighted average of the triple is computed and the
+# triple is replaced with three copies of that average before the original
+# procedure is called: .299R + .587G + .114B
+#
+# For sethsbcolor, the color is first converted to RGB, then to grayscale by
+# the new setrgbcolor operator as described above.  Why is this done?
+# Because simply using the value component will tend to make pure colors
+# white, a very undesirable thing.  Pure blue should not translate to white,
+# but to some level of gray.  Conversion to RGB does the right thing.  It's
+# messy, but it works.
+#
+# From
+# http://en.wikipedia.org/wiki/HSV_color_space#Transformation_from_HSV_to_RGB,
+# HSB = HSV (Value = Brightness), and the formula used to convert to RGB is
+# as follows:
+#
+# Hi = int(floor(6 * H)) mod 6
+# f = 6 * H - Hi
+# p = V(1-S)
+# q = V(1-fS)
+# t = V(1-(1-f)S)
+# if Hi = 0: R G B <-- V t p
+# if Hi = 1: R G B <-- q V p
+# if Hi = 2: R G B <-- p V t
+# if Hi = 3: R G B <-- p q V
+# if Hi = 4: R G B <-- t p V
+# if Hi = 5: R G B <-- V p q
+#
+# The messy stack-based implementation is below
+# $(call create-gray-eps-file,filename)
+define create-gray-eps-file
+$(ECHO) -n -e '\
+/OLDRGB /setrgbcolor load def\n\
+/setrgbcolor {\n\
+    .114 mul exch\n\
+    .587 mul add exch\n\
+    .299 mul add\n\
+    dup dup\n\
+    OLDRGB\n\
+} bind def\n\
+/OLDHSB /sethsbcolor load def\n\
+/sethsbcolor {\n\
+    2 index                     % H V S H\n\
+    6 mul floor cvi 6 mod       % Hi V S H\n\
+    3 index                     % H Hi V S H\n\
+    6 mul                       % 6H Hi V S H\n\
+    1 index                     % Hi 6H Hi V S H\n\
+    sub                         % f Hi V S H\n\
+    2 index 1                   % 1 V f Hi V S H\n\
+    4 index                     % S 1 V f Hi V S H\n\
+    sub mul                     % p f Hi V S H\n\
+    3 index 1                   % 1 V p f Hi V S H\n\
+    6 index                     % S 1 V p f Hi V S H\n\
+    4 index                     % f S 1 V p f Hi V S H\n\
+    mul sub mul                 % q p f Hi V S H\n\
+    4 index 1 1                 % 1 1 V q p f Hi V S H\n\
+    5 index                     % f 1 1 V q p f Hi V S H\n\
+    sub                         % (1-f) 1 V q p f Hi V S H\n\
+    8 index                     % S (1-f) 1 V q p f Hi V S H\n\
+    mul sub mul                 % t q p f Hi V S H\n\
+    4 -1 roll pop               % t q p Hi V S H\n\
+    7 -2 roll pop pop           % t q p Hi V\n\
+    5 -2 roll                   % Hi V t q p\n\
+    dup 0 eq\n\
+    {1 index 3 index 6 index}\n\
+    {\n\
+        dup 1 eq\n\
+        {3 index 2 index 6 index}\n\
+        {\n\
+            dup 2 eq\n\
+            {4 index 2 index 4 index}\n\
+            {\n\
+                dup 3 eq\n\
+                {4 index 4 index 3 index}\n\
+                {\n\
+                    dup 4 eq\n\
+                    {2 index 5 index 3 index}\n\
+                    {\n\
+                        dup 5 eq\n\
+                        {1 index 5 index 5 index}\n\
+                        {0 0 0}\n\
+                        ifelse\n\
+                    }\n\
+                    ifelse\n\
+                }\n\
+                ifelse\n\
+            }\n\
+            ifelse\n\
+        }\n\
+        ifelse\n\
+    }\n\
+    ifelse                      % B G R Hi V t q p\n\
+    setrgbcolor\n\
+    5 {pop} repeat\n\
+} bind def\n'\
+> $1
+endef
+
+# This actually inserts the color-killing code into a postscript file
+# $(call kill-ps-color)
+define kill-ps-color
+$(SED) -e '/%%EndComments/r $(gray_eps_file)'
+endef
+
+# Converts graphviz .dot files into .eps files
+# Grayscale is not directly supported by dot, so we pipe it through fig2dev in
+# that case.
+# $(call convert-dot,<dot file>,<eps file>,<log file>,[gray])
+define convert-dot
+$(DOT) -Tps '$1' 2>'$3' $(if $4,| $(call kill-ps-color)) > $2; \
+$(call colorize-dot-errors,$3)
+endef
+
+# Convert DVI to Postscript
+# $(call make-ps,<dvi file>,<ps file>,<log file>,[<paper size>])
+make-ps		= \
+	$(DVIPS) -o '$2' $(if $(filter-out BEAMER,$4),-t$(firstword $4),) '$1' \
+		$(if $(filter BEAMER,$4),| $(enlarge_beamer)) > $3 2>&1
+
+# Convert Postscript to PDF
+# $(call make-pdf,<ps file>,<pdf file>,<log file>,<embed file>)
+make-pdf	= \
+	$(call ps2pdf,$1,$2,$(filter 1,$(shell $(CAT) '$4'))) > '$3' 2>&1
+
+# Display information about what is being done
+# $(call echo-build,<input file>,<output file>,[<run number>])
+echo-build	= $(ECHO) "$(C_BUILD)= $1 --> $2$(if $3, ($3),) =$(C_RESET)"
+echo-graphic	= $(ECHO) "$(C_GRAPHIC)= $1 --> $2 =$(C_RESET)"
+echo-dep	= $(ECHO) "$(C_DEP)= $1 --> $2 =$(C_RESET)"
+
+# Display a list of something
+# $(call echo-list,<values>)
+echo-list	= for x in $1; do $(ECHO) "$$x"; done
+
+#
+# DEFAULT TARGET
+#
+
+.PHONY: all
+all: $(default_pdf_targets) ;
+
+.PHONY: all-pdf
+all-pdf: $(default_pdf_targets) ;
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+.PHONY: all-ps
+all-ps: $(default_ps_targets) ;
+
+.PHONY: all-dvi
+all-dvi: $(default_dvi_targets) ;
+endif
+
+#
+# VIEWING TARGET
+#
+.PHONY: show
+show: all
+	$(QUIET)for x in $(default_pdf_targets); do \
+		[ -e "$$x" ] && $(VIEW_PDF) $$x & \
+	done
+
+#
+# INCLUDES
+#
+source_includes	:= $(addsuffix .d,$(source_stems_to_include))
+graphic_includes := $(addsuffix .gpi.d,$(graphic_stems_to_include))
+
+# Include only the dependencies used
+ifneq "" "$(source_includes)"
+include $(source_includes)$(call include-message,$(source_includes))
+endif
+ifneq "" "$(graphic_includes)"
+include $(graphic_includes)$(call include-message,$(graphic_includes))
+endif
+
+#
+# MAIN TARGETS
+#
+
+# Note that we don't just say %: %.pdf here - this can tend to mess up our
+# includes, which detect what kind of file we are asking for.  For example,
+# asking to build foo.pdf is much different than asking to build foo when
+# foo.gpi exists, because we look through all of the goals for *.pdf that
+# matches *.gpi, then use that to determine which include files we need to
+# build.
+#
+# Thus, we invoke make recursively with better arugments instead, restarting
+# all of the appropriate machinery.
+.PHONY: $(default_stems_ss)
+$(default_stems_ss): %: %.pdf ;
+
+# This builds and displays the wanted file.
+.PHONY: $(addsuffix ._show,$(stems_ssg))
+%._show: %.pdf
+	$(QUIET)$(VIEW_PDF) $< &
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+.SECONDARY: $(all_pdf_targets)
+%.pdf: %.ps %.embed.make
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call make-pdf,$<,$@.temp,$@.log,$*.embed.make); \
+	if [ x"$$?" = x"0" ]; then \
+	    $(if $(VERBOSE),$(CAT) $@.log,:); \
+	    $(RM) -f '$@'; \
+	    $(MV) '$@.temp' '$@'; \
+	    $(TOUCH) '$@'; \
+	    $(call copy-with-logging,$@,$(BINARY_TARGET_DIR)); \
+	else \
+	    $(CAT) $@.log; \
+	    $(call remove-temporary-files,'$@.temp'); \
+	    $(sh_false); \
+	fi
+
+.SECONDARY: $(all_ps_targets)
+%.ps: %.dvi %.paper.make
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call make-ps,$<,$@.temp,$@.log,\
+			$(firstword $(shell $(CAT) $*.paper.make))); \
+	if [ x"$$?" = x"0" ]; then \
+	    $(if $(VERBOSE),$(CAT) $@.log,:); \
+	    $(RM) -f '$@'; \
+	    $(MV) '$@.temp' '$@'; \
+	    $(TOUCH) '$@'; \
+	    $(call copy-with-logging,$@,$(BINARY_TARGET_DIR)); \
+	else \
+	    $(CAT) $@.log; \
+	    $(call remove-temporary-files,'$@.temp'); \
+	    $(sh_false); \
+	fi
+endif
+
+# Build the final target (dvi or pdf) file.  This is a very tricky rule because
+# of the way that latex runs multiple times, needs graphics after the first run
+# (or maybe already has them), and relies on bibliographies or indices that may
+# not exist.
+#
+#	Check the log for fatal errors.  If they exist, colorize and bail.
+#
+#	Create the .auxtarget.cookie file.  (Needed for next time if not present)
+#
+#	If any of the following are true, we must rebuild at least one time:
+#
+#	* the .bbl was recently rebuilt
+#
+#		check a cookie, then delete it
+#
+#	* any of several output files was created or changed:
+#
+#		check $*.run.cookie, then delete it
+#
+#	* the .aux file changed in a way that necessitates attention
+#
+#		Note that if the .auxtarget.make file doesn't exist, this means
+#		that we are doing a clean build, so it doesn't figure into the
+#		test for running again.
+#
+#		compare against .auxtarget.make
+#
+#		move if different, remove if not
+#
+#	* the .log file has errors or warnings requiring at least one more run
+#
+#	We use a loop over a single item to simplify the process of breaking
+#	out when we find one of the conditions to be true.
+#
+#	If we do NOT need to run latex here, then we move the $@.1st.make file
+#	over to $@ because the target file has already been built by the first
+#	dependency run and is valid.
+#
+#	If we do, we delete that cookie file and do the normal multiple-runs
+#	routine.
+#
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+.SECONDARY: $(all_dvi_targets)
+endif
+%.$(build_target_extension): %.bbl %.aux %.$(build_target_extension).1st.make
+	$(QUIET)\
+	fatal=`$(call colorize-latex-errors,$*.log)`; \
+	if [ x"$$fatal" != x"" ]; then \
+		$(ECHO) "$$fatal"; \
+		exit 1; \
+	fi; \
+	$(call make-auxtarget-file,$*.aux.make,$*.auxtarget.cookie); \
+	run=0; \
+	for i in 1; do \
+		if $(call test-exists,$*.bbl.cookie); then \
+			run=1; \
+			break; \
+		fi; \
+		if $(call test-exists,$*.run.cookie); then \
+			run=1; \
+		    	break; \
+		fi; \
+		if $(call \
+		test-exists-and-different,$*.auxtarget.cookie,$*.auxtarget.make);\
+		then \
+			run=1; \
+			break; \
+		fi; \
+		if $(call test-log-for-need-to-run,$*); then \
+			run=1; \
+			break; \
+		fi; \
+	done; \
+	$(call remove-temporary-files,$*.bbl.cookie $*.run.cookie); \
+	$(MV) $*.auxtarget.cookie $*.auxtarget.make; \
+	if [ x"$$run" = x"1" ]; then \
+		$(call remove-files,$@.1st.make); \
+		for i in 2 3 4 5; do \
+			$(if $(findstring 3.79,$(MAKE_VERSION)),\
+				$(call echo-build,$*.tex,$@,$(RESTARTS)-$$$$i),\
+				$(call echo-build,$*.tex,$@,$(RESTARTS)-$$i)\
+			); \
+			$(call run-latex,$*); \
+			$(CP) '$*.log' '$*.'$(RESTARTS)-$$i'.log'; \
+			$(call test-run-again,$*) || break; \
+		done; \
+	else \
+		$(MV) '$@.1st.make' '$@'; \
+	fi; \
+	$(call copy-with-logging,$@,$(BINARY_TARGET_DIR)); \
+	$(call latex-color-log,$*)
+
+# Build the .bbl file.  When dependencies are included, this will (or will
+# not!) depend on something.bib, which we detect, acting accordingly.  The
+# dependency creation also produces the %.auxbbl.make file.  BibTeX is a bit
+# finicky about what you call the actual files, but we can rest assured that if
+# a .auxbbl.make file exists, then the .aux file does, as well.  The
+# .auxbbl.make file is a cookie indicating whether the .bbl needs to be
+# rewritten.  It only changes if the .aux file changes in ways relevant to .bbl
+# creation.
+#
+# Note that we do NOT touch the .bbl file if there is no need to
+# create/recreate it.  We would like to leave existing files alone if they
+# don't need to be changed, thus possibly avoiding a rebuild trigger.
+%.bbl: %.auxbbl.make
+	$(QUIET)\
+	$(if $(filter %.bib,$^),\
+		$(call echo-build,$(filter %.bib,$?) $*.aux,$@); \
+		$(call run-bibtex,$*); \
+		$(TOUCH) $@.cookie; \
+	) \
+	if $(EGREP) -q 'bibstyle.(apacann|chcagoa|[^}]*annot)' '$*.aux'; then \
+		$(call echo-build,** annotated extra latex **,output ignored,$(RESTARTS)-1); \
+		$(call run-latex,$*); \
+		$(CP) '$*.log' '$*.$(RESTARTS)-annotated.log'; \
+		$(if $(filter %.bib,$^),\
+			$(call echo-build,** annotated extra bibtex ** $(filter %.bib,$?) $*.aux,$@); \
+			$(call run-bibtex,$*); \
+			$(TOUCH) $@.cookie; \
+		) \
+		$(call echo-build,** annotated extra latex **,output ignored,$(RESTARTS)-2); \
+		$(call run-latex,$*); \
+	fi
+
+# Create the index file - note that we do *not* depend on %.tex here, since
+# that unnecessarily restricts the kinds of indices that we can build to those
+# with exactly the same stem as the source file.  Things like splitidx create
+# idx files with other names.
+#
+# Therefore, we add the .tex dependency in the sourcestem.d file in the call to
+# get index file dependencies from the logs.
+%.ind:	%.idx
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call run-makeindex,$<,$@,$*.ilg)
+
+# Create the glossary file
+%.gls:	%.glo %.tex
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call run-makeindex,$<,$@,$*.glg,-s nomencl.ist)
+
+# Create the nomenclature file
+%.nls:	%.nlo %.tex
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call run-makeindex,$<,$@,$*.nlg,-s nomencl.ist)
+
+# SCRIPTED LaTeX TARGETS
+#
+# Keep the generated .tex files around for debugging if needed.
+.SECONDARY: $(all_tex_targets)
+
+%.tex::	%.tex.sh
+	$(QUIET)$(call run-script,$(SHELL),$<,$@)
+
+%.tex::	%.tex.py
+	$(QUIET)$(call run-script,$(PYTHON),$<,$@)
+
+%.tex::	%.tex.pl
+	$(QUIET)$(call run-script,$(PERL),$<,$@)
+
+%.tex::	%.rst $(RST_STYLE_FILE)
+	$(QUIET)\
+	$(call run-script,$(RST2LATEX)\
+		--documentoptions=letterpaper\
+		$(if $(RST_STYLE_FILE),--stylesheet=$(RST_STYLE_FILE),),$<,$@)
+
+#
+# GRAPHICS TARGETS
+#
+.PHONY: all-graphics
+all-graphics:	$(all_graphics_targets);
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+.PHONY: all-pstex
+all-pstex:	$(all_pstex_targets);
+endif
+
+.PHONY: all-dot2tex
+all-dot2tex:	$(all_dot2tex_targets);
+
+.PHONY: show-graphics
+show-graphics: all-graphics
+	$(VIEW_GRAPHICS) $(all_known_graphics)
+
+$(gray_eps_file):
+	$(QUIET)$(call echo-build,$^,$@)
+	$(QUIET)$(call create-gray-eps-file,$@)
+
+ifeq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+%.pdf: %.eps $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-eps-to-pdf,$<,$@,$(GRAY))
+
+ifeq "$(strip $(GNUPLOT_OUTPUT_EXTENSION))" "pdf"
+%.pdf:	%.gpi %.gpi.d $(gpi_sed)
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-gpi,$<,$@,$(GRAY))
+endif
+
+%.pdf:	%.fig
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-fig,$<,$@,$(GRAY))
+
+endif
+
+%.eps:	%.gpi %.gpi.d $(gpi_sed)
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-gpi,$<,$@,$(GRAY))
+
+%.eps: %.fig
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-fig,$<,$@,$(GRAY))
+
+%.eps: %.dot $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-dot,$<,$@,$<.log,$(GRAY))
+
+%.eps: %.xvg $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-xvg,$<,$@,$(GRAY))
+
+%.eps: %.svg $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-svg,$<,$@,$(GRAY))
+
+%.eps: %.jpg $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-jpg,$<,$@,$(GRAY))
+
+%.eps: %.png $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-png,$<,$@,$(GRAY))
+
+%.eps: %.eps.gz $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-epsgz,$<,$@,$(GRAY))
+
+%.pstex: %.fig
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-fig-pstex,$<,$@,$(GRAY))
+
+%.pstex_t: %.fig %.pstex
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-fig-pstex-t,$<,$@,$*.pstex,$(GRAY))
+
+%.dot_t: %.dot
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-dot-tex,$<,$@)
+
+#
+# DEPENDENCY-RELATED TARGETS.
+#
+
+# Generate all of the information needed to get dependencies
+# As a side effect, this creates a .dvi or .pdf file (depending on the build
+# strategy).  We need to be sure to remove it if there are errors.  Errors can
+# take several forms and all of them are found within the log file:
+#	* There was a LaTeX error
+#	* A needed file was not found
+#	* Cross references need adjustment
+#
+# Behavior:
+#	This rule is responsible for generating the following:
+#	%.aux
+#	%.d
+#	%.aux.make
+#	%.(pdf|dvi).1st.make (the .pdf or .dvi output file, moved)
+#
+#	Steps:
+#
+#	Run latex
+#	Move .pdf or .dvi somewhere else (make no judgements about success)
+#	Flatten the .aux file into another file
+#	Add source dependencies
+#	Add graphic dependencies
+#	Add bib dependencies
+#
+#	Create cookies for various suffixes that may represent files that
+#	need to be read by LaTeX in order for it to function properly.
+#
+#	Note that if some of the dependencies are discovered because they turn
+#	up missing in the log file, we really need the .d file to be reloaded.
+#	Adding a sleep command helps with this.  Otherwise make is extremely
+#	nondeterministic, sometimes working, sometimes not.
+#
+#	Usually we can force this by simply removing the generated pdf file and
+#	not creating a .1st.make file..
+#
+%.$(build_target_extension).1st.make %.d %.aux %.aux.make %.fls: %.tex
+	$(QUIET)$(call echo-build,$<,$*.d $*.$(build_target_extension).1st.make,$(RESTARTS)-1)
+	$(QUIET)\
+	$(call run-latex,$<,--recorder) || $(sh_true); \
+	$(CP) '$*.log' '$*.$(RESTARTS)-1.log'; \
+	$(call die-on-dot2tex,$*.log); \
+	$(call die-on-no-aux,$*); \
+	$(call flatten-aux,$*.aux,$*.aux.make); \
+	$(ECHO) "# vim: ft=make" > $*.d; \
+	$(ECHO) ".PHONY: $*._graphics" >> $*.d; \
+	$(call get-inputs,$*.fls,$(addprefix $*.,aux aux.make d $(build_target_extension))) >> $*.d; \
+	$(call get-missing-inputs,$*.log,$(addprefix $*.,aux aux.make d $(build_target_extension))) >> $*.d; \
+	$(ECHO) ".SECONDEXPANSION:" >> $*.d; \
+	$(call get-graphics,$*) >> $*.d; \
+	$(call get-log-index,$*,$(addprefix $*.,d aux aux.make)) >> $*.d; \
+	$(call get-bibs,$*.aux.make,$(addprefix $*.,bbl aux aux.make)) >> $*.d; \
+	$(EGREP) -q "# MISSING" $*.d && $(SLEEP) 1 && $(RM) $*.pdf; \
+	$(call move-if-exists,$*.$(build_target_extension),$*.$(build_target_extension).1st.make); \
+	for s in toc out lot lof lol nav; do \
+		if [ -e "$*.$$s" ]; then \
+			if ! $(DIFF) -q $*.$$s $*.$$s.make >/dev/null 2>&1; then \
+				$(TOUCH) $*.run.cookie; \
+			fi; \
+			$(CP) $*.$$s $*.$$s.make; \
+		fi; \
+	done
+
+# This is a cookie that is updated if the flattened aux file has changed in a
+# way that affects the bibliography generation.
+.SECONDARY: $(addsuffix .auxbbl.make,$(stems_ssg))
+%.auxbbl.make: %.aux.make
+	$(QUIET)\
+	$(call make-auxbbl-file,$<,$@.temp); \
+	$(call replace-if-different-and-remove,$@.temp,$@)
+
+# Build a dependency file for .gpi files.  These often plot data files that
+# also reside in the directory, so if a data file changes, it's nice to know
+# about it.  This also handles loaded .gpi files, whose filename should have
+# _include_. in it.
+%.gpi.d: %.gpi
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call make-gpi-d,$<,$@)
+
+# Store the paper size for this document -- note that if beamer is used we set
+# it to the special BEAMER paper size.  We only do this, however, if the
+# special comment exists, in which case we enlarge the output with psnup.
+#
+#	The paper size is extracted from a documentclass attribute.
+%.paper.make: %.tex
+	$(QUIET)$(SED) \
+	-e '/\\documentclass/,/}/{' \
+	-e '  s/%.*//' \
+	-e '  H' \
+	-e '  /}/{' \
+	-e '    s/.*//' \
+	-e '    x' \
+	-e '    /\\documentclass/!d' \
+	-e '    s/[\n[:space:]]*//g' \
+	-e '    s/\([,{[]\)\([[:alnum:]]\{1,\}\)paper\([],}]\)/\1%-\2-%\3/g' \
+	-e '    s/\([,{[]\)\(landscape\)\([],}]\)/\1%-\2-%\3/g' \
+	-e '    s/^[^%]*%-//' \
+	-e '    s/-%[^%]*$$//' \
+	-e '    s/-%[^%]%-/ /g' \
+	-e '    p' \
+	-e '  }' \
+	-e '  d' \
+	-e '}' \
+	-e 'd' \
+	$< > $@; \
+	$(EGREP) -q '^[^%]*\\documentclass[^{]*{beamer}' $< && \
+	(\
+		$(EGREP) -q '^%%[[:space:]]*BEAMER[[:space:]]*LARGE$$' $< && \
+		$(ECHO) "BEAMER" > $@ || \
+		: > $@ \
+	) || $(sh_true)
+
+# Store embedding instructions for this document using a special comment
+%.embed.make: %.tex
+	$(QUIET)$(EGREP) '^%%[[:space:]]*NO[[:space:]]*EMBED[[:space:]]*$$' $< \
+		&& $(ECHO) '' > $@ \
+		|| $(ECHO) '1' > $@;
+
+#
+# HELPFUL PHONY TARGETS
+#
+
+.PHONY: _all_programs
+_all_programs:
+	$(QUIET)$(ECHO) "== All External Programs Used =="
+	$(QUIET)$(call output-all-programs)
+
+.PHONY: _check_programs
+_check_programs:
+	$(QUIET)$(ECHO) "== Checking Makefile Dependencies =="; $(ECHO)
+	$(QUIET) \
+	$(ECHO) hi; \
+	allprogs=`\
+	 ($(call output-all-programs)) | \
+	 $(SED) \
+	 -e 's/^[[:space:]]*//' \
+	 -e '/^#/d' \
+	 -e 's/[[:space:]]*#.*//' \
+	 -e '/^=/s/[[:space:]]/_/g' \
+	 -e '/^[[:space:]]*$$/d' \
+	 -e 's/^[^=].*=[[:space:]]*\([^[:space:]]\{1,\}\).*$$/\\1/' \
+	 `; \
+	spaces='                             '; \
+	for p in $${allprogs}; do \
+	case $$p in \
+		=*) $(ECHO); $(ECHO) "$$p";; \
+		*) \
+			$(ECHO) -n "$$p:$$spaces" | $(SED) -e 's/^\(.\{0,20\}\).*$$/\1/'; \
+			loc=`$(WHICH) $$p`; \
+			if [ x"$$?" = x"0" ]; then \
+				$(ECHO) "$(C_SUCCESS)Found:$(C_RESET) $$loc"; \
+			else \
+				$(ECHO) "$(C_FAILURE)Not Found$(C_RESET)"; \
+			fi; \
+			;; \
+	esac; \
+	done
+
+.PHONY: _check_gpi_files
+_check_gpi_files:
+	$(QUIET)$(ECHO) "== Checking all .gpi files for common errors =="; \
+	$(ECHO); \
+	for f in $(files.gpi); do \
+	result=`$(EGREP) '^([^#]*set terminal |set output )' $$f`; \
+	$(ECHO) -n "$$f: "; \
+	if [ x"$$result" = x"" ]; then \
+		$(ECHO) "$(C_SUCCESS)Okay$(C_RESET)"; \
+	else \
+		$(ECHO) "$(C_FAILURE)Warning: Problematic commands:$(C_RESET)";\
+		$(ECHO) "$(C_ERROR)$$result$(C_RESET)"; \
+	fi; \
+	done; \
+	$(ECHO)
+
+.PHONY: _all_stems
+_all_stems:
+	$(QUIET)$(ECHO) "== All Stems =="
+	$(QUIET)$(call echo-list,$(sort $(default_stems_ss)))
+
+.PHONY: _includes
+_includes:
+	$(QUIET)$(ECHO) "== Include Stems =="
+	$(QUIET)$(ECHO) "=== Sources ==="
+	$(QUIET)$(call echo-list,$(sort $(source_includes)))
+	$(QUIET)$(ECHO) "=== Graphics ==="
+	$(QUIET)$(call echo-list,$(sort $(graphic_includes)))
+
+.PHONY: _all_sources
+_all_sources:
+	$(QUIET)$(ECHO) "== All Sources =="
+	$(QUIET)$(call echo-list,$(sort $(all_files.tex)))
+
+.PHONY: _dependency_graph
+_dependency_graph:
+	$(QUIET)$(ECHO) "/* LaTeX Dependency Graph */"
+	$(QUIET)$(call output-dependency-graph)
+
+.PHONY: _show_dependency_graph
+_show_dependency_graph:
+	$(QUIET)$(call output-dependency-graph,$(graph_stem).dot)
+	$(QUIET)$(DOT) -Tps -o $(graph_stem).eps $(graph_stem).dot
+	$(QUIET)$(VIEW_POSTSCRIPT) $(graph_stem).eps
+	$(QUIET)$(call remove-temporary-files,$(graph_stem).*)
+
+.PHONY: _sources
+_sources:
+	$(QUIET)$(ECHO) "== Sources =="
+	$(QUIET)$(call echo-list,$(sort $(files.tex)))
+
+.PHONY: _scripts
+_scripts:
+	$(QUIET)$(ECHO) "== Scripts =="
+	$(QUIET)$(call echo-list,$(sort $(files_scripts)))
+
+.PHONY: _graphic_outputs
+_graphic_outputs:
+	$(QUIET)$(ECHO) "== Graphic Outputs =="
+	$(QUIET)$(call echo-list,$(sort $(all_graphics_targets)))
+
+.PHONY: _env
+_env:
+ifdef .VARIABLES
+	$(QUIET)$(ECHO) "== MAKE VARIABLES =="
+	$(QUIET)$(call echo-list,$(foreach var,$(sort $(.VARIABLES)),'$(var)'))
+endif
+	$(QUIET)$(ECHO) "== ENVIRONMENT =="
+	$(QUIET)$(ENV)
+
+#
+# CLEAN TARGETS
+#
+# clean-generated is somewhat unique - it relies on the .fls file being
+# properly built so that it can determine which of the files was generated, and
+# which was not.  Expect it to silently fail if the .fls file is missing.
+#
+# This is used to, e.g., clean up index files that are generated by the LaTeX.
+.PHONY: clean-generated
+clean-generated:
+	$(QUIET)$(call clean-files,$(foreach e,$(addsuffix .fls,$(all_stems_source)),\
+						$(shell $(call get-generated-names,$e))))
+
+.PHONY: clean-deps
+clean-deps:
+	$(QUIET)$(call clean-files,$(all_d_targets) *.make *.make.temp *.cookie)
+
+.PHONY: clean-tex
+clean-tex: clean-deps
+	$(QUIET)$(call clean-files,$(rm_tex))
+
+.PHONY: clean-graphics
+# TODO: This *always* deletes pstex files, even if they were not generated by
+# anything....  In other words, if you create a pstex and pstex_t pair by hand
+# an drop them in here without the generating fig file, they will be deleted
+# and you won't get them back.  It's a hack put in here because I'm not sure we
+# even want to keep pstex functionality, so my motivation is not terribly high
+# for doing it right.
+clean-graphics:
+	$(QUIET)$(call clean-files,$(all_graphics_targets) $(intermediate_graphics_targets) *.gpi.d *.pstex *.pstex_t *.dot_t)
+
+.PHONY: clean-backups
+clean-backups:
+	$(QUIET)$(call clean-files,$(backup_patterns) *.temp)
+
+.PHONY: clean-auxiliary
+clean-auxiliary:
+	$(QUIET)$(call clean-files,$(graph_stem).*)
+
+.PHONY: clean-nographics
+clean-nographics: clean-tex clean-deps clean-backups clean-auxiliary ;
+
+.PHONY: clean
+clean:	clean-generated clean-tex clean-graphics clean-deps clean-backups clean-auxiliary
+
+#
+# HELP TARGETS
+#
+
+.PHONY: help
+help:
+	$(help_text)
+
+.PHONY: version
+version:
+	$(QUIET)\
+	$(ECHO) "$(fileinfo) Version $(version)"; \
+	$(ECHO) "by $(author)"; \
+
+#
+# HELP TEXT
+#
+
+define help_text
+# $(fileinfo) Version $(version)
+#
+# by $(author)
+#
+# Generates a number of possible output files from a LaTeX document and its
+# various dependencies.  Handles .bib files, \include and \input, and .eps
+# graphics.  All dependencies are handled automatically by running LaTeX over
+# the source.
+#
+# USAGE:
+#
+#    make [GRAY=1] [VERBOSE=1] [SHELL_DEBUG=1] <target(s)>
+#
+# STANDARD OPTIONS:
+#    GRAY:
+#        Setting this variable forces all recompiled graphics to be grayscale.
+#        It is useful when creating a document for printing.  The default is
+#        to allow colors.  Note that it only changes graphics that need to be
+#        rebuilt!  It is usually a good idea to do a 'make clean' first.
+#
+#    VERBOSE:
+#        This turns off all @ prefixes for commands invoked by make.  Thus,
+#        you get to see all of the gory details of what is going on.
+#
+#    SHELL_DEBUG:
+#        This enables the -x option for sh, meaning that everything it does is
+#        echoed to stderr.  This is particularly useful for debugging
+#        what is going on in $$(shell ...) invocations.  One of my favorite
+#        debugging tricks is to do this:
+#
+#        make -d SHELL_DEBUG=1 VERBOSE=1 2>&1 | less
+#
+# STANDARD AUXILIARY FILES:
+#
+#      Makefile.ini
+#
+#          This file can contain variable declarations that override various
+#          aspects of the makefile.  For example, one might specify
+#
+#          neverclean := *.pdf *.ps
+#          onlysources.tex := main.tex
+#          LATEX_COLOR_WARNING := 'bold red uline'
+#
+#          And this would override the neverclean setting to ensure that pdf
+#          and ps files always remain behind, set the makefile to treat all
+#          .tex files that are not "main.tex" as includes (and therefore not
+#          default targets).  It also changes the LaTeX warning output to be
+#          red, bold, and underlined.
+#
+#          There are numerous variables in this file that can be overridden in
+#          this way.  Search for '?=' to find them all.
+#
+#          Also, you can put arbitrary targets into it if, for example, you
+#          want your source built from something else, e.g.:
+#
+#          generated.tex: generating_script.weird_lang depA depB
+#          	./generating_script.weird_lang > $$@
+#
+#          Note that if you are not careful, you can override the default
+#          target (what happens when you type "make" without arguments), so if
+#          you do use Makefile.ini, you probably want to start it with
+#          something like the following line:
+#
+#          default: all
+#
+#          Since the first target in any makefile is automatically the default,
+#          and the makefile already has a sensible "all" target, this will do
+#          what you want.
+#
+#          The Makefile.ini is imported before *anything else* is done, so go
+#          wild with your ideas for changes to this makefile in there.  It
+#          makes it easy to test them before submitting patches.
+#
+# STANDARD ENVIRONMENT VARIABLES:
+#
+#      LATEX_COLOR_WARNING		'$(LATEX_COLOR_WARNING)'
+#      LATEX_COLOR_ERROR		'$(LATEX_COLOR_ERROR)'
+#      LATEX_COLOR_UNDERFULL		'$(LATEX_COLOR_UNDERFULL)'
+#      LATEX_COLOR_OVERFULL		'$(LATEX_COLOR_OVERFULL)'
+#      LATEX_COLOR_PAGES		'$(LATEX_COLOR_PAGES)'
+#      LATEX_COLOR_BUILD		'$(LATEX_COLOR_BUILD)'
+#      LATEX_COLOR_GRAPHIC		'$(LATEX_COLOR_GRAPHIC)'
+#      LATEX_COLOR_DEP			'$(LATEX_COLOR_DEP)'
+#      LATEX_COLOR_SUCCESS		'$(LATEX_COLOR_SUCCESS)'
+#      LATEX_COLOR_FAILURE		'$(LATEX_COLOR_FAILURE)'
+#
+#   These may be redefined in your environment to be any of the following:
+#
+#      black
+#      red
+#      green
+#      yellow
+#      blue
+#      magenta
+#      cyan
+#      white
+#
+#   Bold or underline may be used, as well, either alone or in combination
+#   with colors:
+#
+#      bold
+#      uline
+#
+#   Order is not important.  You may want, for example, to specify:
+#
+#   export LATEX_COLOR_SUCCESS='bold blue uline'
+#
+#   in your .bashrc file.  I don't know why, but you may want to.
+#
+# STANDARD TARGETS:
+#
+#    all:
+#        Make all possible documents in this directory.  The documents are
+#        determined by scanning for .tex and .tex.sh (described in more detail
+#        later) and omitting any file that ends in ._include_.tex or
+#        ._nobuild_.tex.  The output is a set of .pdf files.
+#
+#        If you wish to omit files without naming them with the special
+#        underscore names, set the following near the top of the Makefile,
+#        or (this is recommended) within a Makefile.ini in the same directory:
+#
+#        	includes.tex := file1.tex file2.tex
+#
+#        This will cause the files listed to be considered as include files.
+#
+#        If you have only few source files, you can set
+#
+#        	onlysources.tex := main.tex
+#
+#        This will cause only the source files listed to be considered in
+#        dependency detection.  All other .tex files will be considered as
+#        include files.  Note that these options work for *any* source type,
+#        so you could do something similar with includes.gpi, for example.
+#        Note that this works for *any valid source* target.  All of the
+#        onlysources.* variables are commented out in the shipping version of
+#        this file, so it does the right thing when they simply don't exist.
+#        The comments are purely documentation.  If you know, for example, that
+#        file.mycoolformat is supported by this Makefile, but don't see the
+#        "onlysources.mycoolformat" declared in the comments, that doesn't mean
+#        you can't use it.  Go ahead and set "onlysources.mycoolformat" and it
+#        should do the right thing.
+#
+#    show:
+#        Builds and displays all documents in this directory.  It uses the
+#        environment-overridable value of VIEW_PDF (currently $(VIEW_PDF)) to
+#        do its work.
+#
+#    all-graphics:
+#        Make all of the graphics in this directory.
+#
+#    all-pstex (only for BUILD_STRATEGY=latex):
+#        Build all fig files into pstex and pstex_t files.  Gray DOES NOT WORK.
+#
+#    all-gray-pstex (only for BUILD_STRATEGY=latex):
+#    	 Build all fig files into grayscale pstex and pstex_t files.
+#
+#    all-dot2tex:
+#    	 Build all dot files into tex files.
+#
+#    show-graphics:
+#        Builds and displays all graphics in this directory.  Uses the
+#        environment-overridable value of VIEW_GRAPHICS (currently
+#        $(VIEW_GRAPHICS)) to do its work.
+#
+#    clean:
+#        Remove ALL generated files, leaving only source intact.
+#        This will *always* skip files mentioned in the "neverclean" variable,
+#        either in this file or specified in Makefile.ini:
+#
+#        	neverclean := *.pdf *.ps
+#
+#       The neverclean variable works on all "clean" targets below, as well.
+#
+#    clean-graphics:
+#        Remove all generated graphics files.
+#
+#    clean-backups:
+#        Remove all backup files: $(backup_patterns)
+#        (XFig and other editors have a nasty habit of leaving them around)
+#        Also removes Makefile-generated .temp files
+#
+#    clean-tex:
+#        Remove all files generated from LaTeX invocations except dependency
+#        information.  Leaves graphics alone.
+#
+#    clean-deps:
+#        Removes all auto-generated dependency information.
+#
+#    clean-auxiliary:
+#        Removes extra files created by various targets (like the dependency
+#        graph output).
+#
+#    clean-nographics:
+#        Cleans everything *except* the graphics files.
+#
+#    help:
+#        This help text.
+#
+#    version:
+#        Version information about this LaTeX makefile.
+#
+# DEBUG TARGETS:
+#
+#    _all_programs:
+#        A list of the programs used by this makefile.
+#
+#    _check_programs:
+#        Checks your system for the needed software and reports what it finds.
+#
+#    _check_gpi_files:
+#        Checks the .gpi files in the current directory for common errors, such
+#        as specification of the terminal or output file inside of the gpi file
+#        itself.
+#
+#    _dependency_graph:
+#        Outputs a .dot file to stdout that represents a graph of LaTeX
+#        dependencies.  To see it, use the _show_dependency_graph target or
+#        direct the output to a file, run dot on it, and view the output, e.g.:
+#
+#        make _dependency_graph > graph.dot
+#        dot -T ps -o graph.eps graph.dot
+#        gv graph.eps
+#
+#    _show_dependency_graph:
+#        Makes viewing the graph simple: extracts, builds and displays the
+#        dependency graph given in the _dependency_graph target using the value
+#        of the environment-overridable VIEW_POSTSCRIPT variable (currently set
+#        to $(VIEW_POSTSCRIPT)).  The postscript viewer is used because it
+#        makes it easier to zoom in on the graph, a critical ability for
+#        something so dense and mysterious.
+#
+#    _all_sources:
+#        List all .tex files in this directory.
+#
+#    _sources:
+#        Print out a list of all compilable sources in this directory.  This is
+#        useful for determining what make thinks it will be using as the
+#        primary source for 'make all'.
+#
+#    _scripts:
+#        Print out a list of scripts that make knows can be used to generate
+#        .tex files (described later).
+#
+#    _all_stems:
+#        Print a list of stems.  These represent bare targets that can be
+#        executed.  Listing <stem> as a bare target will produce <stem>.pdf.
+#
+#    _includes:
+#        A list of .d files that would be included in this run if _includes
+#        weren't specified.  This target may be used alone or in conjunction
+#        with other targets.
+#
+#    _graphic_outputs:
+#        A list of all generated .eps files
+#
+#    _env:
+#        A list of environment variables and their values.  If supported by
+#        your version of make, also a list of variables known to make.
+#
+# FILE TARGETS:
+#
+#    %, %.pdf:
+#        Build a PDF file from the corresponding %.tex file.
+#
+#        If BUILD_STRATEGY=pdflatex, then this builds the pdf directly.
+#        Otherwise, it uses this old-school but effective approach:
+#
+#            latex -> dvips -> ps2pdf
+#
+#        The BUILD_STRATEGY can be overridden in Makefile.ini in the same
+#        directory.  The default is pdflatex.
+#
+#        Reasons for using latex -> dvips include the "psfrag" package, and the
+#        generation of postscript instead of PDF.  Arguments for using pdflatex
+#        include "new and shiny" and "better supported."  I can't argue with
+#        either of those, and supporting them both didn't turn out to be that
+#        difficult, so there you have it.  Choices.
+#
+#    %._show:
+#        A phony target that builds the pdf file and then displays it using the
+#        environment-overridable value of VIEW_PDF ($(VIEW_PDF)).
+#
+#    %._graphics:
+#        A phony target that generates all graphics on which %.pdf (or %.dvi)
+#        depends.
+#
+#    %.ps (only for BUILD_STRATEGY=latex):
+#        Build a Postscript file from the corresponding %.tex file.
+#        This is done using dvips.  Paper size is automatically
+#        extracted from the declaration
+#
+#        \documentclass[<something>paper]
+#
+#        or it is the system default.
+#
+#        If using beamer (an excellent presentation class), the paper
+#        size is ignored.  More on this later.
+#
+#    %.dvi (only for BUILD_STRATEGY=latex):
+#        Build the DVI file from the corresponding %.tex file.
+#
+#    %.ind:
+#        Build the index for this %.tex file.
+#
+#    %.gls:
+#        Build the nomenclature glossary for this %.tex file.
+#
+#    %.nls:
+#        Build the (newer) nomenclature file for this %.tex file.
+#
+#    %.eps:
+#        Build an eps file from one of the following file types:
+#
+#       .dot    : graphviz
+#       .gpi    : gnuplot
+#       .fig    : xfig
+#       .xvg    : xmgrace
+#       .svg    : scalable vector graphics (goes through inkscape)
+#       .png    : png (goes through NetPBM)
+#       .jpg	: jpeg (goes through ImageMagick)
+#       .eps.gz : gzipped eps
+#
+#       The behavior of this makefile with each type is described in
+#       its own section below.
+#
+#    %.pstex{,_t} (only for BUILD_STRATEGY=latex):
+#       Build a .pstex_t file from a .fig file.
+#
+# FEATURES:
+#
+#    Optional Binary Directory:
+#        If you create the _out_ directory in the same place as the makefile,
+#        it will automatically be used as a dumping ground for .pdf (or .dvi,
+#        .ps, and .pdf) output files.
+#
+#        Alternatively, you can set the BINARY_TARGET_DIR variable, either as a
+#        make argument or in Makefile.ini, to point to your directory of
+#        choice.  Note that no pathname wildcard expansion is done in the
+#        makefile, so make sure that the path is complete before going in
+#        there.  E.g., if you want to specify something in your home directory,
+#        use $$HOME/ instead of ~/ so that the shell expands it before it gets
+#        to the makefile.
+#
+#    External Program Dependencies:
+#        Every external program used by the makefile is represented by an
+#        ALLCAPS variable at the top of this file.  This should allow you to
+#        make judgments about whether your system supports the use of this
+#        makefile.  The list is available in the ALL_PROGRAMS variable and,
+#        provided that you are using GNU make 3.80 or later (or you haven't
+#        renamed this file to something weird like "mylatexmakefile" and like
+#        invoking it with make -f) can be viewed using
+#
+#        make _all_programs
+#
+#        Additionally, the availability of these programs can be checked
+#        automatically for you by running
+#
+#        make _check_programs
+#
+#        The programs are categorized according to how important they are and
+#        what function they perform to help you decide which ones you really
+#        need.
+#
+#    Colorized Output:
+#        The output of commands is colorized to highlight things that are often
+#        important to developers.  This includes {underfull,overfull}
+#        {h,v}boxes, general LaTeX Errors, each stage of document building, and
+#        the number of pages in the final document.  The colors are obtained
+#        using 'tput', so colorization should work pretty well on any terminal.
+#
+#        The colors can be customized very simply by setting any of the
+#        LATEX_COLOR_<CONTEXT> variables in your environment (see above).
+#
+#    Predecessors to TeX Files:
+#        Given a target <target>, if no <target>.tex file exists but a
+#        corresponding script or predecessor file exists, then appropriate
+#        action will be taken to generate the tex file.
+#
+#        Currently supported script or predecessor languages are:
+#
+#        sh:     %.tex.sh
+#        perl:   %.tex.pl
+#        python: %.tex.py
+#
+#           Calls the script using the appropriate interpreter, assuming that
+#           its output is a .tex file.
+#
+#           The script is called thus:
+#
+#              <interpreter> <script file name> <target tex file>
+#
+#           and therefore sees exactly one parameter: the name of the .tex
+#           file that it is to create.
+#
+#           Why does this feature exist?  I ran into this while working on
+#           my paper dissertation.  I wrote a huge bash script that used a
+#           lot of sed to bring together existing papers in LaTeX.  It
+#           would have been nice had I had something like this to make my
+#           life easier, since as it stands I have to run the script and
+#           then build the document with make.  This feature provides hooks
+#           for complicated stuff that you may want to do, but that I have
+#           not considered.  It should work fine with included dependencies,
+#           too.
+#
+#           Scripts are run every time make is invoked.  Some trickery is
+#           employed to make sure that multiple restarts of make don't cause
+#           them to be run again.
+#
+#        reST: %.rst
+#
+#           Runs the reST to LaTeX converter to generate a .tex file
+#           If it finds a file names _rststyle_._include_.tex, uses it as
+#           the "stylesheet" option to rst2latex.
+#
+#           Note that this does not track sub-dependencies in rst files.  It
+#           assumes that the top-level rst file will change if you want a
+#           rebuild.
+#
+#    Dependencies:
+#
+#        In general, dependencies are extracted directly from LaTeX output on
+#        your document.  This includes
+#
+#        *    Bibliography information
+#        *    \include or \input files (honoring \includeonly, too)
+#        *    Graphics files inserted by the graphicx package
+#
+#        Where possible, all of these are built correctly and automatically.
+#        In the case of graphics files, these are generated from the following
+#        file types:
+#
+#        GraphViz:      .dot
+#        GNUPlot:       .gpi
+#        XFig:          .fig
+#        XMgrace:       .xvg
+#        SVG:           .svg
+#        PNG:           .png
+#        JPEG:          .jpg
+#        GZipped EPS:   .eps.gz
+#
+#        If the file exists as a .eps already, it is merely used (and will not
+#        be deleted by 'clean'!).
+#
+#        LaTeX and BibTeX are invoked correctly and the "Rerun to get
+#        cross-references right" warning is heeded a reasonable number of
+#        times.  In my experience this is enough for even the most troublesome
+#        documents, but it can be easily changed (if LaTeX has to be run after
+#        BibTeX more than three times, it is likely that something is moving
+#        back and forth between pages, and no amount of LaTeXing will fix
+#        that).
+#
+#        \includeonly is honored by this system, so files that are not
+#        specified there will not trigger a rebuild when changed.
+#
+#    Beamer:
+#        A special TeX source comment is recognized by this makefile (only when
+#        BUILD_STRATEGY=latex, since this invokes psnup):
+#
+#        %%[[:space:]]*BEAMER[[:space:]]*LARGE
+#
+#        The presence of this comment forces the output of dvips through psnup
+#        to enlarge beamer slides to take up an entire letter-sized page.  This
+#        is particularly useful when printing transparencies or paper versions
+#        of the slides.  For some reason landscape orientation doesn't appear
+#        to work, though.
+#
+#        If you want to put multiple slides on a page, use this option and then
+#        print using mpage, a2ps, or psnup to consolidate slides.  My personal
+#        favorite is a2ps, but your mileage may vary.
+#
+#        When beamer is the document class, dvips does NOT receive a paper size
+#        command line attribute, since beamer does special things with sizes.
+#
+#    GNUPlot Graphics:
+#        When creating a .gpi file, DO NOT INCLUDE the "set terminal" or "set
+#        output" commands!  The makefile will include terminal information for
+#        you.  Besides being unnecessary and potentially harmful, including the
+#        terminal definition in the .gpi file makes it harder for you, the one
+#        writing the document, to preview your graphics, e.g., with
+#
+#           gnuplot -persist myfile.gpi
+#
+#        so don't do specify a terminal or an output file in your .gpi files.
+#
+#        When building a gpi file into an eps file, there are several features
+#        available to the document designer:
+#
+#        Global Header:
+#            The makefile searches for the files in the variable GNUPLOT_GLOBAL
+#            in order:
+#
+#            ($(GNUPLOT_GLOBAL))
+#
+#            Only the first found is used.  All .gpi files in the directory are
+#            treated as though the contents of GNUPLOT_GLOBAL were directly
+#            included at the top of the file.
+#
+#            NOTE: This includes special comments! (see below)
+#
+#        Font Size:
+#            A special comment in a .gpi file (or a globally included file) of
+#            the form
+#
+#            ## FONTSIZE=<number>
+#
+#            will change the font size of the GPI output.  If font size is
+#            specified in both the global file and the GPI file, the
+#            specification in the individual GPI file is used.
+#
+#        Grayscale Output:
+#            GNUplot files also support a special comment to force them to be
+#            output in grayscale *no matter what*:
+#
+#            ## GRAY
+#
+#            This is not generally advisable, since you can always create a
+#            grayscale document using the forms mentioned above.  But, if your
+#            plot simply must be grayscale even in a document that allows
+#            colors, this is how you do it.
+#
+#    XFig Graphics:
+#            No special handling is done with XFig, except when a global
+#            grayscale method is used, e.g.
+#
+#                make GRAY=1 document
+#
+#            In these cases the .eps files is created using the -N switch to
+#            fig2dev to turn off color output.  (Only works with eps, not pstex
+#            output)
+#
+#    GraphVis Graphics:
+#            Color settings are simply ignored here.  The 'dot' program is used
+#            to transform a .dot file into a .eps file.
+#
+#            If you want, you can use the dot2tex program to convert dot files
+#            to tex graphics.  The default is to just call dot2tex with no
+#            arguments, but you can change the DOT2TEX definition to include
+#            options as needed (in your Makefile.ini).
+#
+#            Note that, as with pstex, the makefile cannot use latex's own
+#            output to discover all missing dot_t (output) files, since anytime
+#            TeX includes TeX, it has to bail when it can't find the include
+#            file.  It can therefore only stop on the first missing file it
+#            discovers, and we can't get a large list of them out easily.
+#
+#            So, the makefile errors out if it's missing an included dot_t
+#            file, then prompts the user to run this command manually:
+#
+#                make all-dot2tex
+#
+#    GZipped EPS Graphics:
+#
+#        A .eps.gz file is sometimes a nice thing to have.  EPS files can get
+#        very large, especially when created from bitmaps (don't do this if you
+#        don't have to).  This makefile will unzip them (not in place) to
+#        create the appropriate EPS file.
+#
+endef
+
+#
+# DEPENDENCY CHART:
+#
+#digraph "g" {
+#    rankdir=TB
+#    size="9,9"
+#    edge [fontsize=12 weight=10]
+#    node [shape=box fontsize=14 style=rounded]
+#
+#    eps [
+#        shape=Mrecord
+#        label="{{<gpi> GNUplot|<epsgz> GZip|<dot> Dot|<fig> XFig}|<eps> eps}"
+#        ]
+#    pstex [label="%.pstex"]
+#    pstex_t [label="%.pstex_t"]
+#    tex_outputs [shape=point]
+#    extra_tex_files [shape=point]
+#    gpi_data [label="<data>"]
+#    gpi_includes [label="_include_.gpi"]
+#    aux [label="%.aux"]
+#    fls [label="%.fls"]
+#    idx [label="%.idx"]
+#    glo [label="%.glo"]
+#    ind [label="%.ind"]
+#    log [label="%.log"]
+#    tex_sh [label="%.tex.sh"]
+#    rst [label="%.rst"]
+#    tex [
+#        shape=record
+#        label="<tex> %.tex|<include> _include_.tex"
+#        ]
+#    include_aux [label="_include_.aux"]
+#    file_bib [label=".bib"]
+#    bbl [label="%.bbl"]
+#    dvi [label="%.dvi"]
+#    ps [label="%.ps"]
+#    pdf [label="%.pdf"]
+#    fig [label=".fig"]
+#    dot [label=".dot"]
+#    gpi [label=".gpi"]
+#    eps_gz [label=".eps.gz"]
+#
+#    gpi_files [shape=point]
+#
+#    rst -> tex:tex [label="reST"]
+#    tex_sh -> tex:tex [label="sh"]
+#    tex_pl -> tex:tex [label="perl"]
+#    tex_py -> tex:tex [label="python"]
+#    tex -> tex_outputs [label="latex"]
+#    tex_outputs -> dvi
+#    tex_outputs -> aux
+#    tex_outputs -> log
+#    tex_outputs -> fls
+#    tex_outputs -> idx
+#    tex_outputs -> include_aux
+#    aux -> bbl [label="bibtex"]
+#    file_bib -> bbl [label="bibtex"]
+#    idx -> ind [label="makeindex"]
+#    glo -> gls [label="makeindex"]
+#    nlo -> nls [label="makeindex"]
+#    gls -> extra_tex_files
+#    nls -> extra_tex_files
+#    ind -> extra_tex_files
+#    bbl -> extra_tex_files
+#    eps -> extra_tex_files
+#    extra_tex_files -> dvi [label="latex"]
+#    gpi_files -> eps:gpi [label="gnuplot"]
+#    gpi -> gpi_files
+#    gpi_data -> gpi_files
+#    gpi_includes -> gpi_files
+#    eps_gz -> eps:epsgz [label="gunzip"]
+#    fig -> eps:fig [label="fig2dev"]
+#    fig -> pstex [label="fig2dev"]
+#    fig -> pstex_t [label="fig2dev"]
+#    pstex -> pstex_t [label="fig2dev"]
+#    dot -> eps:dot [label="dot"]
+#    dvi -> ps [label="dvips"]
+#    include_aux -> bbl [label="bibtex"]
+#    ps -> pdf [label="ps2pdf"]
+#
+#    edge [ color=blue label="" style=dotted weight=1 fontcolor=blue]
+#    fls -> tex:include [label="INPUT: *.tex"]
+#    fls -> file_bib [label="INPUT: *.aux"]
+#    aux -> file_bib [label="\\bibdata{...}"]
+#    include_aux -> file_bib [label="\\bibdata{...}"]
+#    log -> gpi [label="Graphic file"]
+#    log -> fig [label="Graphic file"]
+#    log -> eps_gz [label="Graphic file"]
+#    log -> dot [label="Graphic file"]
+#    log -> idx [label="No file *.ind"]
+#    log -> glo [label="No file *.gls"]
+#    log -> nlo [label="No file *.nls"]
+#    gpi -> gpi_data [label="plot '...'"]
+#    gpi -> gpi_includes [label="load '...'"]
+#    tex:tex -> ps [label="paper"]
+#    tex:tex -> pdf [label="embedding"]
+#}
+
+#
+# DEPENDENCY CHART SCRIPT
+#
+# $(call output_dependency_graph,[<output file>])
+define output-dependency-graph
+	if [ -f '$(this_file)' ]; then \
+	$(SED) \
+		-e '/^[[:space:]]*#[[:space:]]*DEPENDENCY CHART:/,/^$$/!d' \
+		-e '/DEPENDENCY CHART/d' \
+		-e '/^$$/d' \
+		-e 's/^[[:space:]]*#//' \
+		$(this_file) $(if $1,> '$1',); \
+	else \
+		$(ECHO) "Cannot determine the name of this makefile."; \
+	fi
+endef
+# vim: noet sts=0 sw=8 ts=8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/datacage-config-manual/README	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,1 @@
+build with `make datacage-config-manual`
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/datacage-config-manual/content.tex	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,164 @@
+\section{Configuration of the Datacage}
+
+\subsection{Tasks and Recommendation types of the datacage}
+
+The datacage serves two purposes.
+It handles automatic 'recommendations', which are instructions
+sent by the client to add newly created artifacts to the collection.
+From a user perspective, these artifacts mainly represent curves or data
+points in the resulting diagrams.
+The second task is to let the user add already existing artifacts (i.e.
+previous calculations) or new artifacts with access to related data.
+
+Irrelevant of the type of elements (recommendations or user picked data) the
+datacage can iterate over possible artifacts by accessing its own database.
+Thus, to create a list of matching entries, database queries are used.
+
+\subsection{Structure of the datacage configuration file meta-data.conf}
+
+The datacages behaviour is defined in the file conf/meta-data.xml .
+
+In meta-data.xml, database queries are defined as \verb!<dc:statement>! elements,
+for example
+\begin{lstlisting}
+                <dc:statement>
+                  SELECT id          AS prot_id,
+                         description AS prot_description
+                  FROM wsts WHERE kind = 1 AND river_id = ${river_id}
+                </dc:statement>
+\end{lstlisting}
+
+As can be seen from the example, the datacage configuration file can maintain
+its own stack of variables (\${river\_id} in above example).
+
+The database query will usually deliver one or many results, over which is
+iterated using the \verb!<dc:elements>! elements.
+
+Information from this results can be used for two goals.
+It can be taken as output, in which
+case the client will either request the creation of these artifacts (considering
+recommendations), or shown by the client in a the 'datacage widget',
+the graphical representation of data which can be added in the current
+context.  The later is seen when the user clicks on the Datacage button in
+a diagram.
+Or information can be used to feed a second (or third...) database query.
+Following above example:
+
+\begin{lstlisting}
+                <dc:statement>
+                  SELECT id          AS prot_id,
+                         description AS prot_description
+                  FROM wsts WHERE kind = 1 AND river_id = ${river_id}
+                </dc:statement>
+                <dc:elements>
+                  <additional>
+                    <dc:attribute name="name" value="${prot_description}"/>
+                    <dc:context>
+                      <dc:statement>
+                        SELECT id       AS prot_column_id,
+                               name     AS prot_column_name,
+                               position AS prot_rel_pos
+                        FROM wst_columns WHERE wst_id = ${prot_id}
+                        ORDER by position
+                      </dc:statement>
+                      <!-- ... -->
+\end{lstlisting}
+
+In both cases, an \verb!<dc:elements>! element makes database queries available.
+Also
+note how the variables are defined in the first query and reused in the second
+query (\$\{prot\_it\}).
+
+Any alement not prefixed with "dc" represents a (sub-) node in the resulting
+tree.  The client will display these nodes and maybe subnodes in the datacage
+widget - \verb!<additional>! in above example.  The elements name is translated by
+the client.
+
+While iterating the final results, \verb!<dc:attributes>! have to be specified
+to define how the artifact is to be created.
+
+\begin{lstlisting}
+                      <dc:elements>
+                        <column>
+                          <dc:attribute name="name" value="${prot_column_name}"/>
+                          <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/>
+                          <dc:attribute name="factory" value="staticwkms"/>
+                        </column>
+                      </dc:elements>
+\end{lstlisting}
+
+The "name" attribute is what is to be displayed in the client, the "ids" are given
+to the server and pass important information about the chosen data.
+The "factory" is chosen according to the type of data displayed.
+
+So far, three other elements have not yet been mentioned: \verb!<dc:comment>!,
+\verb!<dc:if>! and the \verb!<dc:when><dc:otherwise>! structure.
+\verb!<dc:comment>! is an element to allow comments.  Choose these over standard
+\verb=<!-- -->= xml comments, because they are not transferred to the client.
+\verb!<dc:if>! and \verb!<dc:when>! allow control (rather: definition) flow within
+the configuration and work in analogy to the XSL-elements \verb!<xsl:if>!
+and \verb!<xsl:when>!.
+
+When dealing with the behaviour specification of the datacage, multiple
+interpretations for the term "context" are possible.
+A \verb!<dc:context>! element essentially means a database binding.  Thus each
+query (\verb!<dc:statement>!) needs to be nested in its own context.
+Furthermore, two types of databases with own bindings exist:
+The "system" (default for \verb!<dc:context>!, \verb!<dc:context connection="system">!)
+context allows queries related to the backend database with existing
+data (e.g. measurements).
+The "user" context (\verb!<dc:context connection="user">!) allows queries against
+the database which stores information about already existing artifacts and
+calculations.
+
+Another connotation for the term "context" is the situation from which
+the datacage is queried.  The standard case is a from the datacage widget.
+When the user opens the datacage from the graphical client, this is done
+from one of possible multiple diagrams.
+When the datacage is queried, it gets as an argument the "out" of
+the current artifact.  The out corresponds to the diagram type.
+
+For example the inner block of
+
+\begin{lstlisting}
+          <dc:if test="dc:contains($artifact-outs, 'longitudinal_section')">
+              <longitudinal_section>
+                <dc:call-macro name="annotations"/>
+              </longitudinal_section>
+          </dc:if>
+\end{lstlisting}
+
+will only be executed if called from the datacage within a
+longitudinal\_section diagram.
+
+In the given example another concept of the datacage configuration is
+encountered: Macros.
+
+Macros help to avoid duplication of parts of the document.  As the datacage
+of some diagrams should include the same type of data, the same query should
+be executed in multiple situations.
+
+Therefore a macro can be defined, like in
+
+\begin{lstlisting}
+        <dc:macro name="basedata_4_heightmarks-wq">
+          <heightmarks>
+            <dc:context>
+              <dc:statement>
+                SELECT id          AS prot_id,
+                       description AS prot_description
+                FROM wsts WHERE kind = 4 AND river_id = ${river_id}
+              </dc:statement>
+              <dc:elements>
+              <!-- ... -->
+        </dc:macro>
+\end{lstlisting}
+
+and invoked from another location within the document, e.g. with
+
+\begin{lstlisting}
+
+                <dc:call-macro name="basedata_4_heightmarks"/>
+\end{lstlisting}
+.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/datacage-config-manual/datacage-config-manual.tex	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,199 @@
+\documentclass[12pt]{scrartcl}
+
+%----------------------------------------------
+% Load packages
+
+\usepackage{a4}
+\usepackage{times}
+\usepackage[latin1]{inputenc}
+\usepackage{fancyhdr}
+%\usepackage{german}
+%\usepackage[marvosym]{eurofont}
+%\usepackage[all, light]{draftcopy}
+%\usepackage{supertabular}
+%\usepackage{colortbl}
+%\usepackage{epsf}
+\usepackage{graphicx}
+\usepackage{lastpage}
+%\usepackage{proposal}
+\usepackage{listings}
+\usepackage[hyperindex=true, bookmarks=true, breaklinks=true,
+colorlinks=true, linkcolor=red,bookmarksopen]{hyperref}
+
+%----------------------------------------------
+% Document DATE and VERSION
+% set these values when releasing a new version
+
+\newcommand{\documentdate}{July 05th, 2012}
+\newcommand{\documentversion}{1.0}
+\newcommand{\documentrevision}{FIXME SVN REV}
+\newcommand{\documentID}{datacage-config-manual.tex}
+%----------------------------------------------
+
+%----------------------------------------------
+% Document TITLE
+\newcommand{\documenttitle}{FLYS 3.0 -- Configuration of the Datacage}
+
+
+%----------------------------------------------
+% Some parameters for layouting
+
+\paperwidth=21cm
+\hoffset=-0.54cm
+\textwidth=17cm
+
+\paperheight=29.7cm
+\voffset=-1.5cm
+\topmargin=0cm
+\headheight=1cm
+\textheight=24cm
+
+\setcounter{secnumdepth}{4}
+\setcounter{tocdepth}{4}
+
+%----------------------------------------------
+
+\begin{document}
+
+\lstset{ %
+language=sh,
+basicstyle=\ttfamily,       % the size of the fonts that are used for the code
+numbers=left,                   % where to put the line-numbers
+numberstyle=\footnotesize,      % the size of the fonts that are used for the line-numbers
+numbersep=5pt,                  % how far the line-numbers are from the code
+% backgroundcolor=\color{white},  % choose the background color. You must add \usepackage{color}
+showspaces=false,               % show spaces adding particular underscores
+showstringspaces=false,         % underline spaces within strings
+showtabs=false,                 % show tabs within strings adding particular underscores
+frame=single,                   % adds a frame around the code
+tabsize=2,                      % sets default tabsize to 2 spaces
+captionpos=b,                   % sets the caption-position to bottom
+breaklines=true,                % sets automatic line breaking
+breakatwhitespace=false,        % sets if automatic breaks should only happen at whitespace
+title=\lstname,                 % show the filename of files included with \lstinputlisting; also try caption instead of title
+escapeinside={\%*}{*)}          % if you want to add a comment within your code
+% morekeywords={*,...}            % if you want to add more keywords to the set
+}
+
+%-----------------------------------
+% HEADER/FOOTER DEFINITION
+
+% for some pages latex switches back to pagestyle plain :-(
+\fancypagestyle{plain}{%
+	\fancyhf{} % clear all header and footer fields
+	\fancyhead[LO,RE]{\footnotesize \documenttitle\\ \leftmark}
+	\fancyfoot[RO,LE]{\footnotesize Intevation GmbH} % Author
+	\fancyfoot[CO,CE]{\footnotesize \thepage/\pageref{LastPage}}
+	\fancyfoot[LO,RE]{\footnotesize \documentdate
+	\\\documentID}
+	\renewcommand{\footrulewidth}{0.4pt}
+}
+
+% and now define pagestyle fancy
+\fancyhead{} % clear all fields
+\fancyhead[LO]{\footnotesize \documenttitle\\ \leftmark}
+
+\fancyfoot{}% clear all fields
+\fancyfoot[RO]{\footnotesize Intevation GmbH} % Author
+\fancyfoot[CO]{\footnotesize \thepage/\pageref{LastPage}}
+\fancyfoot[LO]{\footnotesize \documentdate
+\\\documentID}
+
+\renewcommand{\footrulewidth}{0.4pt}
+
+%
+% END Header/Footer Definition
+%-----------------------------------
+
+%----------------------------------------------
+% MACRO DEFINITION
+%
+%   \Fig{figure}{lof text}{caption} :
+%			places 'figure' and
+%                       writes 'caption' at the bottom with leading
+%                       'Abbildung figno:'. 'lof text' is added to the list of
+%                       figures.
+%                       Example:
+%                       \Fig{\epsfxsize30mm \epsffile{x.eps}}{the x}{the x}
+%
+%   \FigNoEntry{}{} :
+%			same as above, no entry in figures list
+%
+%   \FigCaption{} :
+%			line with figure caption, setting figure
+%                       counter and figures list
+%
+%   \Tab{table}{lot text}{caption} :
+%			places 'table' and writes caption on top of the table
+%			with leading 'Tabelle tabno:'. 'lot text' is added to
+%			the list of tables.
+%****************************************************************************
+%       Figure makro for graphics continously enumerated.
+%
+
+\newcounter{FigCnt}
+\newcounter{TabCnt}
+
+\newcommand{\Fig}[3]%
+{
+        \refstepcounter{FigCnt}
+        \addcontentsline{lof}{figure}%
+                {\protect\numberline{\arabic{FigCnt}}{#2}}
+        \mbox{#1}
+
+\nopagebreak
+        {Abbildung \arabic{FigCnt}: #3}
+
+}
+
+\newcommand{\FigNoEntry}[2]%
+{
+        \refstepcounter{FigCnt}
+        \mbox{#1}
+
+\nopagebreak
+        {Abbildung \arabic{FigCnt}: #2}
+
+}
+
+\newcommand{\FigCaption}[1]%
+{
+        \refstepcounter{FigCnt}
+        \addcontentsline{lof}{figure}%
+                {\protect\numberline{\arabic{FigCnt}}{#1}}
+
+        %{Figure \thesection.\arabic{FigCnt}: #1}
+}
+
+\newcommand{\Tab}[3]%
+{
+        \refstepcounter{TabCnt}
+        \addcontentsline{lot}{figure}%
+                {\protect\numberline{\arabic{TabCnt}}{#2}}
+        {Tabelle \arabic{TabCnt}: #3}
+\nopagebreak
+        #1
+
+}
+
+\hyphenation{Intevation}
+% end macro definition
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newcounter{schritt}
+\renewcommand{\theschritt}{\Roman{schritt}}
+%\makeatletter\renewcommand{\p@schritt}{Abschnitt~\thesubsubsection~}\makeatother
+
+%-----------------------------------
+% DOCUMENT SETTINGS
+\pagestyle{fancy}
+\setlength{\parindent}{0cm}
+\setlength{\parskip}{5pt plus 2pt minus 1pt}
+
+% Start actual content here
+\include{title}
+\newpage
+\tableofcontents
+\include{content}
+\end{document}
Binary file flys-artifacts/doc/datacage-config-manual/figures/bsh_logo.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/datacage-config-manual/figures/intevation-logo.eps	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,1222 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%For: Frank Koormann,,,
+%%CreationDate: Thu Mar 29 14:37:25 2001
+%%Title: intevation_logo-thin.eps
+%%Creator: Sketch 0.6.8
+%%Pages: 1
+%%BoundingBox: 78 68 132 94
+%%Extensions: CMYK
+%%DocumentSuppliedResources: (atend)
+%%EndComments
+
+%%BeginProlog
+%%BeginResource: procset Linux-Sketch-Procset 1.0 2
+/SketchDict 100 dict def
+SketchDict begin
+/bd { bind def } bind def
+/x { exch } bd
+/xd { exch def } bd
+/PI 3.14159265358979323846264338327 def
+/radgrad { 180 mul PI div } bd
+/skstartmatrix matrix currentmatrix def
+/tmpmat matrix def
+/ISOLatin1Encoding dup where
+{ pop pop }
+{  [/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand
+/quoteright /parenleft /parenright /asterisk /plus /comma /minus /period
+/slash /zero /one /two /three /four /five /six /seven /eight /nine /colon
+/semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J
+/K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash
+/bracketright /asciicircum /underscore /quoteleft /a /b /c /d /e /f /g /h /i
+/j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright
+/asciitilde /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /dotlessi /grave /acute /circumflex /tilde /macron /breve
+/dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek
+/caron /space /exclamdown /cent /sterling /currency /yen /brokenbar /section
+/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen
+/registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu
+/paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright
+/onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex
+/Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex
+/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve
+/Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute
+/Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute
+/acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute
+/ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde
+/ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave
+/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def
+}
+ifelse
+/arct dup where
+{pop pop}
+{
+/arct {arcto pop pop pop pop} bd
+}
+ifelse
+/size 0 def
+/fontname 0 def
+/newfont 0 def
+/sf {
+/size xd
+/fontname xd
+fontname findfont
+dup /Encoding get StandardEncoding eq
+{
+dup
+length dict /newfont xd
+{
+1 index
+/FID ne
+{ newfont 3 1 roll put }
+{ pop pop }
+ifelse
+} forall
+newfont /Encoding ISOLatin1Encoding put
+fontname newfont definefont
+}
+if
+size scalefont setfont
+} bd
+/pusht {matrix currentmatrix} bd
+/popt {setmatrix} bd
+/pushc {gsave} bd
+/popc {grestore} bd
+/rgb {setrgbcolor} bd
+/w { setlinewidth } bd
+/j { setlinejoin } bd
+/J { setlinecap } bd
+/d { setdash } bd
+/F { eofill } bd
+/f { closepath F } bd
+/S {
+pusht
+skstartmatrix setmatrix stroke 
+popt
+} bd
+/s { closepath S } bd
+/m { moveto } bd
+/l { lineto } bd
+/c { curveto } bd
+/txt {
+/tmpmat tmpmat currentmatrix def
+dup type /arraytype eq {concat} {translate} ifelse
+0 0 m
+tmpmat
+} bd
+/T {txt x show popt} bd
+/P {txt x true charpath popt} bd
+/TP {txt x dup show 0 0 m true charpath popt} bd
+/C {newpath 0 360 arc} bd
+/R {
+2 copy m
+x 2 index l
+x 2 index x l
+l
+closepath
+} bd
+/ellipse { 
+dup type /arraytype eq
+{
+pusht x concat
+0 0 1.0 C 
+popt
+}	
+{
+pusht 5 1 roll
+4 -1 roll concat
+newpath
+dup 2 eq {
+0 0 m 
+} if 
+3 1 roll
+radgrad x
+radgrad x
+0 0 1   5 -2 roll
+arc
+0 ne { closepath } if
+popt
+}
+ifelse
+} bd
+/radius1 0 def
+/radius2 0 def
+/factor 0 def
+/rect {
+dup type /arraytype eq
+{
+pusht x concat
+0 0 m  1 0 l  1 1 l  0 1 l  closepath
+popt
+}
+{
+/radius2 xd
+/radius1 xd
+pusht x concat
+radius1 radius2 div  1  scale
+0 radius2 m
+0 1  radius2 1  radius2  arct
+radius2 radius1 div
+dup 1  1 index 0  radius2  arct
+0  0 0  radius2  arct
+0 0  0 1  radius2 arct
+closepath
+popt
+}
+ifelse
+} bd
+/buf 0 def
+/width 0 def
+/height 0 def
+/skcimg {
+/tmpmat tmpmat currentmatrix def
+{ concat } if
+/height xd
+/width xd
+/buf width 3 mul string def
+width height scale
+width height 8
+[width	 0   0	 height neg	  0  height]
+{ currentfile buf readhexstring pop } bind
+false 3 colorimage
+tmpmat setmatrix
+} bd
+/skgimg {
+/tmpmat tmpmat currentmatrix def
+{ concat } if
+/height xd
+/width xd
+/buf width string def
+width height scale
+width height 8
+[width	 0   0	 height neg	  0  height]
+{ currentfile buf readhexstring pop } bind
+image
+tmpmat setmatrix
+} bd
+/rclip {
+4 2 roll m
+dup 0 x rlineto
+x 0 rlineto
+neg 0 x rlineto
+closepath
+clip
+} bd
+/skeps {
+10 dict begin
+/sk_state save def
+concat
+3 index neg 3 index neg translate
+rclip
+0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin
+10 setmiterlimit [ ] 0 setdash
+newpath
+/sk_dict_count countdictstack def
+/sk_count count 1 sub def
+userdict begin
+/showpage { } def
+/languagelevel where
+{
+pop
+languagelevel 1 ne
+{
+false setstrokeadjust
+false setoverprint
+} if
+} if
+} bd 
+/skepsend {
+count sk_count sub { pop } repeat
+countdictstack sk_dict_count sub { end } repeat
+sk_state restore
+end
+} bd
+/gradidx 0 def
+/gradient { 
+3 mul array
+/gradidx 0 def
+} bd
+/$ {
+3 index gradidx       5 -1 roll put 
+2 index gradidx 1 add 4 -1 roll put 
+1 index gradidx 2 add 3 -1 roll put 
+/gradidx gradidx 3 add def
+} bd
+/! { 
+3 
+{
+dup dup gradidx dup 3 1 roll 3 sub get put
+/gradidx gradidx 1 add def
+}
+repeat
+} bd
+/gradcolor {
+3 mul dup 2 add 1 exch	% idx  1  idx+2
+{
+1 index exch	% array array i
+get		% array component
+exch		% component array
+}
+for
+4 1 roll
+} bd
+/x0 0 def /y0 0 def /x1 0 def /y1 0 def
+/left 0 def /right 0 def /top 0 def /bottom 0 def
+/numcolors 0 def
+/axial	{
+/y1 xd /x1 xd /y0 xd /x0 xd
+dup length 3 idiv /numcolors xd
+pusht exch  % ctm array
+x0 x1 ne y0 y1 ne or
+{
+x0 y0 translate
+[x1 x0 sub  y1 y0 sub	dup neg    2 index    0	    0] concat
+clippath flattenpath pathbbox
+/top xd /right xd /bottom xd /left xd
+newpath
+0 gradcolor rgb clippath f
+0 1 numcolors 1 sub
+{
+dup numcolors div
+3 1 roll
+gradcolor rgb
+exch
+bottom right top R f
+}
+for
+}
+if 
+pop
+popt
+} bd
+/r0 0 def /r1 0 def /dr 0 def
+/radial	{
+/r1 xd /r0 xd /y0 xd /x0 xd
+/dr r1 r0 sub def
+dup length 3 idiv /numcolors xd
+pusht exch  % ctm array
+r0 r1 ne
+{
+x0 y0 translate
+clippath flattenpath pathbbox
+/top xd /right xd /bottom xd /left xd
+newpath
+dr 0 gt {numcolors 1 sub}{0} ifelse gradcolor rgb
+clippath f
+dr 0 gt {numcolors 1 sub -1 0} { 0 1 numcolors 1 sub} ifelse
+{
+dup numcolors div dr mul r0 add
+3 1 roll
+gradcolor rgb
+exch
+0 0 3 -1 roll C f
+}
+for
+}
+if 
+pop
+popt
+} bd
+/max {
+2 copy lt {exch} if pop
+} bd
+/conical {
+pusht 5 1 roll
+3 1 roll /y0 xd /x0 xd
+x0 y0 translate
+radgrad rotate
+dup length 3 idiv /numcolors xd
+clippath flattenpath pathbbox newpath
+4 { abs 4 1 roll} repeat
+3 { max } repeat
+2 mul
+dup scale
+0 gradcolor rgb
+0 0 1 0 360 arc f
+1 1 numcolors 1 sub
+{
+dup numcolors div 180 mul
+3 1 roll
+gradcolor rgb
+exch
+0 0 moveto
+0 0 1  4 -1 roll  dup neg  arc
+closepath f
+}
+for
+pop
+popt
+} bd
+/XStep 0 def /YStep 0 def /imagedata 0 def /components 0 def
+/tileimage2 {
+exch 4 2 roll
+/height xd
+/width xd
+mark
+/components 2 index
+/PatternType 1
+/PaintType 1
+/TilingType 1
+/BBox [0 0 width height]
+/XStep width
+/YStep height
+/PaintProc {
+begin
+XStep YStep 8
+matrix
+imagedata
+false
+components
+colorimage
+end
+}
+counttomark 2 div cvi dup dict begin
+{ def } repeat
+pop currentdict end
+dup
+/imagedata
+4 -1 roll
+width height mul mul string
+currentfile exch readhexstring pop
+put
+exch
+makepattern
+setpattern
+clippath
+eofill
+} bd
+/tileimage1 {
+concat
+/components xd
+/height xd
+/width xd
+/imagedata
+currentfile
+width height mul components mul string
+readhexstring pop
+def
+clippath flattenpath pathbbox
+/top xd /right xd /bottom xd /left xd
+left width div floor width mul
+bottom height div floor height mul
+translate
+top bottom sub height div ceiling cvi
+{
+gsave
+right left sub width div ceiling cvi
+{
+width height 8 matrix
+components 1 eq
+{
+{ imagedata }
+image
+}
+{
+imagedata
+false components
+colorimage
+}
+ifelse
+width 0 translate
+}
+repeat
+grestore
+0 height translate
+}
+repeat
+} bd
+/makepattern where
+{
+pop
+/tileimage /tileimage2 load def
+}
+{
+/tileimage /tileimage1 load def
+}
+ifelse
+end
+%%EndResource
+%%EndProlog
+
+%%BeginSetup
+
+10.433 setmiterlimit
+%%EndSetup
+
+%%Page: 1 1
+SketchDict begin
+newpath
+81.1479 90.3363 m
+83.1262 89.4518 85.8962 89.4399 87.7755 90.732 c
+88.4885 91.2221 89.1744 91.8548 89.1744 92.7451 c
+89.3805 92.7446 89.5146 92.3854 89.7059 92.4617 c
+90.3588 92.7216 91.0745 92.5334 91.5725 92.3012 c
+91.8169 92.1873 92.0442 92.7366 92.3141 92.7358 c
+92.4246 92.4106 93.2359 91.4866 93.2359 91.4372 c
+95.3948 89.4748 99.2768 88.555 102.019 89.186 c
+102.881 89.3844 110.268 92.0436 110.268 92.7837 c
+110.735 92.6454 111.042 92.3763 111.801 92.3588 c
+113.208 92.7366 l
+114.425 92.9532 114.356 92.6862 114.93 92.6609 c
+114.93 90.5837 114.005 87.8389 114.95 85.8136 c
+115.043 85.6129 115.327 85.1931 115.474 85.044 c
+119.365 81.1112 125.41 82.6691 129.868 84.5493 c
+129.868 84.4181 130.124 84.2636 130.124 84.1323 c
+130.124 83.9504 129.868 83.7916 129.868 83.6096 c
+129.521 83.6096 129.294 83.4821 129.005 83.2726 c
+126.771 81.6517 123.827 80.5003 121.756 78.5645 c
+121.551 78.3735 121.558 78.1688 121.558 77.872 c
+121.756 77.6246 122.036 77.2541 122.315 77.061 c
+122.399 77.0029 122.564 76.8961 124.449 75.877 c
+126.015 75.0309 127.68 74.6575 129.194 74.6604 c
+129.194 74.475 129.046 74.2851 129.051 74.0807 c
+129.052 74.0297 129.066 73.9744 129.086 73.9171 c
+129.106 73.8599 129.132 73.8003 129.158 73.7411 c
+129.183 73.6819 129.209 73.6226 129.227 73.5659 c
+129.245 73.5087 129.255 73.4539 129.252 73.4038 c
+129.238 73.1617 129.151 72.9814 129.076 72.7773 c
+126.75 73.9407 124.211 75.0082 121.611 75.7449 c
+120.232 76.1358 118.876 76.4938 117.501 76.7872 c
+116.305 77.0426 113.981 77.2912 113.298 75.7452 c
+112.578 74.1158 113.329 72.4451 113.544 70.8622 c
+113.245 70.9989 113.04 71.6163 112.826 71.3291 c
+112.556 70.799 l
+112.21 71.5408 111.908 72.5375 111.698 73.3754 c
+111.413 74.5161 110.852 75.2644 109.473 75.4597 c
+107.323 75.7648 107.541 75.5249 106.808 75.0986 c
+105.489 74.3316 104.447 72.6469 104.427 70.7633 c
+104.103 70.8166 104.04 71.1029 103.715 71.1562 c
+103.661 71.1361 103.594 71.1001 103.521 71.0624 c
+103.448 71.0247 103.368 70.985 103.288 70.9575 c
+103.209 70.9303 103.129 70.9147 103.056 70.9254 c
+102.983 70.9359 102.916 70.9725 102.862 71.049 c
+102.814 71.2619 102.513 71.4476 102.165 71.1947 c
+101.229 70.799 l
+101.108 71.1117 100.582 71.3382 100.316 71.5037 c
+99.0659 72.2807 97.0528 71.5295 96.2781 70.5102 c
+96.093 70.57 95.9079 70.6298 95.7225 70.6896 c
+95.5289 70.7905 95.2567 70.9099 94.8114 70.6321 c
+94.4917 70.5802 l
+94.4917 70.8373 94.9407 70.8557 95.0994 71.1094 c
+95.4787 71.7155 95.856 72.5599 96.434 73.236 c
+97.4233 74.3934 98.3768 75.7545 97.6356 77.2578 c
+97.415 77.7045 97.576 77.5078 96.6749 78.2941 c
+96.1414 78.7598 95.3594 79.3486 94.7173 79.6468 c
+91.9201 80.9465 88.4556 81.0936 85.1714 80.6681 c
+83.4604 80.4467 81.7831 80.1902 80.3068 79.6031 c
+80.2609 79.585 80.3031 79.5122 80.2535 79.5122 c
+80.306 79.6936 80.6359 79.9461 80.4556 80.0496 c
+80.2343 80.1389 80.2481 80.2886 80.2552 80.4833 c
+80.2731 80.7971 l
+80.4213 80.7971 80.3077 80.824 80.4554 80.8396 c
+82.6332 81.0712 84.5517 81.7552 86.5887 82.4718 c
+87.2231 82.6952 87.987 83.0019 88.527 83.452 c
+88.8771 83.744 89.3216 84.2214 89.3216 84.6667 c
+89.3216 85.0624 88.8949 85.959 88.6166 86.1815 c
+86.4209 87.9381 80.8845 88.8736 80.8346 88.9422 c
+80.7828 89.0136 l
+80.7856 89.1103 81.0512 89.1729 81.1198 89.3575 c
+81.1731 89.5006 81.0506 89.7858 81.1017 89.9232 c
+81.1924 90.1679 81.2247 90.3363 81.1479 90.3363 c
+closepath
+gsave
+0.9 0.9 0.9 rgb
+F
+grestore
+0.9 0.9 0.9 rgb
+0.215433 w
+0 j
+0 J
+[] 0 d
+S
+newpath
+108.203 84.2032 m
+107.659 84.1536 106.67 83.9557 106.373 83.5107 c
+106.324 83.5107 106.274 83.4611 106.274 83.4118 c
+106.126 83.3622 106.027 82.9665 105.829 82.8675 c
+105.829 82.1257 105.533 81.4828 106.126 80.8396 c
+106.225 80.7407 l
+106.423 80.6914 l
+107.907 79.8999 109.341 79.9989 110.726 80.8892 c
+110.776 80.9882 l
+110.875 81.0375 111.072 81.3343 111.27 81.3343 c
+111.27 81.8782 111.765 82.4225 111.418 83.115 c
+111.32 83.3129 110.825 83.4611 110.825 83.659 c
+110.726 83.659 110.132 84.0054 110.132 84.0547 c
+109.935 84.0547 l
+109.737 84.2525 108.401 84.2525 108.203 84.2032 c
+closepath
+gsave
+0.8 0.8 0.8 rgb
+F
+grestore
+0.7 0.7 0.7 rgb
+0.566929 w
+0 j
+0 J
+[] 0 d
+S
+newpath
+129.218 74.6074 m
+126.745 74.9042 123.636 75.6956 121.805 77.5256 c
+121.657 77.6742 121.459 78.0203 121.459 78.2677 c
+121.558 78.3171 l
+121.558 78.3667 121.757 78.5634 121.805 78.6139 c
+123.135 79.9966 125.128 80.6576 126.673 81.7561 c
+128.047 82.7323 129.427 83.5107 129.67 83.5107 c
+129.775 83.5629 130.033 83.615 130.115 83.659 c
+129.109 72.8173 m
+127.427 73.3119 125.912 74.363 124.229 74.9042 c
+121.542 75.7684 l
+120.528 76.0947 119.51 76.4014 118.523 76.5599 c
+116.741 76.8465 115.229 77.6229 113.743 76.2892 c
+112.805 75.4467 113.006 74.657 113.006 73.4205 c
+113.121 72.9094 113.569 71.2846 113.569 70.7888 c
+112.54 70.8024 m
+111.897 72.0885 111.86 74.2406 110.585 75.1462 c
+109.981 75.576 107.912 75.6808 107.214 75.4484 c
+106.724 75.2851 106.373 74.7559 106.027 74.4095 c
+105.087 73.4698 104.431 72.0363 104.431 70.7009 c
+101.387 70.7216 m
+100.435 71.9918 98.2462 72.4301 97.0247 71.1409 c
+96.8801 71.0068 96.6052 70.7772 96.0915 70.388 c
+94.588 70.6593 m
+95.3302 71.0054 95.6213 71.8212 95.9603 72.5171 c
+96.561 73.7499 98.571 75.6363 97.6602 77.1169 c
+97.3518 77.6183 l
+97.063 78.124 95.8361 79.0019 95.7069 79.1312 c
+95.509 79.329 94.9892 79.5357 94.7496 79.6525 c
+90.7346 81.6135 86.2429 80.9354 82.0379 80.1471 c
+81.4945 80.0454 80.7354 79.496 80.1915 79.496 c
+80.855 88.9875 m
+81.4486 88.839 81.943 88.619 82.5326 88.4566 c
+83.9216 88.0751 85.6935 87.8542 86.9841 87.1708 c
+87.3753 86.9639 87.8251 86.5772 88.2209 86.3794 c
+88.9627 86.0333 89.3091 85.2418 89.2595 84.4008 c
+89.2595 84.2032 88.8592 83.7624 88.7155 83.6096 c
+88.0678 82.9214 86.6839 82.482 85.7972 82.175 c
+84.1118 81.5919 82.1369 80.7407 80.3068 80.7407 c
+80.2575 80.6914 l
+81.2564 90.302 m
+81.7865 90.031 81.8707 90.1115 82.3007 89.9334 c
+83.7949 89.3152 85.8009 89.932 87.1823 90.5344 c
+88.1222 90.944 89.2116 91.7442 89.2116 92.8407 c
+92.2753 92.7032 m
+92.9678 91.6646 93.7564 90.8221 94.8982 90.2869 c
+95.3392 90.0803 95.9901 89.7098 96.481 89.5944 c
+98.5129 89.1165 100.233 88.7908 102.318 89.1987 c
+102.511 89.2367 102.58 89.2282 103.109 89.3966 c
+105.253 90.0783 107.678 91.2292 109.638 92.3148 c
+109.697 92.3474 110.336 92.8129 110.352 92.8129 c
+114.93 92.7352 m
+114.815 91.7541 114.609 90.9627 114.61 90.427 c
+114.611 88.8645 114.327 87.8086 114.634 86.6268 c
+115.198 84.4504 118.458 82.8638 119.975 82.7193 c
+123.178 82.4137 126.158 83.2958 129.076 84.3515 c
+129.123 84.3682 129.274 84.4008 129.373 84.4008 c
+129.423 84.4997 129.818 84.6483 129.967 84.6483 c
+0.8 0.8 0.8 rgb
+1 j
+1 J
+S
+newpath
+81.6246 86.9766 m
+82.6698 86.9766 l
+82.6698 79.2655 l
+81.6246 79.2655 l
+81.6246 86.9766 l
+closepath
+84.0446 82.4667 m
+84.0446 82.7598 84.0959 83.0368 84.1988 83.297 c
+84.3014 83.5575 84.4553 83.8013 84.6606 84.0286 c
+84.8734 84.2486 85.1226 84.4155 85.4086 84.5292 c
+85.6946 84.6429 86.0209 84.6996 86.3877 84.6996 c
+86.4464 84.6996 86.5104 84.6959 86.5802 84.6885 c
+86.6499 84.6811 86.725 84.6704 86.8058 84.6556 c
+86.8863 84.6409 86.9688 84.6227 87.0533 84.6006 c
+87.1375 84.5785 87.2236 84.5493 87.3118 84.5125 c
+87.4657 84.4467 87.6123 84.3622 87.7517 84.2596 c
+87.8909 84.157 88.0267 84.0323 88.1588 83.8857 c
+88.2906 83.7463 88.3898 83.5739 88.4559 83.3687 c
+88.5216 83.1632 88.5548 82.9285 88.5548 82.6646 c
+88.5548 82.6572 88.5548 82.6481 88.5548 82.6371 c
+88.5548 82.626 88.5548 82.6133 88.5548 82.5985 c
+88.5548 82.5911 88.5548 82.5821 88.5548 82.571 c
+88.5548 82.56 88.5548 82.5472 88.5548 82.5325 c
+88.5548 79.2655 l
+87.5097 79.2655 l
+87.5097 82.3786 l
+87.5097 82.5398 87.4858 82.6994 87.4382 82.857 c
+87.3906 83.0146 87.3192 83.1632 87.2236 83.3026 c
+87.1284 83.4492 87.0037 83.5592 86.8497 83.6326 c
+86.6958 83.706 86.5124 83.7426 86.2998 83.7426 c
+86.1017 83.7426 85.9276 83.7097 85.7771 83.6437 c
+85.6269 83.5776 85.4968 83.4787 85.3868 83.3466 c
+85.2768 83.2145 85.1906 83.0733 85.1283 82.9231 c
+85.0659 82.7729 85.0237 82.6133 85.0016 82.4446 c
+85.0016 79.2655 l
+84.0446 79.2655 l
+84.0446 82.4667 l
+closepath
+89.6767 85.8436 m
+90.7108 85.8436 l
+90.7108 84.5456 l
+92.7126 84.5456 l
+92.7126 83.5997 l
+90.7108 83.5997 l
+90.7108 80.9156 l
+90.7108 80.813 90.7179 80.7211 90.7326 80.6406 c
+90.7474 80.5598 90.7695 80.483 90.7987 80.4096 c
+90.8279 80.3362 90.8922 80.2832 90.9912 80.25 c
+91.0901 80.2171 91.2276 80.2007 91.4036 80.2007 c
+92.6248 80.2225 l
+92.6248 79.2655 l
+91.3268 79.2655 l
+91.3194 79.2655 91.312 79.2655 91.3047 79.2655 c
+91.2973 79.2655 91.2899 79.2655 91.2826 79.2655 c
+91.2755 79.2655 91.2698 79.2655 91.2661 79.2655 c
+91.2624 79.2655 91.2571 79.2619 91.2497 79.2545 c
+91.2423 79.2545 91.2349 79.2545 91.2276 79.2545 c
+91.2205 79.2545 91.2131 79.2545 91.2057 79.2545 c
+91.1984 79.2545 91.193 79.2545 91.1893 79.2545 c
+91.1856 79.2545 91.18 79.2545 91.1726 79.2545 c
+90.9234 79.2545 90.7071 79.2913 90.5237 79.3645 c
+90.3403 79.4379 90.1901 79.5516 90.0727 79.7055 c
+89.9554 79.8597 89.8655 80.0247 89.8032 80.2007 c
+89.7408 80.3764 89.7023 80.5598 89.6878 80.7506 c
+89.6804 80.7654 89.6767 80.7818 89.6767 80.7999 c
+89.6767 80.8184 89.6767 80.8385 89.6767 80.8606 c
+89.6767 80.8753 89.6767 80.8918 89.6767 80.9099 c
+89.6767 80.9283 89.6767 80.9485 89.6767 80.9706 c
+89.6767 80.9927 l
+89.6767 85.8436 l
+closepath
+96.7829 83.1595 m
+96.7682 83.1669 96.7534 83.1762 96.7387 83.187 c
+96.7242 83.198 96.7095 83.2145 96.6948 83.2366 c
+96.68 83.2513 96.6636 83.2695 96.6454 83.2916 c
+96.627 83.3137 96.6069 83.3355 96.5848 83.3576 c
+96.5629 83.3724 96.5388 83.3888 96.5133 83.407 c
+96.4875 83.4254 96.4637 83.4455 96.4419 83.4676 c
+96.4124 83.4824 96.3832 83.4988 96.3537 83.5172 c
+96.3246 83.5354 96.2914 83.5518 96.2548 83.5666 c
+96.1814 83.6031 96.0952 83.6289 95.9963 83.6437 c
+95.8974 83.6584 95.7854 83.6655 95.6607 83.6655 c
+95.3747 83.6655 95.1235 83.6142 94.9072 83.5116 c
+94.6909 83.4089 94.5095 83.2587 94.3627 83.0606 c
+94.2161 82.8627 94.1062 82.6535 94.0327 82.4335 c
+93.9593 82.2136 93.9228 81.9862 93.9228 81.7515 c
+93.9228 81.7442 93.9228 81.7368 93.9228 81.7297 c
+93.9228 81.7186 l
+93.9228 81.5058 93.9613 81.3025 94.0384 81.1081 c
+94.1152 80.9136 94.2272 80.7285 94.3737 80.5525 c
+94.5206 80.3764 94.702 80.2446 94.9183 80.1565 c
+95.1346 80.0686 95.382 80.0247 95.6607 80.0247 c
+95.9614 80.0247 96.2126 80.0592 96.4144 80.129 c
+96.616 80.1987 96.7682 80.3033 96.8708 80.4425 c
+96.9734 80.5893 97.0669 80.7617 97.1514 80.9595 c
+97.2356 81.1577 97.3107 81.3813 97.3768 81.6305 c
+97.3768 81.6415 l
+97.3878 81.6526 l
+97.3878 81.6637 l
+98.3448 81.6087 l
+98.3448 81.5939 98.3448 81.5812 98.3448 81.5701 c
+98.3448 81.5591 98.3485 81.55 98.3559 81.5426 c
+98.3559 81.5279 98.3559 81.5168 98.3559 81.5094 c
+98.3559 81.5024 98.3559 81.4913 98.3559 81.4766 c
+98.3559 81.4692 98.3559 81.4601 98.3559 81.4491 c
+98.3559 81.438 98.3595 81.4289 98.3669 81.4216 c
+98.3669 81.4068 98.3669 81.3958 98.3669 81.3887 c
+98.3669 81.3813 98.3669 81.374 98.3669 81.3666 c
+98.3669 81.3079 98.3632 81.2475 98.3559 81.1852 c
+98.3485 81.1228 98.3374 81.0585 98.323 80.9927 c
+98.3156 80.9632 98.3063 80.9303 98.2952 80.8935 c
+98.2844 80.8569 98.2751 80.824 98.2677 80.7946 c
+98.2532 80.758 98.2402 80.7231 98.2294 80.69 c
+98.2184 80.6571 98.2056 80.6222 98.1909 80.5856 c
+98.1027 80.4022 97.9854 80.2225 97.8388 80.0465 c
+97.6923 79.8705 97.5126 79.7055 97.3 79.5516 c
+97.0944 79.3976 96.8543 79.282 96.5794 79.2052 c
+96.3044 79.1281 95.9983 79.0895 95.6607 79.0895 c
+95.272 79.0895 94.9129 79.1502 94.5827 79.2709 c
+94.2527 79.392 93.9559 79.5774 93.6917 79.8265 c
+93.4205 80.0833 93.2189 80.3711 93.0868 80.69 c
+92.9547 81.0091 92.8887 81.3629 92.8887 81.7515 c
+92.8887 82.1623 92.9437 82.5254 93.0536 82.8406 c
+93.1636 83.1558 93.3289 83.4274 93.5489 83.6547 c
+93.7688 83.882 93.9999 84.0688 94.2417 84.2157 c
+94.4837 84.3622 94.7369 84.4685 95.0008 84.5346 c
+95.0303 84.542 95.0577 84.5473 95.0833 84.551 c
+95.1091 84.5547 95.1366 84.5604 95.1657 84.5675 c
+95.1952 84.5675 95.2227 84.5695 95.2482 84.5731 c
+95.274 84.5768 95.3015 84.5822 95.3307 84.5896 c
+95.3894 84.5969 95.4464 84.6023 95.5014 84.606 c
+95.5564 84.6097 95.6094 84.6117 95.6607 84.6117 c
+95.9614 84.6117 96.2421 84.5695 96.5023 84.485 c
+96.7628 84.4008 97.0029 84.2744 97.2229 84.1057 c
+97.4354 83.937 97.6279 83.75 97.8003 83.5447 c
+97.9726 83.3392 98.1248 83.1192 98.2569 82.8845 c
+94.6158 80.9156 l
+94.1867 81.6855 l
+96.7829 83.1595 l
+closepath
+99.6431 84.5456 m
+101.282 80.3875 l
+102.756 84.5456 l
+103.889 84.5456 l
+102.063 79.7826 l
+102.019 79.6726 101.969 79.5791 101.914 79.502 c
+101.859 79.4251 101.799 79.3608 101.733 79.3095 c
+101.667 79.2655 101.599 79.229 101.53 79.1995 c
+101.46 79.1703 101.385 79.1519 101.304 79.1445 c
+101.297 79.1445 101.291 79.1445 101.287 79.1445 c
+101.284 79.1445 101.278 79.1445 101.271 79.1445 c
+101.264 79.1445 101.256 79.1445 101.249 79.1445 c
+101.168 79.1445 101.09 79.1556 101.012 79.1777 c
+100.935 79.1995 100.857 79.2327 100.776 79.2766 c
+100.703 79.3353 100.637 79.403 100.578 79.4801 c
+100.519 79.5569 100.468 79.6505 100.424 79.7605 c
+98.5101 84.5456 l
+99.6431 84.5456 l
+closepath
+108.388 82.3015 m
+108.388 82.463 108.357 82.6223 108.294 82.7802 c
+108.232 82.9378 108.139 83.0864 108.014 83.2255 c
+107.889 83.3724 107.713 83.4824 107.486 83.5555 c
+107.259 83.6289 106.984 83.6655 106.661 83.6655 c
+106.609 83.6655 106.556 83.6618 106.501 83.6547 c
+106.447 83.6473 106.386 83.6363 106.32 83.6215 c
+106.254 83.6142 106.188 83.5997 106.122 83.5776 c
+106.056 83.5555 105.99 83.5263 105.924 83.4897 c
+105.807 83.4381 105.693 83.3667 105.583 83.2751 c
+105.473 83.1833 105.367 83.0753 105.264 82.9506 c
+105.169 82.8332 105.092 82.6884 105.033 82.516 c
+104.974 82.3437 104.938 82.1475 104.923 81.9276 c
+104.923 81.6342 104.963 81.3793 105.044 81.1631 c
+105.125 80.9468 105.245 80.7654 105.407 80.6185 c
+105.576 80.4793 105.75 80.3674 105.929 80.2832 c
+106.109 80.1987 106.298 80.1454 106.496 80.1236 c
+106.503 80.1236 106.513 80.1236 106.523 80.1236 c
+106.534 80.1236 106.544 80.1236 106.551 80.1236 c
+106.566 80.1162 106.578 80.1125 106.589 80.1125 c
+106.6 80.1125 106.609 80.1125 106.617 80.1125 c
+106.632 80.1125 106.643 80.1125 106.65 80.1125 c
+106.657 80.1125 106.668 80.1125 106.683 80.1125 c
+106.69 80.1125 106.699 80.1125 106.71 80.1125 c
+106.721 80.1125 106.731 80.1125 106.738 80.1125 c
+106.826 80.1125 106.909 80.1179 106.985 80.129 c
+107.062 80.14 107.138 80.1602 107.211 80.1896 c
+107.248 80.2041 107.282 80.2188 107.315 80.2336 c
+107.348 80.2483 107.383 80.2628 107.42 80.2775 c
+107.449 80.2996 107.482 80.3214 107.519 80.3436 c
+107.556 80.3657 107.589 80.3912 107.618 80.4207 c
+107.655 80.4425 107.689 80.47 107.722 80.5032 c
+107.756 80.536 107.79 80.5672 107.827 80.5967 c
+107.864 80.6333 107.9 80.6681 107.937 80.701 c
+107.974 80.7342 108.01 80.7688 108.047 80.8056 c
+108.047 79.6066 l
+108.04 79.5918 108.032 79.5808 108.025 79.5737 c
+108.025 79.5626 l
+107.937 79.5039 107.845 79.4506 107.75 79.403 c
+107.655 79.3554 107.556 79.3132 107.453 79.2766 c
+107.35 79.2471 107.225 79.2233 107.079 79.2052 c
+106.932 79.1867 106.764 79.1777 106.573 79.1777 c
+106.566 79.1777 106.56 79.1777 106.556 79.1777 c
+106.553 79.1777 106.547 79.1777 106.54 79.1777 c
+106.533 79.1777 106.522 79.1777 106.507 79.1777 c
+106.5 79.1777 106.492 79.1777 106.485 79.1777 c
+106.478 79.1777 106.47 79.1777 106.463 79.1777 c
+106.456 79.1777 106.45 79.1777 106.447 79.1777 c
+106.443 79.1777 106.437 79.1777 106.43 79.1777 c
+106.092 79.1777 105.779 79.238 105.49 79.3591 c
+105.2 79.4801 104.934 79.6652 104.692 79.9147 c
+104.45 80.1712 104.268 80.4663 104.147 80.7999 c
+104.026 81.1339 103.966 81.5094 103.966 81.9276 c
+103.966 82.2944 104.025 82.6354 104.142 82.9506 c
+104.259 83.2658 104.435 83.5555 104.67 83.8197 c
+104.904 84.0836 105.194 84.2817 105.539 84.4135 c
+105.884 84.5456 106.283 84.6117 106.738 84.6117 c
+107.17 84.6117 107.556 84.553 107.893 84.4357 c
+108.23 84.3183 108.513 84.1423 108.74 83.9076 c
+108.975 83.6729 109.149 83.4254 109.262 83.1652 c
+109.376 82.9047 109.433 82.6354 109.433 82.3564 c
+109.433 79.2655 l
+108.388 79.2655 l
+108.388 82.3015 l
+closepath
+110.467 85.8436 m
+111.501 85.8436 l
+111.501 84.5456 l
+113.503 84.5456 l
+113.503 83.5997 l
+111.501 83.5997 l
+111.501 80.9156 l
+111.501 80.813 111.508 80.7211 111.523 80.6406 c
+111.538 80.5598 111.56 80.483 111.589 80.4096 c
+111.618 80.3362 111.683 80.2832 111.782 80.25 c
+111.881 80.2171 112.018 80.2007 112.194 80.2007 c
+113.415 80.2225 l
+113.415 79.2655 l
+112.117 79.2655 l
+112.11 79.2655 112.102 79.2655 112.095 79.2655 c
+112.088 79.2655 112.08 79.2655 112.073 79.2655 c
+112.066 79.2655 112.06 79.2655 112.057 79.2655 c
+112.053 79.2655 112.047 79.2619 112.04 79.2545 c
+112.033 79.2545 112.025 79.2545 112.018 79.2545 c
+112.011 79.2545 112.004 79.2545 111.996 79.2545 c
+111.989 79.2545 111.983 79.2545 111.98 79.2545 c
+111.976 79.2545 111.97 79.2545 111.963 79.2545 c
+111.714 79.2545 111.498 79.2913 111.314 79.3645 c
+111.131 79.4379 110.981 79.5516 110.863 79.7055 c
+110.746 79.8597 110.656 80.0247 110.594 80.2007 c
+110.531 80.3764 110.493 80.5598 110.478 80.7506 c
+110.471 80.7654 110.467 80.7818 110.467 80.7999 c
+110.467 80.8184 110.467 80.8385 110.467 80.8606 c
+110.467 80.8753 110.467 80.8918 110.467 80.9099 c
+110.467 80.9283 110.467 80.9485 110.467 80.9706 c
+110.467 80.9927 l
+110.467 85.8436 l
+closepath
+114.449 84.5456 m
+115.406 84.5456 l
+115.406 79.2655 l
+114.449 79.2655 l
+114.449 84.5456 l
+closepath
+114.372 85.7665 m
+114.372 85.8473 114.387 85.9224 114.416 85.9922 c
+114.446 86.0619 114.493 86.1223 114.559 86.1736 c
+114.618 86.2175 114.682 86.2524 114.752 86.2782 c
+114.821 86.3037 114.893 86.3167 114.966 86.3167 c
+115.047 86.3167 115.12 86.3057 115.186 86.2836 c
+115.252 86.2617 115.318 86.2249 115.384 86.1736 c
+115.45 86.1223 115.5 86.0619 115.533 85.9922 c
+115.566 85.9224 115.582 85.8399 115.582 85.7447 c
+115.582 85.6492 115.566 85.565 115.533 85.4916 c
+115.5 85.4181 115.454 85.3561 115.395 85.3045 c
+115.329 85.2532 115.263 85.2166 115.197 85.1945 c
+115.131 85.1727 115.062 85.1616 114.988 85.1616 c
+114.915 85.1542 114.842 85.1616 114.768 85.1837 c
+114.695 85.2055 114.625 85.2424 114.559 85.2937 c
+114.493 85.345 114.446 85.4091 114.416 85.4862 c
+114.387 85.563 114.372 85.6492 114.372 85.7447 c
+114.372 85.7665 l
+closepath
+116.792 82.0375 m
+116.792 82.4409 116.862 82.804 117.001 83.1266 c
+117.14 83.4492 117.346 83.7315 117.617 83.9736 c
+117.896 84.2157 118.191 84.3971 118.503 84.5181 c
+118.814 84.6392 119.143 84.6996 119.487 84.6996 c
+119.502 84.6996 119.518 84.6996 119.537 84.6996 c
+119.555 84.6996 119.571 84.6996 119.586 84.6996 c
+119.601 84.6922 119.617 84.6885 119.636 84.6885 c
+119.654 84.6885 119.674 84.6885 119.696 84.6885 c
+119.711 84.6885 119.727 84.6885 119.746 84.6885 c
+119.764 84.6885 119.784 84.6885 119.806 84.6885 c
+119.821 84.6811 119.837 84.6777 119.856 84.6777 c
+119.874 84.6777 119.89 84.6777 119.905 84.6777 c
+120.199 84.6335 120.479 84.5473 120.747 84.4192 c
+121.014 84.2908 121.273 84.1202 121.522 83.9076 c
+121.764 83.6876 121.947 83.4126 122.072 83.0827 c
+122.197 82.7527 122.259 82.3675 122.259 81.9276 c
+122.259 81.8984 122.259 81.8689 122.259 81.8397 c
+122.259 81.8102 122.256 81.7847 122.248 81.7626 c
+122.248 81.7331 122.246 81.7039 122.243 81.6747 c
+122.239 81.6452 122.237 81.616 122.237 81.5865 c
+122.23 81.5279 122.221 81.4692 122.21 81.4105 c
+122.199 81.3518 122.186 81.2932 122.171 81.2345 c
+122.105 80.9706 122.004 80.7194 121.869 80.481 c
+121.733 80.2426 121.559 80.0173 121.346 79.8044 c
+121.141 79.5918 120.895 79.4342 120.609 79.3316 c
+120.323 79.229 120.004 79.1777 119.652 79.1777 c
+119.153 79.1777 118.723 79.2454 118.36 79.3809 c
+117.997 79.5167 117.701 79.7239 117.474 80.0025 c
+117.247 80.2812 117.076 80.5893 116.962 80.9266 c
+116.849 81.264 116.792 81.6268 116.792 82.0154 c
+116.792 82.0375 l
+closepath
+117.837 82.0375 m
+117.837 81.9789 117.837 81.9259 117.837 81.878 c
+117.837 81.8303 117.841 81.781 117.848 81.7297 c
+117.855 81.6781 117.865 81.6288 117.876 81.5812 c
+117.887 81.5335 117.896 81.4839 117.903 81.4326 c
+117.94 81.2713 117.999 81.1134 118.079 80.9595 c
+118.16 80.8056 118.259 80.6588 118.376 80.5196 c
+118.501 80.3801 118.655 80.2775 118.838 80.2115 c
+119.022 80.1454 119.238 80.1125 119.487 80.1125 c
+119.722 80.1125 119.942 80.1454 120.147 80.2115 c
+120.352 80.2775 120.54 80.3764 120.708 80.5085 c
+120.877 80.6406 121.003 80.8331 121.088 81.086 c
+121.172 81.3391 121.214 81.6489 121.214 82.0154 c
+121.214 82.2722 121.178 82.505 121.104 82.7142 c
+121.031 82.9231 120.921 83.1082 120.774 83.2695 c
+120.627 83.4237 120.446 83.541 120.23 83.6215 c
+120.013 83.7023 119.766 83.7426 119.487 83.7426 c
+119.223 83.7426 118.996 83.7077 118.805 83.638 c
+118.615 83.5685 118.457 83.4603 118.332 83.3137 c
+118.207 83.1742 118.107 83.024 118.03 82.8627 c
+117.953 82.7011 117.899 82.5362 117.87 82.3675 c
+117.863 82.3383 117.855 82.3088 117.848 82.2796 c
+117.841 82.2501 117.837 82.2209 117.837 82.1915 c
+117.837 82.1623 117.837 82.1328 117.837 82.1036 c
+117.837 82.0741 117.837 82.0449 117.837 82.0154 c
+117.837 82.0375 l
+closepath
+123.205 82.4667 m
+123.205 82.7598 123.257 83.0368 123.359 83.297 c
+123.462 83.5575 123.616 83.8013 123.821 84.0286 c
+124.034 84.2486 124.283 84.4155 124.569 84.5292 c
+124.855 84.6429 125.182 84.6996 125.548 84.6996 c
+125.607 84.6996 125.671 84.6959 125.741 84.6885 c
+125.811 84.6811 125.886 84.6704 125.966 84.6556 c
+126.047 84.6409 126.129 84.6227 126.214 84.6006 c
+126.298 84.5785 126.384 84.5493 126.472 84.5125 c
+126.626 84.4467 126.773 84.3622 126.912 84.2596 c
+127.052 84.157 127.187 84.0323 127.319 83.8857 c
+127.451 83.7463 127.55 83.5739 127.616 83.3687 c
+127.682 83.1632 127.715 82.9285 127.715 82.6646 c
+127.715 82.6572 127.715 82.6481 127.715 82.6371 c
+127.715 82.626 127.715 82.6133 127.715 82.5985 c
+127.715 82.5911 127.715 82.5821 127.715 82.571 c
+127.715 82.56 127.715 82.5472 127.715 82.5325 c
+127.715 79.2655 l
+126.67 79.2655 l
+126.67 82.3786 l
+126.67 82.5398 126.646 82.6994 126.599 82.857 c
+126.551 83.0146 126.48 83.1632 126.384 83.3026 c
+126.289 83.4492 126.164 83.5592 126.01 83.6326 c
+125.856 83.706 125.673 83.7426 125.46 83.7426 c
+125.262 83.7426 125.088 83.7097 124.938 83.6437 c
+124.788 83.5776 124.657 83.4787 124.547 83.3466 c
+124.437 83.2145 124.351 83.0733 124.289 82.9231 c
+124.227 82.7729 124.184 82.6133 124.162 82.4446 c
+124.162 79.2655 l
+123.205 79.2655 l
+123.205 82.4667 l
+closepath
+0 0 0 rgb
+F
+newpath
+113.172 76.343 m
+113.172 76.6049 113.208 76.8397 113.279 77.0474 c
+113.35 77.2549 113.455 77.4355 113.593 77.5889 c
+113.736 77.7422 113.883 77.8732 114.037 77.9817 c
+114.19 78.0903 114.351 78.1745 114.519 78.2343 c
+114.549 78.2456 114.58 78.2558 114.612 78.2652 c
+114.644 78.2746 114.676 78.2848 114.71 78.2961 c
+114.74 78.3035 114.771 78.3111 114.803 78.3185 c
+114.835 78.3259 114.865 78.3315 114.895 78.3352 c
+114.959 78.3465 115.02 78.3551 115.078 78.3607 c
+115.136 78.3661 115.193 78.3689 115.249 78.3689 c
+115.402 78.3689 115.55 78.3539 115.692 78.3242 c
+115.835 78.2941 115.969 78.2513 116.096 78.1952 c
+116.223 78.1391 116.349 78.0659 116.472 77.9761 c
+116.596 77.8865 116.718 77.7816 116.837 77.662 c
+116.484 77.2745 l
+116.469 77.2821 116.454 77.2915 116.441 77.3026 c
+116.428 77.3139 116.414 77.3269 116.4 77.3419 c
+116.392 77.3493 116.384 77.357 116.377 77.3643 c
+116.369 77.372 116.362 77.3794 116.354 77.3867 c
+116.343 77.3944 116.334 77.4018 116.326 77.4094 c
+116.319 77.4168 116.311 77.4242 116.304 77.4318 c
+116.237 77.4879 116.164 77.5412 116.085 77.5917 c
+116.007 77.6421 115.922 77.6917 115.833 77.7405 c
+115.743 77.7853 115.649 77.8199 115.552 77.8443 c
+115.455 77.8686 115.354 77.8808 115.249 77.8808 c
+115.021 77.8808 114.819 77.8479 114.645 77.7825 c
+114.472 77.717 114.325 77.6189 114.205 77.4879 c
+114.089 77.3607 113.995 77.2252 113.921 77.0809 c
+113.849 76.9369 113.799 76.7864 113.773 76.6293 c
+113.769 76.603 113.764 76.5777 113.759 76.5534 c
+113.753 76.5293 113.75 76.5037 113.75 76.4777 c
+113.747 76.4516 113.745 76.4264 113.745 76.402 c
+113.745 76.3776 113.745 76.3541 113.745 76.3317 c
+113.745 76.1446 113.776 75.964 113.837 75.7903 c
+113.899 75.6162 113.992 75.4507 114.115 75.2934 c
+114.239 75.1363 114.395 75.0156 114.584 74.9314 c
+114.773 74.8472 114.994 74.7996 115.249 74.7885 c
+115.253 74.7885 115.255 74.7885 115.257 74.7885 c
+115.259 74.7885 115.262 74.7885 115.266 74.7885 c
+115.269 74.7885 115.273 74.7885 115.277 74.7885 c
+115.281 74.7885 115.284 74.7885 115.288 74.7885 c
+115.296 74.7885 115.301 74.7885 115.305 74.7885 c
+115.309 74.7885 115.312 74.7885 115.313 74.7885 c
+115.315 74.7885 115.318 74.7885 115.322 74.7885 c
+115.49 74.7845 115.644 74.8072 115.782 74.8557 c
+115.92 74.9044 116.042 74.9793 116.147 75.0802 c
+116.255 75.1774 116.346 75.2814 116.419 75.3917 c
+116.492 75.502 116.549 75.6171 116.59 75.737 c
+116.601 75.7667 116.612 75.7957 116.621 75.8237 c
+116.631 75.8518 116.637 75.879 116.641 75.9054 c
+116.644 75.9201 116.647 75.9343 116.649 75.9473 c
+116.651 75.9603 116.652 75.9745 116.652 75.9895 c
+116.656 76.0006 116.659 76.0128 116.66 76.0258 c
+116.662 76.0389 116.663 76.053 116.663 76.0681 c
+115.294 76.0791 l
+115.294 76.6123 l
+117.236 76.6123 l
+117.236 76.1242 l
+117.213 75.8285 117.148 75.5695 117.039 75.3469 c
+116.931 75.1241 116.781 74.9342 116.59 74.7772 c
+116.396 74.6201 116.187 74.5031 115.964 74.4262 c
+115.742 74.3497 115.503 74.3114 115.249 74.3114 c
+114.95 74.3114 114.676 74.3571 114.429 74.4489 c
+114.183 74.5405 113.964 74.6816 113.773 74.8727 c
+113.582 75.0595 113.436 75.2758 113.335 75.5207 c
+113.234 75.7659 113.18 76.0363 113.172 76.3317 c
+113.172 76.343 l
+closepath
+117.724 76.2138 m
+117.724 76.33 117.746 76.4394 117.791 76.5423 c
+117.836 76.6452 117.905 76.7396 117.999 76.8258 c
+118.092 76.9117 118.201 76.9763 118.324 77.0194 c
+118.448 77.0622 118.586 77.0837 118.74 77.0837 c
+118.848 77.0837 118.944 77.0755 119.026 77.0585 c
+119.108 77.0418 119.175 77.0182 119.228 76.9885 c
+119.28 76.9584 119.329 76.9219 119.374 76.8791 c
+119.419 76.836 119.458 76.7864 119.492 76.7302 c
+119.525 76.775 119.567 76.8173 119.615 76.8564 c
+119.664 76.8958 119.722 76.9341 119.789 76.9715 c
+119.857 77.0089 119.931 77.0369 120.014 77.0557 c
+120.096 77.0744 120.188 77.0837 120.289 77.0837 c
+120.416 77.0837 120.536 77.0661 120.648 77.0304 c
+120.76 76.995 120.865 76.9397 120.962 76.8649 c
+121.059 76.7937 121.133 76.7124 121.184 76.6208 c
+121.234 76.5293 121.261 76.4272 121.265 76.315 c
+121.265 76.3113 121.265 76.3084 121.265 76.3065 c
+121.265 76.3048 121.265 76.3019 121.265 76.298 c
+121.265 76.2943 121.265 76.2914 121.265 76.2897 c
+121.265 76.2878 121.265 76.2849 121.265 76.2812 c
+121.261 76.2775 121.26 76.2747 121.26 76.2727 c
+121.26 76.271 121.26 76.2682 121.26 76.2645 c
+121.26 76.2605 121.26 76.258 121.26 76.256 c
+121.26 76.254 121.26 76.2512 121.26 76.2475 c
+121.26 74.3562 l
+120.771 74.3562 l
+120.771 76.0791 l
+120.771 76.0754 120.771 76.0746 120.771 76.0763 c
+120.771 76.0783 120.773 76.0791 120.777 76.0791 c
+120.777 76.0828 120.777 76.0856 120.777 76.0876 c
+120.777 76.0896 120.777 76.0922 120.777 76.0961 c
+120.777 76.1035 120.777 76.11 120.777 76.1157 c
+120.777 76.1214 120.777 76.1259 120.777 76.1296 c
+120.777 76.1409 120.776 76.1523 120.774 76.1633 c
+120.772 76.1746 120.769 76.1877 120.766 76.2027 c
+120.762 76.2138 120.759 76.226 120.757 76.2393 c
+120.756 76.2523 120.753 76.2662 120.749 76.2812 c
+120.734 76.326 120.712 76.3691 120.682 76.4102 c
+120.651 76.4516 120.616 76.4907 120.575 76.5281 c
+120.534 76.5655 120.489 76.5936 120.44 76.6123 c
+120.392 76.631 120.341 76.6404 120.289 76.6404 c
+120.221 76.6404 120.159 76.6282 120.101 76.6038 c
+120.043 76.5797 119.989 76.5432 119.941 76.4944 c
+119.892 76.4459 119.854 76.3943 119.826 76.3402 c
+119.798 76.286 119.778 76.2288 119.767 76.169 c
+119.763 76.1616 119.76 76.1531 119.758 76.1437 c
+119.756 76.1344 119.755 76.1259 119.755 76.1185 c
+119.755 76.1072 119.755 76.0978 119.755 76.0905 c
+119.755 76.0828 119.755 76.0754 119.755 76.0681 c
+119.755 74.3562 l
+119.273 74.3562 l
+119.273 76.0343 l
+119.273 76.1165 119.262 76.1934 119.239 76.2645 c
+119.217 76.3354 119.183 76.4008 119.138 76.4609 c
+119.093 76.5208 119.037 76.5655 118.97 76.5956 c
+118.903 76.6254 118.826 76.6404 118.74 76.6404 c
+118.631 76.6293 118.541 76.6049 118.47 76.5675 c
+118.399 76.5301 118.347 76.4797 118.313 76.4159 c
+118.279 76.3524 118.254 76.2849 118.237 76.2138 c
+118.22 76.1429 118.212 76.0698 118.212 75.9949 c
+118.212 75.9912 118.212 75.9876 118.212 75.9839 c
+118.212 75.9782 l
+118.212 74.3562 l
+117.724 74.3562 l
+117.724 76.2138 l
+closepath
+122.23 78.2456 m
+122.23 75.7256 l
+122.23 75.576 122.249 75.4422 122.286 75.3242 c
+122.324 75.2066 122.378 75.1026 122.449 75.0127 c
+122.524 74.9231 122.613 74.8557 122.716 74.8109 c
+122.819 74.7658 122.936 74.7434 123.067 74.7434 c
+123.19 74.7434 123.3 74.7613 123.398 74.7967 c
+123.495 74.8324 123.579 74.8857 123.65 74.9566 c
+123.718 75.0277 123.774 75.1026 123.819 75.1811 c
+123.864 75.2599 123.897 75.3401 123.92 75.4226 c
+123.927 75.4413 123.932 75.4609 123.934 75.4816 c
+123.936 75.502 123.939 75.5235 123.942 75.5459 c
+123.946 75.5686 123.949 75.5899 123.95 75.6105 c
+123.952 75.6312 123.953 75.6508 123.953 75.6695 c
+123.953 75.8192 123.934 75.9501 123.894 76.0624 c
+123.855 76.1746 123.798 76.2662 123.723 76.3374 c
+123.649 76.4122 123.569 76.4711 123.485 76.5142 c
+123.401 76.5573 123.313 76.5843 123.224 76.5956 c
+123.213 76.5956 123.202 76.5956 123.193 76.5956 c
+123.184 76.5956 123.175 76.5956 123.168 76.5956 c
+123.164 76.5956 123.159 76.5956 123.154 76.5956 c
+123.148 76.5956 123.143 76.5973 123.14 76.6013 c
+123.132 76.6013 123.126 76.6013 123.123 76.6013 c
+123.119 76.6013 123.115 76.6013 123.112 76.6013 c
+123.056 76.6013 123.003 76.5973 122.954 76.5899 c
+122.906 76.5826 122.861 76.5712 122.82 76.5562 c
+122.779 76.5412 122.738 76.5253 122.699 76.5086 c
+122.66 76.4918 122.62 76.474 122.578 76.4553 c
+122.573 76.4496 l
+122.567 76.4496 l
+122.56 76.4459 122.552 76.4422 122.545 76.4383 c
+122.537 76.4346 122.532 76.4329 122.528 76.4329 c
+122.52 76.4289 122.514 76.4252 122.508 76.4215 c
+122.503 76.4179 122.496 76.4142 122.489 76.4102 c
+122.474 76.4065 122.46 76.402 122.446 76.3963 c
+122.433 76.3906 122.419 76.3841 122.404 76.3768 c
+122.404 76.8762 l
+122.446 76.8949 122.486 76.9136 122.525 76.9323 c
+122.564 76.9511 122.605 76.9678 122.646 76.9828 c
+122.687 76.9978 122.728 77.0109 122.769 77.0222 c
+122.81 77.0333 122.853 77.0426 122.898 77.0503 c
+122.917 77.054 122.936 77.0568 122.957 77.0585 c
+122.978 77.0605 122.999 77.0633 123.022 77.067 c
+123.033 77.067 123.043 77.067 123.053 77.067 c
+123.062 77.067 123.072 77.069 123.084 77.0727 c
+123.091 77.0727 123.1 77.0727 123.112 77.0727 c
+123.123 77.0727 123.134 77.0727 123.145 77.0727 c
+123.321 77.0727 123.486 77.0435 123.639 76.9856 c
+123.793 76.9275 123.937 76.8388 124.071 76.7189 c
+124.206 76.603 124.308 76.4646 124.377 76.3036 c
+124.446 76.1429 124.481 75.9615 124.481 75.7594 c
+124.481 75.5723 124.451 75.3926 124.391 75.2205 c
+124.331 75.0484 124.242 74.8838 124.122 74.7267 c
+124.006 74.5694 123.859 74.4534 123.681 74.3786 c
+123.503 74.3038 123.298 74.2664 123.067 74.2664 c
+122.835 74.2664 122.633 74.3029 122.461 74.3758 c
+122.288 74.4489 122.146 74.56 122.034 74.7097 c
+121.922 74.8633 121.837 75.0269 121.781 75.2009 c
+121.725 75.375 121.697 75.5609 121.697 75.7594 c
+121.697 78.2456 l
+122.23 78.2456 l
+closepath
+124.969 78.2904 m
+125.497 78.2904 l
+125.497 76.6965 l
+127.181 76.6965 l
+127.181 78.2904 l
+127.708 78.2904 l
+127.708 74.3562 l
+127.181 74.3562 l
+127.181 76.169 l
+125.497 76.169 l
+125.497 74.3562 l
+124.969 74.3562 l
+124.969 78.2904 l
+closepath
+F
+%%PageTrailer
+showpage
+%%Trailer
+end
+%%DocumentSuppliedResources: procset Linux-Sketch-Procset 1.0 2
+%%EOF
Binary file flys-artifacts/doc/datacage-config-manual/figures/intevation-logo.pdf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/datacage-config-manual/title.tex	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,51 @@
+%-----------------------------------
+% TITLE PAGE
+
+% FIXME BSH Logo
+
+\begin{figure}[ht]
+  \begin{minipage}[b]{0.5\linewidth}
+    \centering
+    \includegraphics[scale=0.75]{figures/bsh_logo} \\
+     {\tt http://www.bsh.de/en}\\[4.0cm]
+  \end{minipage}
+  \begin{minipage}[b]{0.5\linewidth}
+    \centering
+    \includegraphics[width=0.75\textwidth]{figures/intevation-logo}
+     {\tt http://intevation.de/geospatial}\\[2.0cm]
+  \end{minipage}
+\end{figure}
+ 
+ \vspace{4cm}
+ 
+ {
+ 	\sffamily\large
+ 	Documentation FLYS 3.0
+ 
+ 	\vspace{1cm}
+ 	{
+ 		\bfseries\huge
+ 	        Documentation of the Datacage
+ 	}
+ 
+ 	\vspace{1cm}
+ 	Version \documentversion~-~Date: \documentdate
+ 
+% 	Revision \documentrevision
+ }
+ 
+ \vspace{4cm}
+ 
+ \thispagestyle{empty}
+ 
+ \vfill
+ 
+ \begin{flushleft}
+ Authors:\\
+ Felix Wolfsteller$<$felix.wolfsteller@intevation.de$>$\\
+ {\bf Intevation GmbH},\\
+ Neuer Graben 17, 49074 Osnabrück, Germany\\
+ Tel: ++49 541 33 50 83 - 0 \\
+ http://www.intevation.net/geospatial
+ 
+ \end{flushleft}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/doc/datacage.txt	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,148 @@
+This document describes how the datacage configuration works, from a user
+perspective.  Some rather technical details are omitted and mechanisms
+simplified.
+
+The datacages behaviour is defined in the file conf/meta-data.xml .
+
+The datacage serves two purposes.
+It handles automatic 'recommendations', which are instructions
+sent by the client to add newly created artifacts to the collection.
+From a user perspective, these artifacts mainly represent curves or data
+points in the resulting diagrams.
+The second task is to let the user add already existing artifacts (i.e.
+previous calculations) or new artifacts with access to related data.
+
+Irrelevant of the type of elements (recommendations or user picked data) the
+datacage can iterate over possible artifacts by accessing its own database.
+Thus, to create a list of matching entries, database queries are used.
+
+In meta-data.xml, database queries are defined as <dc:statement> elements,
+for example
+                <dc:statement>
+                  SELECT id          AS prot_id,
+                         description AS prot_description
+                  FROM wsts WHERE kind = 1 AND river_id = ${river_id}
+                </dc:statement>
+
+As can be seen from the example, the datacage configuration file can maintain
+its own stack of variables (${river_id} in above example).
+
+The database query will usually deliver one or many results, over which is
+iterated using the <dc:elements> elements.
+
+Information from this results can be used for two goals.
+It can be taken as output, in which
+case the client will either request the creation of these artifacts (considering
+recommendations), or shown by the client in a the 'datacage widget',
+the graphical representation of data which can be added in the current
+context.  The later is seen when the user clicks on the Datacage button in
+a diagram.
+Or information can be used to feed a second (or third...) database query.
+Following above example:
+
+                <dc:statement>
+                  SELECT id          AS prot_id,
+                         description AS prot_description
+                  FROM wsts WHERE kind = 1 AND river_id = ${river_id}
+                </dc:statement>
+                <dc:elements>
+                  <additional>
+                    <dc:attribute name="name" value="${prot_description}"/>
+                    <dc:context>
+                      <dc:statement>
+                        SELECT id       AS prot_column_id,
+                               name     AS prot_column_name,
+                               position AS prot_rel_pos
+                        FROM wst_columns WHERE wst_id = ${prot_id}
+                        ORDER by position
+                      </dc:statement>
+                      <!-- ... -->
+
+In both cases, an <dc:elements> element makes database queries available.
+Also
+note how the variables are defined in the first query and reused in the second
+query (${prot_it}).
+
+Any alement not prefixed with "dc" represents a (sub-) node in the resulting
+tree.  The client will display these nodes and maybe subnodes in the datacage
+widget - <additional> in above example.  The elements name is translated by
+the client.
+
+While iterating the final results, <dc:attributes> have to be specified
+to define how the artifact is to be created.
+
+                      <dc:elements>
+                        <column>
+                          <dc:attribute name="name" value="${prot_column_name}"/>
+                          <dc:attribute name="ids" value="additionals-wstv-${prot_rel_pos}-${prot_id}"/>
+                          <dc:attribute name="factory" value="staticwkms"/>
+                        </column>
+                      </dc:elements>
+
+The "name" attribute is what is to be displayed in the client, the "ids" are given
+to the server and pass important information about the chosen data.
+The "factory" is chosen according to the type of data displayed.
+
+So far, three other elements have not yet been mentioned: <dc:comment>,
+<dc:if> and the <dc:when><dc:otherwise> structure.
+<dc:comment> is an element to allow comments.  Choose these over standard
+<!-- --> xml comments, because they are not transferred to the client.
+<dc:if> and <dc:when> allow control (rather: definition) flow within
+the configuration and work in analogy to the XSL-elements <xsl:if>
+and <xsl:when>.
+
+When dealing with the behaviour specification of the datacage, multiple
+interpretations for the term "context" are possible.
+A <dc:context> element essentially means a database binding.  Thus each
+query (<dc:statement>) needs to be nested in its own context.
+Furthermore, two types of databases with own bindings exist:
+The "system" (default for <dc:context>, <dc:context connection="system">)
+context allows queries related to the backend database with existing
+data (e.g. measurements).
+The "user" context (<dc:context connection="user">) allows queries against
+the database which stores information about already existing artifacts and
+calculations.
+
+Another connotation for the term "context" is the situation from which
+the datacage is queried.  The standard case is a from the datacage widget.
+When the user opens the datacage from the graphical client, this is done
+from one of possible multiple diagrams.
+When the datacage is queried, it gets as an argument the "out" of
+the current artifact.  The out corresponds to the diagram type.
+
+For example the inner block of
+
+          <dc:if test="dc:contains($artifact-outs, 'longitudinal_section')">
+              <longitudinal_section>
+                <dc:call-macro name="annotations"/>
+              </longitudinal_section>
+          </dc:if>
+
+will only be executed if called from the datacage within a
+longitudinal_section diagram.
+
+In the given example another concept of the datacage configuration is
+encountered: Macros.
+
+Macros help to avoid duplication of parts of the document.  As the datacage
+of some diagrams should include the same type of data, the same query should
+be executed in multiple situations.
+
+Therefore a macro can be defined, like in
+
+        <dc:macro name="basedata_4_heightmarks-wq">
+          <heightmarks>
+            <dc:context>
+              <dc:statement>
+                SELECT id          AS prot_id,
+                       description AS prot_description
+                FROM wsts WHERE kind = 4 AND river_id = ${river_id}
+              </dc:statement>
+              <dc:elements>
+              <!-- ... -->
+        </dc:macro>
+
+and invoked from another location within the document, e.g. with
+
+                <dc:call-macro name="basedata_4_heightmarks"/>
+.
--- a/flys-artifacts/pom.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/pom.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -21,11 +21,20 @@
           <artifactId>maven-compiler-plugin</artifactId>
           <version>2.0.2</version>
           <configuration>
-              <source>1.5</source>
-              <target>1.5</target>
+              <source>1.6</source>
+              <target>1.6</target>
           </configuration>
       </plugin>
-     </plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>2.8.1</version>
+        <configuration>
+          <show>private</show>
+          <nohelp>true</nohelp>
+        </configuration>
+      </plugin>
+    </plugins>
   </build>
 
   <dependencies>
@@ -121,10 +130,30 @@
       <version>2.7.2</version>
     </dependency>
     <dependency>
+      <groupId>org.geotools</groupId>
+      <artifactId>gt-swing</artifactId>
+      <version>2.7.2</version>
+    </dependency>
+    <dependency>   
+      <groupId>org.json</groupId>   
+      <artifactId>json</artifactId>   
+      <version>20090211</version>   
+    </dependency>
+    <dependency>
       <groupId>org.apache.velocity</groupId>
       <artifactId>velocity</artifactId>
       <version>1.7</version>
     </dependency>
+    <dependency>
+      <groupId>net.sf.jasperreports</groupId>
+      <artifactId>jasperreports</artifactId>
+      <version>4.5.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.groovy</groupId>
+      <artifactId>groovy-all</artifactId>
+      <version>1.6.0</version>
+    </dependency>
   </dependencies>
   <repositories>
     <repository>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/AbstractStaticStateArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,69 @@
+package de.intevation.flys.artifacts;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.intevation.artifactdatabase.state.State;
+
+/**
+ * A abstract baseclass for Artifacts which are using only one static state.
+ *
+ * This class is intended to be used without the config/stateengine to generate
+ * the static state.
+ *
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public abstract class AbstractStaticStateArtifact extends StaticFLYSArtifact {
+
+    private transient State staticstate;
+
+    /**
+     * 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(getStaticState());
+        return states;
+    }
+
+
+    /**
+     * Get the "current" state.
+     * @param cc ignored.
+     * @return always the set static state.
+     */
+    @Override
+    public State getCurrentState(Object cc) {
+        return getStaticState();
+    }
+
+    /**
+     * A child class must override this method to set its static state
+     */
+    protected abstract void initStaticState();
+
+    protected void setStaticState(State state) {
+        this.staticstate = state;
+    }
+
+    protected State getStaticState() {
+        if (staticstate == null) {
+            initStaticState();
+        }
+        return staticstate;
+    }
+
+    /**
+     * Get the state.
+     * @param context ignored.
+     * @param stateID ignored.
+     * @return the state.
+     */
+    @Override
+    protected State getState(Object context, String stateID) {
+        return getStaticState();
+    }
+}
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/AnnotationArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,8 +8,6 @@
 
 import org.apache.log4j.Logger;
 
-import net.sf.ehcache.Cache;
-
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.ArtifactNamespaceContext;
 import de.intevation.artifacts.CallContext;
@@ -24,11 +22,7 @@
 import de.intevation.artifacts.common.utils.XMLUtils;
 
 import de.intevation.flys.artifacts.states.DefaultState;
-import de.intevation.flys.artifacts.cache.CacheFactory;
 import de.intevation.flys.artifacts.context.FLYSContext;
-import de.intevation.flys.artifacts.model.AnnotationsFactory;
-
-import de.intevation.flys.model.Annotation;
 
 import de.intevation.flys.utils.FLYSUtils;
 
@@ -43,17 +37,15 @@
     /** The name of the artifact. */
     public static final String ARTIFACT_NAME = "annotation";
 
-    /* Name of cache. */
-    public static final String CACHE_NAME = "annotations";
-
+    /** Get river, setup Facets. */
     @Override
     protected void initialize(Artifact artifact, Object context,
             CallMeta meta) {
         logger.debug("AnnotationArtifact.initialize, id: "
-                + artifact.identifier());
+            + artifact.identifier());
 
         FLYSArtifact flys = (FLYSArtifact) artifact;
-        addData("river", flys.getData("river"));
+        importData(flys, "river");
 
         List<Facet> fs = new ArrayList<Facet>();
 
@@ -73,7 +65,7 @@
 
     public double[] getDistance() {
         /** TODO In initialize(), access maximal range of river (via
-         * AnnotationFactory) instead of overriding getDistance, 
+         * AnnotationFactory) instead of overriding getDistance,
          * important for diagram generation. */
         return new double[] {0f, 1000f};
     }
@@ -168,13 +160,13 @@
             DefaultState state = (DefaultState) engine.getState(stateId);
 
             List<Output> list = state.getOutputs();
-            if (list == null || list.size() == 0) {
+            if (list == null || list.isEmpty()) {
                 logger.debug("-> No output modes for this state.");
                 continue;
             }
 
             List<Facet> fs = facets.get(stateId);
-            if (fs == null || fs.size() == 0) {
+            if (fs == null || fs.isEmpty()) {
                 logger.debug("No facets found.");
                 continue;
             }
@@ -216,58 +208,6 @@
         catch (IllegalArgumentException iae) {
             // state is not valid, so we do not append its outputs.
         }
-    } 
-
-
-    /**
-     * Get Annotations for Points (opposed to segments) in river in range.
-     *
-     * @return list of Annotations.
-     */
-    public List<Annotation> getAnnotations() {
-        String river = FLYSUtils.getRiver(this).getName();
-        logger.debug("Search annotations for river: " + river);
-
-        Cache cache = CacheFactory.getCache(CACHE_NAME);
-        String  key = river;
-        Object  old = null;
-
-        if (cache != null) {
-            logger.debug("We are using a cache for annotations.");
-
-            net.sf.ehcache.Element element = cache.get(key);
-            if (element != null) {
-                logger.info("Fetched annotations from cache.");
-                old = element.getValue();
-            }
-        }
-
-        if (old == null) {
-            old = getAnnotationsUncached(river);
-        }
-
-        if (cache != null && old != null) {
-            cache.put(new net.sf.ehcache.Element(key, old));
-        }
-
-        return old != null
-            ? (List<Annotation>) old
-            : new ArrayList<Annotation>();
-    }
-
-    /**
-     * Gets Annotations from Session/Database.
-     *
-     * @return List of Annotations fetched fresh from session/database.
-     * @see DistanceInfoService to access cached documents.
-     */
-    protected List<Annotation> getAnnotationsUncached(String river) {
-        logger.info("Fetch annotations from database.");
-
-        List<Annotation> annotations = new ArrayList<Annotation>();
-        annotations = AnnotationsFactory.getPointAnnotations(river);
-
-        return annotations;
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/AreaArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/AreaArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -13,8 +13,6 @@
 
 import de.intevation.flys.artifacts.model.AreaFacet;
 
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
 
 import de.intevation.flys.artifacts.states.AreaCreationState;
 import de.intevation.flys.artifacts.states.StaticState;
@@ -28,9 +26,6 @@
  */
 public class AreaArtifact extends StaticFLYSArtifact {
 
-    /** Access ids of doc. */
-    public static final String XPATH_IDS = "/art:action/art:ids/@value";
-
     /** Name of Artifact. */
     public static final String AREA_ARTIFACT_NAME = "area_artifact";
 
@@ -80,8 +75,7 @@
         super.setup(identifier, factory, context, callMeta, data);
 
         // TODO yet unused.
-        String ids = XMLUtils.xpathString(
-            data, XPATH_IDS, ArtifactNamespaceContext.INSTANCE);
+        String ids = getDatacageIDValue(data);
 
         // TODO this facet will be remodeled during next feed.
         List<Facet> fs = new ArrayList<Facet>();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/BedHeightsArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,163 @@
+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.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
+{
+    /** 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")));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/ChartArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,213 @@
+package de.intevation.flys.artifacts;
+
+import org.apache.log4j.Logger;
+
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.Artifact;
+
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+
+import de.intevation.artifactdatabase.ProtocolUtils;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.State;
+import de.intevation.artifactdatabase.state.StateEngine;
+import de.intevation.artifactdatabase.state.Output;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+import de.intevation.flys.artifacts.states.DefaultState;
+import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.resources.Resources;
+
+
+/** Artifact, open to generate any (?) out. */
+public class ChartArtifact extends FLYSArtifact {
+
+    private static final Logger logger =
+        Logger.getLogger(ChartArtifact.class);
+
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callmeta,
+        Document        data)
+    {
+        logger.debug("ChartArtifact.setup");
+        this.identifier = identifier;
+        name = "new_chart";
+
+        List<State> states = getStates(context);
+
+        setCurrentState(states.get(0));
+    }
+
+    @Override
+    protected void appendBackgroundActivity(
+        ElementCreator cr,
+        Element        root,
+        CallContext    context
+    ) {
+        Element inBackground = cr.create("background-processing");
+        root.appendChild(inBackground);
+
+        cr.addAttr(
+            inBackground,
+            "value",
+            String.valueOf(context.isInBackground()),
+            true);
+    }
+
+
+    /**
+     * Append output mode nodes to a document.
+     */
+    @Override
+    protected void appendOutputModes(
+        Document    doc,
+        Element     outs,
+        CallContext context,
+        String      uuid)
+    {
+        List<String> stateIds = getPreviousStateIds();
+
+        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        FLYSContext flysContext = FLYSUtils.getFlysContext(context);
+        StateEngine engine      = (StateEngine) flysContext.get(
+            FLYSContext.STATE_ENGINE_KEY);
+
+        for (String stateId: stateIds) {
+            logger.debug("Append output modes for state: " + stateId);
+            DefaultState state = (DefaultState) engine.getState(stateId);
+
+            List<Output> list = state.getOutputs();
+            if (list == null || list.isEmpty()) {
+                logger.debug("-> No output modes for this state.");
+                continue;
+            }
+
+            List<Facet> fs = facets.get(stateId);
+
+            if (fs == null || fs.isEmpty()) {
+                logger.debug("No facets for previous state found.");
+                continue;
+            }
+
+            logger.debug("Found " + fs.size() + " facets in previous states.");
+
+            List<Output> generated = generateOutputs(list, fs);
+
+            ProtocolUtils.appendOutputModes(doc, outs, generated);
+        }
+
+        try {
+            DefaultState cur = (DefaultState) getCurrentState(context);
+            List<Output> list = cur.getOutputs();
+            if (list != null && list.size() > 0) {
+                logger.debug(
+                    "Append output modes for current state: " + cur.getID());
+
+                List<Facet> fs = facets.get(cur.getID());
+
+                if (fs != null && fs.size() > 0) {
+                    List<Output> generated = generateOutputs(list, fs);
+
+                    logger.debug("Found " + fs.size() + " current facets.");
+                    if (!generated.isEmpty()) {
+                        ProtocolUtils.appendOutputModes(
+                            doc, outs, generated);
+                    }
+                }
+                else {
+                    logger.debug("No facets found for the current state.");
+                }
+            }
+        }
+        catch (IllegalArgumentException iae) {
+            // state is not valid, so we do not append its outputs.
+        }
+    }
+
+    public static class ChartState extends DefaultState {
+
+        public static final String FIELD_MODE = "chart_type";
+
+        public static final String DURATION_CURVE =
+            "chart.new.durationcurve";
+
+        public static final String COMPUTED_DISCHARGE_CURVE =
+            "chart.new.computeddischargecurve";
+
+        public static final String DISCHARGE_LONGITUDINAL_CURVE =
+            "chart.new.longitudinal_section";
+
+        public static final String W_DIFFERENCES =
+            "chart.new.w_differences";
+
+        public static final String WATERLEVEL =
+            "chart.new.crosssection";
+
+        public static final String[] CHARTS = {
+            COMPUTED_DISCHARGE_CURVE,
+            DURATION_CURVE,
+            DISCHARGE_LONGITUDINAL_CURVE,
+            W_DIFFERENCES,
+            WATERLEVEL };
+
+
+
+        @Override
+        public Object computeAdvance(
+            FLYSArtifact artifact,
+            String       hash,
+            CallContext  context,
+            List<Facet>  facets,
+            Object       old)
+        {
+            logger.debug("ChartState.computeAdvance");
+
+
+            return null;
+        }
+
+
+        @Override
+        protected Element[] createItems(
+            XMLUtils.ElementCreator cr,
+            Artifact    artifact,
+            String      name,
+            CallContext context)
+        {
+            CallMeta meta   = context.getMeta();
+            Element[] charts = new Element[CHARTS.length];
+
+            int i = 0;
+
+            for (String chart: CHARTS) {
+                charts[i++] = createItem(
+                    cr, new String[] {
+                        Resources.getMsg(meta, chart, chart),
+                        chart
+                    });
+            }
+
+            return charts;
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/CollectionMonitor.java	Fri Sep 28 12:15:52 2012 +0200
@@ -24,12 +24,10 @@
 
 import de.intevation.flys.artifacts.datacage.Recommendations;
 
-
 public class CollectionMonitor implements Hook {
 
     public static final String XPATH_RESULT = "/art:result";
 
-
     private static final Logger logger =
         Logger.getLogger(CollectionMonitor.class);
 
@@ -61,6 +59,9 @@
         Map<String, Object> params = getNoneUserSpecificParameters(flys, context);
 
         Recommendations rec = Recommendations.getInstance();
+
+        // TODO For newer official-lines recommendations we actually
+        // need user-id (null here).
         rec.recommend(flys, null, outs, params, recommended);
     }
 
@@ -73,6 +74,10 @@
         FLYSArtifact flys,
         CallContext  context)
     {
+        if (flys instanceof ChartArtifact) {
+            return new String[0];
+        }
+
         List<Output>  outs = flys.getCurrentOutputs(context);
 
         int num = outs == null ? 0 : outs.size();
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,6 +2,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.NavigableMap;
 
 import org.apache.log4j.Logger;
 
@@ -12,29 +13,30 @@
 import de.intevation.artifacts.CallMeta;
 
 import de.intevation.flys.artifacts.model.CrossSectionFacet;
+import de.intevation.flys.artifacts.model.FastCrossSectionLineFactory;
+
+import de.intevation.flys.model.FastCrossSectionLine;
 
 import de.intevation.flys.model.CrossSection;
 import de.intevation.flys.model.CrossSectionLine;
 import de.intevation.flys.artifacts.model.CrossSectionFactory;
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
 
 import de.intevation.flys.artifacts.states.StaticState;
 
 import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
 import de.intevation.artifactdatabase.state.State;
 
 import de.intevation.flys.utils.FLYSUtils;
 
+import de.intevation.flys.artifacts.services.CrossSectionKMService;
+
 
 /**
  * Artifact describing a cross-section.
  */
 public class CrossSectionArtifact extends StaticFLYSArtifact {
 
-    /** Access ids of doc. */
-    public static final String XPATH_IDS = "/art:action/art:ids/@value";
-
     /** Name of Artifact. */
     public static final String CS_ARTIFACT_NAME = "cross_section";
 
@@ -53,10 +55,36 @@
     /** Name of data item flagging whether we are the newest. */
     public static final String DATA_IS_NEWEST = "cross_section.newest?";
 
+    /** Name of data item storing the previous possible km. */
+    public static final String DATA_PREV_KM = "cross_section.km.previous";
+
+    /** Name of data item storing the next possible km. */
+    public static final String DATA_NEXT_KM = "cross_section.km.next";
+
     /** Own logger. */
     private static final Logger logger =
         Logger.getLogger(CrossSectionArtifact.class);
 
+    static {
+        // TODO: Move to configuration.
+        FacetActivity.Registry.getInstance().register(
+            CS_ARTIFACT_NAME,
+            new FacetActivity() {
+                @Override
+                public Boolean isInitialActive(
+                    Artifact artifact,
+                    Facet    facet,
+                    String   outputName
+                ) {
+                    if (artifact instanceof FLYSArtifact) {
+                        FLYSArtifact flys = (FLYSArtifact)artifact;
+                        String data = flys.getDataAsString(DATA_IS_NEWEST);
+                        return data != null && data.equals("1");
+                    }
+                    return null;
+                }
+            });
+    }
 
     /** Return given name. */
     @Override
@@ -78,8 +106,7 @@
 
         super.setup(identifier, factory, context, callMeta, data);
 
-        String ids = XMLUtils.xpathString(
-            data, XPATH_IDS, ArtifactNamespaceContext.INSTANCE);
+        String ids = getDatacageIDValue(data);
 
         if (ids != null && ids.length() > 0) {
             addStringData(DATA_DBID, ids);
@@ -90,18 +117,22 @@
         }
 
         List<Facet> fs = new ArrayList<Facet>();
-        CrossSection cs = CrossSectionFactory.getCrossSection(Integer.valueOf(ids));
-        CrossSectionLine csl = cs.getLines().get(0);
-        // Find min-km of cross sections, than set DATA_KM to min(DATA_KM, minCross).
-        if (csl != null) {
-            double masterKm = Double.valueOf(getDataAsString(DATA_KM));
-            if (masterKm < csl.getKm().doubleValue()) {
+        CrossSection cs = CrossSectionFactory.getCrossSection(
+            Integer.parseInt(ids));
+
+        List<CrossSectionLine> csls = cs.getLines();
+        if (!csls.isEmpty()) {
+            CrossSectionLine csl = csls.get(0);
+            // Find min-km of cross sections,
+            // then set DATA_KM to min(DATA_KM, minCross).
+            double dataKm = Double.valueOf(getDataAsString(DATA_KM));
+            if (dataKm < csl.getKm().doubleValue()) {
                 addStringData(DATA_KM, csl.getKm().toString());
             }
         }
         fs.add(new CrossSectionFacet(0, cs.getDescription()));
 
-        // Find out if we are newest.
+        // Find out if we are newest and become master if so.
         boolean isNewest = CrossSectionFactory.isNewest(cs);
         String newString = (isNewest) ? "1" : "0";
         addStringData(DATA_IS_NEWEST, newString);
@@ -122,7 +153,7 @@
         Object   context,
         CallMeta callMeta)
     {
-        WINFOArtifact winfo = (WINFOArtifact) artifact;
+        FLYSArtifact winfo = (FLYSArtifact) artifact;
         double[] range = FLYSUtils.getKmRange(winfo);
         double min = 0.0f;
         if (range != null && range.length > 0) {
@@ -132,6 +163,18 @@
     }
 
 
+    /** Returns next possible km for a cross-section. */
+    public Double getNextKm() {
+        return getDataAsDouble(DATA_NEXT_KM);
+    }
+
+
+    /** Returns previous possible km for a cross-section. */
+    public Double getPrevKm() {
+        return getDataAsDouble(DATA_PREV_KM);
+    }
+
+
     /**
      * Create and return a new StaticState with charting output.
      */
@@ -176,7 +219,7 @@
     public int getDataAsIntNull(String dataName) {
         String val = getDataAsString(dataName);
         try {
-            return Integer.valueOf(val);
+            return Integer.parseInt(val);
         }
         catch (NumberFormatException e) {
             logger.warn("Could not get data " + dataName + " as int", e);
@@ -222,7 +265,7 @@
     public double [][] getCrossSectionData() {
         logger.info("getCrossSectionData() for cross_section.km "
             + getDataAsString(DATA_KM));
-        CrossSectionLine line = searchCrossSectionLine();
+        FastCrossSectionLine line = searchCrossSectionLine();
 
         return line != null
                ? line.fetchCrossSectionProfile()
@@ -232,48 +275,71 @@
 
     /**
      * Get CrossSectionLine spatially closest to what is specified in the data
-     * "cross_section.km".
+     * "cross_section.km", null if considered too far.
      *
-     * @return CrossSectionLine closest to "cross_section.km".
+     * It also adds DataItems to store the next and previous (numerically)
+     * values at which cross-section data was recorded.
+     *
+     * @return CrossSectionLine closest to "cross_section.km", might be null
+     *         if considered too far.
      */
-    public CrossSectionLine searchCrossSectionLine() {
-        double wishKM = getKm();
+    public FastCrossSectionLine searchCrossSectionLine() {
+        double TOO_FAR = 1d;
+        CrossSection crossSection = CrossSectionFactory
+            .getCrossSection(getDBID());
 
-        CrossSection crossSection = CrossSectionFactory.getCrossSection(getDBID());
-        logger.debug("dbid " + getDBID() + " : " + crossSection);
-        List<CrossSectionLine> crossSectionLines =
-            crossSection.getLines();
-            
-        // Get the cross section closest to requested km.
-        // Naive, linear approach.
-        CrossSectionLine oldLine = crossSectionLines.get(0);
-        double oldDiff = Math.abs(wishKM - oldLine.getKm().doubleValue());
-        for (CrossSectionLine line: crossSectionLines) {
-            double diff = Math.abs(wishKM - line.getKm().doubleValue());
-            if (diff > oldDiff) {
-                break;
-            }
-            oldDiff = diff;
-            oldLine = line;
+        if (logger.isDebugEnabled()) {
+            logger.debug("dbid " + getDBID() + " : " + crossSection);
         }
-        return oldLine;
-    }
-
 
-    /**
-     * Determines Facets initial disposition regarding activity (think of
-     * selection in Client ThemeList GUI). This will be checked one time
-     * when the facet enters a collections describe document.
-     *
-     * @param outputName Ignored.
-     * @param facetName Ignored.
-     * @param index     Ignored.
-     * @return 0 if not active
-     */
-    @Override
-    public int getInitialFacetActivity(String outputName, String facetName, int index) {
-        return (getDataAsString(DATA_IS_NEWEST) != null
-            && getDataAsString(DATA_IS_NEWEST).equals("1")) ? 1 : 0;
+        NavigableMap<Double, Integer> kms = CrossSectionKMService
+            .getKms(crossSection.getId());
+
+        Double wishKM = getKm();
+
+        Double floor = kms.floorKey(wishKM);
+        Double ceil  = kms.ceilingKey(wishKM);
+
+        Double nextKm;
+        Double prevKm;
+
+        double floorD = floor != null
+            ? Math.abs(floor - wishKM)
+            : Double.MAX_VALUE;
+
+        double ceilD = ceil != null
+            ? Math.abs(ceil - wishKM)
+            : Double.MAX_VALUE;
+
+        double km;
+        if (floorD < ceilD) {
+            km = floor;
+        }
+        else {
+            km = ceil;
+        }
+
+        // If we are too far from the wished km, return null.
+        if (Math.abs(km - wishKM) > TOO_FAR) {
+            return null;
+        }
+
+        // Store next and previous km.
+        nextKm = kms.higherKey(km);
+        prevKm = kms.lowerKey(km);
+
+        if (prevKm == null) {
+            prevKm = -1d;
+        }
+        if (nextKm == null) {
+            nextKm = -1d;
+        }
+
+        addStringData(DATA_PREV_KM, prevKm.toString());
+        addStringData(DATA_NEXT_KM, nextKm.toString());
+
+        return FastCrossSectionLineFactory
+            .getCrossSectionLine(crossSection, km);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/ExternalWMSArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -11,9 +11,6 @@
 import de.intevation.artifacts.ArtifactFactory;
 import de.intevation.artifacts.CallMeta;
 
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
-
 import de.intevation.artifactdatabase.state.DefaultOutput;
 import de.intevation.artifactdatabase.state.Facet;
 import de.intevation.artifactdatabase.state.State;
@@ -23,8 +20,6 @@
 
 public class ExternalWMSArtifact extends StaticFLYSArtifact {
 
-    public static final String XPATH_IDS = "/art:action/art:ids/@value";
-
     public static final String NAME = "external_wms";
 
     private static final Logger logger =
@@ -49,8 +44,7 @@
 
         super.setup(identifier, factory, context, callMeta, data);
 
-        String ids = XMLUtils.xpathString(
-            data, XPATH_IDS, ArtifactNamespaceContext.INSTANCE);
+        String ids = getDatacageIDValue(data);
 
         if (ids != null && ids.length() > 0) {
             addStringData("ids", ids);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,44 +1,10 @@
 package de.intevation.flys.artifacts;
 
-import de.intevation.artifactdatabase.ArtifactDatabaseImpl;
-import de.intevation.artifactdatabase.DefaultArtifact;
-
-import de.intevation.artifactdatabase.data.DefaultStateData;
-import de.intevation.artifactdatabase.data.StateData;
-
-import de.intevation.artifactdatabase.state.DefaultFacet;
-import de.intevation.artifactdatabase.state.DefaultOutput;
-import de.intevation.artifactdatabase.state.Facet;
-import de.intevation.artifactdatabase.state.Output;
-import de.intevation.artifactdatabase.state.State;
-import de.intevation.artifactdatabase.state.StateEngine;
-
-import de.intevation.artifactdatabase.transition.TransitionEngine;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactDatabase;
-import de.intevation.artifacts.ArtifactDatabaseException;
-import de.intevation.artifacts.ArtifactFactory;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.CallMeta;
-
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.flys.artifacts.cache.CacheFactory;
-
-import de.intevation.flys.artifacts.context.FLYSContext;
-
-import de.intevation.flys.artifacts.states.DefaultState;
-import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
-
-import de.intevation.flys.utils.FLYSUtils;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -49,20 +15,50 @@
 import net.sf.ehcache.Cache;
 
 import org.apache.log4j.Logger;
-
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import de.intevation.artifactdatabase.ArtifactDatabaseImpl;
+import de.intevation.artifactdatabase.DefaultArtifact;
+import de.intevation.artifactdatabase.ProtocolUtils;
+import de.intevation.artifactdatabase.data.DefaultStateData;
+import de.intevation.artifactdatabase.data.StateData;
+import de.intevation.artifactdatabase.state.DefaultFacet;
+import de.intevation.artifactdatabase.state.DefaultOutput;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.Output;
+import de.intevation.artifactdatabase.state.State;
+import de.intevation.artifactdatabase.state.StateEngine;
+import de.intevation.artifactdatabase.transition.TransitionEngine;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.Message;
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.flys.artifacts.cache.CacheFactory;
+import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.model.CalculationMessage;
+import de.intevation.flys.artifacts.states.DefaultState;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.utils.FLYSUtils;
+
 /**
- * The defaul FLYS artifact.
+ * The default FLYS artifact with convenience added.
+ * (Subclass to get fully functional artifacts).
  *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public abstract class FLYSArtifact extends DefaultArtifact {
 
     /** The logger that is used in this artifact. */
-    private static Logger logger = Logger.getLogger(FLYSArtifact.class);
+    private static Logger log = Logger.getLogger(FLYSArtifact.class);
 
     public static final String COMPUTING_CACHE = "computed.values";
 
@@ -96,7 +92,7 @@
     protected String name;
 
     /** The data that have been inserted into this artifact. */
-    protected Map<String, StateData> data;
+    private Map<String, StateData> data;
 
     /** Mapping of state names to created facets. */
     protected Map<String, List<Facet>> facets;
@@ -117,6 +113,39 @@
         facets           = new HashMap<String, List<Facet>>();
     }
 
+    /**
+     * This method appends the static data - that has already been inserted by
+     * the user - to the static node of the DESCRIBE document.
+     *
+     * @param doc The document.
+     * @param ui The root node.
+     * @param context The CallContext.
+     * @param uuid The identifier of the artifact.
+     */
+    protected void appendStaticUI(
+        Document    doc,
+        Node        ui,
+        CallContext context,
+        String uuid)
+    {
+        List<String> stateIds = getPreviousStateIds();
+
+        FLYSContext flysContext = FLYSUtils.getFlysContext(context);
+        StateEngine engine      = (StateEngine) flysContext.get(
+            FLYSContext.STATE_ENGINE_KEY);
+
+        boolean debug = log.isDebugEnabled();
+
+        for (String stateId: stateIds) {
+            if (debug) {
+                log.debug("Append static data for state: " + stateId);
+            }
+            DefaultState state = (DefaultState) engine.getState(stateId);
+
+            ui.appendChild(state.describeStatic(this, doc, ui, context, uuid));
+        }
+    }
+
 
     /**
      * Returns the name of the concrete artifact.
@@ -145,7 +174,11 @@
         CallMeta        callMeta,
         Document        data)
     {
-        logger.debug("Setup this artifact with the uuid: " + identifier);
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("Setup this artifact with the uuid: " + identifier);
+        }
 
         super.setup(identifier, factory, context, callMeta, data);
 
@@ -154,8 +187,15 @@
         List<State> states = getStates(context);
 
         String name = getName();
-        logger.debug("Set initial state for artifact '" + name + "'");
 
+        if (debug) {
+            log.debug("setup(): Set initial state for artifact '" + name + "'");
+        }
+
+        if (states == null) {
+            log.error("No states found from which an initial "
+                + "state could be picked.");
+        }
         setCurrentState(states.get(0));
 
         String model = XMLUtils.xpathString(
@@ -171,7 +211,7 @@
                 initialize(db.getRawArtifact(model), context, callMeta);
             }
             catch (ArtifactDatabaseException adbe) {
-                logger.error(adbe, adbe);
+                log.error(adbe, adbe);
             }
         }
 
@@ -179,30 +219,35 @@
     }
 
 
+    /** Get copy of previous state ids as Strings in list. */
     protected List<String> clonePreviousStateIds() {
         return new ArrayList<String>(previousStateIds);
     }
 
+
     /**
      * Copies data item from other artifact to this artifact.
+     *
      * @param other Artifact from which to get data.
      * @param name  Name of data.
      */
     protected void importData(FLYSArtifact other, final String name) {
         if (other == null) {
-            logger.error("No other art. to import data " + name + " from.");
+            log.error("No other art. to import data " + name + " from.");
+            return;
         }
 
         StateData sd = other.getData(name);
 
         if (sd == null) {
-            logger.warn("Other artifact has no data " + name + ".");
+            log.warn("Other artifact has no data " + name + ".");
             return;
         }
 
         this.addData(name, sd);
     }
 
+
     protected Map<String, StateData> cloneData() {
         Map<String, StateData> copy = new TreeMap<String, StateData>();
 
@@ -218,7 +263,7 @@
      * @return Mapping of state-ids to facets.
      */
     protected Map<String, List<Facet>> cloneFacets() {
-        Map copy = new HashMap<String, List<Facet>>();
+        Map<String, List<Facet>> copy = new HashMap<String, List<Facet>>();
 
         for (Map.Entry<String, List<Facet>> entry: facets.entrySet()) {
             List<Facet> facets      = entry.getValue();
@@ -254,6 +299,19 @@
         data             = flys.cloneData();
         facets           = flys.cloneFacets();
         // Do not clone filter facets!
+
+        ArrayList<String> stateIds     = (ArrayList<String>) getPreviousStateIds();
+        ArrayList<String> toInitialize = (ArrayList<String>) stateIds.clone();
+
+        toInitialize.add(getCurrentStateId());
+
+        for (String stateId: toInitialize) {
+            State state = getState(context, stateId);
+
+            if (state != null) {
+                state.initialize(artifact, this, context, callMeta);
+            }
+        }
     }
 
 
@@ -298,7 +356,7 @@
                     index = Integer.parseInt(facetElement.getAttribute("index"));
                 }
                 catch (NumberFormatException nfe) {
-                    logger.warn(nfe);
+                    log.warn(nfe);
                     index = 0;
                 }
                 facets.add(new DefaultFacet(index, fName, ""));
@@ -323,7 +381,7 @@
      */
     @Override
     public Document feed(Document target, CallContext context) {
-        logger.info("FLYSArtifact.feed()");
+        log.debug("FLYSArtifact.feed()");
 
         Document doc = XMLUtils.newDocument();
 
@@ -336,7 +394,7 @@
         doc.appendChild(result);
 
         try {
-            saveData(target, XPATH_FEED_INPUT, context);
+            saveData(target, context);
 
             compute(context, ComputeType.FEED, true);
 
@@ -353,6 +411,144 @@
         return doc;
     }
 
+    /**
+     * This method returns a description of this artifact.
+     *
+     * @param data Some data.
+     * @param context The CallContext.
+     *
+     * @return the description of this artifact.
+     */
+    @Override
+    public Document describe(Document data, CallContext context) {
+
+        if (log.isDebugEnabled()) {
+            log.debug(
+                "Describe: the current state is: " + getCurrentStateId());
+            dumpArtifact();
+        }
+
+        FLYSContext flysContext = FLYSUtils.getFlysContext(context);
+
+        StateEngine stateEngine = (StateEngine) flysContext.get(
+            FLYSContext.STATE_ENGINE_KEY);
+
+        TransitionEngine transitionEngine = (TransitionEngine) flysContext.get(
+            FLYSContext.TRANSITION_ENGINE_KEY);
+
+        List<State> reachable = transitionEngine.getReachableStates(
+            this, getCurrentState(context), stateEngine);
+
+        Document description            = XMLUtils.newDocument();
+        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
+            description,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = ProtocolUtils.createRootNode(creator);
+        description.appendChild(root);
+
+        State current = getCurrentState(context);
+
+        ProtocolUtils.appendDescribeHeader(creator, root, identifier(), hash());
+        ProtocolUtils.appendState(creator, root, current);
+        ProtocolUtils.appendReachableStates(creator, root, reachable);
+
+        appendBackgroundActivity(creator, root, context);
+
+        Element ui = ProtocolUtils.createArtNode(
+            creator, "ui", null, null);
+
+        Element staticUI  = ProtocolUtils.createArtNode(
+            creator, "static", null, null);
+
+        Element outs = ProtocolUtils.createArtNode(
+            creator, "outputmodes", null, null);
+        appendOutputModes(description, outs, context, identifier());
+
+        appendStaticUI(description, staticUI, context, identifier());
+
+        Element name = ProtocolUtils.createArtNode(
+            creator, "name",
+            new String[] { "value" },
+            new String[] { getName() });
+
+        Element dynamic = current.describe(
+            this,
+            description,
+            root,
+            context,
+            identifier());
+
+        if (dynamic != null) {
+            ui.appendChild(dynamic);
+        }
+
+        ui.appendChild(staticUI);
+
+        root.appendChild(name);
+        root.appendChild(ui);
+        root.appendChild(outs);
+
+        return description;
+    }
+
+    /** Override me! */
+
+    protected void appendBackgroundActivity(
+        ElementCreator cr,
+        Element        root,
+        CallContext    context
+    ) {
+        LinkedList<Message> messages = context.getBackgroundMessages();
+
+        if (messages == null) {
+            return;
+        }
+
+        Element inBackground = cr.create("background-processing");
+        root.appendChild(inBackground);
+
+        cr.addAttr(
+            inBackground,
+            "value",
+            String.valueOf(context.isInBackground()),
+            true);
+
+        CalculationMessage  message  = (CalculationMessage) messages.getLast();
+        cr.addAttr(
+            inBackground,
+            "steps",
+            String.valueOf(message.getSteps()),
+            true);
+
+        cr.addAttr(
+            inBackground,
+            "currentStep",
+            String.valueOf(message.getCurrentStep()),
+            true);
+
+        inBackground.setTextContent(message.getMessage());
+    }
+
+    /**
+     * Append output mode nodes to a document.
+     */
+    protected void appendOutputModes(
+        Document    doc,
+        Element     outs,
+        CallContext context,
+        String      uuid)
+    {
+        List<Output> generated = getOutputs(context);
+
+        if (log.isDebugEnabled()) {
+            log.debug("This Artifact has " + generated.size() + " Outputs.");
+        }
+
+        ProtocolUtils.appendOutputModes(doc, outs, generated);
+    }
+
 
     /**
      * This method handles request for changing the current state of an
@@ -363,7 +559,11 @@
      *
      * @return a document that contains a SUCCESS or FAILURE message.
      */
+    @Override
     public Document advance(Document target, CallContext context) {
+
+        boolean debug = log.isDebugEnabled();
+
         Document doc = XMLUtils.newDocument();
 
         XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
@@ -373,26 +573,37 @@
 
         Element result = ec.create("result");
 
-        String targetState = XMLUtils.xpathString(
+        String currentStateId = getCurrentStateId();
+        String targetState    = XMLUtils.xpathString(
             target, XPATH_ADVANCE_TARGET, ArtifactNamespaceContext.INSTANCE);
 
-        logger.info("FLYSArtifact.advance() to '" + targetState + "'");
+        if (debug) {
+            log.debug("FLYSArtifact.advance() to '" + targetState + "'");
+        }
 
-        if (isStateReachable(targetState, context)) {
-            logger.info("Advance: Step forward");
+        if (!currentStateId.equals(targetState)
+            && isStateReachable(targetState, context))
+        {
+            if (debug) {
+                log.debug("Advance: Step forward");
+            }
 
             List<String> prev = getPreviousStateIds();
-            prev.add(getCurrentStateId());
+            prev.add(currentStateId);
 
             setCurrentStateId(targetState);
 
-            logger.debug("Compute data for state: " + targetState);
+            if (debug) {
+                log.debug("Compute data for state: " + targetState);
+            }
             compute(context, ComputeType.ADVANCE, true);
 
             return describe(target, context);
         }
         else if (isPreviousState(targetState, context)) {
-            logger.info("Advance: Step back to");
+            if (debug) {
+                log.debug("Advance: Step back to");
+            }
 
             List<String> prevs   = getPreviousStateIds();
             int targetIdx        = prevs.indexOf(targetState);
@@ -402,7 +613,9 @@
 
             for (int i = start; i >= targetIdx; i--) {
                 String prev = prevs.get(i);
-                logger.debug("Remove state id '" + prev + "'");
+                if (debug) {
+                    log.debug("Remove state id '" + prev + "'");
+                }
 
                 prevs.remove(prev);
                 facets.remove(prev);
@@ -414,7 +627,7 @@
             return describe(target, context);
         }
 
-        logger.warn("Advance: Cannot advance to '" + targetState + "'");
+        log.warn("Advance: Cannot advance to '" + targetState + "'");
         ec.addAttr(result, "type", OPERATION_FAILED, true);
 
         doc.appendChild(result);
@@ -508,7 +721,9 @@
      * @return #getPreviousStateIds() + #getCurrentStateId()
      */
     public List<String> getStateHistoryIds() {
-        List<String> allIds = getPreviousStateIds();
+        ArrayList<String> prevIds = (ArrayList) getPreviousStateIds();
+        ArrayList<String> allIds  = (ArrayList) prevIds.clone();
+
         allIds.add(getCurrentStateId());
         return allIds;
     }
@@ -542,7 +757,14 @@
         return data.get(name);
     }
 
+    /**
+     * A derived Artifact class can use this method to set the data
+     */
+    protected void setData(Map<String, StateData> data) {
+        this.data = data;
+    }
 
+    /** Return named data item, null if not found. */
     public String getDataAsString(String name) {
         StateData data = getData(name);
         return data != null ? (String) data.getValue() : null;
@@ -576,6 +798,56 @@
 
     /**
      * This method returns the value of a StateData object stored in the data
+     * pool of this Artifact as Double.
+     *
+     * @param name The name of the StateData object.
+     *
+     * @return an Double representing the value of the data object or null if
+     * no object was found for <i>name</i>.
+     *
+     * @throws NumberFormatException if the value of the data object could not
+     * be transformed into a Double.
+     */
+    public Double getDataAsDouble(String name)
+    throws NumberFormatException
+    {
+        String value = getDataAsString(name);
+
+        if (value != null && value.length() > 0) {
+            return Double.parseDouble(value);
+        }
+
+        return null;
+    }
+
+
+    /**
+     * This method returns the value of a StateData object stored in the data
+     * pool of this Artifact as Long.
+     *
+     * @param name The name of the StateData object.
+     *
+     * @return a Long representing the value of the data object or null if
+     * no object was found for <i>name</i>.
+     *
+     * @throws NumberFormatException if the value of the data object could not
+     * be transformed into a Long.
+     */
+    public Long getDataAsLong(String name)
+    throws NumberFormatException
+    {
+        String value = getDataAsString(name);
+
+        if (value != null && value.length() > 0) {
+            return Long.parseLong(value);
+        }
+
+        return null;
+    }
+
+
+    /**
+     * This method returns the value of a StateData object stored in the data
      * pool of this Artifact is Boolean using Boolean.valueOf().
      *
      * @param name The name of the StateData object.
@@ -603,12 +875,26 @@
         addData(name, new DefaultStateData(name, null, null, value));
     }
 
-
+    /**
+     * This method returns all stored StateData in this artifact as a Collection
+     * @return a Collection of all StateData objects in this artifact
+     */
     public Collection<StateData> getAllData() {
         return data.values();
     }
 
 
+    public List<Facet> getFacets() {
+        List<Facet> all = new ArrayList<Facet>();
+
+        for (List<Facet> fs: facets.values()) {
+            all.addAll(fs);
+        }
+
+        return all;
+    }
+
+
     /**
      * Get facet as stored internally, with equalling name and index than given
      * facet.
@@ -619,15 +905,15 @@
         String name  = facet.getName();
         int    index = facet.getIndex();
 
-        for (Map.Entry<String, List<Facet>> facetList: facets.entrySet()) {
-            for (Facet f: facetList.getValue()) {
+        for (List<Facet> fs: facets.values()) {
+            for (Facet f: fs) {
                 if (f.getIndex() == index && f.getName().equals(name)) {
                     return f;
                 }
             }
         }
 
-        logger.warn("Could not find facet: " + name + " at " + index);
+        log.warn("Could not find facet: " + name + " at " + index);
         return null;
     }
 
@@ -638,16 +924,16 @@
      * @param feed The FEED document.
      * @param xpath The XPath that points to the data nodes.
      */
-    public void saveData(Document feed, String xpath, CallContext context)
+    public void saveData(Document feed, CallContext context)
     throws IllegalArgumentException
     {
-        if (feed == null || xpath == null || xpath.length() == 0) {
+        if (feed == null) {
             throw new IllegalArgumentException("error_feed_no_data");
         }
 
         NodeList nodes = (NodeList) XMLUtils.xpath(
             feed,
-            xpath,
+            XPATH_FEED_INPUT,
             XPathConstants.NODESET,
             ArtifactNamespaceContext.INSTANCE);
 
@@ -655,13 +941,22 @@
             throw new IllegalArgumentException("error_feed_no_data");
         }
 
+        boolean debug = log.isDebugEnabled();
+
         int count = nodes.getLength();
-        logger.debug("Try to save " + count + " data items.");
+
+        if (debug) {
+            log.debug("Try to save " + count + " data items.");
+        }
 
         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
 
         DefaultState current = (DefaultState) getCurrentState(context);
 
+        FLYSContext flysContext = FLYSUtils.getFlysContext(context);
+        StateEngine engine      = (StateEngine) flysContext.get(
+            FLYSContext.STATE_ENGINE_KEY);
+
         for (int i = 0; i < count; i++) {
             Element node = (Element)nodes.item(i);
 
@@ -669,13 +964,22 @@
             String value = node.getAttributeNS(uri, "value");
 
             if (name.length() > 0 && value.length() > 0) {
-                logger.debug("Save data item for '" + name + "' : " + value);
+                if (debug) {
+                    log.debug("Save data item for '" + name + "' : " + value);
+                }
 
-                addData(name, current.transform(this, context, name, value));
+                StateData model = engine.getStateData(getName(), name);
+
+                StateData sd = model != null
+                    ? model.deepCopy()
+                    : new DefaultStateData(name, null, null, value);
+
+                addData(
+                    name, current.transform(this, context, sd, name, value));
             }
             else if (name.length() > 0 && value.length() == 0) {
-                if (removeData(name) != null) {
-                    logger.debug("Removed data '" + name + "' successfully.");
+                if (removeData(name) != null && debug) {
+                    log.debug("Removed data '" + name + "' successfully.");
                 }
             }
         }
@@ -696,7 +1000,10 @@
      * otherwise false.
      */
     protected boolean isStateReachable(String stateId, Object context) {
-        logger.debug("Determine if the state '" + stateId + "' is reachable.");
+
+        if (log.isDebugEnabled()) {
+            log.debug("Determine if the state '" + stateId + "' is reachable.");
+        }
 
         FLYSContext flysContext = FLYSUtils.getFlysContext(context);
 
@@ -719,14 +1026,11 @@
      * @param context The context object.
      */
     protected boolean isPreviousState(String stateId, Object context) {
-        logger.debug("Determine if the state '" + stateId + "' is old.");
-
-        List<String> prevs = getPreviousStateIds();
-        if (prevs.contains(stateId)) {
-            return true;
+        if (log.isDebugEnabled()) {
+            log.debug("Determine if the state '" + stateId + "' is old.");
         }
 
-        return false;
+        return getPreviousStateIds().contains(stateId);
     }
 
 
@@ -761,18 +1065,35 @@
      * @return filtered Outputlist.
      */
     protected List<Output> filterOutputs(List<Output> outs) {
-
         if (filterFacets == null || filterFacets.isEmpty()) {
-            logger.debug("No filter for Outputs.");
+            log.debug("No filter for Outputs.");
             return outs;
         }
 
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug(
+                "Filter Facets with " + filterFacets.size() + " filters.");
+        }
+
         List<Output> filtered = new ArrayList<Output>();
 
         for (Output out: outs) {
+            String outName = out.getName();
 
-            List<Facet> fFacets = filterFacets.get(out.getName());
+            if (debug) {
+                log.debug("  filter Facets for Output: " + outName);
+            }
+
+            List<Facet> fFacets = filterFacets.get(outName);
             if (fFacets != null) {
+                if (debug) {
+                    log.debug("" + fFacets.size() + " filters for: " + outName);
+                    for (Facet tmp: fFacets) {
+                        log.debug("   filter = '" + tmp.getName() + "'");
+                    }
+                }
 
                 List<Facet> resultFacets = new ArrayList<Facet>();
 
@@ -786,6 +1107,11 @@
                     }
                 }
 
+                if (debug) {
+                    log.debug(
+                        "Facets after filtering = " + resultFacets.size());
+                }
+
                 if (!resultFacets.isEmpty()) {
                     DefaultOutput nout = new DefaultOutput(
                         out.getName(),
@@ -797,6 +1123,10 @@
             }
         }
 
+        if (debug) {
+            log.debug("All Facets after filtering = " + filtered.size());
+        }
+
         return filtered;
     }
 
@@ -808,6 +1138,11 @@
      * @return list of outputs
      */
     public List<Output> getOutputs(Object context) {
+        if (log.isDebugEnabled()) {
+            log.debug("##### Get Outputs for: " + identifier() + " #####");
+            dumpArtifact();
+        }
+
         List<String> stateIds  = getPreviousStateIds();
         List<Output> generated = new ArrayList<Output>();
 
@@ -846,20 +1181,44 @@
      * @return list of output(s) for given state.
      */
     protected List<Output> getOutputForState(DefaultState state) {
-        List<Output> list = state.getOutputs();
-        if (list == null || list.size() == 0) {
-            logger.debug("-> No output modes for this state.");
+
+        if (state == null) {
+            log.error("state == null: This should not happen!");
             return new ArrayList<Output>();
         }
 
-        List<Facet> fs = facets.get(state.getID());
+        boolean debug = log.isDebugEnabled();
 
-        if (fs == null || fs.size() == 0) {
-            logger.debug("No facets found.");
+        if (debug) {
+            log.debug("Find Outputs for State: " + state.getID());
+        }
+
+        List<Output> list = state.getOutputs();
+        if (list == null || list.isEmpty()) {
+            if (debug) {
+                log.debug("-> No output modes for this state.");
+            }
             return new ArrayList<Output>();
         }
 
-        return generateOutputs(list, fs);
+        String stateId = state.getID();
+
+        List<Facet> fs = facets.get(stateId);
+
+        if (fs == null || fs.isEmpty()) {
+            if (debug) {
+                log.debug("No facets found.");
+            }
+            return new ArrayList<Output>();
+        }
+
+        List<Output> gen = generateOutputs(list, fs);
+
+        if (debug) {
+            log.debug("State '" + stateId + "' has " + gen.size() + " outs");
+        }
+
+        return gen;
     }
 
 
@@ -873,7 +1232,7 @@
     protected List<Output> generateOutputs(List<Output> list, List<Facet> fs) {
         List<Output> generated = new ArrayList<Output>();
 
-        boolean debug = logger.isDebugEnabled();
+        boolean debug = log.isDebugEnabled();
 
         for (Output out: list) {
             Output o = new DefaultOutput(
@@ -886,7 +1245,7 @@
 
             for (Facet f: out.getFacets()) {
                 if (outTypes.add(f.getName()) && debug) {
-                    logger.debug("configured facet " + f);
+                    log.debug("configured facet " + f);
                 }
             }
 
@@ -896,7 +1255,7 @@
 
                 if (outTypes.contains(type)) {
                     if (debug) {
-                        logger.debug("Add facet " + f);
+                        log.debug("Add facet " + f);
                     }
                     facetAdded = true;
                     o.addFacet(f);
@@ -960,7 +1319,8 @@
         ComputeType type,
         boolean     generateFacets
     ) {
-        DefaultState current = stateID == null
+        DefaultState current =
+            (stateID == null)
             ? (DefaultState)getCurrentState(context)
             : (DefaultState)getState(context, stateID);
 
@@ -999,10 +1359,13 @@
             if (cache != null) {
                 net.sf.ehcache.Element element = cache.get(key);
                 if (element != null) {
-                    logger.debug("Got computation result from cache.");
+                    log.debug("Got computation result from cache.");
                     old = element.getValue();
                 }
             }
+            else {
+                log.debug("cache not configured.");
+            }
 
             Object res;
             switch (type) {
@@ -1019,7 +1382,7 @@
             }
 
             if (cache != null && old != res && res != null) {
-                logger.debug("Store computation result to cache.");
+                log.debug("Store computation result to cache.");
                 net.sf.ehcache.Element element =
                     new net.sf.ehcache.Element(key, res);
                 cache.put(element);
@@ -1033,41 +1396,95 @@
                     facets.remove(stateID);
                 }
                 else {
-                    facets.put(stateID, fs);
+                    addFacets(stateID, fs);
                 }
             }
         }
     }
 
+    /**
+     * Sets the facets for an ID
+     *
+     * Normally the id is a state ID.
+     *
+     * @param id ID to map the facets to
+     * @param facets List of facets to be stored
+     */
+    protected void addFacets(String id, List<Facet> facets) {
+        this.facets.put(id, facets);
+    }
+
 
     /**
      * Method to dump the artifacts state/data.
      */
     protected void dumpArtifact() {
-        if (logger.isDebugEnabled()) {
-            logger.debug("++++++++++++++ DUMP ARTIFACT DATA +++++++++++++++++");
+        log.debug("++++++++++++++ DUMP ARTIFACT DATA +++++++++++++++++");
+        // Include uuid, type, name
 
-            logger.debug("------ DUMP DATA ------");
-            Collection<StateData> allData = data.values();
+        log.debug("------ DUMP DATA ------");
+        Collection<StateData> allData = data.values();
 
-            for (StateData d: allData) {
-                String name  = d.getName();
-                String value = (String) d.getValue();
+        for (StateData d: allData) {
+            String name  = d.getName();
+            String value = (String) d.getValue();
 
-                logger.debug("- " + name + ": " + value);
+            log.debug("- " + name + ": " + value);
+        }
+
+        log.debug("------ DUMP PREVIOUS STATES ------");
+        List<String> stateIds = getPreviousStateIds();
+
+        for (String id: stateIds) {
+            log.debug("- State: " + id);
+        }
+
+        log.debug("CURRENT STATE: " + getCurrentStateId());
+
+        debugFacets();
+        dumpFilterFacets();
+
+        log.debug("++++++++++++++ END ARTIFACT DUMP +++++++++++++++++");
+    }
+
+
+    protected void debugFacets() {
+        log.debug("######### FACETS #########");
+        Set<Map.Entry<String, List<Facet>>> entries = facets.entrySet();
+
+        for (Map.Entry<String, List<Facet>> entry: entries) {
+            String out = entry.getKey();
+            List<Facet> fs = entry.getValue();
+            for (Facet f: fs) {
+                log.debug("  # " + out + " : " + f.getName());
             }
-
-            logger.debug("------ DUMP PREVIOUS STATES ------");
-            List<String> stateIds = getPreviousStateIds();
+        }
 
-            for (String id: stateIds) {
-                logger.debug("- State: " + id);
-            }
+        log.debug("######## FACETS END ########");
+    }
 
-            logger.debug("CURRENT STATE: " + getCurrentStateId());
 
-            logger.debug("++++++++++++++ END ARTIFACT DUMP +++++++++++++++++");
+    protected void dumpFilterFacets() {
+        log.debug("######## FILTER FACETS ########");
+
+        if (filterFacets == null || filterFacets.isEmpty()) {
+            log.debug("No Filter Facets defined.");
+            return;
         }
+
+        Set<Map.Entry<String, List<Facet>>> entries = filterFacets.entrySet();
+        for (Map.Entry<String, List<Facet>> entry: entries) {
+            String      out     = entry.getKey();
+            List<Facet> filters = entry.getValue();
+
+            log.debug("There are " + filters.size() + " filters for: " +out);
+
+            for (Facet filter: filters) {
+                log.debug("  filter: " + filter.getName());
+            }
+        }
+
+        log.debug("######## FILTER FACETS END ########");
     }
 
 
@@ -1095,33 +1512,16 @@
      */
     @Override
     public void endOfLife(Object context) {
-        logger.info("FLYSArtifact.endOfLife: " + identifier());
-
-        List<String> ids = getPreviousStateIds();
-        ids.add(getCurrentStateId());
+        if (log.isDebugEnabled()) {
+            log.debug("FLYSArtifact.endOfLife: " + identifier());
+        }
 
-        destroyStates(ids, context);
-    }
-    
-    
-    /**
-     * Determines Facets initial disposition regarding activity (think of
-     * selection in Client ThemeList GUI). This will be checked one time
-     * when the facet enters a collections describe document.
-     *
-     * @param facetName  name of the facet.
-     * @param outputName name of the output.
-     * @param index      index of the facet.
-     *
-     * @return 1 if wished to be initally active, 0 if not. FLYSArtifact
-     *         defaults to "1".
-     */
-    public int getInitialFacetActivity(
-        String outputName,
-        String facetName,
-        int index)
-    {
-        return 1;
+        ArrayList<String> ids       = (ArrayList<String>) getPreviousStateIds();
+        ArrayList<String> toDestroy = (ArrayList<String>) ids.clone();
+
+        toDestroy.add(getCurrentStateId());
+
+        destroyStates(toDestroy, context);
     }
 }
 // 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/FixationArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,36 @@
+package de.intevation.flys.artifacts;
+
+import org.apache.log4j.Logger;
+
+/**
+ * The default fixation analysis artifact.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixationArtifact
+extends      FLYSArtifact
+{
+    /** The logger for this class. */
+    private static Logger logger = Logger.getLogger(FixationArtifact.class);
+
+    /** The name of the artifact. */
+    public static final String ARTIFACT_NAME = "fixanalysis";
+
+    /**
+     * The default constructor.
+     */
+    public FixationArtifact() {
+        logger.debug("ctor()");
+    }
+
+    /**
+     * Returns the name of the concrete artifact.
+     *
+     * @return the name of the concrete artifact.
+     */
+    @Override
+    public String getName() {
+        return ARTIFACT_NAME;
+    }
+}
+// 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/GaugeDischargeArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,187 @@
+package de.intevation.flys.artifacts;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.WQKms;
+
+import de.intevation.flys.artifacts.states.DefaultState;
+
+import de.intevation.flys.artifacts.model.Calculation;
+import de.intevation.flys.artifacts.model.CalculationResult;
+
+import de.intevation.flys.artifacts.model.DischargeTables;
+
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.River;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+
+/**
+ * Artifact to get discharge curves at gauges.
+ */
+public class GaugeDischargeArtifact
+extends      WINFOArtifact
+implements   FacetTypes
+{
+    /** The logger for this class. */
+    private static Logger logger = Logger.getLogger(GaugeDischargeArtifact.class);
+
+    /** The name of the artifact. */
+    public static final String ARTIFACT_NAME = "gaugedischarge";
+
+
+    /**
+     * Trivial Constructor.
+     */
+    public GaugeDischargeArtifact() {
+        logger.debug("GaugeDischargeArtifact.GaugeDischargeArtifact()");
+    }
+
+
+    /**
+     * Gets called from factory, to set things up.
+     * Especially, when loaded via datacage mechanisms, provide the
+     * data document.
+     * @param data filled with stuff from dc, if any.
+     */
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callMeta,
+        Document        data)
+    {
+        logger.debug("GaugeDischargeArtifact.setup");
+        String ids = StaticFLYSArtifact.getDatacageIDValue(data);
+        addStringData("ids", ids);
+        logger.debug("id for gaugedischarge: " + ids);
+        super.setup(identifier, factory, context, callMeta, data);
+    }
+
+
+    /** Return the name of this artifact. */
+    public String getName() {
+        return ARTIFACT_NAME;
+    }
+
+
+    /**
+     * Setup state and facet, copy from master artifact.
+     */
+    @Override
+    protected void initialize(Artifact art, Object context, CallMeta meta) {
+        logger.debug("GaugeDischargeArtifact.initialize");
+        List<Facet> fs = new ArrayList<Facet>();
+        FLYSArtifact artifact = (FLYSArtifact) art;
+        importData(artifact, "river");
+
+        // Get the location(s)
+        //importData(artifact, "ld_mode", ld_from, ld_to, ld_locations
+        addStringData("ld_from", "0");
+        addStringData("ld_to", "1000");
+        addStringData("ld_mode", "distance");
+
+        DefaultState state = (DefaultState) getCurrentState(context);
+        state.computeInit(this, hash(), context, meta, fs);
+        if (!fs.isEmpty()) {
+            logger.debug("Facets to add in GaugeDischargeArtifact.initialize. ("
+                + state.getID() + "/ " + getCurrentStateId() + ").");
+            facets.put(getCurrentStateId(), fs);
+        }
+        else {
+            logger.debug("No facets to add in GaugeDischargeArtifact.initialize ("
+                + state.getID() + "/ "+getCurrentStateId()+").");
+        }
+    }
+
+
+    /** Get the Gauges name which came with datacage data-document. */
+    public String getGaugeName() {
+        return this.getDataAsString("ids");
+    }
+
+
+    /** Get the Gauges which came with datacage data-document. */
+    public Gauge getGauge() {
+        River river = FLYSUtils.getRiver(this);
+        return river.determineGaugeByName(getGaugeName());
+    }
+
+
+    /**
+     * Returns the data that is used to create discharge curves.
+     * @return CalculationResult with WQKms.
+     */
+    public CalculationResult getDischargeCurveData() {
+
+        River river = FLYSUtils.getRiver(this);
+        if (river == null) {
+            return error(new WQKms[0], "no.river.selected");
+        }
+        /*
+        // This one would allow to automatically pick the right Gauge.
+        double [] distance = FLYSUtils.getKmRange(this);
+        logger.debug("getDischargeCurveData: get range");
+
+        if (distance == null) {
+            return error(new WQKms[0], "no.range.found");
+        }
+
+        List<Gauge> gauges = river.determineGauges(distance[0], distance[1]);
+        logger.debug("getDischargeCurveData: got " + gauges.size() + " gauges");
+
+        if (gauges.isEmpty()) {
+            return error(new WQKms[0], "no.gauge.selected");
+        }
+
+        String [] names = new String[gauges.size()];
+
+        for (int i = 0; i < names.length; ++i) {
+            names[i] = gauges.get(i).getName();
+            logger.debug("getDischargeCurveData: name " + names[i]);
+        }
+        */
+
+        DischargeTables dt = new DischargeTables(river.getName(), getDataAsString("ids"));
+
+        Map<String, double [][]> map = dt.getValues(100);
+
+        ArrayList<WQKms> res = new ArrayList<WQKms>();
+
+        Gauge gauge = river.determineGaugeByName(this.getDataAsString("ids"));
+
+        String name = getGaugeName();
+        double [][] values = map.get(name);
+        if (values == null) {
+            logger.error("No values for this gauge / discharge found.");
+            return error(new WQKms[0], "no.gauge.found");
+        }
+        for (int i = 0 ; i < values[0].length; i++) {
+            values[0][i] += gauge.getDatum().doubleValue();
+        }
+        double [] kms = new double[values[0].length];
+        Arrays.fill(kms, gauge.getStation().doubleValue());
+        res.add(new WQKms(kms, values[0], values[1], name));
+
+        return new CalculationResult(
+            res.toArray(new WQKms[res.size()]),
+            new Calculation());
+    }
+}
+// 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/GaugeDischargeCurveArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,99 @@
+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.DefaultOutput;
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.flys.artifacts.states.StaticState;
+import de.intevation.flys.artifacts.StaticFLYSArtifact;
+import de.intevation.flys.artifacts.model.GaugeDischargeCurveFacet;
+
+import de.intevation.flys.model.Gauge;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+/**
+ * Artifact to calculate a discharge curve from a gauge overview info
+ *
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public class GaugeDischargeCurveArtifact
+extends      AbstractStaticStateArtifact
+{
+
+    private static final Logger logger =
+        Logger.getLogger(GaugeDischargeCurveArtifact.class);
+
+    public static final String XPATH_RIVER = "/art:action/art:river/@name";
+    public static final String XPATH_GAUGE = "/art:action/art:gauge/@reference";
+    public static final String NAME = "gaugedischargecurve";
+    public static final String STATIC_STATE_NAME = "state.gaugedischargecurve.static";
+
+    /**
+     * Setup initializes the data by extracting the river and gauge from
+     * the XML Document.
+     */
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callmeta,
+        Document        data)
+    {
+        logger.debug("GaugeDischargeCurveArtifact.setup");
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("GaugeDischargeCurveState.setup" + XMLUtils.toString(data));
+        }
+        String gaugeref = XMLUtils.xpathString(data, XPATH_GAUGE,
+                ArtifactNamespaceContext.INSTANCE);
+        String rivername = XMLUtils.xpathString(data, XPATH_RIVER,
+                ArtifactNamespaceContext.INSTANCE);
+
+        addStringData("river", rivername);
+        addStringData("reference_gauge", gaugeref);
+
+        Gauge gauge = FLYSUtils.getReferenceGauge(this);
+
+        Facet gfacet = new GaugeDischargeCurveFacet(rivername, gauge);
+
+        List<Facet> fs = new ArrayList<Facet>(1);
+        fs.add(gfacet);
+
+        addFacets(STATIC_STATE_NAME, fs);
+
+        super.setup(identifier, factory, context, callmeta, data);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    protected void initStaticState() {
+        StaticState state = new StaticState(STATIC_STATE_NAME);
+        List<Facet> fs = facets.get(STATIC_STATE_NAME);
+        DefaultOutput output = new DefaultOutput(
+            "discharge_curve",
+            "output.discharge_curve", "image/png",
+            fs,
+            "chart");
+
+        state.addOutput(output);
+        setStaticState(state);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/HYKArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,124 @@
+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.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+
+
+import de.intevation.flys.artifacts.states.DefaultState;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
+
+
+/**
+ * Artifact to get hydr zones (HYKs).
+ */
+public class HYKArtifact extends StaticFLYSArtifact {
+
+    /** Name of Artifact. */
+    public static final String HYK_ARTIFACT_NAME = "hyk";
+
+    /** Name of data item keeping the hyk id to load formations from. */
+    public static final String HYK_ID = "hyk_artifact.data.id";
+
+    /** Name of data item keeping the km of cs master. */
+    public static final String HYK_KM = "hyk_artifact.data.km";
+
+    /** Own logger. */
+    private static final Logger logger =
+        Logger.getLogger(HYKArtifact.class);
+
+    static {
+        // TODO: Move to configuration.
+        FacetActivity.Registry.getInstance()
+            .register(HYK_ARTIFACT_NAME, FacetActivity.INACTIVE);
+    }
+
+    /** Return given name. */
+    @Override
+    public String getName() {
+        return HYK_ARTIFACT_NAME;
+    }
+
+
+    /** Store ids, do super.setup. */
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callMeta,
+        Document        data)
+    {
+        logger.info("HYKArtifact.setup");
+
+        String ids = getDatacageIDValue(data);
+
+        logger.info("HYKArtifact.setup: id is " + ids);
+
+        addStringData(HYK_ID, ids);
+
+        super.setup(identifier, factory, context, callMeta, data);
+    }
+
+
+    /** Set km as Data. */
+    public void setKm(double km) {
+        addStringData(HYK_KM, Double.toString(km));
+    }
+
+
+    /** Get km from state data. */
+    public double getKm() {
+        Double km = getDataAsDouble(HYK_KM);
+        if (km == null) {
+            // XXX returning 0 is to be compatible to older versions that had an
+            // own method getDataAsDouble that returned 0 if parsing the
+            // parameter failed.
+            return 0;
+        }
+        else {
+            return km;
+        }
+    }
+
+
+    /** Get hyk-id from state data. */
+    public int getHykId() {
+        return getDataAsInteger(HYK_ID);
+    }
+
+
+    /** Do not copy data from daddyfact. */
+    @Override
+    protected void initialize(
+        Artifact artifact,
+        Object   context,
+        CallMeta callMeta)
+    {
+        logger.debug("HYKArtifact.initialize");
+        importData((FLYSArtifact)artifact, "river");
+
+        List<Facet> fs = new ArrayList<Facet>();
+
+        DefaultState state = (DefaultState) getCurrentState(context);
+        state.computeInit(this, hash(), context, callMeta, fs);
+        if (!fs.isEmpty()) {
+            logger.debug("Facets to add in HYKArtifact.initialize .");
+            facets.put(getCurrentStateId(), fs);
+        }
+        else {
+            logger.debug("No facets to add in HYKArtifact.initialize ("
+                + state.getID() + ").");
+        }
+    }
+}
+// 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/MINFOArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,31 @@
+package de.intevation.flys.artifacts;
+
+/**
+ * The default MINFO artifact.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class MINFOArtifact
+extends      FLYSArtifact
+{
+    /** The name of the artifact. */
+    public static final String ARTIFACT_NAME = "minfo";
+
+
+    /**
+     * The default constructor.
+     */
+    public MINFOArtifact() {
+    }
+
+    /**
+     * Returns the name of the concrete artifact.
+     *
+     * @return the name of the concrete artifact.
+     */
+    @Override
+    public String getName() {
+        return ARTIFACT_NAME;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/MainValuesArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -9,6 +9,7 @@
 
 import de.intevation.artifactdatabase.data.DefaultStateData;
 import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
 import de.intevation.artifactdatabase.state.DefaultOutput;
 import de.intevation.artifactdatabase.state.State;
 
@@ -56,6 +57,23 @@
     protected transient State state = null;
 
 
+    static {
+        // TODO: Move to configuration.
+        FacetActivity.Registry.getInstance().register(
+            ARTIFACT_NAME,
+            new FacetActivity() {
+                @Override
+                public Boolean isInitialActive(
+                    Artifact artifact,
+                    Facet    facet,
+                    String   outputName
+                ) {
+                    return outputName.equals("computed_discharge_curve")
+                        || outputName.equals("duration_curve");
+                }
+            });
+    }
+
     /**
      * Trivial Constructor.
      */
@@ -78,6 +96,13 @@
         logger.debug("MainValuesArtifact.setup");
         state = new StaticState(STATIC_STATE_NAME);
 
+        Facet qfacet0 = new MainValuesQFacet(
+            DURATION_MAINVALUES_Q,
+            Resources.getMsg(
+                callMeta,
+                "facet.discharge_curves.mainvalues.q",
+                "facet.discharge_curves.mainvalues.q"),
+            false);
         Facet qfacet1 = new MainValuesQFacet(
             COMPUTED_DISCHARGE_MAINVALUES_Q,
             Resources.getMsg(
@@ -108,6 +133,7 @@
             true);
 
         List<Facet> fs = new ArrayList<Facet>();
+        fs.add(qfacet0);
         fs.add(qfacet1);
         fs.add(qfacet2);
         fs.add(wfacet1);
@@ -140,7 +166,7 @@
     @Override
     protected void initialize(Artifact artifact, Object context, CallMeta meta) {
         logger.debug("MainValuesArtifact.initialize");
-        WINFOArtifact winfo = (WINFOArtifact) artifact;
+        FLYSArtifact winfo = (FLYSArtifact) artifact;
         double [] locations = FLYSUtils.getLocations(winfo);
         if (locations != null) {
             double location = locations[0];
@@ -290,7 +316,7 @@
                     if (mv.getMainValue().getType().getName().equals("W")) {
                         filteredList.add(new NamedDouble(mv.getMainValue().getName(),
                                 mv.getValue().doubleValue()));
-                    
+
                     }
                 } else
                 // We cannot interpolate the W values, so derive them
@@ -307,35 +333,5 @@
         }
         return filteredList;
     }
-
-
-    /**
-     * Determines Facets initial disposition regarding activity (think of
-     * selection in Client ThemeList GUI). This will be checked one time
-     * when the facet enters a collections describe document.
-     *
-     * @param facetName name of the facet.
-     * @param index     index of the facet.
-     * @return 0 if not active
-     */
-    @Override
-    public int getInitialFacetActivity(
-        String outputName,
-        String facetName,
-        int index)
-    {
-        logger.debug("MainValuesArtifact.active?: "
-           + outputName
-           + "/"
-           + facetName);
-
-        if (outputName.equals("computed_discharge_curve")
-            || outputName.equals("duration_curve")) {
-            return 0;
-        }
-        else {
-            return 1;
-        }
-    }
 }
 // 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/ManualPointsArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,142 @@
+package de.intevation.flys.artifacts;
+
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.flys.artifacts.geom.Lines;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.states.DefaultState;
+import de.intevation.flys.model.FastCrossSectionLine;
+
+
+/**
+ * Artifact to store user-added points and water lines.
+ */
+public class ManualPointsArtifact
+extends      StaticFLYSArtifact
+implements   FacetTypes, WaterLineArtifact
+{
+    private static final long serialVersionUID = 7096025125474986011L;
+
+    /** The logger for this class. */
+    private static Logger logger = Logger.getLogger(ManualPointsArtifact.class);
+
+    /** The name of the artifact. */
+    public static final String ARTIFACT_NAME = "manualpoints";
+
+
+    public ManualPointsArtifact() {
+        logger.debug("ManualPointsArtifact.ManualPointsArtifact()");
+    }
+
+
+    /**
+     * Gets called from factory to set things up.
+     */
+    @Override
+    public void setup(
+            String          identifier,
+            ArtifactFactory factory,
+            Object          context,
+            CallMeta        callMeta,
+            Document        data)
+    {
+        logger.debug("ManualPointsArtifact.setup");
+        super.setup(identifier, factory, context, callMeta, data);
+        initialize(null, context, callMeta);
+    }
+
+
+    /** Return the name of this artifact. */
+    @Override
+    public String getName() {
+        return ARTIFACT_NAME;
+    }
+
+
+    /** Access state data storing the jsonstring with points. */
+    public String getPointsData(String facetName) {
+        return getDataAsString(facetName + ".data");
+    }
+
+
+    /**
+     * Access state data storing the jsonstring with lines.
+     * @param facetName Name of facet or null if the so far
+     *                  only known case should be picked.
+     * @return (String) value of data element (expect json).
+     */
+    public String getLinesData(String facetName) {
+        if (facetName == null)
+            return getDataAsString("cross_section.manualpoints.lines");
+        // TODO .lineS?
+        return getDataAsString(facetName + ".line");
+    }
+
+
+    /** Setup state and facet. */
+    @Override
+    protected void initialize(Artifact artifact, Object context, CallMeta meta) {
+        logger.debug("ManualPointsArtifact.initialize");
+        List<Facet> fs = new ArrayList<Facet>();
+
+        DefaultState state = (DefaultState) getCurrentState(context);
+        state.computeInit(this, hash(), context, meta, fs);
+        if (!fs.isEmpty()) {
+            logger.debug("Facets to add in ManualPointsArtifact.initialize .");
+            facets.put(getCurrentStateId(), fs);
+        }
+        else {
+            logger.debug("No facets to add in ManualPointsArtifact.initialize ("
+                    + state.getID() + ").");
+        }
+    }
+
+
+    /**
+     * Get value of line at index.
+     * @param index index in json array defining lines.
+     * @return water height of line at given index.
+     */
+    protected double getLine(int index) {
+        try {
+            JSONArray lines = new JSONArray(getLinesData(null));
+            JSONArray array = lines.getJSONArray(index);
+
+            return array.getDouble(0);
+        }
+        catch(JSONException e){
+            logger.error("Could not decode json for line.");
+            return 0d;
+        }
+    }
+
+
+    /**
+     * Get the water line "surface".
+     * @param index index of facets data.
+     * @param csl 'ground' against which to determine water surface.
+     * @param a (ignored in this implementation).
+     * @param b (ignored in this implementation).
+     */
+    @Override
+    public Lines.LineData getWaterLines(
+            int                  index,
+            FastCrossSectionLine csl,
+            double a, double b
+            ) {
+        List<Point2D> points = csl.getPoints();
+        return Lines.createWaterLines(points, getLine(index));
+    }
+}
+// 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/MapArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,201 @@
+package de.intevation.flys.artifacts;
+
+import org.apache.log4j.Logger;
+
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+
+import de.intevation.artifactdatabase.ProtocolUtils;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.State;
+import de.intevation.artifactdatabase.state.StateEngine;
+import de.intevation.artifactdatabase.state.Output;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.utils.FLYSUtils;
+
+import de.intevation.flys.artifacts.RiverAxisArtifact.RiverAxisState;
+import de.intevation.flys.artifacts.states.DefaultState;
+import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.model.map.WMSDBLayerFacet;
+
+
+public class MapArtifact extends FLYSArtifact {
+
+    private static final Logger logger =
+        Logger.getLogger(MapArtifact.class);
+
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callmeta,
+        Document        data)
+    {
+        logger.debug("MapArtifact.setup");
+        this.identifier = identifier;
+        name = "new_map";
+
+        FLYSContext flysContext = FLYSUtils.getFlysContext(context);
+
+        List<State> states = getStates(context);
+
+        setCurrentState(states.get(0));
+    }
+
+
+    @Override
+    protected void appendBackgroundActivity(
+        ElementCreator cr,
+        Element        root,
+        CallContext    context
+    ) {
+        Element inBackground = cr.create("background-processing");
+        root.appendChild(inBackground);
+
+        cr.addAttr(
+            inBackground,
+            "value",
+            String.valueOf(context.isInBackground()),
+            true);
+    }
+
+
+    /**
+     * Append output mode nodes to a document.
+     */
+    @Override
+    protected void appendOutputModes(
+        Document    doc,
+        Element     outs,
+        CallContext context,
+        String      uuid)
+    {
+        List<String> stateIds = getPreviousStateIds();
+
+        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        FLYSContext flysContext = FLYSUtils.getFlysContext(context);
+        StateEngine engine      = (StateEngine) flysContext.get(
+            FLYSContext.STATE_ENGINE_KEY);
+
+        for (String stateId: stateIds) {
+            logger.debug("Append output modes for state: " + stateId);
+            DefaultState state = (DefaultState) engine.getState(stateId);
+
+            List<Output> list = state.getOutputs();
+            if (list == null || list.isEmpty()) {
+                logger.debug("-> No output modes for this state.");
+                continue;
+            }
+
+            List<Facet> fs = facets.get(stateId);
+
+            if (fs == null || fs.isEmpty()) {
+                logger.debug("No facets for previous state found.");
+                continue;
+            }
+
+            logger.debug("Found " + fs.size() + " facets in previous states.");
+
+            List<Output> generated = generateOutputs(list, fs);
+
+            ProtocolUtils.appendOutputModes(doc, outs, generated);
+        }
+
+        try {
+            DefaultState cur = (DefaultState) getCurrentState(context);
+            if (cur.validate(this)) {
+                List<Output> list = cur.getOutputs();
+                if (list != null && list.size() > 0) {
+                    logger.debug(
+                        "Append output modes for current state: " + cur.getID());
+
+                    List<Facet> fs = facets.get(cur.getID());
+
+                    if (fs != null && fs.size() > 0) {
+                        List<Output> generated = generateOutputs(list, fs);
+
+                        logger.debug("Found " + fs.size() + " current facets.");
+                        if (!generated.isEmpty()) {
+                            ProtocolUtils.appendOutputModes(
+                                doc, outs, generated);
+                        }
+                    }
+                    else {
+                        logger.debug("No facets found for the current state.");
+                    }
+                }
+            }
+        }
+        catch (IllegalArgumentException iae) {
+            // state is not valid, so we do not append its outputs.
+        }
+    }
+
+    public static class MapState extends RiverAxisState {
+
+        @Override
+        public Object computeAdvance(
+            FLYSArtifact artifact,
+            String       hash,
+            CallContext  context,
+            List<Facet>  facets,
+            Object       old)
+        {
+            logger.debug("MapState.computeAdvance");
+
+            this.artifact = artifact;
+
+            String type = getFacetType();
+
+            WMSDBLayerFacet facet = new WMSDBLayerFacet(
+                0,
+                type,
+                getTitle(context.getMeta()),
+                ComputeType.ADVANCE,
+                getID(), hash,
+                getUrl());
+
+            String name = type + "-" + artifact.identifier();
+
+            facet.addLayer(name);
+            facet.setExtent(getExtent(false));
+            facet.setOriginalExtent(getExtent(true));
+            facet.setSrid(getSrid());
+            facet.setData(getDataString());
+            facet.setFilter(getFilter());
+            facet.setGeometryType(getGeometryType());
+            facet.setConnection(getConnection());
+            facet.setConnectionType(getConnectionType());
+            facet.setLabelItem(getLabelItem());
+
+            facets.add(facet);
+
+            return null;
+        }
+
+        @Override
+        public int getRiverId() {
+            River r = FLYSUtils.getRiver(artifact);
+            int riverId = r.getId();
+
+            return riverId;
+        }
+    }
+}
+// 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/QSectorArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,131 @@
+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.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.model.GaugeFinder;
+import de.intevation.flys.artifacts.model.GaugeFinderFactory;
+import de.intevation.flys.artifacts.model.GaugeRange;
+import de.intevation.flys.artifacts.model.NamedDouble;
+
+import de.intevation.flys.artifacts.services.FixingsKMChartService;
+
+import de.intevation.flys.artifacts.states.DefaultState;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+
+/**
+ * Artifact to produce sector markers.
+ */
+public class QSectorArtifact
+extends      StaticFLYSArtifact
+{
+    /** The logger for this class. */
+    private static Logger logger = Logger.getLogger(QSectorArtifact.class);
+
+    /** The name of the artifact. */
+    public static final String ARTIFACT_NAME = "qsector";
+
+
+    /**
+     * Trivial Constructor.
+     */
+    public QSectorArtifact() {
+        logger.debug("QSectorArtifact.QSectorArtifact()");
+    }
+
+
+    /**
+     * Gets called from factory, to set things up.
+     */
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callMeta,
+        Document        data)
+    {
+        logger.debug("QSectorArtifact.setup");
+        super.setup(identifier, factory, context, callMeta, data);
+        initialize(null, context, callMeta);
+    }
+
+
+    /** Return the name of this artifact. */
+    public String getName() {
+        return ARTIFACT_NAME;
+    }
+
+
+    /** Get list of NamedDouble s (QSectors). */
+    public Object getQSectors(double km, CallContext context) {
+
+        String river = getDataAsString("river");
+        List<NamedDouble> qsectors = new ArrayList<NamedDouble>();
+
+        GaugeFinderFactory ggf = GaugeFinderFactory.getInstance();
+        GaugeFinder        gf  = ggf.getGaugeFinder(river);
+
+        if (gf == null) {
+            logger.warn("No gauge finder found for river '" + river + "'");
+            return null;
+        }
+
+        GaugeRange gr = gf.find(km);
+        if (gr == null) {
+            logger.debug("No gauge range found for km "
+                + km + " on river " + river + ".");
+            return null;
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug(gr);
+        }
+
+        for (int i = 0; i < FixingsKMChartService.I18N_Q_SECTOR_BOARDERS.length; ++i) {
+            String key   = FixingsKMChartService.I18N_Q_SECTOR_BOARDERS[i];
+            String def   = FixingsKMChartService.DEFAULT_Q_SECTOR_BORDERS[i];
+            String label = Resources.getMsg(context.getMeta(), key, def);
+
+            qsectors.add(new NamedDouble(label, gr.getSectorBorder(i)));
+        }
+
+        return qsectors;
+    }
+
+
+    /** Setup state and facet. */
+    @Override
+    protected void initialize(Artifact artifact, Object context, CallMeta meta) {
+        logger.debug("QSectorArtifact.initialize");
+        List<Facet> fs = new ArrayList<Facet>();
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+        importData(flys, "river");
+
+        DefaultState state = (DefaultState) getCurrentState(context);
+        state.computeInit(this, hash(), context, meta, fs);
+        if (!fs.isEmpty()) {
+            logger.debug("Facets to add in QSectorArtifact.initialize .");
+            facets.put(getCurrentStateId(), fs);
+        }
+        else {
+            logger.debug("No facets to add in QSectorArtifact.initialize ("
+                + state.getID() + ").");
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/RiverAxisArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,7 +20,6 @@
 
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.utils.FLYSUtils;
 import de.intevation.flys.utils.GeometryUtils;
 
@@ -81,7 +80,9 @@
         protected Geometry geom;
         protected int      riverId;
 
-        public RiverAxisState(WMSDBArtifact artifact) {
+        public RiverAxisState(){}
+
+        public RiverAxisState(FLYSArtifact artifact) {
             super(artifact);
             riverId = 0;
         }
@@ -91,7 +92,7 @@
                 String ids = artifact.getDataAsString("ids");
 
                 try {
-                    riverId = Integer.valueOf(ids);
+                    riverId = Integer.parseInt(ids);
                 }
                 catch (NumberFormatException nfe) {
                     logger.error("Cannot parse river id from '" + ids + "'");
@@ -107,14 +108,6 @@
         }
 
         @Override
-        protected String getTitle(CallMeta meta) {
-            return Resources.getMsg(
-                meta,
-                FLOODMAP_RIVERAXIS,
-                FLOODMAP_RIVERAXIS);
-        }
-
-        @Override
         protected String getUrl() {
             return FLYSUtils.getUserWMSUrl(artifact.identifier());
         }
@@ -126,9 +119,20 @@
         }
 
         @Override
-        protected Envelope getExtent() {
+        protected Envelope getExtent(boolean reproject) {
             River river = RiverFactory.getRiver(getRiverId());
-            return GeometryUtils.getRiverBoundary(river.getName());
+
+            if (reproject) {
+                logger.debug("Query extent for RiverAxis with Srid: " + getSrid());
+                return GeometryUtils.transform(
+                    GeometryUtils.getRiverBoundary(river.getName()),
+                    getSrid());
+            }
+            else {
+                return GeometryUtils.transform(
+                    GeometryUtils.getRiverBoundary(river.getName()),
+                    "31467");
+            }
         }
 
         @Override
@@ -138,13 +142,11 @@
 
         @Override
         protected String getDataString() {
-            String srid = getSrid();
-
             if (FLYSUtils.isUsingOracle()) {
-                return "geom FROM river_axes USING SRID " + srid;
+                return "geom FROM river_axes";
             }
             else {
-                return "geom FROM river_axes USING UNIQUE id USING SRID " + srid;
+                return "geom FROM river_axes USING UNIQUE id";
             }
         }
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticFLYSArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -25,9 +25,12 @@
  */
 public abstract class StaticFLYSArtifact extends FLYSArtifact {
 
+    /** Private logger. */
     private static final Logger logger =
         Logger.getLogger(StaticFLYSArtifact.class);
 
+    /** Path to 'ids' (data) in doc that comes from datacage. */
+    public static final String XPATH_IDS = "/art:action/art:ids/@value";
 
     /**
      * Create description document which includes outputmodes.
@@ -47,11 +50,18 @@
         Element root = ProtocolUtils.createRootNode(creator);
         desc.appendChild(root);
 
+        Element name = ProtocolUtils.createArtNode(
+            creator, "name",
+            new String[] { "value" },
+            new String[] { getName() });
+
+        root.appendChild(name);
+
         ProtocolUtils.appendDescribeHeader(creator, root, identifier(), hash());
         root.appendChild(createOutputModes(cc, desc, creator));
 
         // Add the data to an anonymous state.
-        Collection<StateData> datas = this.data.values();
+        Collection<StateData> datas = getAllData();
         if (datas.size() > 0) {
             Element ui = creator.create("ui");
             Element staticE = creator.create("static");
@@ -59,7 +69,7 @@
             ui.appendChild(staticE);
             staticE.appendChild(state);
             root.appendChild(ui);
-    
+
             for (StateData dataItem : datas) {
                 Element itemelent = creator.create("data");
                 creator.addAttr(itemelent, "name", dataItem.getName(), true);
@@ -76,7 +86,18 @@
     }
 
 
-    protected Element createOutputModes(
+    /**
+     * Return the value of id element in Datacage data document.
+     * @param data Document as passed by datacage.
+     * @return the id element value of data document.
+     */
+    public static String getDatacageIDValue(Document data) {
+        return XMLUtils.xpathString(data, XPATH_IDS,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    private Element createOutputModes(
         CallContext    cc,
         Document       doc,
         ElementCreator creator)
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,36 @@
 package de.intevation.flys.artifacts;
 
+import de.intevation.artifactdatabase.state.DefaultOutput;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
+import de.intevation.artifactdatabase.state.State;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.flys.artifacts.geom.Lines;
+
+import de.intevation.flys.artifacts.math.Distance;
+import de.intevation.flys.artifacts.math.Linear;
+
+import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.RelativePointFacet;
+import de.intevation.flys.artifacts.model.WKms;
+import de.intevation.flys.artifacts.model.WKmsFacet;
+import de.intevation.flys.artifacts.model.WKmsFactory;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import de.intevation.flys.artifacts.states.StaticState;
+
+import de.intevation.flys.model.FastCrossSectionLine;
+
+import java.awt.geom.Point2D;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -7,31 +38,6 @@
 
 import org.w3c.dom.Document;
 
-import java.awt.geom.Point2D;
-
-import de.intevation.artifactdatabase.state.Facet;
-import de.intevation.artifactdatabase.state.DefaultOutput;
-import de.intevation.artifactdatabase.state.State;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactFactory;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-import de.intevation.artifacts.CallMeta;
-
-import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet;
-import de.intevation.flys.artifacts.model.FacetTypes;
-import de.intevation.flys.artifacts.model.WKms;
-import de.intevation.flys.artifacts.model.WKmsFacet;
-import de.intevation.flys.artifacts.model.WKmsFactory;
-
-import de.intevation.flys.artifacts.states.StaticState;
-import de.intevation.flys.artifacts.resources.Resources;
-
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.flys.geom.Lines;
-import de.intevation.flys.model.CrossSectionLine;
-
 /**
  * Artifact to access additional "waterlevel"-type of data, like the height
  * of protective measures (dikes).
@@ -47,13 +53,22 @@
     private static Logger logger =
         Logger.getLogger(StaticWKmsArtifact.class);
 
-    /** XPath to access initial parameter. */
-    public static final String XPATH_DATA =
-        "/art:action/art:ids/@value";
+    private static final String NAME = "staticwkms";
+
+    static {
+        // TODO: Move to configuration.
+        FacetActivity.Registry.getInstance()
+            .register(NAME, FacetActivity.INACTIVE);
+    }
 
     public static final String STATIC_STATE_NAME =
         "state.additional_wkms.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;
 
@@ -65,6 +80,10 @@
         logger.debug("StaticWKmsArtifact.StaticWKmsArtifact");
     }
 
+    @Override
+    public String getName() {
+        return NAME;
+    }
 
     /**
      * Gets called from factory, to set things up.
@@ -81,10 +100,12 @@
 
         state = new StaticState(STATIC_STATE_NAME);
 
+        if (logger.isDebugEnabled()) {
+            logger.debug(XMLUtils.toString(data));
+        }
+
         List<Facet> fs = new ArrayList<Facet>();
-        logger.debug(XMLUtils.toString(data));
-        String code = XMLUtils.xpathString(
-            data, XPATH_DATA, ArtifactNamespaceContext.INSTANCE);
+        String code = getDatacageIDValue(data);
 
         // TODO Go for JSON, one day.
         //ex.: flood_protection-wstv-114-12
@@ -93,17 +114,17 @@
 
             if (parts.length >= 4) {
                 int col = -1;
-                int wst = Integer.valueOf(parts[3]);
+                int wst = Integer.parseInt(parts[3]);
 
                 if (!parts[2].equals("A")) {
-                    col = Integer.valueOf(parts[2]);
+                    col = Integer.parseInt(parts[2]);
                 }
 
                 addStringData("col_pos", parts[2]);
                 addStringData("wst_id",  parts[3]);
 
                 String wkmsName;
-                if (col > 0) {
+                if (col >= 0) {
                     wkmsName = WKmsFactory.getWKmsName(col, wst);
                 }
                 else {
@@ -113,6 +134,7 @@
                 String name;
                 if (parts[0].equals(HEIGHTMARKS_POINTS)) {
                     name = HEIGHTMARKS_POINTS;
+                    addStringData(DATA_HEIGHT_TYPE, "true");
                 }
                 else {
                     name = STATIC_WKMS;
@@ -125,8 +147,11 @@
                     facetDescription);
                 Facet csFacet = new CrossSectionWaterLineFacet(0,
                     facetDescription);
+                Facet rpFacet = new RelativePointFacet(facetDescription);
+
                 fs.add(wKmsFacet);
                 fs.add(csFacet);
+                fs.add(rpFacet);
                 facets.put(state.getID(), fs);
             }
         }
@@ -166,7 +191,7 @@
         CallMeta meta)
     {
         logger.debug("StaticWKmsArtifact.initialize");
-        WINFOArtifact winfo = (WINFOArtifact) artifact;
+        FLYSArtifact winfo = (FLYSArtifact) artifact;
         // TODO: The river is of no interest, so far.
         addData("river", winfo.getData("river"));
     }
@@ -221,27 +246,114 @@
 
     /**
      * Get WKms from factory.
-     * @param TODO idx param is not needed
+     * @param idx param is not needed (TODO?)
      * @return WKms according to parameterization (can be null);
      */
     public WKms getWKms(int idx) {
         logger.debug("StaticWKmsArtifact.getWKms");
 
         return WKmsFactory.getWKms(
-            Integer.valueOf(getDataAsString("col_pos")),
-            Integer.valueOf(getDataAsString("wst_id")));
+            Integer.parseInt(getDataAsString("col_pos")),
+            Integer.parseInt(getDataAsString("wst_id")));
+    }
+
+
+    /**
+     * Returns W at Km of WKms, linearly interpolated.
+     * Returns -1 if not found.
+     */
+    public static double getWAtKmLin(WKms wkms, double km) {
+        // Uninformed search.
+        int size = wkms.size();
+        int idx = 0;
+        boolean kmIncreasing = (wkms.getKm(0) < wkms.getKm(wkms.size()-1))
+            ? true : false;
+        if (kmIncreasing) {
+            while (idx < size && wkms.getKm(idx) < km) {
+                idx++;
+            }
+        }
+        else {
+            idx = wkms.size() -1;
+            while (idx > 0 && wkms.getKm(idx) > km) {
+                idx--;
+            }
+        }
+
+        if (idx == size -1 || idx == 0) {
+            return -1;
+        }
+
+        // Do linear interpolation
+        int mod = kmIncreasing ? -1 : +1;
+        return Linear.linear(km, wkms.getKm(idx+mod), wkms.getKm(idx), wkms.getW(idx+mod), wkms.getW(idx));
+    }
+
+
+    /**
+     * Get the W at a specific km, only if it is closer to km than to any of
+     * the other given km.
+     * Return Double.NaN otherwise
+     *
+     * @param wkms WKms in which to search for a spatially close W value.
+     * @param km the input km, which is compared to values from wkms.
+     * @param next the next available input km (-1 if unavailable).
+     * @param prev the previous available input km (-1 if unavailable).
+     *
+     * @return W in wkms that is closer to km than to next and prev, or Double.NaN.
+     */
+    public double getWAtCloseKm(WKms wkms, double km, double next, double prev) {
+        // TODO symbolic "-1" pr next/prev is a bad idea (tm), as we compare
+        //      distances to these values later.
+        // TODO issue888
+
+        int size = wkms.size();
+        for (int i = 0; i < size; i++) {
+            double wkmsKm = wkms.getKm(i);
+            double dist = Distance.distance(wkmsKm, km);
+            if (dist == 0d) {
+                return wkms.getW(i);
+            }
+
+            // Problematic Cases:
+            // X == km , | and | == prev and next, (?) == wkmsKm
+            //
+            // Standard case:
+            // ----------|----X-----|-------
+            //     (1)    (2)    (3)   (4)
+            //
+            // With prev==-1
+            // -1 ------X-------|------
+            //    (5)      (6)     (7)
+            //
+            // With next==-1
+            //
+            // ---|-----X----- -1
+            // (8)  (9)   (10)
+
+            if (dist <= Distance.distance(wkmsKm, prev)
+                && dist <= Distance.distance(wkmsKm, next)) {
+                return wkms.getW(i);
+            }
+        }
+
+        return Double.NaN;
     }
 
 
     /**
      * Returns W at Km of WKms, searching linearly.
      * Returns -1 if not found.
+     * @param wkms the WKms object to search for given km.
+     * @param km The searched km.
+     * @return W at given km if in WKms, -1 if not found.
      */
-    public double getWAtKm(WKms wkms, double km) {
-        // Uninformed search.
+    public static double getWAtKm(WKms wkms, double km) {
+        // Uninformed search, intolerant.
+        double TOLERANCE = 0.0d;
         int size = wkms.size();
         for (int i = 0; i < size; i++) {
-            if (wkms.getKm(i) == km) {
+            if (Distance.within(wkms.getKm(i), km, TOLERANCE)) {
                 return wkms.getW(i);
             }
         }
@@ -253,46 +365,44 @@
     /**
      * Get points of line describing the surface of water at cross section.
      *
+     * @param idx Index of facet and in wkms array.
+     * @param csl FastCrossSectionLine to compute water surface agains.
+     * @param next The km of the next crosssectionline.
+     * @param prev The km of the previous crosssectionline.
+     *
      * @return an array holding coordinates of points of surface of water (
-     *         in the form {{x1, x2} {y1, y2}} ).
+     *         in the form {{x1, x2}, {y1, y2}} ).
      */
-    public double [][] getWaterLines(int idx, CrossSectionLine csl) {
-        logger.debug("getWaterLines(" + idx + ")");
+    @Override
+    public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl,
+        double next, double prev
+    ) {
+        logger.debug("getWaterLines(" + idx + ")/" + identifier());
 
-        List<Point2D> points = csl.fetchCrossSectionLinesPoints();
+        List<Point2D> points = csl.getPoints();
 
         WKms wkms = getWKms(0);
 
-        double km = csl.getKm().doubleValue();
+        double km = csl.getKm();
 
         // Find W at km.
-        double wAtKm = getWAtKm(wkms, km);
-        if (wAtKm == -1) {
+        double wAtKm;
+
+        // If heightmarks, only deliver if data snaps.
+        if (getDataAsString(DATA_HEIGHT_TYPE) != null &&
+            getDataAsString(DATA_HEIGHT_TYPE).equals("true")) {
+            wAtKm = getWAtCloseKm(wkms, km, next, prev);
+        }
+        else {
+            wAtKm = getWAtKm(wkms, km);
+        }
+
+        if (wAtKm == -1 || Double.isNaN(wAtKm)) {
             logger.warn("Waterlevel at km " + km + " unknown.");
-            return new double[][] {{}};
+            return new Lines.LineData(new double[][] {{}}, 0d, 0d);
         }
 
         return Lines.createWaterLines(points, wAtKm);
     }
-
-
-    /**
-     * Determines Facets initial disposition regarding activity (think of
-     * selection in Client ThemeList GUI). This will be checked one time
-     * when the facet enters a collections describe document.
-     *
-     * @param facetName name of the facet.
-     * @param index     index of the facet.
-     *
-     * @return Always 0. Static Data will enter plots inactive.
-     */
-    @Override
-    public int getInitialFacetActivity(
-        String outputName,
-        String facetName,
-        int index)
-    {
-        return 0;
-    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWQKmsArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,24 +8,21 @@
 import org.w3c.dom.Document;
 
 import de.intevation.artifactdatabase.state.Facet;
-import de.intevation.artifactdatabase.state.DefaultOutput;
-import de.intevation.artifactdatabase.state.State;
+import de.intevation.artifactdatabase.state.FacetActivity;
 
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.ArtifactFactory;
-import de.intevation.artifacts.ArtifactNamespaceContext;
 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.WQKms;
-import de.intevation.flys.artifacts.model.WQKmsFacet;
 import de.intevation.flys.artifacts.model.WKmsFactory;
 import de.intevation.flys.artifacts.model.WQKmsFactory;
 
-import de.intevation.flys.artifacts.states.StaticState;
-import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.artifacts.states.DefaultState;
 
-import de.intevation.artifacts.common.utils.XMLUtils;
 
 /**
  * Artifact to access additional "waterlevel/discharge"-type of data, like
@@ -42,16 +39,16 @@
     private static Logger logger =
         Logger.getLogger(StaticWQKmsArtifact.class);
 
-    /** XPath to access initial parameter. */
-    public static final String XPATH_DATA =
-        "/art:action/art:ids/@value";
-
     public static final String STATIC_STATE_NAME =
         "state.additional_wqkms.static";
 
-    /** One and only state to be in. */
-    protected transient State state = null;
+    private static final String NAME = "staticwqkms";
 
+    static {
+        // TODO: Move to configuration.
+        FacetActivity.Registry.getInstance()
+            .register(NAME, FacetActivity.INACTIVE);
+    }
 
     /**
      * Trivial Constructor.
@@ -74,72 +71,31 @@
     {
         logger.debug("StaticWQKmsArtifact.setup");
 
-        state = new StaticState(STATIC_STATE_NAME);
+        // Store the 'ids' (from datacage).
+        if (logger.isDebugEnabled()) {
+            logger.debug("StaticWQKmsArtiact.setup" + XMLUtils.toString(data));
+        }
 
-        List<Facet> fs = new ArrayList<Facet>();
-        logger.debug(XMLUtils.toString(data));
-        String code = XMLUtils.xpathString(
-            data, XPATH_DATA, ArtifactNamespaceContext.INSTANCE);
-
-        // TODO Go for JSON, one day.
-        //ex.: flood_protection-wstv-114-12
+        String code = getDatacageIDValue(data);
+        addStringData("ids", code);
         if (code != null) {
             String [] parts = code.split("-");
 
             if (parts.length >= 4) {
-                int col = Integer.valueOf(parts[2]);
-                int wst = Integer.valueOf(parts[3]);
+                int col = Integer.parseInt(parts[2]);
+                int wst = Integer.parseInt(parts[3]);
 
                 addStringData("col_pos", parts[2]);
                 addStringData("wst_id",  parts[3]);
-
-                String wkmsName = WKmsFactory.getWKmsName(col, wst);
-
-                String name;
-                if (parts[0].equals(HEIGHTMARKS_POINTS)) {
-                    name = HEIGHTMARKS_POINTS;
-                }
-                else {
-                    name = STATIC_WQKMS;
-                }
-
-                Facet facet = new WQKmsFacet(
-                    name,
-                    Resources.getMsg(
-                        callMeta,
-                        wkmsName,
-                        wkmsName));
-                fs.add(facet);
-                facets.put(state.getID(), fs);
             }
         }
 
-        spawnState();
+        // Do this AFTER we have set the col_pos etc.
         super.setup(identifier, factory, context, callMeta, data);
     }
 
 
     /**
-     * Initialize the static state with output.
-     * @return static state
-     * @TODO merge with StaticWKmsArtifact implementation.
-     */
-    protected State spawnState() {
-        state = new StaticState(STATIC_STATE_NAME);
-        List<Facet> fs = facets.get(STATIC_STATE_NAME);
-        DefaultOutput output = new DefaultOutput(
-            "general",
-            "general",
-            "image/png",
-            fs,
-            "chart");
-
-        state.getOutputs().add(output);
-        return state;
-    }
-
-
-    /**
      * Called via setup.
      *
      * @param artifact The master-artifact.
@@ -152,89 +108,48 @@
     {
         logger.debug("StaticWQKmsArtifact.initialize");
         WINFOArtifact winfo = (WINFOArtifact) artifact;
-        // TODO: The river is of no interest, so far.
-        addData("river", winfo.getData("river"));
-    }
-
-
-    /**
-     * 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;
-    }
-
+        // TODO: The river is of no interest, so far., also use importData
+        importData(winfo, "river");
 
-    /**
-     * 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();
-    }
-
+        List<Facet> fs = new ArrayList<Facet>();
 
-    /**
-     * 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
-            : spawnState();
+        DefaultState state = (DefaultState) getCurrentState(context);
+        state.computeInit(this, hash(), context, meta, fs);
+        if (!fs.isEmpty()) {
+            logger.debug("Facets to add in StaticWQKmsArtifact.initialize .");
+            facets.put(getCurrentStateId(), fs);
+        }
+        else {
+            logger.debug("No facets to add in StaticWQKmsArtifact.initialize ("
+                + state.getID() + ").");
+        }
     }
 
 
     /**
      * Get WQKms from factory.
-     * @param TODO idx param is not needed
      * @return WQKms according to parameterization (can be null);
      */
-    public WQKms getWQKms(int idx) {
+    public WQKms getWQKms() {
         logger.debug("StaticWQKmsArtifact.getWQKms");
 
-        return WQKmsFactory.getWQKms(
-            Integer.valueOf(getDataAsString("col_pos")),
-            Integer.valueOf(getDataAsString("wst_id")));
+        int col = Integer.parseInt(getDataAsString("col_pos"));
+        int wst = Integer.parseInt(getDataAsString("wst_id"));
+
+        /** TODO do not run twice against db to do this. */
+        String wkmsName = WKmsFactory.getWKmsName(col, wst);
+
+        WQKms res = WQKmsFactory.getWQKms(col, wst);
+        res.setName(wkmsName);
+        return res;
     }
 
+    /** Return specific name. */
+    @Override
+    public String getName() {
+        return NAME;
+    }
 
-    /**
-     * Determines Facets initial disposition regarding activity (think of
-     * selection in Client ThemeList GUI). This will be checked one time
-     * when the facet enters a collections describe document.
-     *
-     * @param facetName name of the facet.
-     * @param index     index of the facet.
-     *
-     * @return Always 0. Static Data will enter plots inactive.
-     */
-    @Override
-    public int getInitialFacetActivity(
-        String outputName,
-        String facetName,
-        int index)
-    {
-        return 0;
-    }
+    // TODO implement deepCopy.
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,72 +1,57 @@
 package de.intevation.flys.artifacts;
 
-import java.awt.geom.Point2D;
-
-import de.intevation.artifactdatabase.ProtocolUtils;
-
 import de.intevation.artifactdatabase.data.StateData;
 
 import de.intevation.artifactdatabase.state.Facet;
-import de.intevation.artifactdatabase.state.Output;
-import de.intevation.artifactdatabase.state.State;
-import de.intevation.artifactdatabase.state.StateEngine;
+import de.intevation.artifactdatabase.state.FacetActivity;
 
-import de.intevation.artifactdatabase.transition.TransitionEngine;
-
+import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.Message;
-
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
 
-import de.intevation.artifacts.common.utils.XMLUtils;
-import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.artifacts.common.utils.StringUtils;
 
-import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.geom.Lines;
 
 import de.intevation.flys.artifacts.model.Calculation1;
 import de.intevation.flys.artifacts.model.Calculation2;
 import de.intevation.flys.artifacts.model.Calculation3;
 import de.intevation.flys.artifacts.model.Calculation4;
+import de.intevation.flys.artifacts.model.Calculation5;
+import de.intevation.flys.artifacts.model.Calculation6;
 import de.intevation.flys.artifacts.model.Calculation;
 import de.intevation.flys.artifacts.model.CalculationResult;
-import de.intevation.flys.artifacts.model.CrossSectionFactory;
 import de.intevation.flys.artifacts.model.DischargeTables;
 import de.intevation.flys.artifacts.model.FacetTypes;
-import de.intevation.flys.artifacts.model.MainValuesFactory;
 import de.intevation.flys.artifacts.model.Segment;
+import de.intevation.flys.artifacts.model.WQCKms;
 import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.WW;
 import de.intevation.flys.artifacts.model.WstValueTable;
 import de.intevation.flys.artifacts.model.WstValueTableFactory;
 
-import de.intevation.flys.artifacts.states.DefaultState;
 import de.intevation.flys.artifacts.states.LocationDistanceSelect;
 
-import de.intevation.flys.geom.Lines;
-
+import de.intevation.flys.model.DischargeTable;
+import de.intevation.flys.model.FastCrossSectionLine;
 import de.intevation.flys.model.Gauge;
 import de.intevation.flys.model.River;
-import de.intevation.flys.model.CrossSection;
-import de.intevation.flys.model.CrossSectionLine;
 
 import de.intevation.flys.utils.DoubleUtil;
 import de.intevation.flys.utils.FLYSUtils;
 
 import gnu.trove.TDoubleArrayList;
 
-import java.util.ArrayList;
+import java.awt.geom.Point2D;
+
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.Collections;
-import java.util.LinkedList;
+import java.util.GregorianCalendar;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.log4j.Logger;
 
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import de.intevation.flys.artifacts.model.CalculationMessage;
 
 /**
  * The default WINFO artifact.
@@ -93,6 +78,33 @@
     /** The default step width between the start end end kilometer. */
     public static final double DEFAULT_KM_STEPS = 0.1;
 
+    private static final String [] INACTIVES = new String[] {
+        LONGITUDINAL_Q,
+        DURATION_Q
+    };
+
+    static {
+        // TODO: Move to configuration.
+        FacetActivity.Registry.getInstance().register(
+            ARTIFACT_NAME,
+            new FacetActivity() {
+                @Override
+                public Boolean isInitialActive(
+                    Artifact artifact,
+                    Facet    facet,
+                    String   outputName
+                ) {
+                    String fname = facet.getName();
+                    if ((fname.equals(COMPUTED_DISCHARGE_MAINVALUES_Q)
+                    ||   fname.equals(COMPUTED_DISCHARGE_MAINVALUES_W))
+                    && outputName.equals("computed_discharge_curve")) {
+                        return Boolean.FALSE;
+                    }
+                    return !StringUtils.contains(fname, INACTIVES);
+
+                }
+            });
+    }
 
     /**
      * The default constructor.
@@ -101,236 +113,42 @@
     }
 
 
-    /**
-     * This method returns a description of this artifact.
-     *
-     * @param data Some data.
-     * @param context The CallContext.
-     *
-     * @return the description of this artifact.
-     */
-    public Document describe(Document data, CallContext context) {
-        logger.debug("Describe: the current state is: " + getCurrentStateId());
-
-        if (logger.isDebugEnabled()) {
-            dumpArtifact();
-        }
-
-        FLYSContext flysContext = FLYSUtils.getFlysContext(context);
-
-        StateEngine stateEngine = (StateEngine) flysContext.get(
-            FLYSContext.STATE_ENGINE_KEY);
-
-        TransitionEngine transitionEngine = (TransitionEngine) flysContext.get(
-            FLYSContext.TRANSITION_ENGINE_KEY);
-
-        List<State> reachable = transitionEngine.getReachableStates(
-            this, getCurrentState(context), stateEngine);
-
-        Document description            = XMLUtils.newDocument();
-        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
-            description,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element root = ProtocolUtils.createRootNode(creator);
-        description.appendChild(root);
-
-        State current = getCurrentState(context);
-
-        ProtocolUtils.appendDescribeHeader(creator, root, identifier(), hash());
-        ProtocolUtils.appendState(creator, root, current);
-        ProtocolUtils.appendReachableStates(creator, root, reachable);
-
-        appendBackgroundActivity(creator, root, context);
-
-        Element name = ProtocolUtils.createArtNode(
-            creator, "name",
-            new String[] { "value" },
-            new String[] { getName() });
-
-        Element ui = ProtocolUtils.createArtNode(
-            creator, "ui", null, null);
-
-        Element staticUI  = ProtocolUtils.createArtNode(
-            creator, "static", null, null);
-
-        Element outs = ProtocolUtils.createArtNode(
-            creator, "outputmodes", null, null);
-        appendOutputModes(description, outs, context, identifier());
-
-        appendStaticUI(description, staticUI, context, identifier());
-
-        Element dynamic = current.describe(
-            this,
-            description,
-            root,
-            context,
-            identifier());
-
-        if (dynamic != null) {
-            ui.appendChild(dynamic);
-        }
-
-        ui.appendChild(staticUI);
-
-        root.appendChild(name);
-        root.appendChild(ui);
-        root.appendChild(outs);
-
-        return description;
-    }
-
 
     /**
      * Returns the name of the concrete artifact.
      *
      * @return the name of the concrete artifact.
      */
+    @Override
     public String getName() {
         return ARTIFACT_NAME;
     }
 
-
-    protected static void appendBackgroundActivity(
-        ElementCreator cr,
-        Element        root,
-        CallContext    context
+    protected static boolean reportGeneratedWs(
+        Calculation report,
+        double []   ws
     ) {
-        Element inBackground = cr.create("background-processing");
-        root.appendChild(inBackground);
-
-        cr.addAttr(
-            inBackground,
-            "value",
-            String.valueOf(context.isInBackground()),
-            true);
-
-        LinkedList<Message> messages = context.getBackgroundMessages();
-
-        if (messages == null) {
-            return;
+        if (ws == null || ws.length < 2) {
+            return false;
         }
 
-        CalculationMessage  message  = (CalculationMessage) messages.getLast();
-        cr.addAttr(
-            inBackground,
-            "steps",
-            String.valueOf(message.getSteps()),
-            true);
-
-        cr.addAttr(
-            inBackground,
-            "currentStep",
-            String.valueOf(message.getCurrentStep()),
-            true);
-
-        inBackground.setTextContent(message.getMessage());
-    }
-
-
-    /**
-     * Append output mode nodes to a document.
-     */
-    protected void appendOutputModes(
-        Document    doc,
-        Element     outs,
-        CallContext context,
-        String      uuid)
-    {
-        List<String> stateIds = getPreviousStateIds();
+        double  lastW = ws[0];
+        boolean alreadyReported = false;
 
-        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        FLYSContext flysContext = FLYSUtils.getFlysContext(context);
-        StateEngine engine      = (StateEngine) flysContext.get(
-            FLYSContext.STATE_ENGINE_KEY);
-
-        for (String stateId: stateIds) {
-            logger.debug("Append output modes for state: " + stateId);
-            DefaultState state = (DefaultState) engine.getState(stateId);
-
-            List<Output> list = state.getOutputs();
-            if (list == null || list.size() == 0) {
-                logger.debug("-> No output modes for this state.");
-                continue;
+        for (int i = 1; i < ws.length; ++i) {
+            if (Math.abs(lastW - ws[i]) < 1e-5) {
+                if (!alreadyReported) {
+                    alreadyReported = true;
+                    report.addProblem("more.than.one.q.for.w", ws[i]);
+                }
             }
-
-            List<Facet> fs = facets.get(stateId);
-
-            if (fs == null || fs.size() == 0) {
-                logger.debug("No facets for previous state found.");
-                continue;
+            else {
+                alreadyReported = false;
             }
-
-            logger.debug("Found " + fs.size() + " facets in previous states.");
-
-            List<Output> generated = generateOutputs(list, fs);
-
-            ProtocolUtils.appendOutputModes(doc, outs, generated);
+            lastW = ws[i];
         }
 
-        try {
-            DefaultState cur = (DefaultState) getCurrentState(context);
-            if (cur.validate(this)) {
-                List<Output> list = cur.getOutputs();
-                if (list != null && list.size() > 0) {
-                    logger.debug(
-                        "Append output modes for current state: " + cur.getID());
-
-                    List<Facet> fs = facets.get(cur.getID());
-
-                    if (fs != null && fs.size() > 0) {
-                        List<Output> generated = generateOutputs(list, fs);
-
-                        logger.debug("Found " + fs.size() + " current facets.");
-                        if (!generated.isEmpty()) {
-                            ProtocolUtils.appendOutputModes(
-                                doc, outs, generated);
-                        }
-                    }
-                    else {
-                        logger.debug("No facets found for the current state.");
-                    }
-                }
-            }
-        }
-        catch (IllegalArgumentException iae) {
-            // state is not valid, so we do not append its outputs.
-        }
-    }
-
-
-    /**
-     * This method appends the static data - that has already been inserted by
-     * the user - to the static node of the DESCRIBE document.
-     *
-     * @param doc The document.
-     * @param ui The root node.
-     * @param context The CallContext.
-     * @param uuid The identifier of the artifact.
-     */
-    protected void appendStaticUI(
-        Document    doc,
-        Node        ui,
-        CallContext context,
-        String uuid)
-    {
-        List<String> stateIds = getPreviousStateIds();
-
-        FLYSContext flysContext = FLYSUtils.getFlysContext(context);
-        StateEngine engine      = (StateEngine) flysContext.get(
-            FLYSContext.STATE_ENGINE_KEY);
-
-        for (String stateId: stateIds) {
-            logger.debug("Append static data for state: " + stateId);
-            DefaultState state = (DefaultState) engine.getState(stateId);
-
-            ui.appendChild(state.describeStatic(this, doc, ui, context, uuid));
-        }
+        return true;
     }
 
 
@@ -347,44 +165,57 @@
     {
         logger.debug("WINFOArtifact.getWaterlevelData");
 
+        if (getDataAsString("calculation_mode")
+            .equals("calc.discharge.longitudinal.section")
+        ) {
+            return getDischargeLongitudinalSectionData();
+        }
+
         River river = FLYSUtils.getRiver(this);
         if (river == null) {
-            return error(new WQKms[0], "No river selected.");
+            return error(new WQKms[0], "no.river.selected");
         }
 
         double[] kms = getKms();
         if (kms == null) {
-            return error(new WQKms[0], "No Kms selected.");
+            return error(new WQKms[0], "no.kms.selected");
         }
 
         double[] qs   = getQs();
         double[] ws   = null;
         boolean  qSel = true;
 
+        Calculation report = new Calculation();
+
         if (qs == null) {
             logger.debug("Determine Q values based on a set of W values.");
             qSel = false;
             ws   = getWs();
-            qs   = getQsForWs(ws);
-            if (qs == null) {
-                return error(new WQKms[0], "conversion ws to qs failed.");
+            double [][] qws = getQsForWs(ws);
+            if (qws == null || qws.length == 0) {
+                return error(new WQKms[0], "converting.ws.to.qs.failed");
+            }
+            qs = qws[0];
+
+            if (reportGeneratedWs(report, qws[1])) {
+                ws = qws[1];
             }
         }
 
         WstValueTable wst = WstValueTableFactory.getTable(river);
         if (wst == null) {
-            return error(new WQKms[0], "No Wst found for selected river.");
+            return error(new WQKms[0], "no.wst.for.selected.river");
         }
 
 
         double [] range = FLYSUtils.getKmRange(this);
         if (range == null) {
-            return error(new WQKms[0], "No range found");
+            return error(new WQKms[0], "no.range.found");
         }
 
         double refKm;
 
-        if (isFreeQ()) {
+        if (isFreeQ() || isFreeW()) {
             refKm = range[0];
             logger.debug("'free' calculation (km " + refKm + ")");
         }
@@ -392,7 +223,7 @@
             Gauge gauge = river.determineGaugeByPosition(range[0]);
             if (gauge == null) {
                 return error(
-                    new WQKms[0], "No gauge found for km " + range[0]);
+                    new WQKms[0], "no.gauge.found.for.km");
             }
 
             refKm = gauge.getStation().doubleValue();
@@ -401,7 +232,7 @@
                 "reference gauge: " + gauge.getName() + " (km " + refKm + ")");
         }
 
-        return computeWaterlevelData(kms, qs, ws, wst, refKm);
+        return computeWaterlevelData(kms, qs, ws, wst, refKm, report);
     }
 
 
@@ -410,7 +241,7 @@
      * in WstValueTable.
      *
      * @param kms The kilometer values.
-     * @param qa The discharge values.
+     * @param qs The discharge values.
      * @param wst The WstValueTable used for the interpolation.
      *
      * @return an array of data triples that consist of W, Q and Kms.
@@ -420,12 +251,17 @@
         double []     qs,
         double []     ws,
         WstValueTable wst,
-        double        refKm
+        double        refKm,
+        Calculation   report
     ) {
         logger.info("WINFOArtifact.computeWaterlevelData");
 
         Calculation1 calc1 = new Calculation1(kms, qs, ws, refKm);
 
+        if (report != null) {
+            calc1.addProblems(report);
+        }
+
         return calc1.calculate(wst);
     }
 
@@ -441,24 +277,24 @@
         River r = FLYSUtils.getRiver(this);
 
         if (r == null) {
-            return error(null, "Cannot determine river.");
+            return error(null, "no.river.selected");
         }
 
         Gauge g = getGauge();
 
         if (g == null) {
-           return error(null, "Cannot determine gauge.");
+           return error(null, "no.gauge.selected");
         }
 
         double[] locations = FLYSUtils.getLocations(this);
 
         if (locations == null) {
-            return error(null, "Cannot determine location.");
+            return error(null, "no.locations.selected");
         }
 
         WstValueTable wst = WstValueTableFactory.getTable(r);
         if (wst == null) {
-            return error(null, "No Wst found for selected river.");
+            return error(null, "no.wst.for.river");
         }
 
         return computeDurationCurveData(g, wst, locations[0]);
@@ -480,7 +316,7 @@
     {
         logger.info("WINFOArtifact.computeDurationCurveData");
 
-        Object[] obj = MainValuesFactory.getDurationCurveData(gauge);
+        Object[] obj = gauge.fetchDurationCurveData();
 
         int[]    days = (int[]) obj[0];
         double[] qs   = (double[]) obj[1];
@@ -492,58 +328,6 @@
 
 
     /**
-     * Returns the data that is used to create discharge curves.
-     *
-     */
-    public CalculationResult getDischargeCurveData() {
-
-        River river = FLYSUtils.getRiver(this);
-        if (river == null) {
-            return error(new WQKms[0], "no river found");
-        }
-
-        double [] distance = FLYSUtils.getKmRange(this);
-
-        if (distance == null) {
-            return error(new WQKms[0], "no range found");
-        }
-
-        List<Gauge> gauges = river.determineGauges(distance[0], distance[1]);
-
-        if (gauges.isEmpty()) {
-            return error(new WQKms[0], "no gauges found");
-        }
-
-        String [] names = new String[gauges.size()];
-
-        for (int i = 0; i < names.length; ++i) {
-            names[i] = gauges.get(i).getName();
-        }
-
-        DischargeTables dt = new DischargeTables(river.getName(), names);
-
-        Map<String, double [][]> map = dt.getValues(100d);
-
-        ArrayList<WQKms> res = new ArrayList<WQKms>();
-
-        for (Gauge gauge: gauges) {
-            String name = gauge.getName();
-            double [][] values = map.get(name);
-            if (values == null) {
-                continue;
-            }
-            double [] kms = new double[values[0].length];
-            Arrays.fill(kms, gauge.getStation().doubleValue());
-            res.add(new WQKms(kms, values[0], values[1], name));
-        }
-
-        return new CalculationResult(
-            res.toArray(new WQKms[res.size()]),
-            new Calculation());
-    }
-
-
-    /**
      * Returns the data that is computed by a discharge curve computation.
      *
      * @return the data computed by a discharge curve computation.
@@ -556,18 +340,18 @@
         River r = FLYSUtils.getRiver(this);
 
         if (r == null) {
-            return error(new WQKms[0], "Cannot determine river.");
+            return error(new WQKms[0], "no.river.selected");
         }
 
         double[] locations = FLYSUtils.getLocations(this);
 
         if (locations == null) {
-            return error(new WQKms[0], "Cannot determine location.");
+            return error(new WQKms[0], "no.locations.selected");
         }
 
         WstValueTable wst = WstValueTableFactory.getTable(r);
         if (wst == null) {
-            return error(new WQKms[0], "No Wst found for selected river.");
+            return error(new WQKms[0], "no.wst.for.river");
         }
 
         return computeDischargeCurveData(wst, locations[0]);
@@ -577,7 +361,8 @@
     /**
      * Computes the data used to create computed discharge curves.
      *
-     * @param wst The WstValueTable that is used for the interpolation.
+     * @param wst The WstValueTable that is used for the interpolation (river-
+     *            bound).
      * @param location The location where the computation should be based on.
      *
      * @return an object that contains tuples of W/Q values at the specified
@@ -594,6 +379,8 @@
         return calculation.calculate(wst);
     }
 
+
+    /** Create CalculationResult with data and message. */
     protected static final CalculationResult error(Object data, String msg) {
         return new CalculationResult(data, new Calculation(msg));
     }
@@ -612,27 +399,27 @@
         River river = FLYSUtils.getRiver(this);
         if (river == null) {
             logger.debug("No river selected.");
-            return error(new WQKms[0], "No river selected.");
+            return error(new WQKms[0], "no.river.selected");
         }
 
         WstValueTable table = WstValueTableFactory.getTable(river);
         if (table == null) {
             logger.debug("No wst found for selected river.");
-            return error(new WQKms[0], "No wst found for selected river.");
+            return error(new WQKms[0], "no.wst.for.river");
         }
 
         List<Segment> segments = getSegments();
 
         if (segments == null) {
             logger.debug("Cannot create segments.");
-            return error(new WQKms[0], "Cannot create segments.");
+            return error(new WQKms[0], "cannot.create.segments");
         }
 
         double [] range = getFromToStep();
 
         if (range == null) {
             logger.debug("Cannot figure out range.");
-            return error(new WQKms[0], "Cannot figure out range.");
+            return error(new WQKms[0], "no.range.found");
         }
 
         Calculation4 calc4 = new Calculation4(segments, river, isQ());
@@ -641,46 +428,205 @@
     }
 
 
+    /**
+     * Returns the data that is computed by a reference curve computation.
+     *
+     * @return the data computed by a reference curve computation.
+     */
+    public CalculationResult getReferenceCurveData(CallContext context) {
+
+        Double startKm = getReferenceStartKm();
+
+        if (startKm == null) {
+            return error(new WW[0], "no.reference.start.km");
+        }
+
+        double [] endKms = getReferenceEndKms();
+
+        if (endKms == null || endKms.length == 0) {
+            return error(new WW[0], "no.reference.end.kms");
+        }
+
+        Calculation5 calc5 = new Calculation5(startKm, endKms);
+
+        River r = FLYSUtils.getRiver(this);
+        if (r == null) {
+            return error(new WW[0], "no.river.found");
+        }
+
+        WstValueTable wst = WstValueTableFactory.getTable(r);
+        if (wst == null) {
+            return error(new WW[0], "no.wst.for.river");
+        }
+
+        Map<Double, Double> kms2gaugeDatums = r.queryGaugeDatumsKMs();
+
+        return calc5.calculate(wst, kms2gaugeDatums, context);
+    }
+
+
+    /** Get reference (start) km. */
+    public Double getReferenceStartKm() {
+        StateData sd = getData("reference_startpoint");
+
+        if (sd == null) {
+            logger.warn("no reference start given.");
+            return null;
+        }
+
+        logger.debug("Reference start km given: " + sd.getValue());
+
+        String input = (String) sd.getValue();
+
+        if (input == null || (input = input.trim()).length() == 0) {
+            logger.warn("reference start string is empty.");
+            return null;
+        }
+
+        try {
+            return Double.valueOf(input);
+        }
+        catch (NumberFormatException nfe) {
+            logger.warn("reference start string is not numeric.");
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Get end kms for reference curve (null if none).
+     */
+    public double [] getReferenceEndKms() {
+        StateData sd = getData("reference_endpoint");
+
+        if (sd == null) {
+            logger.warn("no reference end given.");
+            return null;
+        }
+        else {
+            logger.debug("Reference end km : " + sd.getValue());
+        }
+
+        String input = (String) sd.getValue();
+
+        if (input == null || (input = input.trim()).length() == 0) {
+            logger.warn("reference end string is empty.");
+            return null;
+        }
+
+        TDoubleArrayList endKms = new TDoubleArrayList();
+
+        for (String part: input.split("\\s+")) {
+            try {
+                double km = Double.parseDouble(part);
+                if (!endKms.contains(km)) {
+                    endKms.add(km);
+                }
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("reference end string is not numeric.");
+            }
+        }
+
+        return endKms.toNativeArray();
+    }
+
+
+    public CalculationResult getHistoricalDischargeData() {
+        Gauge  gauge        = FLYSUtils.getReferenceGauge(this);
+        String rawTimerange = getDataAsString("year_range");
+        String rawValues    = getDataAsString("historical_values");
+        int    mode         = getDataAsInteger("historical_mode");
+
+        long[]   timerange = FLYSUtils.longArrayFromString(rawTimerange);
+        double[] values    = FLYSUtils.doubleArrayFromString(rawValues);
+
+        Calendar start = new GregorianCalendar();
+        start.setTimeInMillis(timerange[0]);
+        Calendar end   = new GregorianCalendar();
+        end.setTimeInMillis(timerange[1]);
+
+        Calculation6 calc = new Calculation6(
+            mode,
+            new long[] { start.getTimeInMillis(), end.getTimeInMillis() },
+            values);
+
+        return calc.calculate(gauge);
+    }
+
+
     public List<Segment> getSegments() {
         StateData wqValues = getData("wq_values");
         if (wqValues == null) {
             logger.warn("no wq_values given");
-            return Collections.emptyList();
+            return Collections.<Segment>emptyList();
         }
-        String input = (String)wqValues.getValue();
+        String input = (String) wqValues.getValue();
         if (input == null || (input = input.trim()).length() == 0) {
             logger.warn("wq_values are empty");
-            return Collections.emptyList();
+            return Collections.<Segment>emptyList();
         }
         return Segment.parseSegments(input);
     }
 
 
     /**
-     * Get List of all cross-sections for current river.
-     *
-     * @return List of CrossSections for current river, null in case of error.
+     * Get corrected waterline against surface/profile.
      */
-    protected List<CrossSection> getCrossSections() {
-        River river = FLYSUtils.getRiver(this);
-        if (river == null) {
-            logger.warn("No river in WINFO found");
-            return null;
+    public Lines.LineData waterLineC(int idx, FastCrossSectionLine csl) {
+        List<Point2D> points = csl.getPoints();
+
+        WQKms[] wqckms = (WQKms[])
+            getDischargeLongitudinalSectionData().getData();
+
+        // Find index of km.
+        double wishKM = csl.getKm();
+
+        // Find W/C at km, linear naive approach.
+        WQCKms triple = (WQCKms) wqckms[idx-1];
+
+        int old_idx = 0;
+
+        if (triple.size() == 0) {
+            logger.warn("Calculation of c/waterline is empty.");
+            return Lines.createWaterLines(points, 0.0f);
         }
-        return CrossSectionFactory.getCrossSections(river);
+
+        // Linear seach in WQKms for closest km.
+        double old_dist_wish = Math.abs(wishKM - triple.getKm(0));
+        double last_c = triple.getC(0);
+
+        for (int i = 0, T = triple.size(); i < T; i++) {
+            double diff = Math.abs(wishKM - triple.getKm(i));
+            if (diff > old_dist_wish) {
+                break;
+            }
+            last_c = triple.getC(i);
+            old_dist_wish = diff;
+        }
+
+        return Lines.createWaterLines(points, last_c);
     }
 
 
     /**
      * Get points of line describing the surface of water at cross section.
      *
+     * @param idx Index for getWaterlevelData.
+     * @param csl The profile/surface to fill with water.
+     * @param nextIgnored Ignored in this implementation of WaterLineArtifact.
+     * @param prevIgnored Ignored in this implementation of WaterLineArtifact.
+     *
      * @return an array holding coordinates of points of surface of water (
      *         in the form {{x1, x2} {y1, y2}} ).
      */
-    public double [][] getWaterLines(int idx, CrossSectionLine csl) {
+    @Override
+    public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl,
+        double nextIgnored, double prevIgnored) {
         logger.debug("getWaterLines(" + idx + ")");
 
-        List<Point2D> points = csl.fetchCrossSectionLinesPoints();
+        List<Point2D> points = csl.getPoints();
 
         // Need W at km
         WQKms [] wqkms = (WQKms[]) getWaterlevelData().getData();
@@ -689,28 +635,40 @@
             return Lines.createWaterLines(points, 0.0f);
         }
 
-        if (wqkms.length < idx) {
+        if (wqkms.length <= idx) {
             logger.error("getWaterLines() requested index ("
                          + idx + " not found.");
+            return waterLineC(idx, csl);
         }
 
+        // Find index of km.
+        double wishKM = csl.getKm();
+
         // Find W at km, linear naive approach.
         WQKms triple = wqkms[idx];
 
-        // Find index of km.
-        double wishKM = csl.getKm().doubleValue();
-        int old_idx = 0;
-
         if (triple.size() == 0) {
             logger.warn("Calculation of waterline is empty.");
             return Lines.createWaterLines(points, 0.0f);
         }
 
+        // Early abort if we would need to extrapolate.
+        int T = triple.size();
+        double max_km = triple.getKm(T-1), min_km = triple.getKm(0);
+        if (wishKM < min_km || wishKM > max_km) {
+            // TODO Does this have to be done in the other WaterlineArtifact
+            //      implementations, too?
+            logger.warn("Will not extrapolate waterlevels.");
+            return Lines.createWaterLines(points, 0.0f);
+        }
+
+        int old_idx = 0;
+
         // Linear seach in WQKms for closest km.
         double old_dist_wish = Math.abs(wishKM - triple.getKm(0));
         double last_w = triple.getW(0);
 
-        for (int i = 0, T = triple.size(); i < T; i++) {
+        for (int i = 0; i < T; i++) {
             double diff = Math.abs(wishKM - triple.getKm(i));
             if (diff > old_dist_wish) {
                 break;
@@ -718,23 +676,8 @@
             last_w = triple.getW(i);
             old_dist_wish = diff;
         }
-        return Lines.createWaterLines(points, last_w);
-    }
-
 
-    /**
-     * Get name of cross sections.
-     * @return list of names of cross-sections.
-     */
-    public List<String> getCrossSectionNames() {
-        logger.debug("getCrossSectionNames");
-        List<String> names = new ArrayList<String>();
-
-        for (CrossSection section: getCrossSections()) {
-            names.add(section.getDescription());
-        }
-
-        return names;
+        return Lines.createWaterLines(points, last_w);
     }
 
 
@@ -746,7 +689,12 @@
      *
      * @return an array of Q values.
      */
-    public double[] getQsForWs(double[] ws) {
+    public double [][] getQsForWs(double[] ws) {
+
+        if (ws == null) {
+            logger.error("getQsForWs: ws == null");
+            return null;
+        }
 
         boolean debug = logger.isDebugEnabled();
 
@@ -766,6 +714,45 @@
             return null;
         }
 
+        if (isFreeW()) {
+            logger.debug("Bezugslinienverfahren I: W auf freier Strecke");
+            // The simple case of the "Bezugslinienverfahren"
+            // "W auf freier Strecke".
+            WstValueTable wst = WstValueTableFactory.getTable(r);
+            if (wst == null) {
+                logger.warn("no wst value table found");
+                return null;
+            }
+            double km = range[0];
+
+            TDoubleArrayList outQs = new TDoubleArrayList(ws.length);
+            TDoubleArrayList outWs = new TDoubleArrayList(ws.length);
+
+            boolean generatedWs = false;
+
+            for (int i = 0; i < ws.length; ++i) {
+                double w = ws[i];
+                if (debug) {
+                    logger.debug("getQsForWs: lookup Q for W: " + w);
+                }
+                // There could bemore than one Q per W.
+                double [] qs = wst.findQsForW(km, w);
+                for (int j = 0; j < qs.length; ++j) {
+                    outWs.add(ws[i]);
+                    outQs.add(qs[j]);
+                }
+                generatedWs |= qs.length != 1;
+            }
+
+            if (debug) {
+                logger.debug("getQsForWs: number of Qs: " + outQs.size());
+            }
+
+            return new double [][] {
+                outQs.toNativeArray(),
+                generatedWs ? outWs.toNativeArray() : null };
+        }
+
         if (debug) {
             logger.debug("range: " + Arrays.toString(range));
         }
@@ -780,20 +767,45 @@
             logger.debug("convert w->q with gauge '" + g.getName() + "'");
         }
 
-        DischargeTables dt = new DischargeTables(r.getName(), g.getName());
-        Map<String, double [][]>  tmp = dt.getValues();
+        DischargeTable dt = g.fetchMasterDischargeTable();
 
-        double[][] values = tmp.get(g.getName());
-        double[]   qs     = new double[ws.length];
+        if (dt == null) {
+            logger.warn("No master discharge table found for gauge '"
+                + g.getName() + "'");
+            return null;
+        }
+
+        double [][] values = DischargeTables.loadDischargeTableValues(dt, 1);
+
+        TDoubleArrayList wsOut = new TDoubleArrayList(ws.length);
+        TDoubleArrayList qsOut = new TDoubleArrayList(ws.length);
+
+        boolean generatedWs = false;
 
         for (int i = 0; i < ws.length; i++) {
-            qs[i] = dt.getQForW(values, ws[i]);
-            if (debug) {
-                logger.debug("w: " + ws[i] + " -> q: " + qs[i]);
+            if (Double.isNaN(ws[i])) {
+                logger.warn("W is NaN: ignored");
+                continue;
             }
+            double w = ws[i] / 100d;
+            double [] qs = DischargeTables.getQsForW(values, w);
+
+            if (qs.length == 0) {
+                logger.warn("No Qs found for W = " + ws[i]);
+            }
+            else {
+                for (double q: qs) {
+                    wsOut.add(ws[i]);
+                    qsOut.add(q * 100d);
+                }
+            }
+            generatedWs |= qs.length != 1;
         }
 
-        return qs;
+        return new double [][] {
+            qsOut.toNativeArray(),
+            generatedWs ? wsOut.toNativeArray() : null
+        };
     }
 
 
@@ -918,25 +930,6 @@
     }
 
 
-    /**
-     * Returns the gauges that match the selected kilometer range.
-     *
-     * @return the gauges based on the selected kilometer range.
-     */
-    public List<Gauge> getGauges() {
-
-        River river = FLYSUtils.getRiver(this);
-        if (river == null) {
-            return null;
-        }
-
-        double [] dist = FLYSUtils.getKmRange(this);
-        if (dist == null) {
-            return null;
-        }
-
-        return river.determineGauges(dist[0], dist[1]);
-    }
 
 
     /**
@@ -945,14 +938,15 @@
      * @return the selected Q values or null, if no Q values are selected.
      */
     public double[] getQs() {
-        StateData dMode      = getData("wq_mode");
-        StateData dSelection = getData("wq_selection");
+        StateData dMode      = getData("wq_isq");
+        StateData dSelection = getData("wq_isrange");
 
-        String mode = dMode != null ? (String) dMode.getValue() : "";
-        String sel  = dSelection != null ? (String)dSelection.getValue() : null;
+        boolean isRange = dSelection != null
+            ? Boolean.valueOf((String)dSelection.getValue())
+            : false;
 
-        if (mode.equals("Q")) {
-            if (sel != null && sel.equals("single")) {
+        if (isQ()) {
+            if (!isRange) {
                 return getSingleWQValues();
             }
             else {
@@ -967,8 +961,25 @@
 
 
     public boolean isQ() {
-        StateData mode = getData("wq_mode");
-        return mode != null && mode.getValue().equals("Q");
+        StateData mode = getData("wq_isq");
+        String value = (mode != null) ? (String) mode.getValue() : null;
+        return value != null ? Boolean.valueOf(value) : false;
+    }
+
+    public boolean isW() {
+        StateData mode = getData("wq_isq");
+        String value = (mode != null) ? (String) mode.getValue() : null;
+        return value != null ? !Boolean.valueOf(value) : false;
+    }
+
+    public boolean isFreeW() {
+        if(!isW()) {
+            return false;
+        }
+        StateData mode = getData("wq_isfree");
+        String value =  (mode != null) ? (String) mode.getValue() : null;
+
+        return value != null ? Boolean.valueOf(value) : false;
     }
 
 
@@ -981,16 +992,15 @@
      * false and the calculation is bound to a gauge.
      */
     public boolean isFreeQ() {
-        StateData mode  = getData("wq_free");
+        if(!isQ()) {
+            return false;
+        }
+        StateData mode  = getData("wq_isfree");
         String    value = (mode != null) ? (String) mode.getValue() : null;
 
         logger.debug("isFreeQ: " + value);
 
-        if (value == null) {
-            return false;
-        }
-
-        return Boolean.valueOf(value);
+        return value != null && Boolean.valueOf(value);
     }
 
 
@@ -1002,12 +1012,9 @@
      * @return an array of Q values.
      */
     public double[] getQs(double[] range) {
-        StateData dMode   = getData("wq_mode");
-        StateData dValues = getData("wq_values");
+        StateData dMode   = getData("wq_isq");
 
-        String mode = (dMode != null) ? (String) dMode.getValue() : "";
-
-        if (mode.equals("Q")) {
+        if (isQ()) {
             return getWQForDist(range);
         }
 
@@ -1024,12 +1031,7 @@
      * @return an array of W values.
      */
     public double[] getWs(double[] range) {
-        StateData dMode   = getData("wq_mode");
-        StateData dValues = getData("wq_values");
-
-        String mode = (dMode != null) ? (String) dMode.getValue() : "";
-
-        if (mode.equals("W")) {
+        if (isW()) {
             return getWQForDist(range);
         }
 
@@ -1044,12 +1046,9 @@
      * @return the selected W values or null, if no W values are selected.
      */
     public double[] getWs() {
-        StateData dMode   = getData("wq_mode");
         StateData dSingle = getData("wq_single");
 
-        String mode = (dMode != null) ? (String) dMode.getValue() : "";
-
-        if (mode.equals("W")) {
+        if (isW()) {
             if (dSingle != null) {
                 return getSingleWQValues();
             }
@@ -1058,7 +1057,7 @@
             }
         }
         else {
-            logger.warn("You try to get Qs, but W has been inserted.");
+            logger.warn("You try to get Ws, but Q has been inserted.");
             return null;
         }
     }
@@ -1185,37 +1184,12 @@
         return values.toNativeArray();
     }
 
-
     /**
-     * Determines Facets initial disposition regarding activity (think of
-     * selection in Client ThemeList GUI). This will be checked one time
-     * when the facet enters a collections describe document.
-     *
-     * @param facetName name of the facet.
-     * @param index     index of the facet.
-     * @return 0 if not active
+     * Returns the WstValueTable of current river.
      */
-    @Override
-    public int getInitialFacetActivity(String outputName, String facetName, int index) {
-        String [] inactives = new String[] {
-                                            LONGITUDINAL_Q,
-                                            DURATION_Q
-                                           };
-
-        logger.debug("WINFOArtifact.active?: "
-            + outputName
-            + "/"
-            + facetName);
-
-        if (facetName.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) ||
-             facetName.equals(COMPUTED_DISCHARGE_MAINVALUES_W)
-             && outputName.equals("computed_discharge_curve"))
-            {
-                return 0;
-            }
-        return Arrays.asList(inactives).contains(facetName)
-               ? 0
-               : 1;
+    public WstValueTable getWstValueTable() {
+        River r = FLYSUtils.getRiver(this);
+        return WstValueTableFactory.getTable(r);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSBuildingsArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,8 +20,8 @@
 
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
 
 
 public class WMSBuildingsArtifact extends WMSDBArtifact {
@@ -84,35 +84,12 @@
             riverId = 0;
         }
 
-        public int getRiverId() {
-            if (riverId == 0) {
-                String ids = artifact.getDataAsString("ids");
-
-                try {
-                    riverId = Integer.valueOf(ids);
-                }
-                catch (NumberFormatException nfe) {
-                    logger.error("Cannot parse river id from '" + ids + "'");
-                }
-            }
-
-            return riverId;
-        }
-
         @Override
         protected String getFacetType() {
             return FLOODMAP_BUILDINGS;
         }
 
         @Override
-        protected String getTitle(CallMeta meta) {
-            return Resources.getMsg(
-                meta,
-                FLOODMAP_BUILDINGS,
-                FLOODMAP_BUILDINGS);
-        }
-
-        @Override
         protected String getUrl() {
             return FLYSUtils.getUserWMSUrl(artifact.identifier());
         }
@@ -124,8 +101,9 @@
         }
 
         @Override
-        protected Envelope getExtent() {
-            List<Building> buildings = Building.getBuildings(getRiverId());
+        protected Envelope getExtent(boolean reproject) {
+            List<Building> buildings =
+                Building.getBuildings(getRiverId(), getName());
 
             Envelope max = null;
 
@@ -140,12 +118,15 @@
                 max.expandToInclude(env);
             }
 
-            return max;
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
         }
 
         @Override
         protected String getFilter() {
-            return "river_id=" + String.valueOf(getRiverId());
+            return "river_id=" + String.valueOf(getRiverId()) +
+                " AND name='" + getName() + "'";
         }
 
         @Override
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSCatchmentArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,8 +20,8 @@
 
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
 
 
 public class WMSCatchmentArtifact extends WMSDBArtifact {
@@ -86,10 +86,11 @@
 
         public int getRiverId() {
             if (riverId == 0) {
-                String ids = artifact.getDataAsString("ids");
+                String   ids   = artifact.getDataAsString("ids");
+                String[] parts = ids.split(";");
 
                 try {
-                    riverId = Integer.valueOf(ids);
+                    riverId = Integer.parseInt(parts[0]);
                 }
                 catch (NumberFormatException nfe) {
                     logger.error("Cannot parse river id from '" + ids + "'");
@@ -105,14 +106,6 @@
         }
 
         @Override
-        protected String getTitle(CallMeta meta) {
-            return Resources.getMsg(
-                meta,
-                FLOODMAP_CATCHMENT,
-                FLOODMAP_CATCHMENT);
-        }
-
-        @Override
         protected String getUrl() {
             return FLYSUtils.getUserWMSUrl(artifact.identifier());
         }
@@ -124,8 +117,9 @@
         }
 
         @Override
-        protected Envelope getExtent() {
-            List<Catchment> catchments = Catchment.getCatchments(getRiverId());
+        protected Envelope getExtent(boolean reproject) {
+            List<Catchment> catchments =
+                Catchment.getCatchments(getRiverId(), getName());
 
             Envelope max = null;
 
@@ -140,12 +134,15 @@
                 max.expandToInclude(env);
             }
 
-            return max;
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
         }
 
         @Override
         protected String getFilter() {
-            return "river_id=" + String.valueOf(getRiverId());
+            return "river_id=" + String.valueOf(getRiverId())
+                + " AND name='" + getName() + "'";
         }
 
         @Override
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSDBArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,7 @@
 package de.intevation.flys.artifacts;
 
+import java.io.File;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -18,29 +20,32 @@
 import de.intevation.artifacts.ArtifactFactory;
 import de.intevation.artifacts.CallMeta;
 
+import de.intevation.artifacts.common.utils.FileTools;
+
 import de.intevation.artifactdatabase.data.DefaultStateData;
 import de.intevation.artifactdatabase.state.Facet;
 import de.intevation.artifactdatabase.state.State;
 
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
 
 import de.intevation.flys.backend.SessionFactoryProvider;
 
+import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.artifacts.states.DefaultState;
-import de.intevation.flys.artifacts.model.WMSDBLayerFacet;
+import de.intevation.flys.artifacts.model.map.WMSDBLayerFacet;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.MapfileGenerator;
 
 
 public abstract class WMSDBArtifact extends StaticFLYSArtifact {
 
     private static final Logger logger = Logger.getLogger(WMSDBArtifact.class);
 
-    public static final String XPATH_IDS = "/art:action/art:ids/@value";
-
     public static final Pattern DB_URL_PATTERN =
         Pattern.compile("(.*)\\/\\/(.*):([0-9]+)\\/([a-zA-Z]+)");
 
+    public static final Pattern DB_PSQL_URL_PATTERN =
+        Pattern.compile("(.*)\\/\\/(.*):([0-9]+)\\/([a-zA-Z0-9]+)");
+
 
     @Override
     public void setup(
@@ -54,8 +59,7 @@
 
         super.setup(identifier, factory, context, callMeta, data);
 
-        String ids = XMLUtils.xpathString(
-            data, XPATH_IDS, ArtifactNamespaceContext.INSTANCE);
+        String ids = getDatacageIDValue(data);
 
         if (ids != null && ids.length() > 0) {
             addData("ids", new DefaultStateData("ids", null, null, ids));
@@ -85,6 +89,12 @@
     }
 
 
+    @Override
+    protected State getState(Object context, String stateID) {
+        return getCurrentState(context);
+    }
+
+
     /**
      * Get a list containing the one and only State.
      * @param  context ignored.
@@ -103,10 +113,18 @@
     public static abstract class WMSDBState extends DefaultState {
         private static final Logger logger = Logger.getLogger(WMSDBState.class);
 
-        protected WMSDBArtifact artifact;
+        protected FLYSArtifact artifact;
 
-        public WMSDBState(WMSDBArtifact artifact) {
+        protected String name;
+        protected int    riverId;
+
+
+        public WMSDBState() {}
+
+        public WMSDBState(FLYSArtifact artifact) {
             this.artifact = artifact;
+            this.name     = null;
+            this.riverId  = 0;
         }
 
         @Override
@@ -133,6 +151,7 @@
 
             facet.addLayer(name);
             facet.setExtent(getExtent());
+            facet.setOriginalExtent(getExtent(true));
             facet.setSrid(getSrid());
             facet.setData(getDataString());
             facet.setFilter(getFilter());
@@ -164,14 +183,16 @@
 
             Matcher m = DB_URL_PATTERN.matcher(url);
             if (!m.matches()) {
-                logger.warn("Could not parse Connection string.");
-                return null;
+                logger.warn("Could not parse Connection string." +
+                	"Try to parse PostgreSQL string.");
+                // maybe this is a PostgreSQL connection...
+                return getPostgreSQLConnection();
             }
 
             logger.debug("Groups for connection string: " + m.groupCount());
             int groups = m.groupCount();
 
-            for (int i = 0; i <= m.groupCount(); i++) {
+            for (int i = 0; i <= groups; i++) {
                 logger.debug("Group " + i + ": " + m.group(i));
             }
 
@@ -213,6 +234,55 @@
             return connection;
         }
 
+        protected String getPostgreSQLConnection() {
+            SessionFactoryImpl sf = (SessionFactoryImpl)
+                SessionFactoryProvider.getSessionFactory();
+
+            String user = SessionFactoryProvider.getUser(sf);
+            String pass = SessionFactoryProvider.getPass(sf);
+            String url  = SessionFactoryProvider.getURL(sf);
+
+            Matcher m = DB_PSQL_URL_PATTERN.matcher(url);
+            if (!m.matches()) {
+                logger.warn("Could not parse PostgreSQL Connection string.");
+                return null;
+            }
+
+            int groups = m.groupCount();
+            logger.debug("Groups for PostgreSQL connection string: " + groups);
+
+            if (logger.isDebugEnabled()) {
+                for (int i = 0; i <= groups; i++) {
+                    logger.debug("Group " + i + ": " + m.group(i));
+                }
+            }
+
+            String connection = null;
+
+            if (groups < 4) {
+                logger.warn("Could only partially parse connection string.");
+                return null;
+            }
+
+            String host = m.group(2);
+            String port = m.group(3);
+            String db   = m.group(4);
+
+            StringBuilder sb = new StringBuilder();
+            sb.append("dbname=" + db);
+            sb.append(" host='" + host + "'");
+            sb.append(" port=" + port);
+            sb.append(" user=" + user);
+            sb.append(" password='" + pass + "'");
+            sb.append(" sslmode=disable");
+
+            connection = sb.toString();
+
+            logger.debug("Created connection: '" + connection + "'");
+
+            return connection;
+        }
+
         protected String getConnectionType() {
             return FLYSUtils.isUsingOracle() ? "oraclespatial" : "postgis";
         }
@@ -221,15 +291,110 @@
             return null;
         }
 
+        public int getRiverId() {
+            if (riverId == 0) {
+                String   ids   = artifact.getDataAsString("ids");
+                String[] parts = ids.split(";");
+
+                try {
+                    riverId = Integer.parseInt(parts[0]);
+                }
+                catch (NumberFormatException nfe) {
+                    logger.error("Cannot parse river id from '" + parts[0] + "'");
+                }
+            }
+
+            return riverId;
+        }
+
+        /**
+         * Returns the name of the WMS layer. This method extracts the name
+         * from 'ids' data string. It is expected, that the 'ids' string is
+         * seperated by ';' and that the name is placed at index 1.
+         *
+         * @return the name of the WMS layer.
+         */
+        public String getName() {
+            if (name == null) {
+                String ids = artifact.getDataAsString("ids");
+
+                String parts[] = ids != null ? ids.split(";") : null;
+
+                if (parts != null && parts.length >= 2) {
+                    name = parts[1];
+                }
+            }
+
+            return name;
+        }
+
+
+        /**
+         * Returns the name of the layer (returned by getName()) or the layer
+         * type if the name is empty. The layer type is created by an i18n
+         * string of getFacetType().
+         *
+         * @param meta A CallMeta used for i18n.
+         *
+         * @return the name of the layer or its type if name is empty.
+         */
+        protected String getTitle(CallMeta meta) {
+            String name = getName();
+
+            return name != null && name.length() > 0
+                ? name
+                : Resources.getMsg(
+                    meta,
+                    getFacetType(),
+                    getFacetType());
+        }
+
+
+        @Override
+        public void endOfLife(Artifact owner, Object context) {
+            logger.info("Destroy WMSDBState: " + getID());
+
+            String p = FLYSUtils.getXPathString(FLYSUtils.XPATH_SHAPEFILE_DIR);
+            File dir = new File(p, owner.identifier());
+
+            if (dir != null && dir.exists()) {
+                logger.debug("Try to delete directory '" + dir + "'");
+
+                FileTools.deleteRecursive(dir);
+                MapfileGenerator.getInstance().update();
+            }
+        }
+
+        /**
+         * This method returns the extent of a DB layer in the projection of the
+         * database.
+         *
+         * @return the extent of the DB layer in the projection of the database.
+         */
+        protected Envelope getExtent() {
+            return getExtent(false);
+        }
+
+
         protected abstract String getFacetType();
 
-        protected abstract String getTitle(CallMeta meta);
-
         protected abstract String getUrl();
 
         protected abstract String getSrid();
 
-        protected abstract Envelope getExtent();
+        /**
+         * This method returns the extent of the DB layer. The projection of the
+         * extent depends on the <i>reproject</i> parameter. If reproject is set,
+         * the extent is reprojected into the original projection which is
+         * specified in the configuration. Otherwise, the projection of the
+         * database is used.
+         *
+         * @param reproject True, to reproject the extent into the projection
+         * specified in the configuration.
+         *
+         * @return the extent of the database layer.
+         */
+        protected abstract Envelope getExtent(boolean reproject);
 
         protected abstract String getFilter();
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSFixpointsArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,8 +20,8 @@
 
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
 
 
 public class WMSFixpointsArtifact extends WMSDBArtifact {
@@ -84,35 +84,12 @@
             riverId = 0;
         }
 
-        public int getRiverId() {
-            if (riverId == 0) {
-                String ids = artifact.getDataAsString("ids");
-
-                try {
-                    riverId = Integer.valueOf(ids);
-                }
-                catch (NumberFormatException nfe) {
-                    logger.error("Cannot parse river id from '" + ids + "'");
-                }
-            }
-
-            return riverId;
-        }
-
         @Override
         protected String getFacetType() {
             return FLOODMAP_FIXPOINTS;
         }
 
         @Override
-        protected String getTitle(CallMeta meta) {
-            return Resources.getMsg(
-                meta,
-                FLOODMAP_FIXPOINTS,
-                FLOODMAP_FIXPOINTS);
-        }
-
-        @Override
         protected String getUrl() {
             return FLYSUtils.getUserWMSUrl(artifact.identifier());
         }
@@ -124,7 +101,7 @@
         }
 
         @Override
-        protected Envelope getExtent() {
+        protected Envelope getExtent(boolean reproject) {
             List<Fixpoint> fixpoints = Fixpoint.getFixpoints(getRiverId());
 
             Envelope max = null;
@@ -140,7 +117,9 @@
                 max.expandToInclude(env);
             }
 
-            return max;
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSFloodmapsArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,150 @@
+package de.intevation.flys.artifacts;
+
+import java.util.List;
+
+import org.w3c.dom.Document;
+
+import org.apache.log4j.Logger;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifactdatabase.state.DefaultOutput;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.State;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.Floodmaps;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.RiverFactory;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
+
+
+public class WMSFloodmapsArtifact extends WMSDBArtifact {
+
+    public static final String NAME = "floodmaps";
+
+
+    private static final Logger logger =
+        Logger.getLogger(WMSFloodmapsArtifact.class);
+
+
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callMeta,
+        Document        data)
+    {
+        logger.debug("WMSFloodmapsArtifact.setup");
+
+        super.setup(identifier, factory, context, callMeta, data);
+    }
+
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+
+    @Override
+    public State getCurrentState(Object cc) {
+        State s = new FloodmapsState(this);
+
+        List<Facet> fs = facets.get(getCurrentStateId());
+
+        DefaultOutput o = new DefaultOutput(
+            "floodmap",
+            "floodmap",
+            "image/png",
+            fs,
+            "map");
+
+        s.getOutputs().add(o);
+
+        return s;
+    }
+
+
+    public static class FloodmapsState extends WMSDBState implements FacetTypes
+    {
+        private static final Logger logger =
+            Logger.getLogger(FloodmapsState.class);
+
+        protected int    riverId;
+
+        public FloodmapsState(WMSDBArtifact artifact) {
+            super(artifact);
+            riverId      = 0;
+        }
+
+        @Override
+        protected String getFacetType() {
+            return FLOODMAP_FLOODMAPS;
+        }
+
+        @Override
+        protected String getUrl() {
+            return FLYSUtils.getUserWMSUrl(artifact.identifier());
+        }
+
+        @Override
+        protected String getSrid() {
+            River river = RiverFactory.getRiver(getRiverId());
+            return FLYSUtils.getRiverSrid(river.getName());
+        }
+
+        @Override
+        protected Envelope getExtent(boolean reproject) {
+            List<Floodmaps> floodmaps =
+                Floodmaps.getFloodmaps(getRiverId(), getName());
+
+            Envelope max = null;
+
+            for (Floodmaps f: floodmaps) {
+                Envelope env = f.getGeom().getEnvelopeInternal();
+
+                if (max == null) {
+                    max = env;
+                    continue;
+                }
+
+                max.expandToInclude(env);
+            }
+
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
+        }
+
+        @Override
+        protected String getFilter() {
+            return "river_id=" + String.valueOf(getRiverId())
+                + " AND name='" + getName() + "'";
+        }
+
+        @Override
+        protected String getDataString() {
+            String srid = getSrid();
+
+            if (FLYSUtils.isUsingOracle()) {
+                return "geom FROM floodmaps USING SRID " + srid;
+            }
+            else {
+                return "geom FROM floodmaps USING UNIQUE id USING SRID " + srid;
+            }
+        }
+
+        @Override
+        protected String getGeometryType() {
+            return "POLYGON";
+        }
+    } // end of WMSKmState
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSFloodplainArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,8 +20,8 @@
 
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
 
 
 public class WMSFloodplainArtifact extends WMSDBArtifact {
@@ -89,7 +89,7 @@
                 String ids = artifact.getDataAsString("ids");
 
                 try {
-                    riverId = Integer.valueOf(ids);
+                    riverId = Integer.parseInt(ids);
                 }
                 catch (NumberFormatException nfe) {
                     logger.error("Cannot parse river id from '" + ids + "'");
@@ -109,14 +109,6 @@
         }
 
         @Override
-        protected String getTitle(CallMeta meta) {
-            return Resources.getMsg(
-                meta,
-                FLOODMAP_FLOODPLAIN,
-                FLOODMAP_FLOODPLAIN);
-        }
-
-        @Override
         protected String getUrl() {
             return FLYSUtils.getUserWMSUrl(artifact.identifier());
         }
@@ -128,10 +120,15 @@
         }
 
         @Override
-        protected Envelope getExtent() {
+        protected Envelope getExtent(boolean reproject) {
             River      river = getRiver();
             Floodplain plain = Floodplain.getFloodplain(river.getName());
-            return plain.getGeom().getEnvelopeInternal();
+
+            Envelope e = plain.getGeom().getEnvelopeInternal();
+
+            return e != null && reproject
+                ? GeometryUtils.transform(e, getSrid())
+                : e;
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSGaugeLocationArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,153 @@
+package de.intevation.flys.artifacts;
+
+import java.util.List;
+
+import org.w3c.dom.Document;
+
+import org.apache.log4j.Logger;
+
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Geometry;
+
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.DefaultOutput;
+import de.intevation.artifactdatabase.state.State;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.GaugeLocation;
+
+import de.intevation.flys.artifacts.WMSDBArtifact.WMSDBState;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.RiverFactory;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
+
+
+public class WMSGaugeLocationArtifact extends WMSDBArtifact {
+
+    public static final String NAME = "wmsgaugelocation";
+
+
+    private static final Logger logger =
+        Logger.getLogger(WMSGaugeLocationArtifact.class);
+
+
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callMeta,
+        Document        data)
+    {
+        logger.debug("WMSGaugeLocationArtifact.setup");
+
+        super.setup(identifier, factory, context, callMeta, data);
+    }
+
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+
+    @Override
+    public State getCurrentState(Object cc) {
+        State s = new WMSGaugeLocationState(this);
+
+        List<Facet> fs = facets.get(getCurrentStateId());
+
+        DefaultOutput o = new DefaultOutput(
+            "floodmap",
+            "floodmap",
+            "image/png",
+            fs,
+            "map");
+
+        s.getOutputs().add(o);
+
+        return s;
+    }
+
+
+
+    public static class WMSGaugeLocationState extends WMSDBState implements FacetTypes {
+
+        private static final Logger logger =
+            Logger.getLogger(WMSGaugeLocationState.class);
+
+        protected Geometry geom;
+
+        public WMSGaugeLocationState(WMSDBArtifact artifact) {
+            super(artifact);
+        }
+
+        @Override
+        protected String getFacetType() {
+            return FLOODMAP_GAUGE_LOCATION;
+        }
+
+        @Override
+        protected String getUrl() {
+            return FLYSUtils.getUserWMSUrl(artifact.identifier());
+        }
+
+        @Override
+        protected String getSrid() {
+            River river = RiverFactory.getRiver(getRiverId());
+            return FLYSUtils.getRiverSrid(river.getName());
+        }
+
+        @Override
+        protected Envelope getExtent(boolean reproject) {
+            List<GaugeLocation> gauges =
+                GaugeLocation.getGaugeLocations(getRiverId(), getName());
+
+            Envelope max = null;
+
+            for (GaugeLocation gauge: gauges) {
+                Envelope env = gauge.getGeom().getEnvelopeInternal();
+
+                if (max == null) {
+                    max = env;
+                    continue;
+                }
+
+                max.expandToInclude(env);
+            }
+
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
+        }
+
+        @Override
+        protected String getFilter() {
+            return "river_id=" + String.valueOf(getRiverId()) +
+                " and name='" + getName() + "'";
+        }
+
+        @Override
+        protected String getDataString() {
+            String srid = getSrid();
+
+            if (FLYSUtils.isUsingOracle()) {
+                return "geom FROM gauge_location USING SRID " + srid;
+            }
+            else {
+                return "geom FROM gauge_location " +
+                       "USING UNIQUE id USING SRID " + srid;
+            }
+        }
+
+        @Override
+        protected String getGeometryType() {
+            return "POINT";
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSHwsArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,8 +20,8 @@
 
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
 
 
 public class WMSHwsArtifact extends WMSDBArtifact {
@@ -86,13 +86,14 @@
 
         public int getRiverId() {
             if (riverId == 0) {
-                String ids = artifact.getDataAsString("ids");
+                String   ids   = artifact.getDataAsString("ids");
+                String[] parts = ids.split(";");
 
                 try {
-                    riverId = Integer.valueOf(ids);
+                    riverId = Integer.parseInt(parts[0]);
                 }
                 catch (NumberFormatException nfe) {
-                    logger.error("Cannot parse river id from '" + ids + "'");
+                    logger.error("Cannot parse river id from '" + parts[0] + "'");
                 }
             }
 
@@ -105,14 +106,6 @@
         }
 
         @Override
-        protected String getTitle(CallMeta meta) {
-            return Resources.getMsg(
-                meta,
-                FLOODMAP_HWS,
-                FLOODMAP_HWS);
-        }
-
-        @Override
         protected String getUrl() {
             return FLYSUtils.getUserWMSUrl(artifact.identifier());
         }
@@ -124,8 +117,8 @@
         }
 
         @Override
-        protected Envelope getExtent() {
-            List<Hws> hws = Hws.getHws(getRiverId());
+        protected Envelope getExtent(boolean reproject) {
+            List<Hws> hws = Hws.getHws(getRiverId(), getName());
 
             Envelope max = null;
 
@@ -140,12 +133,15 @@
                 max.expandToInclude(env);
             }
 
-            return max;
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
         }
 
         @Override
         protected String getFilter() {
-            return "river_id=" + String.valueOf(getRiverId());
+            return "river_id=" + String.valueOf(getRiverId())
+                + " AND name='" + getName() + "'";
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSHydrBoundaryArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,150 @@
+package de.intevation.flys.artifacts;
+
+import java.util.List;
+
+import org.w3c.dom.Document;
+
+import org.apache.log4j.Logger;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifactdatabase.state.DefaultOutput;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.State;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.HydrBoundary;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.RiverFactory;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
+
+
+public class WMSHydrBoundaryArtifact extends WMSDBArtifact {
+
+    public static final String NAME = "hydr_boundary";
+
+
+    private static final Logger logger =
+        Logger.getLogger(WMSHydrBoundaryArtifact.class);
+
+
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callMeta,
+        Document        data)
+    {
+        logger.debug("WMSHydrBoundaryArtifact.setup");
+
+        super.setup(identifier, factory, context, callMeta, data);
+    }
+
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+
+    @Override
+    public State getCurrentState(Object cc) {
+        State s = new HydrBoundaryState(this);
+
+        List<Facet> fs = facets.get(getCurrentStateId());
+
+        DefaultOutput o = new DefaultOutput(
+            "floodmap",
+            "floodmap",
+            "image/png",
+            fs,
+            "map");
+
+        s.getOutputs().add(o);
+
+        return s;
+    }
+
+
+    public static class HydrBoundaryState extends WMSDBState implements FacetTypes
+    {
+        private static final Logger logger =
+            Logger.getLogger(HydrBoundaryState.class);
+
+        protected int riverId;
+
+        public HydrBoundaryState(WMSDBArtifact artifact) {
+            super(artifact);
+            riverId = 0;
+        }
+
+        @Override
+        protected String getFacetType() {
+            return FLOODMAP_HYDR_BOUNDARY;
+        }
+
+        @Override
+        protected String getUrl() {
+            return FLYSUtils.getUserWMSUrl(artifact.identifier());
+        }
+
+        @Override
+        protected String getSrid() {
+            River river = RiverFactory.getRiver(getRiverId());
+            return FLYSUtils.getRiverSrid(river.getName());
+        }
+
+        @Override
+        protected Envelope getExtent(boolean reproject) {
+            List<HydrBoundary> boundaries = HydrBoundary.getHydrBoundaries(
+                getRiverId(), getName());
+
+            Envelope max = null;
+
+            for (HydrBoundary b: boundaries) {
+                Envelope env = b.getGeom().getEnvelopeInternal();
+
+                if (max == null) {
+                    max = env;
+                    continue;
+                }
+
+                max.expandToInclude(env);
+            }
+
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
+        }
+
+        @Override
+        protected String getFilter() {
+            return "river_id=" + String.valueOf(getRiverId())
+                + " AND name='" + getName() + "'";
+        }
+
+        @Override
+        protected String getDataString() {
+            String srid = getSrid();
+
+            if (FLYSUtils.isUsingOracle()) {
+                return "geom FROM hydr_boundaries USING SRID " + srid;
+            }
+            else {
+                return "geom FROM hydr_boundaries USING UNIQUE id USING SRID " + srid;
+            }
+        }
+
+        @Override
+        protected String getGeometryType() {
+            return "LINE";
+        }
+    } // end of HydrBoundaryState
+}
+// 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/WMSHydrBoundaryPolyArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,150 @@
+package de.intevation.flys.artifacts;
+
+import java.util.List;
+
+import org.w3c.dom.Document;
+
+import org.apache.log4j.Logger;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+import de.intevation.artifacts.ArtifactFactory;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifactdatabase.state.DefaultOutput;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.State;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.HydrBoundaryPoly;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.RiverFactory;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
+
+
+public class WMSHydrBoundaryPolyArtifact extends WMSDBArtifact {
+
+    public static final String NAME = "hydr_boundary_poly";
+
+
+    private static final Logger logger =
+        Logger.getLogger(WMSHydrBoundaryPolyArtifact.class);
+
+
+    @Override
+    public void setup(
+        String          identifier,
+        ArtifactFactory factory,
+        Object          context,
+        CallMeta        callMeta,
+        Document        data)
+    {
+        logger.debug("WMSHydrBoundaryArtifact.setup");
+
+        super.setup(identifier, factory, context, callMeta, data);
+    }
+
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+
+    @Override
+    public State getCurrentState(Object cc) {
+        State s = new HydrBoundaryPolyState(this);
+
+        List<Facet> fs = facets.get(getCurrentStateId());
+
+        DefaultOutput o = new DefaultOutput(
+            "floodmap",
+            "floodmap",
+            "image/png",
+            fs,
+            "map");
+
+        s.getOutputs().add(o);
+
+        return s;
+    }
+
+
+    public static class HydrBoundaryPolyState extends WMSDBState implements FacetTypes
+    {
+        private static final Logger logger =
+            Logger.getLogger(HydrBoundaryPolyState.class);
+
+        protected int riverId;
+
+        public HydrBoundaryPolyState(WMSDBArtifact artifact) {
+            super(artifact);
+            riverId = 0;
+        }
+
+        @Override
+        protected String getFacetType() {
+            return FLOODMAP_HYDR_BOUNDARY_POLY;
+        }
+
+        @Override
+        protected String getUrl() {
+            return FLYSUtils.getUserWMSUrl(artifact.identifier());
+        }
+
+        @Override
+        protected String getSrid() {
+            River river = RiverFactory.getRiver(getRiverId());
+            return FLYSUtils.getRiverSrid(river.getName());
+        }
+
+        @Override
+        protected Envelope getExtent(boolean reproject) {
+            List<HydrBoundaryPoly> boundaries = HydrBoundaryPoly.getHydrBoundaries(
+                getRiverId(), getName());
+
+            Envelope max = null;
+
+            for (HydrBoundaryPoly b: boundaries) {
+                Envelope env = b.getGeom().getEnvelopeInternal();
+
+                if (max == null) {
+                    max = env;
+                    continue;
+                }
+
+                max.expandToInclude(env);
+            }
+
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
+        }
+
+        @Override
+        protected String getFilter() {
+            return "river_id=" + String.valueOf(getRiverId())
+                + " AND name='" + getName() + "'";
+        }
+
+        @Override
+        protected String getDataString() {
+            String srid = getSrid();
+
+            if (FLYSUtils.isUsingOracle()) {
+                return "geom FROM hydr_boundaries USING SRID " + srid;
+            }
+            else {
+                return "geom FROM hydr_boundaries USING UNIQUE id USING SRID " + srid;
+            }
+        }
+
+        @Override
+        protected String getGeometryType() {
+            return "POLYGON";
+        }
+    } // end of HydrBoundaryState
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSKmArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -22,8 +22,8 @@
 import de.intevation.flys.artifacts.WMSDBArtifact.WMSDBState;
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
 
 
 public class WMSKmArtifact extends WMSDBArtifact {
@@ -91,7 +91,7 @@
                 String ids = artifact.getDataAsString("ids");
 
                 try {
-                    riverId = Integer.valueOf(ids);
+                    riverId = Integer.parseInt(ids);
                 }
                 catch (NumberFormatException nfe) {
                     logger.error("Cannot parse river id from '" + ids + "'");
@@ -107,11 +107,6 @@
         }
 
         @Override
-        protected String getTitle(CallMeta meta) {
-            return Resources.getMsg(meta, FLOODMAP_KMS, FLOODMAP_KMS);
-        }
-
-        @Override
         protected String getUrl() {
             return FLYSUtils.getUserWMSUrl(artifact.identifier());
         }
@@ -123,7 +118,7 @@
         }
 
         @Override
-        protected Envelope getExtent() {
+        protected Envelope getExtent(boolean reproject) {
             List<RiverAxisKm> kms = RiverAxisKm.getRiverAxisKms(getRiverId());
 
             Envelope max = null;
@@ -139,7 +134,9 @@
                 max.expandToInclude(env);
             }
 
-            return max;
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
         }
 
         @Override
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSLineArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,8 +20,8 @@
 
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
 
 
 public class WMSLineArtifact extends WMSDBArtifact {
@@ -86,13 +86,14 @@
 
         public int getRiverId() {
             if (riverId == 0) {
-                String ids = artifact.getDataAsString("ids");
+                String   ids   = artifact.getDataAsString("ids");
+                String[] parts = ids.split(";");
 
                 try {
-                    riverId = Integer.valueOf(ids);
+                    riverId = Integer.parseInt(parts[0]);
                 }
                 catch (NumberFormatException nfe) {
-                    logger.error("Cannot parse river id from '" + ids + "'");
+                    logger.error("Cannot parse river id from '" + parts[0] + "'");
                 }
             }
 
@@ -105,14 +106,6 @@
         }
 
         @Override
-        protected String getTitle(CallMeta meta) {
-            return Resources.getMsg(
-                meta,
-                FLOODMAP_LINES,
-                FLOODMAP_LINES);
-        }
-
-        @Override
         protected String getUrl() {
             return FLYSUtils.getUserWMSUrl(artifact.identifier());
         }
@@ -124,8 +117,8 @@
         }
 
         @Override
-        protected Envelope getExtent() {
-            List<Line> lines = Line.getLines(getRiverId());
+        protected Envelope getExtent(boolean reproject) {
+            List<Line> lines = Line.getLines(getRiverId(), getName());
 
             Envelope max = null;
 
@@ -140,12 +133,15 @@
                 max.expandToInclude(env);
             }
 
-            return max;
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
         }
 
         @Override
         protected String getFilter() {
-            return "river_id=" + String.valueOf(getRiverId());
+            return "river_id=" + String.valueOf(getRiverId()) +
+                " AND name='" + getName() + "'";
         }
 
         @Override
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WMSQPSArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,8 +20,8 @@
 
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
 
 
 public class WMSQPSArtifact extends WMSDBArtifact {
@@ -89,7 +89,7 @@
                 String ids = artifact.getDataAsString("ids");
 
                 try {
-                    riverId = Integer.valueOf(ids);
+                    riverId = Integer.parseInt(ids);
                 }
                 catch (NumberFormatException nfe) {
                     logger.error("Cannot parse river id from '" + ids + "'");
@@ -105,11 +105,6 @@
         }
 
         @Override
-        protected String getTitle(CallMeta meta) {
-            return Resources.getMsg(meta, FLOODMAP_QPS, FLOODMAP_QPS);
-        }
-
-        @Override
         protected String getUrl() {
             return FLYSUtils.getUserWMSUrl(artifact.identifier());
         }
@@ -121,7 +116,7 @@
         }
 
         @Override
-        protected Envelope getExtent() {
+        protected Envelope getExtent(boolean reproject) {
             River river = RiverFactory.getRiver(getRiverId());
 
             List<CrossSectionTrack> qps =
@@ -140,7 +135,9 @@
                 max.expandToInclude(env);
             }
 
-            return max;
+            return max != null && reproject
+                ? GeometryUtils.transform(max, getSrid())
+                : max;
         }
 
         @Override
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,12 +8,12 @@
 import org.w3c.dom.Document;
 
 import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
 import de.intevation.artifactdatabase.state.DefaultOutput;
 import de.intevation.artifactdatabase.state.State;
 
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.ArtifactFactory;
-import de.intevation.artifacts.ArtifactNamespaceContext;
 import de.intevation.artifacts.CallMeta;
 
 import de.intevation.flys.artifacts.model.FacetTypes;
@@ -27,7 +27,6 @@
 import de.intevation.flys.artifacts.states.StaticState;
 import de.intevation.flys.artifacts.resources.Resources;
 
-import de.intevation.artifacts.common.utils.XMLUtils;
 
 /**
  * Artifact to access additional "waterlevel/discharge"-type of data, like
@@ -44,13 +43,19 @@
     private static Logger logger =
         Logger.getLogger(WQKmsInterpolArtifact.class);
 
-    /** XPath to access initial parameter. */
-    public static final String XPATH_DATA =
-        "/art:action/art:ids/@value";
-
+    /** State name. */
     public static final String STATIC_STATE_NAME =
         "state.additional_wqkms.interpol.static";
 
+    /** Artifact name. */
+    private static final String NAME = "staticwqkmsinterpol";
+
+    static {
+        // TODO: Move to configuration.
+        FacetActivity.Registry.getInstance()
+            .register(NAME, FacetActivity.INACTIVE);
+    }
+
     /** One and only state to be in. */
     protected transient State state = null;
 
@@ -63,6 +68,13 @@
     }
 
 
+    /** Return fixed artifact (types) name. */
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+
     /**
      * Gets called from factory, to set things up.
      */
@@ -79,16 +91,17 @@
         state = new StaticState(STATIC_STATE_NAME);
 
         List<Facet> fs = new ArrayList<Facet>();
-        String code = XMLUtils.xpathString(
-            data, XPATH_DATA, ArtifactNamespaceContext.INSTANCE);
+        String code = getDatacageIDValue(data);
 
         // TODO Go for JSON, one day.
         //ex.: flood_protection-wstv-114-12
         if (code != null) {
             String [] parts = code.split("-");
 
+            logger.debug("WQKmsInterpolArtifact.setup: code " + code);
+
             if (parts.length >= 4) {
-                int wst = Integer.valueOf(parts[3]);
+                int wst = Integer.parseInt(parts[3]);
                 int col = -1;
                 String colpos = parts[2];
                 // Are we interested in a single column or in all columns?
@@ -96,11 +109,11 @@
                     ; // Take all.
                 }
                 else {
-                    col = Integer.valueOf(colpos);
+                    col = Integer.parseInt(colpos);
                     addStringData("col_pos", parts[2]);
                 }
                 addStringData("wst_id",  parts[3]);
-                String wkmsName = (col > 0)
+                String wkmsName = (col >= 0)
                                 ? WKmsFactory.getWKmsName(col, wst)
                                 : WKmsFactory.getWKmsName(wst);
                 String name;
@@ -114,15 +127,18 @@
                     name = STATIC_WQ;
                 }
 
-                Facet facet = new WQFacet(name,
+                Facet wQFacet = new WQFacet(name,
                     Resources.getMsg(
                         callMeta,
                         wkmsName,
                         wkmsName));
-                fs.add(facet);
+                fs.add(wQFacet);
                 facets.put(state.getID(), fs);
             }
         }
+        else {
+            logger.warn("WQKmsInterpolArtifact: no code");
+        }
 
         spawnState();
         super.setup(identifier, factory, context, callMeta, data);
@@ -161,7 +177,7 @@
         CallMeta meta)
     {
         logger.debug("WQKmsInterpolArtifact.initialize");
-        WINFOArtifact winfo = (WINFOArtifact) artifact;
+        FLYSArtifact winfo = (FLYSArtifact) artifact;
         importData(winfo, "river");
         importData(winfo, "ld_locations");
     }
@@ -182,8 +198,10 @@
 
     /**
      * Get WQ at a given km.
+     * @param currentKm the requested km. If NULL, ld_location data
+     *        will be used.
      */
-    public double [][] getWQAtKm(double km) {
+    public double [][] getWQAtKm(Double currentKm) {
 
         WstValueTable interpolator = null;
         // Get WstValueTable
@@ -196,8 +214,12 @@
                 getDataAsInt("wst_id"));
         }
 
+        Double tmp = (currentKm != null)
+                     ? currentKm
+                     : getDataAsDouble("ld_locations");
+
         double [][] vs = interpolator.interpolateWQColumnwise(
-            getDataAsDouble("ld_locations"));
+            tmp != null ? tmp : 0);
 
         for (int x = 0; x < vs[1].length; x++) {
             logger.debug("getWQAtKm: Q/W " + vs[0][x] + " / " + vs[1][x]);
@@ -213,7 +235,7 @@
     public int getDataAsInt(String dataName) {
         String val = getDataAsString(dataName);
         try {
-            return Integer.valueOf(val);
+            return Integer.parseInt(val);
         }
         catch (NumberFormatException e) {
             logger.warn("Could not get data " + dataName + " as int", e);
@@ -223,21 +245,6 @@
 
 
     /**
-     * Get a DataItem casted to double (0 if fails).
-     */
-    public double getDataAsDouble(String dataName) {
-        String val = getDataAsString(dataName);
-        try {
-            return Double.valueOf(val);
-        }
-        catch (NumberFormatException e) {
-            logger.warn("Could not get data " + dataName + " as double", e);
-            return 0;
-        }
-    }
-
-
-    /**
      * Get the "current" state (there is but one).
      * @param cc ignored.
      * @return the "current" (only possible) state.
@@ -273,7 +280,7 @@
 
     /**
      * Get WQKms from factory.
-     * @param TODO idx param is not needed
+     * @param idx param is not needed (TODO)
      * @return WQKms according to parameterization (can be null);
      */
     public WQKms getWQKms(int idx) {
@@ -281,28 +288,8 @@
         logger.warn("Stub, getWQKms not yet implemented.");
 
         return WQKmsFactory.getWQKms(
-            Integer.valueOf(getDataAsString("col_pos")),
-            Integer.valueOf(getDataAsString("wst_id")));
-    }
-
-
-    /**
-     * Determines Facets initial disposition regarding activity (think of
-     * selection in Client ThemeList GUI). This will be checked one time
-     * when the facet enters a collections describe document.
-     *
-     * @param facetName name of the facet.
-     * @param index     index of the facet.
-     *
-     * @return Always 0. Static Data will enter plots inactive.
-     */
-    @Override
-    public int getInitialFacetActivity(
-        String outputName,
-        String facetName,
-        int index)
-    {
-        return 0;
+            Integer.parseInt(getDataAsString("col_pos")),
+            Integer.parseInt(getDataAsString("wst_id")));
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,13 +1,14 @@
 package de.intevation.flys.artifacts;
 
-import de.intevation.flys.model.CrossSectionLine;
+import de.intevation.flys.artifacts.geom.Lines;
+import de.intevation.flys.model.FastCrossSectionLine;
 /**
- * Interfacet, Artifact can create WaterLines (Water against Cross-Profile).
+ * Interface, Artifact can create WaterLines (Water against Cross-Profile).
  */
 public interface WaterLineArtifact {
 
     /** Get points that define a line of a (water)facet against a cross-
      * section. */
-    public double [][] getWaterLines(int facetIdx, CrossSectionLine csl);
+    public Lines.LineData getWaterLines(int facetIdx, FastCrossSectionLine csl, double d, double w);
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WaterlevelArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,6 +1,8 @@
 package de.intevation.flys.artifacts;
 
+import de.intevation.artifactdatabase.state.DefaultFacet;
 import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
 
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.ArtifactFactory;
@@ -31,6 +33,11 @@
     /** The name of the artifact. */
     public static final String ARTIFACT_NAME = "waterlevel";
 
+    static {
+        // TODO: Move to configuration.
+        FacetActivity.Registry.getInstance()
+            .register(ARTIFACT_NAME, FacetActivity.INACTIVE);
+    }
 
     /**
      * The default constructor.
@@ -41,7 +48,8 @@
 
     /**
      * Setup and restate longitudinal_section filterfacets to apply to the
-     * w_differences output, too.
+     * w_differences output, too. Also, for w_differences, add respective q-
+     * filter facets.
      */
     public void setup(
         String          identifier,
@@ -51,10 +59,21 @@
         Document        data)
     {
         super.setup(identifier, factory, context, callMeta, data);
+        // For w_differences, also allow q-facets.
         if(filterFacets != null) {
-            filterFacets.put(
-                "w_differences",
-                filterFacets.get("longitudinal_section"));
+            List<Facet> list = new ArrayList<Facet>();
+            List<Facet> wlist = filterFacets.get("longitudinal_section");
+            for (Facet f: wlist) {
+                if (!f.getName().equals("longitudinal_section.q")) {
+                    DefaultFacet df = new DefaultFacet(f.getIndex(),
+                        "longitudinal_section.q", "");
+                    list.add(df);
+                }
+            }
+
+            list.addAll(wlist);
+
+            filterFacets.put("w_differences", list);
         }
     }
 
@@ -69,17 +88,17 @@
         CallMeta meta)
     {
         WINFOArtifact winfo = (WINFOArtifact) artifact;
-        this.data = winfo.cloneData();
-	logger.debug("Cloned data of winfo artifact.");
+        setData(winfo.cloneData());
+        logger.debug("Cloned data of winfo artifact.");
         // Statically add Facets.
         List<Facet> fs = new ArrayList<Facet>();
         DefaultState state = (DefaultState) getCurrentState(context);
         state.computeInit(this, hash(), context, meta, fs);
-        if (!fs.isEmpty()) { 
-            logger.debug("Facets to add in WaterlevelArtifact.initialize ."); 
-            facets.put(getCurrentStateId(), fs); 
-        } 
-        else { 
+        if (!fs.isEmpty()) {
+            logger.debug("Facets to add in WaterlevelArtifact.initialize .");
+            facets.put(getCurrentStateId(), fs);
+        }
+        else {
             logger.debug("No facets to add in WaterlevelArtifact.initialize ("
                 + state.getID() + ").");
         }
@@ -94,26 +113,5 @@
     public String getName() {
         return ARTIFACT_NAME;
     }
-
-
-    /**
-     * Determines Facets initial disposition regarding activity (think of
-     * selection in Client ThemeList GUI).
-     * WaterlevelArtifact Facets should come to live "inactive" (always
-     * return 0).
-     *
-     * @param facetName name of the facet.
-     * @param index     index of the facet.
-     *
-     * @return Always 0 to have Facets initial predisposition to "inactive".
-     */
-    @Override
-    public int getInitialFacetActivity(
-        String outputName,
-        String facetName,
-        int index)
-    {
-        return 0;
-    }
 }
 // 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/access/Access.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,174 @@
+package de.intevation.flys.artifacts.access;
+
+import de.intevation.artifactdatabase.data.StateData;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.DateRange;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+import gnu.trove.TDoubleArrayList;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import org.apache.log4j.Logger;
+
+public class Access
+{
+    private static Logger log = Logger.getLogger(Access.class);
+
+    protected FLYSArtifact artifact;
+
+    public Access() {
+    }
+
+    public Access(FLYSArtifact artifact) {
+        this.artifact = artifact;
+    }
+
+    public FLYSArtifact getArtifact() {
+        return artifact;
+    }
+
+    public void setArtifact(FLYSArtifact artifact) {
+        this.artifact = artifact;
+    }
+
+    protected String getString(String key) {
+        StateData sd = artifact.getData(key);
+        if (sd == null) {
+            log.warn("missing '" + key + "' value");
+            return null;
+        }
+        return (String)sd.getValue();
+    }
+
+    protected Double getDouble(String key) {
+        StateData sd = artifact.getData(key);
+        if (sd == null) {
+            log.warn("missing '" + key + "' value");
+            return null;
+        }
+        try {
+            return Double.valueOf((String)sd.getValue());
+        }
+        catch (NumberFormatException nfe) {
+            log.warn(key + " '" + sd.getValue() + "' is not numeric.");
+        }
+        return null;
+    }
+
+    protected Long getLong(String key) {
+        StateData sd = artifact.getData(key);
+        if (sd == null) {
+            log.warn("missing '" + key + "' value");
+            return null;
+        }
+        try {
+            return Long.valueOf((String)sd.getValue());
+        }
+        catch (NumberFormatException nfe) {
+            log.warn(key + " '" + sd.getValue() + "' is not a long integer.");
+        }
+        return null;
+    }
+
+    protected Integer getInteger(String key) {
+        StateData sd = artifact.getData(key);
+        if (sd == null) {
+            log.warn("missing '" + key + "' value");
+            return null;
+        }
+        try {
+            return Integer.valueOf((String)sd.getValue());
+        }
+        catch (NumberFormatException nfe) {
+            log.warn(key + " '" + sd.getValue() + "' is not a integer.");
+        }
+        return null;
+    }
+
+    protected int [] getIntArray(String key) {
+        StateData sd = artifact.getData(key);
+        if (sd == null) {
+            log.warn("missing '" + key +"' value");
+            return null;
+        }
+        return FLYSUtils.intArrayFromString((String)sd.getValue());
+    }
+
+    protected DateRange [] getDateRange(String key) {
+
+        StateData sd = artifact.getData(key);
+
+        if (sd == null) {
+            log.warn("missing '" + key + "'");
+            return null;
+        }
+
+        String data = (String)sd.getValue();
+        String[] pairs = data.split("\\s*;\\s*");
+
+        ArrayList<DateRange> aPs = new ArrayList<DateRange>(pairs.length);
+
+        for (int i = 0; i < pairs.length; i++) {
+            String[] fromTo = pairs[i].split("\\s*,\\s*");
+            if (fromTo.length >= 2) {
+                try {
+                    Date from = new Date(Long.parseLong(fromTo[0]));
+                    Date to   = new Date(Long.parseLong(fromTo[1]));
+                    DateRange aP = new DateRange(from, to);
+                    if (!aPs.contains(aP)) {
+                        aPs.add(aP);
+                    }
+                }
+                catch (NumberFormatException nfe) {
+                    log.warn(key + " contains no long values.", nfe);
+                }
+            }
+        }
+
+        DateRange [] result = aPs.toArray(new DateRange[aPs.size()]);
+
+        if (log.isDebugEnabled()) {
+            for (int i = 0; i < result.length; ++i) {
+                DateRange ap = result[i];
+                log.debug("period " +
+                    ap.getFrom() + " - " + ap.getTo());
+            }
+        }
+
+        return result;
+    }
+
+    protected Boolean getBoolean(String key) {
+        StateData sd = artifact.getData(key);
+        if (sd == null) {
+            log.warn("missing '" + key + "' value");
+            return null;
+        }
+        return Boolean.valueOf((String)sd.getValue());
+    }
+
+    protected double [] getDoubleArray(String key) {
+        StateData sd = artifact.getData(key);
+        if (sd == null) {
+            log.warn("missing '" + key + "'");
+            return null;
+        }
+        String [] parts = ((String)sd.getValue()).split("[\\s;]+");
+        TDoubleArrayList list = new TDoubleArrayList(parts.length);
+        for (String part: parts) {
+            try {
+                list.add(Double.parseDouble(part));
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("'" + part + "' is not numeric.");
+            }
+        }
+        return list.toNativeArray();
+    }
+}
+// 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/access/BedDifferencesAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,52 @@
+package de.intevation.flys.artifacts.access;
+
+import java.util.Arrays;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.StringUtil;
+
+
+public class BedDifferencesAccess
+extends RiverAccess
+{
+    private static Logger logger = Logger.getLogger(BedDifferencesAccess.class);
+    private String yearEpoch;
+    private String[] diffs;
+
+    private CallContext context;
+
+    public BedDifferencesAccess(FLYSArtifact artifact, CallContext context) {
+        super(artifact);
+        this.context = context;
+    }
+
+    public String getYearEpoch() {
+        yearEpoch = getString("ye_select");
+        return yearEpoch;
+    }
+
+    public FLYSArtifact[][] getDifferenceArtifacts() {
+        diffs = getString("diffids").split("#");
+        logger.debug("diffs: " + Arrays.toString(diffs));
+        FLYSArtifact[][] artifacts = new FLYSArtifact[diffs.length/2][2];
+        for (int i = 0; i < diffs.length; i += 2) {
+            String diff1 = StringUtil.unbracket(diffs[0 + 2*i]);
+            String diff2 = StringUtil.unbracket(diffs[1 + 2*i]);
+            String[] diff1parts = diff1.split(";");
+            String[] diff2parts = diff2.split(";");
+            logger.debug("creating 2 artifacts." + diff1parts[0] + "; " + diff2parts[0]);
+            artifacts[i][0] = FLYSUtils.getArtifact(diff1parts[0], context);
+            artifacts[i][1] = FLYSUtils.getArtifact(diff2parts[0], context);
+        }
+        return artifacts;
+    }
+
+    public static int getHeightId(FLYSArtifact artifact) {
+        Access a = new Access(artifact);
+        return a.getInteger("height_id");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/BedHeightAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,119 @@
+package de.intevation.flys.artifacts.access;
+
+import gnu.trove.TIntArrayList;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.states.SoundingsSelect;
+
+
+public class BedHeightAccess extends Access {
+
+    private static final Logger logger = Logger.getLogger(BedHeightAccess.class);
+
+    private int[] singleIDs;
+    private int[] epochIDs;
+
+    private Double lowerKM;
+    private Double upperKM;
+
+    private String time;
+
+    public BedHeightAccess(FLYSArtifact artifact) {
+        super(artifact);
+    }
+
+
+    public Double getLowerKM() {
+        if (lowerKM == null) {
+            lowerKM = getDouble("ld_from");
+        }
+
+        return lowerKM;
+    }
+
+
+    public Double getUpperKM() {
+        if (upperKM == null) {
+            upperKM = getDouble("ld_to");
+        }
+
+        return upperKM;
+    }
+
+
+    public int[] getBedHeightSingleIDs() {
+        if (singleIDs == null) {
+            String data = getString("soundings");
+
+            if (data == null) {
+                logger.warn("No 'soundings' parameter specified!");
+                return null;
+            }
+
+            String[] parts = data.split(";");
+
+            TIntArrayList ids = new TIntArrayList();
+
+            for (String part: parts) {
+                if (part.indexOf(SoundingsSelect.PREFIX_SINGLE) >= 0) {
+                    String tmp = part.replace(SoundingsSelect.PREFIX_SINGLE, "");
+
+                    try {
+                        ids.add(Integer.parseInt(tmp));
+                    }
+                    catch (NumberFormatException nfe) {
+                        logger.warn("Cannot parse int from string: '" + tmp + "'");
+                    }
+                }
+            }
+
+            singleIDs = ids.toNativeArray();
+        }
+
+        return singleIDs;
+    }
+
+
+    public String getYearEpoch() {
+        if (time == null) {
+            time =  getString("ye_select");
+        }
+        return time;
+    }
+
+
+    public int[] getBedHeightEpochIDs() {
+        if (epochIDs == null) {
+            String data = getString("soundings");
+
+            if (data == null) {
+                logger.warn("No 'soundings' parameter specified!");
+                return null;
+            }
+
+            String[] parts = data.split(";");
+
+            TIntArrayList ids = new TIntArrayList();
+
+            for (String part: parts) {
+                if (part.indexOf(SoundingsSelect.PREFIX_EPOCH) >= 0) {
+                    String tmp = part.replace(SoundingsSelect.PREFIX_EPOCH, "");
+
+                    try {
+                        ids.add(Integer.parseInt(tmp));
+                    }
+                    catch (NumberFormatException nfe) {
+                        logger.warn("Cannot parse int from string: '" + tmp + "'");
+                    }
+                }
+            }
+
+            epochIDs = ids.toNativeArray();
+        }
+
+        return epochIDs;
+    }
+}
+// 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/access/BedQualityAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,97 @@
+package de.intevation.flys.artifacts.access;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.DateRange;
+
+
+public class BedQualityAccess extends RiverAccess {
+
+    private static final Logger logger = Logger
+        .getLogger(BedQualityAccess.class);
+
+    private Double from;
+    private Double to;
+    private List<String> bedDiameter;
+    private List<String> bedloadDiameter;
+    private List<DateRange> ranges;
+
+    public BedQualityAccess(FLYSArtifact artifact) {
+        super(artifact);
+    }
+
+    public double getFrom() {
+        if (from == null) {
+            from = getDouble("ld_from");
+        }
+        return from.doubleValue();
+    }
+
+    public double getTo() {
+        if (to == null) {
+            to = getDouble("ld_to");
+        }
+        return to.doubleValue();
+    }
+
+    public List<DateRange> getDateRanges() {
+        if (ranges == null) {
+            ranges = extractRanges(getString("periods"));
+        }
+        return ranges;
+    }
+
+    public List<String> getBedDiameter() {
+        String value = getString("bed_diameter");
+        if (bedDiameter == null && value != null) {
+            bedDiameter = extractDiameter(value);
+        }
+        return bedDiameter;
+    }
+
+    public List<String> getBedloadDiameter() {
+        String value = getString("load_diameter");
+        if (bedloadDiameter == null && value != null) {
+            bedloadDiameter = extractDiameter(value);
+        }
+        return bedloadDiameter;
+    }
+
+    private List<DateRange> extractRanges(String dateString) {
+        List<DateRange> list = new LinkedList<DateRange>();
+        String[] dates = dateString.split(";");
+        for (String s : dates) {
+            String[] pair = s.split(",");
+            try {
+                long l1      = Long.parseLong(pair[0]);
+                long l2      = Long.parseLong(pair[1]);
+                Date first   = new Date(l1);
+                Date second  = new Date(l2);
+                DateRange dr = new DateRange(first, second);
+                list.add(dr);
+            }
+            catch (NumberFormatException nfe) {
+                continue;
+            }
+        }
+        return list;
+    }
+
+    private List<String> extractDiameter(String value) {
+        List<String> result = new LinkedList<String>();
+        String[] diameter = value.split(";");
+        for (String v : diameter) {
+            logger.debug("diameter: " + v);
+            String[] parts = v.split("\\.");
+            result.add(parts[parts.length - 1]);
+            logger.debug(parts[parts.length-1]);
+        }
+        return result;
+    }
+}
+// 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/access/ExtremeAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,126 @@
+package de.intevation.flys.artifacts.access;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.RangeWithValues;
+
+import de.intevation.flys.utils.DoubleUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class ExtremeAccess
+extends      RiverAccess
+{
+    private static Logger log = Logger.getLogger(ExtremeAccess.class);
+
+    protected Double from;
+    protected Double to;
+    protected Double step;
+
+    protected Long start;
+    protected Long end;
+
+    protected Double percent;
+
+    protected String function;
+
+    protected List<RangeWithValues> ranges;
+
+    public ExtremeAccess() {
+    }
+
+    public ExtremeAccess(FLYSArtifact artifact) {
+        super(artifact);
+    }
+
+    public Double getFrom() {
+
+        if (from == null) {
+            from = getDouble("ld_from");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("from: '" + from + "'");
+        }
+
+        return from;
+    }
+
+    public Double getTo() {
+
+        if (to == null) {
+            to = getDouble("ld_to");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("to: '" + to + "'");
+        }
+
+        return to;
+    }
+
+    public Double getStep() {
+
+        if (step == null) {
+            step = getDouble("ld_step");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("step: '" + step + "'");
+        }
+
+        return step;
+    }
+
+    public Double getPercent() {
+
+        if (percent == null) {
+            percent = getDouble("percent");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("percent: '" + percent + "'");
+        }
+
+        return percent;
+    }
+
+    public String getFunction() {
+        if (function == null) {
+            function = getString("function");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("function: '" + function + "'");
+        }
+
+        return function;
+    }
+
+    public List<RangeWithValues> getRanges() {
+
+        if (ranges == null) {
+            String rangesS = getString("ranges");
+            if (ranges == null) {
+                return null;
+            }
+            ranges = new ArrayList<RangeWithValues>();
+            DoubleUtil.parseSegments(rangesS, new DoubleUtil.SegmentCallback() {
+                @Override
+                public void newSegment(double from, double to, double [] values) {
+                    ranges.add(new RangeWithValues(from, to, values));
+                }
+            });
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("ranges: " + ranges);
+        }
+
+        return ranges;
+    }
+}
+// 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/access/FixAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,158 @@
+package de.intevation.flys.artifacts.access;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import java.util.Arrays;
+
+import org.apache.log4j.Logger;
+
+public class FixAccess
+extends      RiverAccess
+{
+    private static Logger log = Logger.getLogger(FixAccess.class);
+
+    protected Double from;
+    protected Double to;
+    protected Double step;
+
+    protected Long start;
+    protected Long end;
+
+    protected Integer qSectorStart;
+    protected Integer qSectorEnd;
+
+    protected int [] events;
+
+    protected Boolean preprocessing;
+
+    protected String  function;
+
+    public FixAccess() {
+    }
+
+    public FixAccess(FLYSArtifact artifact) {
+        super(artifact);
+    }
+
+    public Double getFrom() {
+
+        if (from == null) {
+            from = getDouble("from");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("from: '" + from + "'");
+        }
+
+        return from;
+    }
+
+    public Double getTo() {
+
+        if (to == null) {
+            to = getDouble("to");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("to: '" + to + "'");
+        }
+
+        return to;
+    }
+
+    public Double getStep() {
+
+        if (step == null) {
+            step = getDouble("step");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("step: '" + step + "'");
+        }
+
+        return step;
+    }
+
+    public Long getStart() {
+
+        if (start == null) {
+            start = getLong("start");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("start: '" + start + "'");
+        }
+
+        return start;
+    }
+
+    public Long getEnd() {
+
+        if (end == null) {
+            end = getLong("end");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("end: '" + end + "'");
+        }
+
+        return end;
+    }
+
+    public Integer getQSectorStart() {
+
+        if (qSectorStart == null) {
+            qSectorStart = getInteger("q1");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("q1: '" + qSectorStart + "'");
+        }
+
+        return qSectorStart;
+    }
+
+    public Integer getQSectorEnd() {
+
+        if (qSectorEnd == null) {
+            qSectorEnd = getInteger("q2");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("q2: '" + qSectorEnd + "'");
+        }
+
+        return qSectorEnd;
+    }
+
+    public int [] getEvents() {
+        if (events == null) {
+            events = getIntArray("events");
+        }
+        if (log.isDebugEnabled() && events != null) {
+            log.debug("events: " + Arrays.toString(events));
+        }
+        return events;
+    }
+
+    public Boolean getPreprocessing() {
+        if (preprocessing == null) {
+            preprocessing = getBoolean("preprocessing");
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("preprocessing: " + preprocessing);
+        }
+        return preprocessing;
+    }
+
+    public String getFunction() {
+        if (function == null) {
+            function = getString("function");
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("function: " + function);
+        }
+        return function;
+    }
+}
+// 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/access/FixAnalysisAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,105 @@
+package de.intevation.flys.artifacts.access;
+
+import de.intevation.artifactdatabase.data.StateData;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.DateRange;
+
+import java.util.Arrays;
+import java.util.Date;
+
+import org.apache.log4j.Logger;
+
+public class FixAnalysisAccess
+extends      FixAccess
+{
+    private static Logger log = Logger.getLogger(FixAnalysisAccess.class);
+
+    protected DateRange    referencePeriod;
+    protected DateRange [] analysisPeriods;
+
+    protected double [] qs;
+
+    public FixAnalysisAccess() {
+    }
+
+    public FixAnalysisAccess(FLYSArtifact artifact) {
+        super(artifact);
+    }
+
+    public DateRange getReferencePeriod() {
+        if (referencePeriod == null) {
+            StateData refStart = artifact.getData("ref_start");
+            StateData refEnd   = artifact.getData("ref_end");
+
+            if (refStart == null || refEnd == null) {
+                log.warn("missing 'ref_start' or 'ref_start' value");
+                return null;
+            }
+
+            try {
+                long rs = Long.parseLong((String)refStart.getValue());
+                long re = Long.parseLong((String)refEnd  .getValue());
+
+                if (rs > re) { long t = rs; rs = re; re = t; }
+
+                Date from = new Date(rs);
+                Date to   = new Date(re);
+                referencePeriod = new DateRange(from, to);
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("ref_start or ref_end is not an integer.");
+            }
+        }
+
+        return referencePeriod;
+    }
+
+    public DateRange [] getAnalysisPeriods() {
+        if (analysisPeriods == null) {
+            analysisPeriods = getDateRange("ana_data");
+        }
+
+        return analysisPeriods;
+    }
+
+    /**
+     * @return DateRange object ranging from eldest to youngest date
+     * of analysis and reference periods.
+     */
+    public DateRange getDateRange() {
+        DateRange refP = getReferencePeriod();
+
+        if (refP == null) {
+            return null;
+        }
+
+        Date from = refP.getFrom();
+        Date to   = refP.getTo();
+
+        DateRange[] rs = getAnalysisPeriods();
+        for (DateRange r: rs) {
+            if (r.getFrom().before(from)) {
+                from = r.getFrom();
+            }
+            if (r.getTo().after(to)) {
+                to = r.getTo();
+            }
+        }
+
+        return new DateRange(from, to);
+    }
+
+    public double [] getQs() {
+        if (qs == null) {
+            qs = getDoubleArray("qs");
+        }
+
+        if (log.isDebugEnabled() && qs != null) {
+            log.debug("qs: " + Arrays.toString(qs));
+        }
+        return qs;
+    }
+}
+// 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/access/FixRealizingAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,53 @@
+package de.intevation.flys.artifacts.access;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.Segment;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class FixRealizingAccess
+extends      FixAccess
+{
+    private static Logger log = Logger.getLogger(FixRealizingAccess.class);
+
+    protected Boolean isQ;
+
+    protected List<Segment> segments;
+
+    public FixRealizingAccess() {
+    }
+
+    public FixRealizingAccess(FLYSArtifact artifact) {
+        super(artifact);
+    }
+
+    public Boolean isQ() {
+        if (isQ == null) {
+            isQ = getBoolean("wq_isq");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("isQ: " + isQ);
+        }
+
+        return isQ;
+    }
+
+    public List<Segment> getSegments() {
+        if (segments == null) {
+            String segmentsS = getString("wq_values");
+            if (segmentsS != null) {
+                segments = Segment.parseSegments(segmentsS);
+            }
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("segments: " + segments);
+        }
+
+        return segments;
+    }
+}
+// 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/access/FlowVelocityAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,56 @@
+package de.intevation.flys.artifacts.access;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+
+/** Access to data that deals with flow velocity stuff. */
+public class FlowVelocityAccess extends RiverAccess {
+
+    private int[] mainChannels;
+    private int[] totalChannels;
+
+    private Double lowerKM;
+    private Double upperKM;
+
+
+    public FlowVelocityAccess(FLYSArtifact artifact) {
+        super(artifact);
+    }
+
+
+    public int[] getMainChannels() {
+        if (mainChannels == null) {
+            mainChannels = getIntArray("main_channel");
+        }
+
+        return mainChannels;
+    }
+
+
+    public int[] getTotalChannels() {
+        if (totalChannels == null) {
+            totalChannels = getIntArray("total_channel");
+        }
+
+        return totalChannels;
+    }
+
+
+    public Double getLowerKM() {
+        if (lowerKM == null) {
+            lowerKM = getDouble("ld_from");
+        }
+
+        return lowerKM;
+    }
+
+
+    public Double getUpperKM() {
+        if (upperKM == null) {
+            upperKM = getDouble("ld_to");
+        }
+
+        return upperKM;
+    }
+}
+// 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/access/RiverAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,31 @@
+package de.intevation.flys.artifacts.access;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import org.apache.log4j.Logger;
+
+public class RiverAccess
+extends      Access
+{
+    private static Logger log = Logger.getLogger(RiverAccess.class);
+
+    protected String river;
+
+    public RiverAccess() {
+    }
+
+    public RiverAccess(FLYSArtifact artifact) {
+        super(artifact);
+    }
+
+    public String getRiver() {
+        if (river == null) {
+            river = getString("river");
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("river: '" + river + "'");
+        }
+        return river;
+    }
+}
+// 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/access/SQRelationAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.artifacts.access;
+
+import java.util.Date;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.DateRange;
+
+public class SQRelationAccess
+extends      RiverAccess
+{
+    private static Logger log = Logger.getLogger(SQRelationAccess.class);
+
+    protected Double    location;
+
+    protected DateRange period;
+
+    protected Double    outliers;
+
+    public SQRelationAccess() {
+    }
+
+    public SQRelationAccess(FLYSArtifact artifact) {
+        super(artifact);
+    }
+
+    public Double getLocation() {
+        if (location == null) {
+            // XXX: The parameter name suggests plural!?
+            location = getDouble("ld_locations");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("location: " + location);
+        }
+
+        return location;
+    }
+
+    public DateRange getPeriod() {
+        if (period == null) {
+            Long start = getLong("start");
+            Long end   = getLong("end");
+
+            if (start != null && end != null) {
+                period = new DateRange(new Date(start), new Date(end));
+            }
+        }
+
+        return period;
+    }
+
+    public Double getOutliers() {
+        if (outliers == null) {
+            outliers = getDouble("outliers");
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("outliers: " + outliers);
+        }
+        return outliers;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,7 +2,7 @@
 
 import de.intevation.flys.backend.SessionFactoryProvider;
 
-import de.intevation.flys.geom.Lines;
+import de.intevation.flys.artifacts.geom.Lines;
 
 import de.intevation.flys.model.CrossSection;
 import de.intevation.flys.model.CrossSectionLine;
@@ -29,6 +29,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 
+import java.math.BigDecimal;
 import java.math.MathContext;
 
 import java.util.ArrayList;
@@ -127,7 +128,7 @@
 
         @Override
         public int getColumnCount() {
-            return 5; 
+            return 5;
         }
 
         @Override
@@ -151,7 +152,7 @@
         @Override
         public void setValueAt(Object value, int row, int col) {
             switch (col) {
-                case 1: 
+                case 1:
                     if (change(drawCrossSection, row, (Boolean)value)) {
                         fireTableCellUpdated(row, col);
                     }
@@ -180,7 +181,7 @@
                 case 0: return String.class;
                 case 1:
                 case 2:
-                case 3: 
+                case 3:
                 case 4: return Boolean.class;
             }
             return null;
@@ -197,7 +198,7 @@
 
     private static boolean change(
         boolean [] values,
-        int        index, 
+        int        index,
         boolean    value
     ) {
         if (values[index] != value) {
@@ -213,7 +214,7 @@
         List<Pair<CrossSection, CrossSectionLine>> lines;
 
         public CrossSectionLineItem(
-            Double km, 
+            Double km,
             List<Pair<CrossSection, CrossSectionLine>> lines
         ) {
             this.km    = km;
@@ -449,8 +450,8 @@
                 out.println("# " + pair.getA().getDescription());
                 for (CrossSectionPoint point: pair.getB().getPoints()) {
                     out.println(
-                        point.getX().round(mc) + " " +
-                        point.getY().round(mc));
+                        new BigDecimal(point.getX()).round(mc) + " " +
+                        new BigDecimal(point.getY()).round(mc));
                 }
             }
 
@@ -474,7 +475,7 @@
             return;
         }
 
-        double [][] data = Lines.createWaterLines(points, lastWaterLevel);
+        double [][] data = Lines.createWaterLines(points, lastWaterLevel).points;
         XYSeries series =
             new XYSeries(String.valueOf(lastWaterLevel), false);
 
@@ -497,7 +498,7 @@
             return;
         }
 
-        double [][] data   = Lines.createWaterLines(points, lastWaterLevel);
+        double [][] data   = Lines.createWaterLines(points, lastWaterLevel).points;
         double [][] values = CrossSectionLine.fetchCrossSectionProfile(points);
 
         DefaultXYDataset dataset = new DefaultXYDataset();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/TimeseriesStepChart.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,218 @@
+package de.intevation.flys.artifacts.charts;
+
+import java.awt.Dimension;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.ui.ApplicationFrame;
+
+import org.jfree.data.time.SimpleTimePeriod;
+import org.jfree.data.time.Second;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.jfree.data.time.TimePeriodValues;
+import org.jfree.data.time.TimePeriodValuesCollection;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+
+
+public class TimeseriesStepChart extends ApplicationFrame {
+
+    private static final Logger logger =
+        Logger.getLogger(TimeseriesStepChart.class);
+
+
+    public static final String LOG4J_PROPERTIES = "FLYS_CLIENT_LOG4J_PROPERIES";
+
+    public static final int USER_CHART_TYPE =
+        Integer.getInteger("chart.type", -1);
+
+    public static final int CHART_TYPE_TIMEPERIOD = 1;
+    public static final int CHART_TYPE_TIMESERIES = 2;
+
+
+    public static void main(String[] args) {
+        configureLogging();
+
+        logger.info("Start TimeseriesStepChart demo.");
+
+        if (USER_CHART_TYPE <= 0) {
+            logger.error("Unknown chart type: " + USER_CHART_TYPE);
+        }
+
+        logger.debug("Create Chart from type: " + USER_CHART_TYPE);
+
+        TimeseriesStepChart tsc = new TimeseriesStepChart();
+        tsc.build(USER_CHART_TYPE);
+
+        logger.info("End of TimeseriesStepChart demo.");
+    }
+
+
+    public static void configureLogging() {
+        String log4jProperties = System.getenv(LOG4J_PROPERTIES);
+
+        if (log4jProperties != null && log4jProperties.length() > 0) {
+            PropertyConfigurator.configure(log4jProperties);
+            logger.info("Log4J logging initialized.");
+        }
+        else {
+            System.out.println("Error while setting up Log4J configuration.");
+        }
+
+        System.out.println("LoggingConfigurator.init finished");
+    }
+
+
+    public TimeseriesStepChart() {
+        super("TimeseriesStepChart");
+    }
+
+
+    public void build(int type) {
+        ChartPanel chartPanel = createChartPanel(type);
+        chartPanel.setPreferredSize(new Dimension(500, 300));
+
+        setContentPane(chartPanel);
+
+        pack();
+        setVisible(true);
+    }
+
+
+    protected ChartPanel createChartPanel(int type) {
+        JFreeChart chart = createJFreeChart(type);
+        ChartPanel panel = new ChartPanel(chart);
+        return panel;
+    }
+
+
+    protected JFreeChart createJFreeChart(int type) {
+        if (type == CHART_TYPE_TIMEPERIOD) {
+            return createTimePeriodValuesChart();
+        }
+        else if (type == CHART_TYPE_TIMESERIES) {
+            return createTimeSeriesChart();
+        }
+
+        logger.error("Unknown chart type: " + type);
+
+        return null;
+    }
+
+
+    public static Date createDate(int year, int month, int day) {
+        GregorianCalendar cal = new GregorianCalendar(year, month, day);
+        return cal.getTime();
+    }
+
+
+
+    //
+    // XXX FOLLOWING METHODS ARE USED FOR "TimePeriodValues" CHART TYPE
+    //
+    protected JFreeChart createTimePeriodValuesChart() {
+        return ChartFactory.createTimeSeriesChart(
+            "TimePeriodValues Chart",
+            "Time Axis",
+            "Y Axis",
+            createTimePeriodValuesDataset(),
+            true,
+            false,
+            false);
+    }
+
+
+    protected TimePeriodValuesCollection createTimePeriodValuesDataset() {
+        TimePeriodValuesCollection dataset = new TimePeriodValuesCollection();
+        TimePeriodValues series = createTimePeriodValues();
+
+        dataset.addSeries(series);
+
+        return dataset;
+    }
+
+
+    protected TimePeriodValues createTimePeriodValues() {
+        TimePeriodValues series1 = new TimePeriodValues("Series 1");
+
+        Date start1 = createDate(2000, 0, 1);
+        Date end1   = createDate(2000, 11, 31);
+
+        logger.debug("START DATE 1 = " + start1);
+        logger.debug("END   DATE 1 = " + end1);
+
+        SimpleTimePeriod period1 = new SimpleTimePeriod(start1, end1);
+
+        Date start2 = createDate(2001, 0, 1);
+        Date end2   = createDate(2001, 11, 31);
+        SimpleTimePeriod period2 = new SimpleTimePeriod(start2, end2);
+
+        Date start3 = createDate(2002, 0, 1);
+        Date end3   = createDate(2002, 11, 31);
+        SimpleTimePeriod period3 = new SimpleTimePeriod(start3, end3);
+
+        series1.add(period1, 100);
+        series1.add(period2, 200);
+        series1.add(period3, 150);
+
+        return series1;
+    }
+
+
+    //
+    // XXX FOLLOWING METHODS ARE USED FOR "TimePeriodValues" CHART TYPE
+    //
+    protected JFreeChart createTimeSeriesChart() {
+        return ChartFactory.createTimeSeriesChart(
+            "TimeSeriesCollection Chart",
+            "Time Axis",
+            "Y Axis",
+            createTimeSeriesCollectionDataset(),
+            true,
+            false,
+            false);
+    }
+
+
+    protected TimeSeriesCollection createTimeSeriesCollectionDataset() {
+        TimeSeriesCollection dataset = new TimeSeriesCollection();
+        TimeSeries[]         series  = createTimeSeries();
+
+        for (TimeSeries tmp: series) {
+            dataset.addSeries(tmp);
+        }
+
+        return dataset;
+    }
+
+
+    protected TimeSeries[] createTimeSeries() {
+        TimeSeries series1 = new TimeSeries("Series 1");
+        series1.add(new Second(0, 0, 0, 1, 1, 2000), 100);
+        series1.add(new Second(59, 59, 23, 31, 12, 2000), 100);
+
+        series1.add(new Second(0, 0, 0, 1, 1, 2001), 200);
+        series1.add(new Second(59, 59, 23, 31, 12, 2001), 200);
+
+        series1.add(new Second(0, 0, 0, 1, 1, 2002), 150);
+        series1.add(new Second(59, 59, 23, 31, 12, 2002), 150);
+
+        TimeSeries series2 = new TimeSeries("Series 2");
+        series2.add(new Second(0, 0, 0, 1, 1, 2000), 10);
+        series2.add(new Second(59, 59, 23, 31, 12, 2000), 10);
+
+        series2.add(new Second(0, 0, 0, 1, 1, 2001), 20);
+        series2.add(new Second(59, 59, 23, 31, 12, 2001), 20);
+
+        series2.add(new Second(0, 0, 0, 1, 1, 2002), 15);
+        series2.add(new Second(59, 59, 23, 31, 12, 2002), 15);
+
+        return new TimeSeries[] { series1, series2 };
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContext.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,10 +1,14 @@
 package de.intevation.flys.artifacts.context;
 
+import java.util.Map;
+
 import org.apache.log4j.Logger;
 
 import org.w3c.dom.Document;
 
 import de.intevation.artifactdatabase.DefaultArtifactContext;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.exports.OutGenerator;
 
 
 /**
@@ -50,6 +54,9 @@
     public static final String SCHEDULER =
         "flys.wsplgen.scheduler";
 
+    /** Key to store the configured modules in the context. */
+    public static final String MODULES = "flys.modules";
+
 
     /**
      * The default constructor.
@@ -65,5 +72,45 @@
     public FLYSContext(Document config) {
         super(config);
     }
+
+    /**
+     * Returns the OutGenerator for a specified <i>type</i>.
+     *
+     * @param name The name of the output type.
+     * @param type Defines the type of the desired OutGenerator.
+     *
+     * @return Instance of an OutGenerator for specified <i>type</i>.
+     */
+    public static OutGenerator getOutGenerator(
+        CallContext context,
+        String      name,
+        String      type)
+    {
+
+        FLYSContext flysContext = context instanceof FLYSContext
+            ? (FLYSContext) context
+            : (FLYSContext) context.globalContext();
+
+        Map<String, Class> generators = (Map<String, Class>)
+            flysContext.get(FLYSContext.OUTGENERATORS_KEY);
+
+        if (generators == null) {
+            return null;
+        }
+
+        Class clazz = generators.get(name);
+
+        try {
+            return clazz != null ? (OutGenerator) clazz.newInstance() : null;
+        }
+        catch (InstantiationException ie) {
+            logger.error(ie, ie);
+        }
+        catch (IllegalAccessException iae) {
+            logger.error(iae, iae);
+        }
+
+        return null;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -26,9 +26,11 @@
 import de.intevation.artifactdatabase.transition.Transition;
 import de.intevation.artifactdatabase.transition.TransitionEngine;
 
+import de.intevation.flys.artifacts.model.Module;
 import de.intevation.flys.artifacts.states.StateFactory;
 import de.intevation.flys.artifacts.transitions.TransitionFactory;
 import de.intevation.flys.themes.Theme;
+import de.intevation.flys.themes.ThemeGroup;
 import de.intevation.flys.themes.ThemeFactory;
 import de.intevation.flys.themes.ThemeMapping;
 
@@ -69,7 +71,10 @@
         "/artifact-database/flys/themes/configuration/text()";
 
     public static final String XPATH_THEMES =
-        "/themes/theme";
+        "theme";
+
+    public static final String XPATH_THEME_GROUPS =
+        "/themes/themegroup";
 
     public static final String XPATH_THEME_MAPPINGS =
         "/themes/mappings/mapping";
@@ -77,6 +82,8 @@
     public static final String XPATH_RIVER_WMS =
         "/artifact-database/floodmap/river";
 
+    public static final String XPATH_MODULES = "/artifact-database/modules/module";
+
     /**
      * Creates a new FLYSArtifactContext object and initialize all
      * components required by the application.
@@ -93,6 +100,7 @@
         configureThemes(config, context);
         configureThemesMappings(config, context);
         configureRiverWMS(config, context);
+        configureModules(config, context);
 
         return context;
     }
@@ -120,7 +128,8 @@
                 doc, XPATH_TRANSITIONS, XPathConstants.NODESET);
 
             if (list == null) {
-                logger.warn("The artifact has no transitions configured.");
+                logger.warn("The artifact " + artName +
+                    " has no transitions configured.");
                 continue;
             }
 
@@ -193,7 +202,8 @@
                 doc, XPATH_STATES, XPathConstants.NODESET);
 
             if (stateList == null) {
-                logger.warn("The artifact has no states configured.");
+                logger.warn("The artifact " + artName +
+                    " has no states configured.");
                 continue;
             }
 
@@ -279,36 +289,54 @@
 
         Document cfg = getThemeConfig(config);
 
-        NodeList themes = (NodeList) XMLUtils.xpath(
-            cfg, XPATH_THEMES, XPathConstants.NODESET);
+        NodeList themeGroups = (NodeList) XMLUtils.xpath(
+            cfg, XPATH_THEME_GROUPS, XPathConstants.NODESET);
 
-        int num = themes != null ? themes.getLength() : 0;
+        int groupNum = themeGroups != null ? themeGroups.getLength() : 0;
 
-        if (num == 0) {
-            logger.warn("There are no themes configured!");
-            return;
+        if (groupNum == 0) {
+            logger.warn("There are no theme groups configured!");
         }
 
-        logger.debug("Found " + num + " configured themes.");
-
-        Map<String, Theme> theThemes = new HashMap<String, Theme>();
-
-        for (int i = 0; i < num; i++) {
-            Node theme = themes.item(i);
-
-            Theme theTheme = ThemeFactory.createTheme(cfg, theme);
+        logger.info("Found " + groupNum + " theme groups in configuration");
 
-            if (theme != null) {
-                theThemes.put(theTheme.getName(), theTheme);
-            }
-        }
+        List<ThemeGroup> groups = new ArrayList<ThemeGroup>();
 
-        logger.debug("Initialized " + theThemes.size() + "/" + num + " themes");
+        for (int g = 0; g < groupNum; g++) {
+            Element themeGroup = (Element) themeGroups.item(g);
+            NodeList themes = (NodeList) XMLUtils.xpath(
+                themeGroup, XPATH_THEMES, XPathConstants.NODESET);
 
-        context.put(FLYSContext.THEMES, theThemes);
+            int num = themes != null ? themes.getLength() : 0;
+
+            if (num == 0) {
+                logger.warn("There are no themes configured!");
+                return;
+            }
+
+            logger.info("Theme group has " + num + " themes.");
+
+            Map<String, Theme> theThemes = new HashMap<String, Theme>();
+
+            for (int i = 0; i < num; i++) {
+                Node theme = themes.item(i);
+
+                Theme theTheme = ThemeFactory.createTheme(cfg, theme);
+
+                if (theme != null) {
+                    theThemes.put(theTheme.getName(), theTheme);
+                }
+            }
+            String gName = themeGroup.getAttribute("name");
+            groups.add(new ThemeGroup(gName, theThemes));
+
+            logger.info(
+                "Initialized " + theThemes.size() + "/" + num + " themes " +
+                "of theme-group '" + gName + "'");
+        }
+        context.put(FLYSContext.THEMES, groups);
     }
 
-
     /**
      * This method is used to retrieve the theme configuration document.
      *
@@ -349,24 +377,15 @@
             new HashMap<String, List<ThemeMapping>>();
 
         for (int i = 0; i < num; i++) {
-            Node node = mappings.item(i);
-
-            String from = (String) XMLUtils.xpath(
-                node, "@from", XPathConstants.STRING);
-
-            String to = (String) XMLUtils.xpath(
-                node, "@to", XPathConstants.STRING);
+            Element node = (Element)mappings.item(i);
 
-            String pattern = (String) XMLUtils.xpath(
-                node, "@pattern", XPathConstants.STRING);
+            String from              = node.getAttribute("from");
+            String to                = node.getAttribute("to");
+            String pattern           = node.getAttribute("pattern");
+            String masterAttrPattern = node.getAttribute("masterAttr");
+            String outputPattern     = node.getAttribute("output");
 
-            String masterAttrPattern = (String) XMLUtils.xpath(
-                node, "@masterAttr", XPathConstants.STRING);
-
-            String outputPattern = (String) XMLUtils.xpath(
-                node, "@output", XPathConstants.STRING);
-
-            if (from != null && to != null) {
+            if (from.length() > 0 && to.length() > 0) {
                 List<ThemeMapping> tm = mapping.get(from);
 
                 if (tm == null) {
@@ -408,5 +427,31 @@
 
         context.put(FLYSContext.RIVER_WMS, riverWMS);
     }
+
+
+    /**
+     * This method initializes the modules configuration.
+     *
+     * @param config the config document.
+     * @param context the FLYSContext.
+     */
+    protected void configureModules(Document cfg, FLYSContext context) {
+        NodeList modulenodes = (NodeList) XMLUtils.xpath(
+            cfg, XPATH_MODULES, XPathConstants.NODESET);
+
+        int num = modulenodes != null ? modulenodes.getLength() : 0;
+        ArrayList<Module> modules = new ArrayList<Module>(num);
+
+        for (int i = 0; i < num; i++) {
+            Element e = (Element) modulenodes.item(i);
+            String modulename = e.getAttribute("name");
+            String attrselected = e.getAttribute("selected");
+            boolean selected = attrselected == null ? false :
+                attrselected.equalsIgnoreCase("true");
+            logger.debug("Loaded module " + modulename);
+            modules.add(new Module(modulename, selected));
+        }
+        context.put(FLYSContext.MODULES, modules);
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/DBConfig.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/DBConfig.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,7 +8,7 @@
 import org.apache.log4j.Logger;
 
 public class DBConfig
-{ 
+{
     private static Logger logger = Logger.getLogger(DBConfig.class);
 
      /**
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/Datacage.java	Fri Sep 28 12:15:52 2012 +0200
@@ -84,7 +84,7 @@
 
     protected SQLExecutor sqlExecutor;
 
-    public class InitialScan 
+    public class InitialScan
     implements   ArtifactDatabase.ArtifactLoadedCallback
     {
         protected LRUCache<String, Integer> users;
@@ -402,10 +402,10 @@
     }
 
     protected static final void setString(
-        PreparedStatement stmnt, 
+        PreparedStatement stmnt,
         int               index,
         Object            value
-    ) 
+    )
     throws SQLException
     {
         if (value == null) {
@@ -451,7 +451,6 @@
     }
 
     protected boolean cleanDatabase() {
-
         log.debug("cleanDatabase");
 
         boolean success = sqlExecutor.new Instance() {
@@ -482,7 +481,7 @@
     }
 
     public void createdArtifact(
-        Artifact      artifact, 
+        Artifact      artifact,
         Backend       backend,
         GlobalContext context
     ) {
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/DatacageBackendListener.java	Fri Sep 28 12:15:52 2012 +0200
@@ -14,6 +14,7 @@
 
 import org.w3c.dom.Document;
 
+/** Triggers Datacage to update db. */
 public class DatacageBackendListener
 implements   BackendListener
 {
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/Recommendations.java	Fri Sep 28 12:15:52 2012 +0200
@@ -35,6 +35,10 @@
 
 import de.intevation.flys.artifacts.datacage.templating.Builder;
 
+
+/**
+ * Also accessible as Singleton with getInstance().
+ */
 public class Recommendations
 {
     private static Logger log = Logger.getLogger(Recommendations.class);
@@ -115,7 +119,7 @@
     }
 
     protected static void artifactToParameters(
-        FLYSArtifact        artifact, 
+        FLYSArtifact        artifact,
         Map<String, Object> parameters
     ) {
         parameters.put("CURRENT-STATE-ID", artifact.getCurrentStateId());
@@ -140,6 +144,10 @@
         }
     }
 
+
+    /**
+     * Append recommendations to \param result.
+     */
     public void  recommend(
         FLYSArtifact        artifact,
         String              userId,
@@ -168,6 +176,10 @@
         recommend(parameters, userId, result);
     }
 
+
+    /**
+     * Append recommendations to \param result.
+     */
     public void recommend(
         Map<String, Object> parameters,
         String              userId,
@@ -218,6 +230,8 @@
         });
     }
 
+
+    /** Get singleton instance. */
     public static synchronized Recommendations getInstance() {
         if (INSTANCE == null) {
             INSTANCE = createRecommendations();
@@ -225,6 +239,7 @@
         return INSTANCE;
     }
 
+
     protected static Document loadTemplate(File file) throws IOException {
         InputStream in = null;
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/Builder.java	Fri Sep 28 12:15:52 2012 +0200
@@ -64,14 +64,14 @@
         }
 
         public NamedConnection(
-            String     name, 
+            String     name,
             Connection connection
         ) {
             this(name, connection, true);
         }
 
         public NamedConnection(
-            String     name, 
+            String     name,
             Connection connection,
             boolean    cached
         ) {
@@ -209,7 +209,7 @@
         /**
          * Kind of foreach over results of a statement within a context.
          */
-        protected void elements(Node parent, Element current) 
+        protected void elements(Node parent, Element current)
         throws SQLException
         {
             log.debug("dc:elements");
@@ -290,7 +290,7 @@
 
         /**
          * Add attribute to an element
-         * @see element
+         * @see Element
          */
         protected void attribute(Node parent, Element current) {
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java	Fri Sep 28 12:15:52 2012 +0200
@@ -107,7 +107,7 @@
         protected ResultData executeUncached(
             Connection  connection,
             StackFrames frames
-        ) 
+        )
         throws SQLException
         {
             log.debug("executeUncached");
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,4 +1,4 @@
-package de.intevation.flys.geom;
+package de.intevation.flys.artifacts.geom;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -13,6 +13,9 @@
 
 import gnu.trove.TDoubleArrayList;
 
+/**
+ * Utility to create lines (intersect water with cross-section etc).
+ */
 public class Lines
 {
     private static Logger log = Logger.getLogger(Lines.class);
@@ -21,10 +24,63 @@
 
     public static enum Mode { UNDEF, WET, DRY };
 
+
+    /** Never instantiate Lines, use static functions instead. */
     protected Lines() {
     }
 
-    public static List<Line2D> fillWater(List<Point2D> points, double waterLevel) {
+
+    /**
+     * Calculate area of polygon with four vertices.
+     * @return area of polygon with four vertices.
+     */
+    public static double area(Point2D p1, Point2D p2, Point2D p3, Point2D p4) {
+        double[] x = new double[] {p1.getX(), p2.getX(), p3.getX(), p4.getX(), p1.getX() };
+        double[] y = new double[] {p1.getY(), p2.getY(), p3.getY(), p4.getY(), p1.getY() };
+        double area = 0d;
+        for (int i=0; i <4; i++) {
+            area += (x[i] * y[i+1]) - (x[i+1] * y[i]);
+        }
+        return Math.abs(area * 0.5d);
+    }
+
+
+    /**
+     * Calculate the 'length' of the given lines.
+     * @param lines lines of which to calculate length.
+     */
+    public static double length(List<Line2D> lines) {
+        double sum = 0d;
+        for (Line2D line: lines) {
+            double xDiff = line.getX1() - line.getX2();
+            double yDiff = line.getY1() - line.getY2();
+            sum += Math.sqrt(xDiff*xDiff + yDiff*yDiff);
+        }
+        return sum;
+    }
+
+
+    /** List of lines and a double-precision area. */
+    private static class ListWithArea {
+        public List<Line2D> lines;
+        public double area;
+        public ListWithArea(List<Line2D> lines, double area) {
+            this.lines = lines;
+            this.area = area;
+        }
+    }
+
+
+    /**
+     * For a cross section given as points and a waterlevel (in meters),
+     * create a set of lines that represent the water surface, assuming it
+     * is distributed horizontally equally.
+     * @param points the points describing the river bed.
+     * @param waterLevel the height of the horizontal water line.
+     * @return A list of Lines representing the water surface and the
+     *         calculated area between water surface and river bed.
+     */
+    public static ListWithArea fillWater(List<Point2D> points, double waterLevel) {
 
         boolean debug = log.isDebugEnabled();
 
@@ -38,18 +94,19 @@
         int N = points.size();
 
         if (N == 0) {
-            return result;
+            return new ListWithArea(result, 0d);
         }
 
         if (N == 1) {
             Point2D p = points.get(0);
-            // Only generate point if over water
+            // Only generate point if over profile
             if (waterLevel > p.getY()) {
                 result.add(new Line2D.Double(
                     p.getX(), waterLevel,
                     p.getX(), waterLevel));
             }
-            return result;
+            // TODO continue calculating area.
+            return new ListWithArea(result, 0d);
         }
 
         double minX =  Double.MAX_VALUE;
@@ -69,19 +126,22 @@
 
         if (minY > waterLevel) { // profile completely over water level
             log.debug("complete over water");
-            return result;
+            return new ListWithArea(result, 0d);
         }
 
         if (waterLevel > maxY) { // water floods profile
             log.debug("complete under water");
             result.add(new Line2D.Double(minX, waterLevel, maxX, waterLevel));
-            return result;
+            return new ListWithArea(result, 0d);
         }
 
+        // Water is sometimes above, sometimes under profile.
         Mode mode = Mode.UNDEF;
 
         double startX = minX;
 
+        double area = 0d;
+        // Walking along the profile.
         for (int i = 1; i < N; ++i) {
             Point2D p1 = points.get(i-1);
             Point2D p2 = points.get(i);
@@ -95,9 +155,13 @@
                     startX = p1.getX();
                     mode = Mode.WET;
                 }
+                area += area(p1, p2,
+                    new Point2D.Double(p2.getX(), waterLevel),
+                    new Point2D.Double(p1.getX(), waterLevel));
                 continue;
             }
 
+            // TODO trigger area calculation
             if (p1.getY() > waterLevel && p2.getY() > waterLevel) {
                 if (debug) {
                     log.debug("over water: " + p1 + " " + p2);
@@ -113,6 +177,7 @@
                 continue;
             }
 
+            // TODO trigger area calculation
             if (Math.abs(p1.getX() - p2.getX()) < EPSILON) {
                 // vertical line
                 switch (mode) {
@@ -146,6 +211,7 @@
             boolean p1W = Math.abs(waterLevel - p1.getY()) < EPSILON;
             boolean p2W = Math.abs(waterLevel - p2.getY()) < EPSILON;
 
+            // TODO trigger area calculation
             if (p1W || p2W) {
                 if (debug) {
                     log.debug("water hits vertex: " + p1 + " " + p2 + " " + mode);
@@ -174,6 +240,9 @@
                             startX = p1.getX();
                             mode = Mode.WET;
                         }
+                        area += area(p1, p2,
+                            new Point2D.Double(p2.getX(), waterLevel),
+                            new Point2D.Double(p2.getX(), waterLevel));
                     }
                 }
                 else { // p2 == waterlevel
@@ -191,6 +260,9 @@
                                 p2.getX(), waterLevel));
                         }
                         mode = Mode.DRY;
+                        area += area(p1, p2,
+                            new Point2D.Double(p1.getX(), waterLevel),
+                            new Point2D.Double(p1.getX(), waterLevel));
                     }
                 }
                 if (debug) {
@@ -199,6 +271,7 @@
                 continue;
             }
 
+            // TODO trigger area calculation
             // intersection case
             double x = Linear.linear(
                 waterLevel,
@@ -211,6 +284,20 @@
                 log.debug("intersection at x: " + x);
             }
 
+            // Add area of that part of intersection that is 'wet'.
+            if (p1.getY() > waterLevel) {
+                area += area(new Point2D.Double(x, waterLevel),
+                             p2,
+                             new Point2D.Double(p2.getX(), waterLevel),
+                             new Point2D.Double(x, waterLevel));
+            }
+            else {
+                area += area(new Point2D.Double(x, waterLevel),
+                             p1,
+                             new Point2D.Double(p1.getX(), waterLevel),
+                             new Point2D.Double(x, waterLevel));
+            }
+
             switch (mode) {
                 case WET:
                     log.debug("intersect/wet");
@@ -248,33 +335,69 @@
                 maxX, waterLevel));
         }
 
-        return result;
+        return new ListWithArea(result, area);
     }
 
-    public static double [][] createWaterLines(
+
+    /**
+     * Class holding points that form lines and the calculated length.
+     */
+    public static class LineData {
+        public double [][] points;
+        public double width;
+        public double area;
+        public LineData(double[][] points, double width, double area) {
+            this.points = points;
+            this.width = width;
+            this.area = area;
+        }
+    }
+
+
+    /** Return length of a single line. */
+    public static double lineLength(Line2D line) {
+        double xDiff = line.getX1() - line.getX2();
+        double yDiff = line.getY1() - line.getY2();
+        return Math.sqrt(xDiff*xDiff + yDiff*yDiff);
+    }
+
+
+    /**
+     * @param points the riverbed.
+     */
+    public static LineData createWaterLines(
         List<Point2D> points,
         double        waterlevel
     ) {
-        List<Line2D> lines = fillWater(points, waterlevel);
+        ListWithArea listAndArea = fillWater(points, waterlevel);
+        List<Line2D> lines = listAndArea.lines;
 
         TDoubleArrayList lxs = new TDoubleArrayList();
         TDoubleArrayList lys = new TDoubleArrayList();
+        double linesLength = 0.0f;
 
         for (Iterator<Line2D> iter = lines.iterator(); iter.hasNext();) {
-            Line2D  l  = iter.next();
-            Point2D p1 = l.getP1();
-            Point2D p2 = l.getP2();
+            Line2D  line = iter.next();
+            Point2D p1   = line.getP1();
+            Point2D p2   = line.getP2();
             lxs.add(p1.getX());
             lys.add(p1.getY());
             lxs.add(p2.getX());
             lys.add(p2.getY());
+
+            // Length calculation.
+            linesLength += lineLength(line);
+
             if (iter.hasNext()) {
                 lxs.add(Double.NaN);
                 lys.add(Double.NaN);
             }
         }
 
-        return new double [][] { lxs.toNativeArray(), lys.toNativeArray() };
+        return new LineData(
+            new double [][] { lxs.toNativeArray(), lys.toNativeArray() },
+            linesLength, listAndArea.area
+            );
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Polygon2D.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,430 +0,0 @@
-package de.intevation.flys.geom;
-
-import java.io.Serializable;
-
-import java.awt.Shape;
-
-import java.awt.geom.Path2D;
-import java.awt.geom.Point2D;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Collections;
-
-import de.intevation.flys.artifacts.math.Linear;
-
-import static de.intevation.flys.geom.VectorUtils.X;
-import static de.intevation.flys.geom.VectorUtils.Y;
-import static de.intevation.flys.geom.VectorUtils.EPSILON;
-
-public class Polygon2D
-implements   Serializable
-{
-    public static final Comparator<Point2D> POINT_X_CMP =
-        new Comparator<Point2D>() {
-            public int compare(Point2D a, Point2D b) {
-                double d = X(a) - X(b);
-                if (d < 0d) return -1;
-                return d > 0d ? + 1 : 0;
-            }
-        };
-
-    public static final Comparator<Point2D []> FIRST_POINT_X =
-        new Comparator<Point2D []>() {
-            public int compare(Point2D [] a, Point2D [] b) {
-                if (a.length == 0) return -1; // should not happen.
-                if (b.length == 0) return +1; // should not happen.
-                double d = X(a[0]) - Y(b[0]);
-                if (d < 0d) return -1;
-                return d > 0d ? + 1 : 0;
-            }
-        };
-
-    protected List<Point2D> points;
-
-    public Polygon2D() {
-        points = new ArrayList<Point2D>();
-    }
-
-    public Polygon2D(List<Point2D> points) {
-        this.points = points;
-    }
-
-    public void add(double x, double y) {
-        points.add(new Point2D.Double(x, y));
-    }
-
-    protected static boolean addCheck(Point2D p, List<Point2D> points) {
-        switch (points.size()) {
-            case 0:
-                points.add(p);
-                return true;
-            case 1:
-                if (VectorUtils.epsilonEquals(points.get(0), p)) {
-                    return false;
-                }
-                points.add(p);
-                return true;
-            default:
-                int L = points.size()-1;
-                Point2D last = points.get(L);
-                if (VectorUtils.epsilonEquals(last, p)) {
-                    return false;
-                }
-                Point2D before = points.get(L-1);
-                if (VectorUtils.collinear(before, last, p)) {
-                    points.set(L, p);
-                }
-                else {
-                    points.add(p);
-                }
-                return true;
-        }
-    }
-
-    public boolean addCheck(Point2D p) {
-        return addCheck(p, points);
-    }
-
-    public void addReversed(List<Point2D> other) {
-        for (int i = other.size()-1; i >= 0; --i) {
-            addCheck(other.get(i));
-        }
-    }
-
-    public double area() {
-        double area = 0d;
-
-		for (int i = 0, N = points.size(); i < N; ++i) {
-			int j = (i + 1) % N;
-            Point2D pi = points.get(i);
-            Point2D pj = points.get(j);
-			area += X(pi)*Y(pj);
-			area -= X(pj)*Y(pi);
-		}
-
-        return 0.5d*area;
-    }
-
-    public Shape toShape() {
-        Path2D.Double path = new Path2D.Double();
-
-        int N = points.size();
-
-        if (N > 0) {
-            Point2D p = points.get(0);
-            path.moveTo(X(p), Y(p));
-            for (int i = 1; i < N; ++i) {
-                p = points.get(i);
-                path.lineTo(X(p), Y(p));
-            }
-            path.closePath();
-        }
-
-        return path;
-    }
-
-    protected static List<Point2D []> splitByNaNs(
-        double [] xs,
-        double [] ys
-    ) {
-        List<Point2D []> parts = new ArrayList<Point2D []>();
-
-        List<Point2D> tmp = new ArrayList<Point2D>(xs.length);
-
-        for (int i = 0; i < xs.length; ++i) {
-            double x = xs[i];
-            double y = ys[i];
-
-            if (Double.isNaN(x) || Double.isNaN(y)) {
-                if (!tmp.isEmpty()) {
-                    Point2D [] part = new Point2D[tmp.size()];
-                    parts.add(tmp.toArray(part));
-                    tmp.clear();
-                }
-            }
-            else {
-                tmp.add(new Point2D.Double(x, y));
-            }
-        }
-
-        if (!tmp.isEmpty()) {
-            Point2D [] part = new Point2D[tmp.size()];
-            parts.add(tmp.toArray(part));
-        }
-
-        return parts;
-    }
-
-    protected static boolean removeNoneIntersecting(
-        List<Point2D []> As,
-        List<Point2D []> Bs
-    ) {
-        int B = Bs.size()-1;
-        OUTER: for (int i = 0; i < As.size();) {
-            Point2D [] a = As.get(i);
-            int lo = 0, hi = B;
-            while (lo <= hi) {
-                int mid = (lo + hi) >> 1;
-                Point2D [] b = Bs.get(mid);
-                     if (X(a[0]) > X(b[b.length-1])) lo = mid+1;
-                else if (X(a[a.length-1]) < X(b[0])) hi = mid-1;
-                else {
-                    // found: keep
-                    ++i;
-                    continue OUTER;
-                }
-            }
-            // not found: remove
-            As.remove(i);
-        }
-
-        return As.isEmpty();
-    }
-
-    protected static void buildPolygons(
-        Point2D []      as,
-        Point2D []      bs,
-        Point2D [][]    rest,
-        List<Polygon2D> positives,
-        List<Polygon2D> negatives
-    ) {
-        List<Point2D> apoints = new ArrayList<Point2D>();
-        List<Point2D> bpoints = new ArrayList<Point2D>();
-
-        double ax = X(as[0]);
-        double bx = X(bs[0]);
-
-        int ai = 1;
-        int bi = 1;
-
-        boolean intersect = false;
-
-        if (ax == bx) {
-            apoints.add(as[0]);
-            bpoints.add(bs[0]);
-        }
-        else if (ax > bx) {
-            apoints.add(as[0]);
-            double bx1;
-            while ((bx1 = X(bs[bi])) < ax) ++bi;
-            if (bx1 == ax) {
-                bpoints.add(bs[bi]);
-            }
-            else { // need to calculate start b point.
-                intersect = true;
-                double by1 = Linear.linear(
-                    ax,
-                    X(bs[bi-1]), bx1,
-                    Y(bs[bi-1]), Y(bs[bi]));
-
-                bpoints.add(new Point2D.Double(ax, by1));
-            }
-        }
-        else { // bx > ax: Symmetric case
-            bpoints.add(bs[0]);
-            double ax1;
-            while ((ax1 = X(as[ai])) < bx) ++ai;
-            if (ax1 == bx) {
-                apoints.add(as[ai]);
-            }
-            else { // need to calculate start b point.
-                intersect = true;
-                double ay1 = Linear.linear(
-                    bx,
-                    X(as[ai-1]), ax1,
-                    Y(as[ai-1]), Y(as[ai]));
-
-                apoints.add(new Point2D.Double(bx, ay1));
-            }
-        }
-
-        // now we have a point in each list, decide if neg/pos.
-        boolean neg = Y(bpoints.get(0)) > Y(apoints.get(0));
-
-        // Continue with inner points
-
-        Line line = new Line();
-
-        while (ai < as.length && bi < bs.length) {
-            double xan = X(as[ai]);
-            double xbn = X(bs[bi]);
-            if (xan == xbn) { 
-                double yan = Y(as[ai]);
-                double ybn = Y(bs[ai]);
-
-                if (neg) {
-                    if (yan > ybn) { // intersection
-                        Point2D ip = VectorUtils.intersection(
-                            apoints.get(apoints.size()-1), as[ai],
-                            bpoints.get(bpoints.size()-1), bs[bi]);
-                        addCheck(ip, apoints);
-                        addCheck(ip, bpoints);
-                        Polygon2D p = new Polygon2D(
-                            new ArrayList<Point2D>(apoints));
-                        p.addReversed(bpoints);
-                        negatives.add(p);
-                        apoints.clear();
-                        bpoints.clear();
-                        apoints.add(ip);
-                        bpoints.add(ip);
-                        neg = !neg;
-                    }
-                    else { // no intersection
-                        addCheck(as[ai], apoints);
-                        addCheck(bs[bi], bpoints);
-                    }
-                }
-                else { // not neg
-                    if (ybn > yan) { // intersection
-                        Point2D ip = VectorUtils.intersection(
-                            apoints.get(apoints.size()-1), as[ai],
-                            bpoints.get(bpoints.size()-1), bs[bi]);
-                        addCheck(ip, apoints);
-                        addCheck(ip, bpoints);
-                        Polygon2D p = new Polygon2D(
-                            new ArrayList<Point2D>(apoints));
-                        p.addReversed(bpoints);
-                        positives.add(p);
-                        apoints.clear();
-                        bpoints.clear();
-                        apoints.add(ip);
-                        bpoints.add(ip);
-                        neg = !neg;
-                    }
-                    else { // no intersection
-                        addCheck(as[ai], apoints);
-                        addCheck(bs[bi], bpoints);
-                    }
-                }
-                ++ai;
-                ++bi;
-            }
-            else if (xan > xbn) {
-                line.set(apoints.get(apoints.size()-1), as[ai]);
-                double dir = neg ? -1d: 1d; // XXX: correct sign?
-                while  (bi < bs.length 
-                    && X(bs[bi]) < xan
-                    && line.eval(bs[bi])*dir > EPSILON) 
-                    ++bi;
-                if (bi == bs.length) {
-                    // b run out of points
-                    // calculate Y(last_a, as[ai]) for X(bs[bi-1])
-                    double ay1 = Linear.linear(
-                        X(bs[bi-1]),
-                        X(apoints.get(apoints.size()-1)), X(as[ai]),
-                        Y(apoints.get(apoints.size()-1)), Y(as[ai]));
-                    addCheck(new Point2D.Double(X(bs[bi-1]), ay1), apoints);
-                    addCheck(bs[bi-1], bpoints);
-                    Polygon2D p = new Polygon2D(
-                        new ArrayList<Point2D>(apoints));
-                    p.addReversed(bpoints);
-                    apoints.clear();
-                    bpoints.clear();
-                    (neg ? negatives : positives).add(p);
-                    break;
-                }
-                else {
-                    // TODO: intersect line and/or X(bs[bi]) >= xan?
-                }
-            }
-            else { // xbn > xan
-                line.set(bpoints.get(bpoints.size()-1), bs[bi]);
-                // TODO: continue symmetric
-            }
-        }
-
-        // TODO: Continue with closing segment
-    }
-
-    public static final class Line {
-
-        private double a;
-        private double b;
-        private double c;
-
-        public Line() {
-        }
-
-        public Line(Point2D p1, Point2D p2) {
-            set(p1, p2);
-        }
-
-        public void set(Point2D p1, Point2D p2) {
-            Point2D p3 = 
-                VectorUtils.normalize(
-                VectorUtils.sub(p1, p2));
-
-            Point2D n = VectorUtils.ortho(p3);
-
-            a = X(n);
-            b = Y(n);
-
-            // a*x + b*y + c = 0
-            // c = -a*x -b*y
-
-            c = -a*X(p1) - b*Y(p1);
-        }
-
-        public double eval(Point2D p) {
-            return a*X(p) + b*Y(p) + c;
-        }
-    }
-
-    public static void createPolygons(
-        double [] xAs, double [] yAs,
-        double [] xBs, double [] yBs,
-        List<Polygon2D> positives,
-        List<Polygon2D> negatives
-    ) {
-        if (xAs.length == 0 || xBs.length == 0) {
-            return;
-        }
-
-        List<Point2D []> splAs = splitByNaNs(xAs, yAs);
-        List<Point2D []> splBs = splitByNaNs(xBs, yBs);
-
-        // They feeded us with NaNs only.
-        if (splAs.isEmpty() || splBs.isEmpty()) {
-            return;
-        }
-
-        // Sort each part by x to ensure that the first
-        // is the smallest.
-        for (Point2D [] splA: splAs) {
-            Arrays.sort(splA, POINT_X_CMP);
-        }
-
-        for (Point2D [] splB: splBs) {
-            Arrays.sort(splB, POINT_X_CMP);
-        }
-
-        // Now sort all parts by there first elements.
-        // Should be good enough to find overlapping regions.
-        Collections.sort(splAs, FIRST_POINT_X);
-        Collections.sort(splBs, FIRST_POINT_X);
-
-        // Check if the two series intersect at all.
-        // If no then there will be no area between them.
-
-        Point2D [] p1 = splAs.get(0);
-        Point2D [] p2 = splBs.get(splBs.size()-1);
-
-        // Sort out the ranges that are not intersecting
-        // the ranges in the other series.
-        // We are going to merge them anyway
-        // so this is not strictly required. 
-        // Keep it to recude cases.
-        if (removeNoneIntersecting(splAs, splBs)
-        ||  removeNoneIntersecting(splBs, splAs)
-        ) {
-            // They do not intersect at all.
-            return;
-        }
-
-        // TODO: Intersect/split the two series parts.
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/VectorUtils.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-package de.intevation.flys.geom;
-
-import java.awt.geom.Point2D;
-
-public final class VectorUtils
-{
-    public static final double EPSILON = 1e-4;
-
-    private VectorUtils() {
-    }
-
-    public static final double X(Point2D p) {
-        return p.getX();
-    }
-
-    public static final double Y(Point2D p) {
-        return p.getY();
-    }
-
-    public static final Point2D sub(Point2D a, Point2D b) {
-        return new Point2D.Double(X(a)-X(b), Y(a)-Y(b));
-    }
-
-    public static final double dot(Point2D a, Point2D b) {
-        return X(a)*X(b) + Y(a)*Y(b);
-    }
-
-    public static final Point2D add(Point2D a, Point2D b) {
-        return new Point2D.Double(X(a)+X(b), Y(a)+Y(b));
-    }
-
-    public static final Point2D negate(Point2D a) {
-        return new Point2D.Double(-X(a), -Y(a));
-    }
-
-    public static final Point2D ortho(Point2D a) {
-        return new Point2D.Double(-Y(a), X(a));
-    }
-
-    public static final Point2D scale(Point2D a, double s) {
-        return new Point2D.Double(s*X(a), s*Y(a));
-    }
-
-    public static final double lengthSq(Point2D a) {
-        double x = X(a);
-        double y = Y(a);
-        return x*x + y*y;
-    }
-
-    public static final double length(Point2D a) {
-        return Math.sqrt(lengthSq(a));
-    }
-
-    public static final Point2D normalize(Point2D a) {
-        double length = length(a);
-        return length != 0d
-            ? scale(a, 1d/length) 
-            : new Point2D.Double(X(a), Y(a));
-    }
-
-    public static final double L1(Point2D a, Point2D b) {
-        return Math.abs(X(a)-X(b)) + Math.abs(Y(a)-Y(b));
-    }
-
-    public static final boolean collinear(Point2D a, Point2D b, Point2D c) {
-        double x1 = X(a);
-        double y1 = Y(a);
-        double x2 = X(b);
-        double y2 = Y(b);
-        double x3 = X(c);
-        double y3 = Y(c);
-
-        return Math.abs((x2-x1)*(y3-y1)-(y2-y1)*(x3-x1)) < EPSILON;
-    }
-
-    public static boolean epsilonEquals(Point2D a, Point2D b) {
-        return Math.abs(X(a)-X(b)) < EPSILON 
-            && Math.abs(Y(a)-Y(b)) < EPSILON;
-    }
-
-    public static final Point2D intersection(
-        Point2D p1, Point2D p2,
-        Point2D p3, Point2D p4
-    ) {
-        double x1 = X(p1);
-        double y1 = Y(p1);
-        double x2 = X(p2);
-        double y2 = Y(p2);
-        double x3 = X(p3);
-        double y3 = Y(p3);
-        double x4 = X(p4);
-        double y4 = Y(p4);
-
-        // Compute a1, b1, c1, where line joining points 1 and 2
-        // is "a1 x + b1 y + c1 = 0".
-        double a1 = y2 - y1;
-        double b1 = x1 - x2;
-        double c1 = x2*y1 - x1*y2;
-
-        // Compute r3 and r4.
-        double r3 = a1*x3 + b1*y3 + c1;
-        double r4 = a1*x4 + b1*y4 + c1;
-
-        if (r3 != 0d && r4 != 0d && r3*r4 >= 0) {
-            return null;
-        }
-
-        // Compute a2, b2, c2
-        double a2 = y4 - y3;
-        double b2 = x3 - x4;
-        double c2 = (x4 * y3) - (x3 * y4);
-
-        // Compute r1 and r2
-        double r1 = a2*x1 + b2*y1 + c2;
-        double r2 = a2*x2 + b2*y2 + c2;
-
-        if (r1 != 0d && r2 != 0d && r1*r2 >= 0) {
-            return null;
-        }
-
-        // Line segments intersect: compute intersection point.
-        double denom = a1*b2 - a2*b1;
-
-        if (denom == 0d) { // collinear
-            return null;
-        }
-
-        double offset = Math.abs(denom)/2d;
-
-        // The denom/2 is to get rounding instead of truncating. It
-        // is added or subtracted to the numerator, depending upon the
-        // sign of the numerator.
-        double num = b1*c2 - b2*c1;
-
-        double x = num < 0d
-            ? (num - offset)/denom
-            : (num + offset)/denom;
-
-        num = a2*c1 - a1*c2;
-
-        double y = num < 0d
-            ? (num - offset)/denom
-            : (num + offset)/denom;
-
-        return new Point2D.Double(x, y);
-    }
-
-}
-// 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/map/PrintMap.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,131 @@
+package de.intevation.flys.artifacts.map;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+import java.util.List;
+
+import java.net.URL;
+import java.net.MalformedURLException;
+
+import javax.imageio.ImageIO;
+
+
+import org.geotools.data.ows.Layer;
+import org.geotools.data.ows.WMSCapabilities;
+import org.geotools.data.wms.WebMapServer;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.map.MapContext;
+import org.geotools.map.WMSMapLayer;
+import org.geotools.ows.ServiceException;
+import org.geotools.renderer.lite.StreamingRenderer;
+import org.geotools.renderer.GTRenderer;
+
+
+public class PrintMap {
+
+    public static final String DEFAULT_WMS = "http://map1.naturschutz.rlp.de/service_lanis/mod_wms/wms_getmap.php?mapfile=group_gdide&REQUEST=GetCapabilities&SERVICE=WMS";
+    public static final String DEFAULT_OUTFILE = "~/map.jpeg";
+
+    public static final String MAPSERVER = System.getProperty("wms", DEFAULT_WMS);
+    public static final String MAP_IMAGE = System.getProperty("outfile", DEFAULT_OUTFILE);
+
+
+    public static void main(String[] args) {
+        System.out.println("-> start PrintMap");
+        System.out.println("  -> Print layers of WMS: " + MAPSERVER);
+
+        try {
+            WebMapServer    server = getMapserver();
+            WMSMapLayer[] wmsLayer = getWMSLayers(server);
+
+            MapContext mapcontent = new MapContext( wmsLayer );
+            mapcontent.setTitle(" NEW MAP CONTENT TITLE ");
+
+            printMap(mapcontent);
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        System.out.println("-> finished PrintMap");
+    }
+
+
+    public static void printMap(MapContext map) throws Exception {
+        int imageWidth = 600;
+
+        GTRenderer renderer = new StreamingRenderer();
+        renderer.setContext(map);
+
+        Rectangle imageBounds = null;
+        ReferencedEnvelope mapBounds = null;
+
+        try {
+            mapBounds = map.getLayerBounds();
+            double heightToWidth = mapBounds.getSpan(1) / mapBounds.getSpan(0);
+            imageBounds = new Rectangle(
+                0, 0,
+                imageWidth,
+                (int) Math.round(imageWidth * heightToWidth));
+
+        }
+        catch (Exception e) {
+            // failed to access map layers
+            throw new RuntimeException(e);
+        }
+
+        BufferedImage image = new BufferedImage(imageBounds.width, imageBounds.height, BufferedImage.TYPE_INT_RGB);
+        Graphics2D gr = image.createGraphics();
+        gr.setPaint(Color.WHITE);
+        gr.fill(imageBounds);
+
+        try {
+            renderer.paint(gr, imageBounds, mapBounds);
+            File fileToSave = new File(MAP_IMAGE);
+            ImageIO.write(image, "jpeg", fileToSave);
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    public static WebMapServer getMapserver() throws MalformedURLException, IOException, ServiceException {
+        return new WebMapServer(getServerUrl());
+    }
+
+
+    public static URL getServerUrl() throws MalformedURLException {
+        return new URL(MAPSERVER);
+    }
+
+
+    public static WMSMapLayer[] getWMSLayers(WebMapServer server) {
+        if (server == null) {
+            System.out.println("WebMapServer == null");
+            throw new RuntimeException("WebMapServer == null");
+        }
+
+        WMSCapabilities capabilities = server.getCapabilities();
+
+        List<Layer> layers = capabilities.getLayerList();
+        WMSMapLayer[] wmslayers = new WMSMapLayer[layers.size()];
+
+        for (int i = 0, L = layers.size(); i < L; i++) {
+            Layer l = layers.get(i);
+
+            System.out.println("   -> add layer: " + l);
+            wmslayers[i] = new WMSMapLayer(server, l);
+        }
+
+        return wmslayers;
+    }
+}
+// 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/math/AddScaleFunction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,19 @@
+package de.intevation.flys.artifacts.math;
+
+public class AddScaleFunction
+implements   Function
+{
+    protected double b;
+    protected double m;
+
+    public AddScaleFunction(double b, double m) {
+        this.b = b;
+        this.m = m;
+    }
+
+    @Override
+    public double value(double x) {
+        return (x + b)*m;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/BackJumpCorrector.java	Fri Sep 28 12:15:52 2012 +0200
@@ -154,8 +154,7 @@
                 spline = interpolator.interpolate(x, y);
             }
             catch (MathIllegalArgumentException miae) {
-                // TODO: I18N
-                errors.addProblem("creating spline interpolation failed.");
+                errors.addProblem("spline.creation.failed");
                 log.error(miae);
                 continue;
             }
@@ -179,8 +178,7 @@
                 }
             }
             catch (ArgumentOutsideDomainException aode) {
-                // TODO: I18N
-                errors.addProblem("spline interpolation failed.");
+                errors.addProblem("spline.interpolation.failed");
                 log.error("spline interpolation failed", aode);
             }
         } // for all km
@@ -190,8 +188,8 @@
 
 
     protected static double aboveWaterKM(
-        double [] km, 
-        double [] ws, 
+        double [] km,
+        double [] ws,
         int       wIndex
     ) {
         double w = ws[wIndex];
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/DifferenceCurveFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-package de.intevation.flys.artifacts.model;
-
-import org.apache.log4j.Logger;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.CallContext;
-
-import de.intevation.artifactdatabase.state.Facet;
-
-import de.intevation.flys.artifacts.WINFOArtifact;
-
-import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
-
-
-/**
- * Facet with the curve of a subtraction of two waterlevel-lines.
- */
-public class DifferenceCurveFacet extends WaterlevelFacet {
-
-    private static Logger logger = Logger.getLogger(DifferenceCurveFacet.class);
-
-
-    public DifferenceCurveFacet() {
-    }
-
-    public DifferenceCurveFacet(
-        int         index,
-        String      name,
-        String      description,
-        ComputeType type,
-        String      stateID,
-        String      hash
-
-    ) {
-        super(index, name, description, type, stateID, hash);
-    }
-
-    /**
-     * Get difference curve data.
-     * @return a WKms at given index.
-     */
-    @Override
-    public Object getData(Artifact artifact, CallContext context) {
-        WINFOArtifact winfo = (WINFOArtifact)artifact;
-
-        CalculationResult res = (CalculationResult)
-            winfo.compute(context, hash, stateID, type, false);
-
-        WKms [] wkms = (WKms [])res.getData();
-
-        WKms result = wkms[index];
-        logger.debug("Got difference curve data (" + result.getName() 
-            + ") at index: " + index);
-
-        return result;
-    }
-
-
-    /** Copy deeply. */
-    @Override
-    public Facet deepCopy() {
-        WaterlevelFacet copy = new DifferenceCurveFacet();
-        copy.set(this);
-        copy.type    = type;
-        copy.stateID = stateID;
-        copy.hash    = hash;
-        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/math/Distance.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.artifacts.math;
+
+/** Helper to calculate distance(s). */
+public final class Distance {
+    /** Return distance between two values. */
+    public static double distance(double a, double b) {
+        return Math.abs(a - b);
+    }
+
+    /** Return whether a and be are within a certain distance. */
+    public static boolean within(double a, double b, double threshold) {
+        return distance(a, b) <= threshold;
+    }
+}
+// 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/math/FilterFunction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,16 @@
+package de.intevation.flys.artifacts.math;
+
+public class FilterFunction implements Function {
+
+    protected Function parent;
+
+    public FilterFunction(Function parent) {
+        this.parent = parent;
+    }
+
+    @Override
+    public double value(double x) {
+        return parent.value(x);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/Linear.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/Linear.java	Fri Sep 28 12:15:52 2012 +0200
@@ -64,5 +64,15 @@
         //return (1.0-factor)*a + factor*b;
         return a + factor*(b-a);
     }
+
+    public static final void weight(
+        double factor,
+        double [] a, double [] b, double [] c
+    ) {
+        int N = Math.min(Math.min(a.length, b.length), c.length);
+        for (int i = 0; i < N; ++i) {
+            c[i] = weight(factor, a[i], b[i]);
+        }
+    }
 }
 // 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/math/LinearFilterFunction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,24 @@
+package de.intevation.flys.artifacts.math;
+
+public class LinearFilterFunction
+extends      FilterFunction
+{
+    protected double m;
+    protected double b;
+
+    public LinearFilterFunction(double m, double b) {
+        this(Identity.IDENTITY, m, b);
+    }
+
+    public LinearFilterFunction(Function parent, double m, double b) {
+        super(parent);
+        this.m = m;
+        this.b = b;
+    }
+
+    @Override
+    public double value(double x) {
+        return super.value(x)*m + b;
+    }
+}
+// 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/math/LinearFunction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,19 @@
+package de.intevation.flys.artifacts.math;
+
+public class LinearFunction
+implements   Function
+{
+    protected double m;
+    protected double b;
+
+    public LinearFunction(double m, double b) {
+        this.m = m;
+        this.b = b;
+    }
+
+    @Override
+    public double value(double x) {
+        return x*m + b;
+    }
+}
+// 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/math/NaNFunction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,16 @@
+package de.intevation.flys.artifacts.math;
+
+public final class NaNFunction
+implements         Function
+{
+    public static final Function INSTANCE = new NaNFunction();
+
+    private NaNFunction() {
+    }
+
+    @Override
+    public double value(double x) {
+        return Double.NaN;
+    }
+}
+// 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/math/Outlier.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,107 @@
+package de.intevation.flys.artifacts.math;
+
+import java.util.List;
+
+import org.apache.commons.math.MathException;
+
+import org.apache.commons.math.distribution.TDistributionImpl;
+
+import org.apache.commons.math.stat.descriptive.moment.Mean;
+import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
+
+import org.apache.log4j.Logger;
+
+public class Outlier
+{
+    public static final double EPSILON = 1e-5;
+
+    public static final double DEFAULT_ALPHA = 0.05;
+
+    private static Logger log = Logger.getLogger(Outlier.class);
+
+    protected Outlier() {
+    }
+
+    public static Integer findOutlier(List<Double> values) {
+        return findOutlier(values, DEFAULT_ALPHA);
+    }
+
+    public static Integer findOutlier(List<Double> values, double alpha) {
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("outliers significance: " + alpha);
+        }
+
+        alpha = 1d - alpha;
+
+        int N = values.size();
+
+        if (debug) {
+            log.debug("Values to check: " + N);
+        }
+
+        if (N < 3) {
+            return null;
+        }
+
+        Mean mean = new Mean();
+        StandardDeviation std = new StandardDeviation();
+
+        for (Double value: values) {
+            double v = value.doubleValue();
+            mean.increment(v);
+            std .increment(v);
+        }
+
+        double m = mean.getResult();
+        double s = std.getResult();
+
+        if (debug) {
+            log.debug("mean: " + m);
+            log.debug("std dev: " + s);
+        }
+
+        double maxZ = -Double.MAX_VALUE;
+        int iv = -1;
+        for (int i = N-1; i >= 0; --i) {
+            double v = values.get(i).doubleValue();
+            double z = Math.abs(v - m);
+            if (z > maxZ) {
+                maxZ = z;
+                iv = i;
+            }
+        }
+
+        if (Math.abs(s) < EPSILON) {
+            return null;
+        }
+
+        maxZ /= s;
+
+        TDistributionImpl tdist = new TDistributionImpl(N-2);
+
+        double t;
+
+        try {
+            t = tdist.inverseCumulativeProbability(alpha/(N+N));
+        }
+        catch (MathException me) {
+            log.error(me);
+            return null;
+        }
+
+        t *= t;
+
+        double za = ((N-1)/Math.sqrt(N))*Math.sqrt(t/(N-2d+t));
+
+        if (debug) {
+            log.debug("max: " + maxZ + " crit: " + za);
+        }
+
+        return maxZ > za
+            ? Integer.valueOf(iv)
+            : null;
+    }
+}
+// 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/math/Sub.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.artifacts.math;
+
+public final class Sub
+implements         Function
+{
+    private double s;
+
+    public Sub(double s) {
+        this.s = s;
+    }
+
+    @Override
+    public double value(double x) {
+        return x - s;
+    }
+}
+// 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/math/UnivariateRealFunctionFunction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,34 @@
+package de.intevation.flys.artifacts.math;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+
+public final class UnivariateRealFunctionFunction
+implements         Function
+{
+    private UnivariateRealFunction function;
+
+    public UnivariateRealFunctionFunction(UnivariateRealFunction function) {
+        this.function = function;
+    }
+
+    @Override
+    public double value(double x) {
+        try {
+            return function.value(x);
+        }
+        catch (FunctionEvaluationException fee) {
+            return Double.NaN;
+        }
+    }
+
+    public UnivariateRealFunction getFunction() {
+        return function;
+    }
+
+    public void setFunction(UnivariateRealFunction function) {
+        this.function = function;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/WKmsOperation.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/WKmsOperation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -9,7 +9,7 @@
 {
     public static final double EPSILON = 1e-6;
 
-    public static final class KmW 
+    public static final class KmW
     implements                Comparable<KmW>
     {
         protected double km;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/fitting/App.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,127 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+import java.util.List;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.TreeMap;
+import java.util.Comparator;
+
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.Reader;
+import java.io.InputStreamReader;
+
+import org.apache.commons.math.optimization.fitting.CurveFitter;
+
+import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer;
+
+import org.apache.commons.math.MathException;
+
+public class App
+{
+    public static final double EPS = 1e-5;
+
+    public static final String FUNCTION_NAME =
+        System.getProperty("function", "linear");
+
+    public static final Comparator<Double> EPS_CMP =
+        new Comparator<Double>()  {
+            @Override
+            public int compare(Double a, Double b) {
+                double diff = a - b;
+                if (diff < -EPS) return -1;
+                if (diff >  EPS) return +1;
+                return 0;
+            }
+        };
+
+    public static final List<Double []>readPoints(Reader reader)
+    throws IOException
+    {
+        Map<Double, Double> map = new TreeMap<Double, Double>(EPS_CMP);
+
+        BufferedReader input = new BufferedReader(reader);
+
+        String line;
+        while ((line = input.readLine()) != null) {
+            if ((line = line.trim()).length() == 0 || line.startsWith("#")) {
+                continue;
+            }
+
+            String [] parts = line.split("\\s+");
+
+            if (parts.length < 2) {
+                continue;
+            }
+
+            try {
+                Double x = Double.valueOf(parts[0]);
+                Double y = Double.valueOf(parts[1]);
+
+                Double old = map.put(x, y);
+
+                if (old != null) {
+                    System.err.println("duplicate x: " + x);
+                }
+            }
+            catch (NumberFormatException nfe) {
+                nfe.printStackTrace();
+            }
+        }
+
+        List<Double []> list = new ArrayList<Double []>(map.size());
+
+        for (Map.Entry<Double, Double> entry: map.entrySet()) {
+            list.add(new Double [] { entry.getKey(), entry.getValue() });
+        }
+
+        return list;
+    }
+
+    public static void main(String [] args) {
+
+        Function function = FunctionFactory
+            .getInstance()
+            .getFunction(FUNCTION_NAME);
+
+        if (function == null) {
+            System.err.println("Cannot find function '" + FUNCTION_NAME + "'.");
+            System.exit(1);
+        }
+
+        List<Double []> points = null;
+
+        try {
+            points = readPoints(new InputStreamReader(System.in));
+        }
+        catch (IOException ioe) {
+            ioe.printStackTrace();
+            System.exit(1);
+        }
+
+        LevenbergMarquardtOptimizer lmo = new LevenbergMarquardtOptimizer();
+
+        CurveFitter cf = new CurveFitter(lmo);
+
+        for (Double [] point: points) {
+            cf.addObservedPoint(point[0], point[1]);
+        }
+
+        double [] parameters = null;
+
+        try {
+            parameters = cf.fit(function, function.getInitialGuess());
+        }
+        catch (MathException me) {
+            me.printStackTrace();
+            System.exit(1);
+        }
+
+        String [] parameterNames = function.getParameterNames();
+
+        for (int i = 0; i < parameterNames.length; ++i) {
+            System.err.println(parameterNames[i] + ": " + parameters[i]);
+        }
+    }
+}
+// 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/math/fitting/Exp.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,62 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class Exp
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("W'(Q) = a^Q*log(a)*m") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+                  double m     = parameters[0];
+            final double a     = parameters[1];
+            final double logam = Math.log(a)*m;
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double Q) {
+                    return Math.pow(a, Q)*logam;
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new Exp();
+
+    public Exp() {
+        super(
+            "exp",
+            "W(Q) = m * a^Q + b",
+            new String [] { "m", "a", "b" });
+    }
+
+    @Override
+    public double value(double x, double [] parameters) {
+        return parameters[0]*Math.pow(parameters[1], x) + parameters[2];
+    }
+
+    @Override
+    public double [] gradient(double Q, double [] parameters) {
+        double m = parameters[0];
+        double a = parameters[1];
+        double b = parameters[2];
+        return new double [] {
+            Math.pow(a, Q),
+            Math.pow(a, Q-1d)*m*Q,
+            1d
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return InvExp.INSTANCE;
+    }
+}
+// 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/math/fitting/Function.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,100 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+import org.apache.commons.math.optimization.fitting.ParametricRealFunction;
+
+import de.intevation.flys.utils.DoubleUtil;
+
+public abstract class Function
+implements            ParametricRealFunction
+{
+    protected String    name;
+    protected String    description;
+    protected String [] parameterNames;
+    protected double [] initialGuess;
+
+    public static abstract class Derivative {
+
+        protected String description;
+
+        public Derivative() {
+        }
+
+        public Derivative(String description) {
+            this.description = description;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public abstract de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters);
+
+    } // interface Derivative
+
+    public Function() {
+    }
+
+    public Function(
+        String    name,
+        String    description,
+        String [] parameterNames
+    ) {
+        this(name,
+            description,
+            parameterNames,
+            DoubleUtil.fill(parameterNames.length, 1d));
+    }
+
+    public Function(
+        String    name,
+        String    description,
+        String [] parameterNames,
+        double [] initialGuess
+    ) {
+        this.name           = name;
+        this.description    = description;
+        this.parameterNames = parameterNames;
+        this.initialGuess   = initialGuess;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String [] getParameterNames() {
+        return parameterNames;
+    }
+
+    public double [] getInitialGuess() {
+        return initialGuess;
+    }
+
+    public de.intevation.flys.artifacts.math.Function instantiate(
+        final double [] parameters
+    ) {
+        return new de.intevation.flys.artifacts.math.Function() {
+
+            @Override
+            public double value(double x) {
+                try {
+                    return Function.this.value(x, parameters);
+                }
+                catch (FunctionEvaluationException fee) {
+                    return Double.NaN;
+                }
+            }
+        };
+    }
+
+    public abstract Derivative getDerivative();
+
+    public abstract Function getInverse();
+}
+// 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/math/fitting/FunctionFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,44 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public final class FunctionFactory
+{
+    private static FunctionFactory instance;
+
+    private Map<String, Function> functions;
+
+    private FunctionFactory() {
+        functions = new LinkedHashMap<String, Function>();
+
+        registerFunction(Log.INSTANCE);
+        registerFunction(Linear.INSTANCE);
+        registerFunction(LogLinear.INSTANCE);
+        registerFunction(Exp.INSTANCE);
+        registerFunction(Quad.INSTANCE);
+        registerFunction(Pow.INSTANCE);
+        registerFunction(SQPow.INSTANCE);
+    }
+
+    public static synchronized FunctionFactory getInstance() {
+        if (instance == null) {
+            instance = new FunctionFactory();
+        }
+        return instance;
+    }
+
+    public Function getFunction(String name) {
+        return functions.get(name);
+    }
+
+    public void registerFunction(Function function) {
+        functions.put(function.getName(), function);
+    }
+
+    public Collection<Function> getFunctions() {
+        return functions.values();
+    }
+}
+// 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/math/fitting/InvExp.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,66 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class InvExp
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("W'(Q) = 1/(log(a)*(Q-b))") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double a = parameters[1];
+            final double b = parameters[2];
+            final double loga = Math.log(a);
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double Q) {
+                    return 1d/(loga*(Q-a));
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new InvExp();
+
+    public InvExp() {
+        super(
+            "inv-exp",
+            "Q(W) = log((W-b)/m)/log(a)",
+            new String [] { "m", "a", "b" });
+    }
+
+    @Override
+    public double value(double W, double [] parameters) {
+        double m = parameters[0];
+        double a = parameters[1];
+        double b = parameters[2];
+        return Math.log((W-b)/m)/Math.log(a);
+    }
+
+    @Override
+    public double [] gradient(double Q, double [] parameters) {
+        double m = parameters[0];
+        double a = parameters[1];
+        double b = parameters[2];
+        double loga = Math.log(a);
+        return new double [] {
+            -1d/(loga*m),
+            -Math.log((Q-b)/m)/(a*loga*loga),
+            -1d/(loga*(Q-b))
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return Exp.INSTANCE;
+    }
+}
+// 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/math/fitting/InvLinear.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,57 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class InvLinear
+extends      Function
+{
+    public static Function INSTANCE = new InvLinear();
+
+    public static final Derivative DERIVATIVE =
+        new Derivative("Q'(W) = 1/m") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double _1m = 1d/parameters[0];
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double Q) {
+                    return _1m;
+                }
+            };
+        }
+    };
+
+    public InvLinear() {
+        super("inv-linear", "W(Q) = (Q-b)/m", new String [] { "m", "b" });
+    }
+
+    @Override
+    public double value(double Q, double [] parameters) {
+        double m = parameters[0];
+        double b = parameters[1];
+        return (Q-b)/m;
+    }
+
+    @Override
+    public double [] gradient(double Q, double [] parameters) {
+        double m = parameters[0];
+        double b = parameters[1];
+        return new double [] {
+            -(Q-b)/(m*m),
+            -1d/m
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return Linear.INSTANCE;
+    }
+}
+// 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/math/fitting/InvLog.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,55 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class InvLog
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("Q'(W) = exp(W/m)/m") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double _1m = 1d / parameters[0];
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double W) {
+                    return Math.exp(W*_1m)*_1m;
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new InvLog();
+
+    public InvLog() {
+        super("inv-log",  "Q(W) = e^(W/m) - b", new String [] { "m", "b" });
+    }
+
+    @Override
+    public double value(double w, double [] parameters) {
+        double m = parameters[0];
+        double b = parameters[1];
+        return Math.exp(w/m) - b;
+    }
+
+    @Override
+    public double [] gradient(double w, double [] parameters) {
+        double m   = parameters[0];
+        double b   = parameters[1];
+        double ewm = Math.exp(w/m);
+        return new double [] { -w*ewm/(m*m), -1 };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return Log.INSTANCE;
+    }
+}
+// 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/math/fitting/InvLogLinear.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class InvLogLinear
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("Q'(W) = e^(W/a)/(a*m)") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double _1a = 1d/parameters[0];
+            final double _1am = 1d/(parameters[0] * parameters[1]);
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double W) {
+                    return Math.exp(W*_1a)*_1am;
+                }
+            };
+        }
+    };
+    public static final Function INSTANCE = new InvLogLinear();
+
+    public InvLogLinear() {
+        super(
+            "inv-log-linear",
+            "Q(W)=(e^(W/a)-b)/m",
+            new String [] { "a", "m", "b" });
+    }
+
+    @Override
+    public double value(double W, double [] parameters) {
+        double a = parameters[0];
+        double m = parameters[1];
+        double b = parameters[2];
+        return (Math.exp(W/a) - b)/m;
+    }
+
+    @Override
+    public double [] gradient(double W, double [] parameters) {
+        double a   = parameters[0];
+        double m   = parameters[1];
+        double b   = parameters[2];
+        double eWa = Math.exp(W/a);
+        return new double [] {
+            -(W*eWa)/(a*a*m)
+            -(eWa-b)/(m*m),
+            -1/m
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return LogLinear.INSTANCE;
+    }
+}
+// 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/math/fitting/InvPow.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,72 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class InvPow
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("Q'(W) = ((W-d)/a)^(1/c)/(c*(W-d))") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+                  double  a = parameters[0];
+            final double  c = parameters[1];
+            final double  d = parameters[2];
+            final double _1a = 1d/a;
+            final double _1c = 1d/c;
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double W) {
+                    double Wd = W-d;
+                    return Math.pow(Wd*_1a, _1c)/(c*Wd);
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new InvPow();
+
+    public InvPow() {
+        super(
+            "pow",
+            "Q(W) = ((W-d)/a)^(1/c)",
+            new String [] { "a", "c", "d" });
+    }
+
+    @Override
+    public double value(double W, double [] parameters) {
+        double a = parameters[0];
+        double c = parameters[1];
+        double d = parameters[2];
+        return Math.pow((W-d)/a, 1d/c);
+    }
+
+    @Override
+    public double [] gradient(double W, double [] parameters) {
+        double a = parameters[0];
+        double c = parameters[1];
+        double d = parameters[2];
+        double _1c = 1d/c;
+        double Wdac = Math.pow((W-d)/a, 1d/c);
+        double Wd = W-d;
+        return new double [] {
+            -Wdac/(a*c),
+            (Wdac*Math.log(Wd/a))/(c*c),
+            -Wdac/(c*Wd)
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        // TODO: Implement me!
+        return null;
+    }
+
+    @Override
+    public Function getInverse() {
+        return Pow.INSTANCE;
+    }
+}
+// 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/math/fitting/InvQuad.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,69 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class InvQuad
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("Q'(W) = 1/sqrt(4*n*(W-b)+m^2)") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+                  double n  = parameters[0];
+                  double m  = parameters[1];
+            final double b  = parameters[2];
+            final double n4 = 4d*n;
+            final double mm = m*m;
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double W) {
+                    return 1d/Math.sqrt(n4*(W-b)+mm);
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new InvQuad();
+
+    public InvQuad() {
+        super(
+            "inv-quad",
+            "(sqrt(4*n*W-4*b*n+m^2)-m)/(2*n)",
+            new String [] { "n", "m", "b" });
+    }
+
+    @Override
+    public double value(double W, double [] parameters) {
+        double n = parameters[0];
+        double m = parameters[1];
+        double b = parameters[2];
+        return (Math.sqrt(4d*n*(W - b) + m*m)-m)/(2d*n);
+    }
+
+    @Override
+    public double [] gradient(double W, double [] parameters) {
+        double n  = parameters[0];
+        double m  = parameters[1];
+        double b  = parameters[2];
+        double Wb = W-b;
+        double sn4Wb = Math.sqrt(4d*n*Wb + m*m);
+        return new double [] {
+            Wb/(n*sn4Wb)-(sn4Wb-m)/(2d*n*n),
+            (m/sn4Wb-1d)/(2d*n),
+            -1d/sn4Wb
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return Quad.INSTANCE;
+    }
+}
+// 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/math/fitting/InvSQPow.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class InvSQPow
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("Q'(S) = (S/a)^(1/b)/(b*S)") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double _1a = 1d/parameters[0];
+            final double   b = parameters[1];
+            final double _1b = 1d/b;
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double S) {
+                    return Math.pow(S*_1a, _1b)/(b*S);
+                }
+            };
+        }
+    };
+    public static final Function INSTANCE = new InvSQPow();
+
+    public InvSQPow() {
+        super(
+            "inv-sq-pow",
+            "Q(S) = Q=(S/a)^(1/b)",
+            new String [] { "a", "b" });
+    }
+
+    @Override
+    public double value(double S, double [] parameters) {
+        double a = parameters[0];
+        double b = parameters[1];
+        return Math.pow(S/a, 1d/b);
+    }
+
+    @Override
+    public double [] gradient(double S, double [] parameters) {
+        double a     = parameters[0];
+        double b     = parameters[1];
+        double Sa    = S/a;
+        double _1b   = 1d/b;
+        double eSa1b = Math.pow(Sa, _1b);
+        return new double [] {
+            -eSa1b/(a*b),
+            -(eSa1b*Math.log(Sa))/(b*b)
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return SQPow.INSTANCE;
+    }
+}
+// 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/math/fitting/Linear.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,50 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class Linear
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("W'(Q) = m") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double m = parameters[0];
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double Q) {
+                    return m;
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new Linear();
+
+    public Linear() {
+        super("linear", "W(Q) = m*Q + b", new String [] { "m", "b" });
+    }
+
+    @Override
+    public double value(double x, double [] parameters) {
+        return x*parameters[0] + parameters[1];
+    }
+
+    @Override
+    public double [] gradient(double x, double [] parameters) {
+        return new double [] { x, 1d };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return InvLinear.INSTANCE;
+    }
+}
+// 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/math/fitting/Log.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,57 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class Log
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("W'(Q) = m/(Q+b)") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double m = parameters[0];
+            final double b = parameters[1];
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double Q) {
+                    return m/(Q+b);
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new Log();
+
+    public Log() {
+        super("log",  "W(Q) = m*ln(Q + b)", new String [] { "m", "b" });
+    }
+
+    @Override
+    public double value(double x, double [] parameters) {
+        return parameters[0]*Math.log(x + parameters[1]);
+    }
+
+    @Override
+    public double [] gradient(double x, double [] parameters) {
+        double m = parameters[0];
+        double b = parameters[1];
+        double b_x = b + x;
+        return new double [] {
+            Math.log(b_x),
+            m/b_x
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return InvLog.INSTANCE;
+    }
+}
+// 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/math/fitting/LogLinear.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,65 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class LogLinear
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("W'(Q) = a*m/(m*Q + b)") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double a = parameters[0];
+            final double m = parameters[1];
+            final double b = parameters[2];
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double Q) {
+                    return a*m/(m*Q + b);
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new LogLinear();
+
+    public LogLinear() {
+        super(
+            "log-linear",
+            "W(Q) = a*ln(m*Q + b)",
+            new String [] { "a", "m", "b" });
+    }
+
+    @Override
+    public double value(double x, double [] parameters) {
+        return parameters[0]*Math.log(parameters[1]*x + parameters[2]);
+    }
+
+    @Override
+    public double [] gradient(double x, double [] parameters) {
+        double a = parameters[0];
+        double m = parameters[1];
+        double b = parameters[2];
+
+        double lin = m*x + b;
+
+        return new double [] {
+            Math.log(lin),
+            a*x / lin,
+            a / lin
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return InvLogLinear.INSTANCE;
+    }
+}
+// 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/math/fitting/Pow.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,61 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class Pow
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("W'(Q) = a*c*Q^(c-1)") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double a = parameters[0];
+            final double c = parameters[1];
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double Q) {
+                    return a*c*Math.pow(Q, c-1);
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new Pow();
+
+    public Pow() {
+        super(
+            "pow",
+            "W(Q) = a*Q^c + d",
+            new String [] { "a", "c", "d" });
+    }
+
+    @Override
+    public double value(double x, double [] parameters) {
+        return parameters[0]*Math.pow(x, parameters[1]) + parameters[2];
+    }
+
+    @Override
+    public double [] gradient(double x, double [] parameters) {
+        double a   = parameters[0];
+        double c   = parameters[1];
+        double x_c = Math.pow(x, c);
+        return new double [] {
+            x_c,
+            a*x_c*Math.log(x),
+            1d
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return InvPow.INSTANCE;
+    }
+}
+// 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/math/fitting/Quad.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,55 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class Quad
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("W'(Q) = 2*n*Q+m") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double n2 = 2d*parameters[0];
+            final double m  = parameters[1];
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double Q) {
+                    return n2*Q+m;
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new Quad();
+
+    public Quad() {
+        super(
+            "quad",
+            "W(Q) = n*Q^2 + m*Q + b",
+            new String [] { "n", "m", "b" });
+    }
+
+    @Override
+    public double value(double x, double [] parameters) {
+        // n*Q^2 + m*Q + b <=> Q*(n*Q + m) + b
+        return x*(parameters[0]*x + parameters[1]) + parameters[2];
+    }
+
+    @Override
+    public double [] gradient(double x, double [] parameters) {
+        return new double [] { x*x, x, 1d };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return InvQuad.INSTANCE;
+    }
+}
+// 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/math/fitting/SQPow.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,60 @@
+package de.intevation.flys.artifacts.math.fitting;
+
+public class SQPow
+extends      Function
+{
+    public static final Derivative DERIVATIVE =
+        new Derivative("S'(Q) = a*b*Q^(b-1)") {
+
+        @Override
+        public de.intevation.flys.artifacts.math.Function
+            instantiate(double [] parameters)
+        {
+            final double a = parameters[0];
+            final double b = parameters[1];
+
+            return new de.intevation.flys.artifacts.math.Function() {
+                @Override
+                public double value(double Q) {
+                    return a*b*Math.pow(Q, b-1);
+                }
+            };
+        }
+    };
+
+    public static final Function INSTANCE = new SQPow();
+
+    public SQPow() {
+        super(
+            "sq-pow",
+            "S(Q) = a*Q^b",
+            new String [] { "a", "b" });
+    }
+
+    @Override
+    public double value(double x, double [] parameters) {
+        return parameters[0]*Math.pow(x, parameters[1]);
+    }
+
+    @Override
+    public double [] gradient(double q, double [] parameters) {
+        double a   = parameters[0];
+        double b   = parameters[1];
+        double q_b = Math.pow(q, b);
+        return new double [] {
+            q_b,
+            a*q_b*Math.log(q),
+        };
+    }
+
+    @Override
+    public Derivative getDerivative() {
+        return DERIVATIVE;
+    }
+
+    @Override
+    public Function getInverse() {
+        return InvSQPow.INSTANCE;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AnnotationFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,24 +1,30 @@
 package de.intevation.flys.artifacts.model;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import org.apache.log4j.Logger;
 
-import org.jfree.chart.annotations.XYTextAnnotation;
-
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
 
 import de.intevation.flys.artifacts.AnnotationArtifact;
+
 import de.intevation.flys.jfree.FLYSAnnotation;
 import de.intevation.flys.jfree.StickyAxisAnnotation;
 
 import de.intevation.flys.model.Annotation;
+import de.intevation.flys.model.FastAnnotations;
 
 import de.intevation.artifactdatabase.state.DefaultFacet;
 import de.intevation.artifactdatabase.state.Facet;
 
+import de.intevation.flys.utils.FLYSUtils;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+
 /**
  * Facet to access Annotations (landmarks, POIs) of a river.
  */
@@ -58,13 +64,20 @@
     public Object getData(Artifact artifact, CallContext context) {
         AnnotationArtifact annotationArtifact = (AnnotationArtifact) artifact;
 
-        List<Annotation>       as = annotationArtifact.getAnnotations();
-        List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
+        String riverName = FLYSUtils.getRivername((FLYSArtifact)artifact);
 
-        for (Annotation a: as) {
+        FastAnnotations fas = LocationProvider.getAnnotations(riverName);
+
+        List<StickyAxisAnnotation> xy =
+            new ArrayList<StickyAxisAnnotation>(fas.size());
+
+        for (Iterator<FastAnnotations.Annotation> iter =
+                fas.filter(FastAnnotations.IS_POINT); iter.hasNext();) {
+            FastAnnotations.Annotation fa = iter.next();
+
             xy.add(new StickyAxisAnnotation(
-                a.getPosition().getValue(),
-                (float) a.getRange().getA().doubleValue(),
+                fa.getPosition(),
+                (float)fa.getA(),
                 StickyAxisAnnotation.SimpleAxis.X_AXIS));
         }
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -100,8 +100,7 @@
         riverQuery.setParameter("name", riverName);
         List<River> rivers = riverQuery.list();
         if (rivers.isEmpty()) {
-            List<Annotation> list = Collections.emptyList();
-            return list.iterator();
+            return Collections.<Annotation>emptyList().iterator();
         }
 
         Query query = session.createQuery(
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AreaFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -27,8 +27,7 @@
  */
 public class AreaFacet
 extends      DefaultFacet
-implements   FacetTypes {
-
+{
     private static Logger logger = Logger.getLogger(AreaFacet.class);
 
     /**
@@ -57,16 +56,20 @@
         AreaArtifact artifact = (AreaArtifact) art;
         Object lowerData      = null;
         Object upperData      = null;
+        String stemFacetName  = null;
 
         List<DataProvider> providers = context.
             getDataProvider(artifact.getLowerDPKey());
         if (providers.size() < 1) {
-            logger.warn("No 'lower' provider given for area [" + 
+            logger.warn("No 'lower' provider given for area [" +
                 artifact.getLowerDPKey() + "]");
         }
         else {
             lowerData = providers.get(0).provideData(
                 artifact.getLowerDPKey(), null, context);
+            logger.debug("'Lower' data provider key for area [" +
+                artifact.getLowerDPKey() + "]");
+            stemFacetName = artifact.getLowerDPKey().split(":")[1];
         }
 
         providers = context.getDataProvider(artifact.getUpperDPKey());
@@ -77,24 +80,66 @@
         else {
             upperData = providers.get(0).provideData(
                 artifact.getUpperDPKey(), null, context);
+            logger.debug("'Upper' data provider key for area [" +
+                artifact.getUpperDPKey() + "]");
+            if (stemFacetName == null) {
+                stemFacetName = artifact.getUpperDPKey().split(":")[1];
+            }
         }
 
         if (upperData == null && lowerData == null) {
             logger.warn("Not given 'upper' and 'lower' for area");
         }
 
-        return new Object[] {lowerData,
-            upperData,
-            Boolean.valueOf(artifact.getPaintBetween())};
+        return new Data(stemFacetName, lowerData, upperData,
+            Boolean.valueOf(artifact.getPaintBetween()));
     }
 
 
     /** Do a deep copy. */
-    @Override 
+    @Override
     public Facet deepCopy() {
         AreaFacet copy = new AreaFacet(this.index, this.name, this.description);
         copy.set(this);
         return copy;
     }
+
+    /** Result data bundle. */
+    public class Data {
+        protected String  rootFacetName;
+        protected Object  upperData;
+        protected Object  lowerData;
+        protected boolean doPaintBetween;
+
+        /** Create a new result data bundle. */
+        public Data(String rootName, Object low, Object up, boolean between) {
+            this.rootFacetName  = rootName;
+            this.lowerData      = low;
+            this.upperData      = up;
+            this.doPaintBetween = between;
+        }
+
+        /** Get name of a facet that is involved in area generation
+         * to induce type (e.g. longitudinal_section.w -> "W over km"). */
+        public String getRootFacetName() {
+            return this.rootFacetName;
+        }
+
+        /** Get data for 'upper' curve of area. */
+        public Object getUpperData() {
+            return this.upperData;
+        }
+
+        /** Get data for 'lower' curve of area. */
+        public Object getLowerData() {
+            return this.lowerData;
+        }
+
+        /** Whether to fill whole area between (in contrast to 'under'
+         *  or 'over'). */
+        public boolean doPaintBetween() {
+            return this.doPaintBetween;
+        }
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/BlackboardDataFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -6,6 +6,7 @@
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
 
+import de.intevation.artifactdatabase.state.Facet;
 import de.intevation.artifactdatabase.state.DefaultFacet;
 
 
@@ -23,10 +24,24 @@
     }
 
 
-    /** Hey, We can ArtifactUUID+FacetIndex (i.e. getData)! */
-    public List getDataProviderKeys(Artifact art) {
+    /** Do not instantiate a BlackboardDataFacet, subclass it instead. */
+    public BlackboardDataFacet(String name, String description) {
+        super(0, name, description);
+    }
+
+
+    /** Define key to which to respond when asked for 'blackboard'
+     * (DataProvider)- data. */
+    public String areaDataKey(Artifact art) {
+        return art.identifier() + ":" + getName() + ":" + getIndex();
+    }
+
+
+    /** Hey, We can ArtifactUUID+:+FacetName+:+FacetIndex (i.e. getData)! */
+    @Override
+    public List getStaticDataProviderKeys(Artifact art) {
         List list = new ArrayList();
-        list.add(art.identifier() + getIndex());
+        list.add(areaDataKey(art));
         return list;
     }
 
@@ -38,12 +53,13 @@
      * @param context  ignored
      * @return whatever getData delivers.
      */
+    @Override
     public Object provideBlackboardData(Artifact artifact,
         Object key,
         Object param,
         CallContext context
     ) {
-        if (key.equals(artifact.identifier() + getIndex())) {
+        if (key.equals(areaDataKey(artifact))) {
             return getData(artifact, context);
         }
         else {
@@ -51,5 +67,12 @@
         }
     }
 
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        BlackboardDataFacet copy = new BlackboardDataFacet();
+        copy.set(this);
+        return copy;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,19 +5,25 @@
 
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Arrays;
 
 import java.io.Serializable;
 
 import de.intevation.artifacts.CallMeta;
 
+import de.intevation.flys.artifacts.resources.Resources;
+
+import de.intevation.flys.utils.Formatter;
+
 public class Calculation
 implements   Serializable
 {
     public static class Problem
     implements          Serializable
     {
-        protected Double km;
-        protected String msg;
+        protected Double    km;
+        protected String    msg;
+        protected Object [] args;
 
         public Problem() {
         }
@@ -26,20 +32,48 @@
             this.msg = msg;
         }
 
+        public Problem(String msg, Object [] args) {
+            this.msg  = msg;
+            this.args = args;
+        }
+
         public Problem(double km, String msg) {
             this.km  = km;
             this.msg = msg;
         }
 
+        public Problem(double km, String msg, Object [] args) {
+            this.km   = km;
+            this.msg  = msg;
+            this.args = args;
+        }
+
         public Element toXML(Document document, CallMeta meta) {
-            // TODO: i18n
             Element problem = document.createElement("problem");
             if (km != null) {
-                problem.setAttribute("km", String.valueOf(km));
+                problem.setAttribute(
+                    "km",
+                    Formatter.getCalculationKm(meta).format(km));
             }
-            problem.setTextContent(msg);
+            String text = args != null
+                ? Resources.getMsg(meta, msg, msg, args)
+                : Resources.getMsg(meta, msg, msg);
+            problem.setTextContent(text);
             return problem;
         }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof Problem)) {
+                return false;
+            }
+            Problem o = (Problem)other;
+            return !(!msg.equals(o.msg)
+                || (km == null && o.km != null)
+                || (km != null && o.km == null)
+                || (km != null && !km.equals(o.km))
+                || !Arrays.equals(args, o.args));
+        }
     } // class Problem
 
     protected List<Problem> problems;
@@ -58,12 +92,39 @@
         return problems;
     }
 
+    public void addProblems(Calculation other) {
+        List<Problem> otherProblems = other.problems;
+        if (otherProblems != null) {
+            List<Problem> problems = checkProblems();
+            for (Problem problem: otherProblems) {
+                if (!problems.contains(problem)) {
+                    problems.add(problem);
+                }
+            }
+        }
+    }
+
+    public void addProblem(Problem problem) {
+        List<Problem> problems = checkProblems();
+        if (!problems.contains(problem)) {
+            problems.add(problem);
+        }
+    }
+
     public void addProblem(String msg) {
-        checkProblems().add(new Problem(msg));
+        addProblem(new Problem(msg));
+    }
+
+    public void addProblem(String msg, Object ... args) {
+        addProblem(new Problem(msg, args));
     }
 
     public void addProblem(double km, String msg) {
-        checkProblems().add(new Problem(km, msg));
+        addProblem(new Problem(km, msg));
+    }
+
+    public void addProblem(double km, String msg, Object ... args) {
+        addProblem(new Problem(km, msg, args));
     }
 
     public boolean hasProblems() {
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation2.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation2.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,6 +4,8 @@
 
 import org.apache.log4j.Logger;
 
+
+/** ComputedDischargeCurve. */
 public class Calculation2
 extends      Calculation
 {
@@ -25,8 +27,7 @@
         double [][] wqs = wst.interpolateWQ(km, this);
 
         if (wqs == null || wqs[0].length == 0) {
-            logger.debug("Cannot compute discharge curve data.");
-            addProblem("Cannot compute discharge curve data.");
+            addProblem("cannot.compute.discharge.curve");
             return new CalculationResult(new WQKms[0], this);
         }
 
@@ -39,7 +40,7 @@
         WQKms wqkms = new WQKms(kms, qs, ws, String.valueOf(km));
 
         if (hasProblems()) {
-            logger.debug("found + "+numProblems()+" problems.");
+            logger.debug("found " + numProblems() + " problems.");
             wqkms.removeNaNs();
         }
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation3.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation3.java	Fri Sep 28 12:15:52 2012 +0200
@@ -25,7 +25,7 @@
         double [] ws = wst.interpolateW(km, qs, new double[qs.length], this);
 
         if (days == null || days.length == 0) {
-            addProblem(km, "cannot find Ds");
+            addProblem(km, "cannot.find.ds");
         }
 
         if (logger.isDebugEnabled()) {
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation4.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation4.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,21 +1,18 @@
 package de.intevation.flys.artifacts.model;
 
-import java.util.List;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Collections;
+import de.intevation.flys.artifacts.math.BackJumpCorrector;
+import de.intevation.flys.artifacts.math.Function;
+import de.intevation.flys.artifacts.math.Identity;
+import de.intevation.flys.artifacts.math.Linear;
+
+import de.intevation.flys.artifacts.model.WstValueTable.QPosition;
+
+import de.intevation.flys.model.River;
 
 import de.intevation.flys.utils.DoubleUtil;
 
-import de.intevation.flys.model.River;
-import de.intevation.flys.model.Gauge;
-
-import de.intevation.flys.artifacts.model.WstValueTable.QPosition;
-
-import de.intevation.flys.artifacts.math.Function;
-import de.intevation.flys.artifacts.math.Linear;
-import de.intevation.flys.artifacts.math.Identity;
-import de.intevation.flys.artifacts.math.BackJumpCorrector;
+import java.util.Arrays;
+import java.util.List;
 
 import org.apache.log4j.Logger;
 
@@ -26,15 +23,6 @@
 
     public static final double MINIMAL_STEP_WIDTH = 1e-5;
 
-    public static final Comparator<Segment> REF_CMP =
-        new Comparator<Segment>() {
-            public int compare(Segment a, Segment b) {
-                double d = a.referencePoint - b.referencePoint;
-                if (d < 0d) return -1;
-                return d > 0d ? +1 : 0;
-            }
-        };
-
     protected List<Segment> segments;
 
     protected boolean       isQ;
@@ -47,49 +35,7 @@
         this.segments = segments;
         this.isQ      = isQ;
 
-        int numResults = -1;
-
-        // assign reference points
-        for (Segment segment: segments) {
-            Gauge gauge = river.maxOverlap(segment.getFrom(), segment.getTo());
-
-            if (gauge == null) {
-                logger.warn("no gauge found. Defaults to mid point.");
-                segment.setReferencePoint(
-                    0.5*(segment.getFrom()+segment.getTo()));
-            }
-            else {
-                double ref = gauge.getStation().doubleValue();
-                logger.debug(
-                    "reference gauge: " + gauge.getName() +
-                    " (km " + ref + ")");
-                segment.setReferencePoint(ref);
-            }
-
-            double [] values = segment.values;
-
-            if (numResults == -1) {
-                numResults = values.length;
-            }
-            else if (numResults != values.length) {
-                throw new IllegalArgumentException("wrong length of values");
-            }
-
-            // convert to Q if needed
-            if (!isQ && gauge != null) {
-                double [][] table = new DischargeTables(
-                    river.getName(), gauge.getName()).getFirstTable();
-
-                // need the original values for naming
-                segment.backup();
-
-                for (int i = 0; i < values.length; ++i) {
-                    values[i] = DischargeTables.getQForW(table, values[i]);
-                }
-            }
-        } // for all segments
-
-        Collections.sort(segments, REF_CMP);
+        Segment.setReferencePointConvertQ(segments, river, isQ, this);
     }
 
     public CalculationResult calculate(
@@ -109,8 +55,7 @@
 
         if (segments.isEmpty()) {
             logger.debug("no segments found");
-            // TODO: I18N
-            addProblem("no segments found");
+            addProblem("no.segments.found");
             return new CalculationResult(new WQKms[0], this);
         }
 
@@ -118,8 +63,7 @@
 
         if (numResults < 1) {
             logger.debug("no values given");
-            // TODO: I18N
-            addProblem("no values given");
+            addProblem("no.values.given");
             return new CalculationResult(new WQKms[0], this);
         }
 
@@ -226,8 +170,7 @@
                             anchor.values[i]);
 
                         if ((qPositions[i] = qi) == null) {
-                            // TODO: I18N
-                            addProblem(pos, "cannot find q = " + anchor.values[i]);
+                            addProblem(pos, "cannot.find.q", anchor.values[i]);
                             functions[i] = Identity.IDENTITY;
                         }
                         else {
@@ -263,8 +206,7 @@
                     results[i].add(out[0], out[1], pos);
                 }
                 else {
-                    // TODO: I18N
-                    addProblem(pos, "cannot interpolate w/q");
+                    addProblem(pos, "cannot.interpolate.w.q");
                 }
             }
         }
@@ -290,7 +232,7 @@
     }
 
     protected String createName(int index) {
-        // TODO: I18N
+        // TODO: i18n
         StringBuilder sb = new StringBuilder(isQ ? "Q" : "W");
         sb.append(" benutzerdefiniert (");
         for (int i = 0, N = segments.size(); i < N; ++i) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation5.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,77 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.flys.utils.Formatter;
+
+import java.text.NumberFormat;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+public class Calculation5
+extends      Calculation
+{
+    private static Logger log = Logger.getLogger(Calculation5.class);
+
+    protected double    startKm;
+    protected double [] endKms;
+
+    public Calculation5() {
+    }
+
+    public Calculation5(double startKm, double [] endKms) {
+        this.startKm = startKm;
+        this.endKms  = endKms;
+    }
+
+    public CalculationResult calculate(
+        WstValueTable       wst,
+        Map<Double, Double> kms2gaugeDatums,
+        CallContext         context
+    ) {
+        ArrayList<WWQQ> results = new ArrayList<WWQQ>();
+
+        int numProblems = numProblems();
+
+        CallMeta meta = context.getMeta();
+
+        for (double endKm: endKms) {
+
+            double [][] wws = wst.relateWs(startKm, endKm, this);
+            int newNumProblems = numProblems();
+
+            if (wws.length == 4) {
+                WWQQ wwqq = new WWQQ(
+                    generateName(meta, startKm, endKm),
+                    startKm, kms2gaugeDatums.get(startKm), wws[0], wws[1],
+                    endKm,   kms2gaugeDatums.get(endKm),   wws[2], wws[3]);
+
+                if (newNumProblems > numProblems) {
+                    wwqq.removeNaNs();
+                }
+
+                results.add(wwqq);
+            }
+            numProblems = newNumProblems;
+        }
+
+        return new CalculationResult(
+            results.toArray(new WWQQ[results.size()]),
+            this);
+    }
+
+    protected static String generateName(
+        CallMeta meta,
+        double   startKm,
+        double   endKm
+    ) {
+        NumberFormat nf = Formatter.getCalculationKm(meta);
+        return "W(km " + nf.format(startKm) +
+               ") ~ W(km " + nf.format(endKm) + ")";
+    }
+}
+// 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/Calculation6.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,315 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.model.DischargeTable;
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.TimeInterval;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class Calculation6 extends Calculation {
+
+    private static final Logger logger = Logger.getLogger(Calculation6.class);
+
+    private int      mode;
+    private long[]   timerange;
+    private double[] values;
+
+
+    public static final int MODE_W = 0;
+    public static final int MODE_Q = 1;
+
+    public static final double SCALE = 100d;
+
+
+    public Calculation6(int mode, long[] timerange, double[] values) {
+        this.mode      = mode;
+        this.timerange = timerange;
+        this.values    = values;
+    }
+
+
+    public CalculationResult calculate(Gauge gauge) {
+        if (!checkParameters() || gauge == null) {
+            logger.warn("Parameters not valid for calculation.");
+
+            return null;
+        }
+
+        if (logger.isDebugEnabled()) {
+            debug();
+        }
+
+        DischargeTable  refTable = fetchReferenceTable(gauge);
+        List<DischargeTable> dts = fetchDischargeTables(gauge);
+
+        int numTables = dts.size();
+
+        logger.debug("Take " + numTables + " into account.");
+
+        if (numTables == 0) {
+            addProblem("cannot.find.hist.q.tables");
+        }
+
+        WQTimerange[] wqt = prepareCalculationData(refTable, dts);
+
+        logger.debug("Number of calculation results: " + wqt.length);
+
+        return new CalculationResult(wqt, this);
+    }
+
+
+    protected boolean checkParameters() {
+        if (!(mode == MODE_W || mode == MODE_Q)) {
+            logger.warn("Invalid mode '" + mode + "' for calculation.");
+            return false;
+        }
+
+        if (timerange == null || timerange.length < 2) {
+            logger.warn("Invalid timerange for calculation.");
+            return false;
+        }
+
+        if (values == null || values.length == 0) {
+            logger.warn("No values for W or Q specified.");
+            return false;
+        }
+
+        return true;
+    }
+
+
+    protected DischargeTable fetchReferenceTable(Gauge gauge) {
+        return gauge.fetchMasterDischargeTable();
+    }
+
+
+    protected List<DischargeTable> fetchDischargeTables(Gauge gauge) {
+        List<DischargeTable> relevant = new ArrayList<DischargeTable>();
+        List<DischargeTable> all      = gauge.getDischargeTables();
+
+        for (DischargeTable dt: all) {
+            if (isDischargeTableRelevant(dt)) {
+                relevant.add(dt);
+            }
+        }
+
+        return relevant;
+    }
+
+
+    protected boolean isDischargeTableRelevant(DischargeTable dt) {
+        TimeInterval ti = dt.getTimeInterval();
+
+        if (dt.getKind() == Gauge.MASTER_DISCHARGE_TABLE || ti == null) {
+            return false;
+        }
+
+        Date start     = ti.getStartTime();
+        long startTime = start.getTime();
+
+        if (startTime >= timerange[0] && startTime <= timerange[1]) {
+            return true;
+        }
+
+        Date stop     = ti.getStopTime();
+        long stopTime = stop != null ? stop.getTime() : -1l;
+
+        if (stopTime >= timerange[0] && stopTime <= timerange[1]) {
+            return true;
+        }
+
+        logger.debug("DischargeTable not in range: " + start + " -> " + stop);
+
+        return false;
+    }
+
+
+    protected WQTimerange[] prepareCalculationData(
+        DischargeTable       refTable,
+        List<DischargeTable> dts
+    ) {
+        if (refTable == null) {
+            addProblem("cannot.find.hist.q.reftable");
+            return prepareSimpleData(dts);
+        }
+        else {
+            return prepareData(refTable, dts);
+        }
+    }
+
+
+    protected WQTimerange[] prepareSimpleData(List<DischargeTable> dts) {
+        List<WQTimerange> wqts =
+            new ArrayList<WQTimerange>(values.length);
+
+        for (double value: values) {
+            logger.debug("Prepare data for value: " + value);
+
+            String name      = mode == MODE_W ? "W=" + value : "Q=" + value;
+            WQTimerange wqt  = null;
+
+            for (DischargeTable dt: dts) {
+                Date[]   ti = prepareTimeInterval(dt);
+                Timerange t = new Timerange(ti[0], ti[1]);
+                double    w;
+                double    q;
+
+                if (mode == MODE_W) {
+                    w = value;
+                    q = findValueForW(dt, w);
+
+                    if (Double.isNaN(q)) {
+                        logger.warn("Cannot find Q for W: " + w);
+                        addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]);
+                        continue;
+                    }
+                }
+                else {
+                    q = value;
+                    w = findValueForQ(dt, q);
+                }
+
+                logger.debug("Q=" + q + " | W=" + w);
+
+                if (wqt == null) {
+                    wqt = new WQTimerange(name);
+                }
+
+                wqt.add(w, q, t);
+            }
+
+            if (wqt != null) {
+                wqts.add(wqt);
+            }
+        }
+
+        return wqts.toArray(new WQTimerange[wqts.size()]);
+    }
+
+
+    protected HistoricalWQTimerange[] prepareData(
+        DischargeTable       refTable,
+        List<DischargeTable> dts
+    ) {
+        List<HistoricalWQTimerange> wqts =
+            new ArrayList<HistoricalWQTimerange>(values.length);
+
+        for (double value: values) {
+            logger.debug("Prepare data plus diff for value: " + value);
+
+            String name = mode == MODE_W ? "W=" + value : "Q=" + value;
+            HistoricalWQTimerange wqt  = null;
+
+            double ref;
+            double diff;
+
+            if (refTable != null && mode == MODE_W) {
+                ref = findValueForW(refTable, value);
+            }
+            else if (refTable != null) {
+                ref = findValueForQ(refTable, value);
+            }
+            else {
+                ref = Double.NaN;
+            }
+
+            for (DischargeTable dt: dts) {
+                Date[] ti = prepareTimeInterval(dt);
+
+                Timerange t = new Timerange(ti[0] ,ti[1]);
+                double    w;
+                double    q;
+
+                if (mode == MODE_W) {
+                    w    = value;
+                    q    = findValueForW(dt, w);
+
+                    if (Double.isNaN(q)) {
+                        logger.warn("Cannot find Q for W: " + w);
+                        addProblem("cannot.find.hist.q.for.w", w, ti[0], ti[1]);
+                        continue;
+                    }
+
+                    diff = ref-q;
+                }
+                else {
+                    q    = value;
+                    w    = findValueForQ(dt, q);
+                    diff = ref-w;
+                }
+
+                logger.debug("Q=" + q + " | W=" + w + " | Ref = " + ref);
+
+                if (wqt == null) {
+                    wqt = new HistoricalWQTimerange(name);
+                }
+
+                wqt.add(w, q, diff, t);
+            }
+
+            if (wqt != null) {
+                wqts.add(wqt);
+            }
+        }
+
+        return (HistoricalWQTimerange[])
+            wqts.toArray(new HistoricalWQTimerange[wqts.size()]);
+    }
+
+
+    protected Date[] prepareTimeInterval(DischargeTable dt) {
+        TimeInterval ti = dt.getTimeInterval();
+
+        Date start = ti.getStartTime();
+        Date end   = ti.getStopTime();
+
+        if (end == null) {
+            logger.warn("TimeInterval has no stop time set!");
+
+            end = new Date();
+        }
+
+        return new Date[] { start, end };
+    }
+
+
+    protected double findValueForW(DischargeTable dt, double w) {
+        double[][] vs = DischargeTables.loadDischargeTableValues(dt, SCALE);
+        double [] qs = DischargeTables.getQsForW(vs, w);
+        return qs.length == 0 ? Double.NaN : qs[0];
+    }
+
+
+    protected double findValueForQ(DischargeTable dt, double q) {
+        double[][] vs = DischargeTables.loadDischargeTableValues(dt, SCALE);
+        logger.warn("TODO: IMPLEMENT ME!");
+
+        return 10;
+    }
+
+
+    /**
+     * Writes the parameters used for this calculation to logger.
+     */
+    public void debug() {
+        StringBuilder sb = new StringBuilder();
+        for (double value: values) {
+            sb.append(String.valueOf(value) + " ");
+        }
+
+        logger.debug("========== Calculation6 ==========");
+        logger.debug("   Mode:         " + mode);
+        logger.debug("   Timerange:    " + timerange[0] + " - " + timerange[1]);
+        logger.debug("   Input values: " + sb.toString());
+        logger.debug("==================================");
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CalculationMessage.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CalculationMessage.java	Fri Sep 28 12:15:52 2012 +0200
@@ -43,3 +43,4 @@
             " - " + getMessage();
     }
 }
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CalculationResult.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CalculationResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -14,6 +14,10 @@
     public CalculationResult() {
     }
 
+    public CalculationResult(Calculation report) {
+        this(null, report);
+    }
+
     /**
      * @param report report (e.g. error messages).
      */
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,7 +8,6 @@
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
 
-import de.intevation.artifactdatabase.state.DefaultFacet;
 import de.intevation.artifactdatabase.state.Facet;
 
 import de.intevation.flys.artifacts.CrossSectionArtifact;
@@ -20,12 +19,19 @@
  * Trival Facet for Cross Sections (profiles).
  */
 public class CrossSectionFacet
-extends      DefaultFacet
+extends      BlackboardDataFacet
 implements   FacetTypes {
 
     public static String BLACKBOARD_CS_MASTER_DATA
         = "crosssection.masterprofile.data";
 
+    public static String BLACKBOARD_CS_PREV_KM
+        = "crosssection.masterprofile.km.prev";
+
+    public static String BLACKBOARD_CS_NEXT_KM
+        = "crosssection.masterprofile.km.next";
+
+
     private static Logger logger = Logger.getLogger(CrossSectionFacet.class);
 
     protected ComputeType type;
@@ -39,13 +45,16 @@
 
 
     /** Tell world we know about crosssection masters data and its index. */
-    public List getDataProviderKeys(Artifact art) {
+    public List getStaticDataProviderKeys(Artifact art) {
         CrossSectionArtifact artifact = (CrossSectionArtifact) art;
         List keys = new ArrayList();
         if (artifact.isMaster()) {
             keys.add(BLACKBOARD_CS_MASTER_DATA);
+            keys.add(BLACKBOARD_CS_PREV_KM);
+            keys.add(BLACKBOARD_CS_NEXT_KM);
         }
         keys.add(artifact.identifier() + getIndex());
+        keys.addAll(super.getStaticDataProviderKeys(art));
         return keys;
     }
 
@@ -71,9 +80,19 @@
         else if (key.equals(artifact.identifier() + getIndex())) {
             return getData(artifact, context);
         }
+        else if (key.equals(BLACKBOARD_CS_NEXT_KM)) {
+            return crossSection.getNextKm();
+        }
+        else if (key.equals(BLACKBOARD_CS_PREV_KM)) {
+            return crossSection.getPrevKm();
+        }
         else {
-            logger.warn("Cannot provide data for key: " + key);
-            return null;
+            Object obj = super.provideBlackboardData(artifact, key, param,
+                context);
+            if (obj == null) {
+                logger.warn("Cannot provide data for key: " + key);
+            }
+            return obj;
         }
     }
 
@@ -93,7 +112,7 @@
 
 
     /** Do a deep copy. */
-    @Override 
+    @Override
     public Facet deepCopy() {
         CrossSectionFacet copy = new CrossSectionFacet(this.index, this.description);
         copy.set(this);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -38,14 +38,14 @@
     /**
      * Get Cross Sections for a river by name.
      *
-     * @param river name of the river of interest.
+     * @param riverName name of the river of interest.
      *
      * @return List of Cross Sections of river.
      */
     public static List<CrossSection> getCrossSections(String riverName) {
         Session session = SessionHolder.HOLDER.get();
         Query query = session.createQuery(
-                "from CrossSection where river.name = :rivername");
+            "from CrossSection where river.name = :rivername");
         query.setParameter("rivername", riverName);
         return query.list();
     }
@@ -64,8 +64,15 @@
             + " order by timeInterval.stopTime desc, timeInterval.startTime desc");
         query.setParameter("riverid", section.getRiver().getId());
 
-        CrossSection cs = (CrossSection) query.list().get(0);
-        return section.getId().equals(cs.getId());
+        List result = query.list();
+
+        if (result == null || result.isEmpty()) {
+            return true;
+        }
+        else {
+            CrossSection cs = (CrossSection) result.get(0);
+            return section.getId().equals(cs.getId());
+        }
     }
 
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,16 +4,18 @@
 
 import java.util.List;
 
-import de.intevation.flys.model.CrossSectionLine;
-
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.DataProvider;
 
 import de.intevation.artifactdatabase.state.Facet;
-import de.intevation.artifacts.DataProvider;
 
 import de.intevation.flys.artifacts.WaterLineArtifact;
 
+import de.intevation.flys.model.FastCrossSectionLine;
+
+import de.intevation.flys.artifacts.geom.Lines;
+
 
 /**
  * Facet for Waterlines in Cross Sections.
@@ -22,7 +24,9 @@
 extends      BlackboardDataFacet
 implements   FacetTypes {
 
-    private static Logger logger = Logger.getLogger(CrossSectionWaterLineFacet.class);
+    /** Private logger to use. */
+    private static Logger logger =
+        Logger.getLogger(CrossSectionWaterLineFacet.class);
 
 
     /** Trivial constructor, set (maybe localized) description. */
@@ -32,6 +36,17 @@
 
 
     /**
+     * Trivial constructor, set (maybe localized) description.
+     * @param idx Index of this facet.
+     * @param name 'type' of this facet.
+     * @param description (maybe) localized user-visible description.
+     */
+    public CrossSectionWaterLineFacet(int idx, String name, String description) {
+        super(idx, name, description);
+    }
+
+
+    /**
      * Gets waterline (crossed with cross section) of waterlevel.
      */
     public Object getData(Artifact artifact, CallContext context) {
@@ -41,20 +56,35 @@
             getDataProvider(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA);
         if (providers.size() < 1) {
             logger.warn("Could not find Cross-Section data provider.");
-            return new double[][] {};
+            return new Lines.LineData(new double[][] {}, 0d, 0d);
         }
-        
+
         Object crossSection = providers.get(0)
-            .provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA, null, context);
+            .provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA,
+                null, context);
+        Object nextKm = providers.get(0).
+            provideData(CrossSectionFacet.BLACKBOARD_CS_NEXT_KM, null, context);
+        Object prevKm = providers.get(0).
+            provideData(CrossSectionFacet.BLACKBOARD_CS_PREV_KM, null, context);
+        if (prevKm == null)
+            prevKm = new Double(-1d);
+        if (nextKm == null)
+            nextKm = new Double(-1d);
 
-        WaterLineArtifact winfo = (WaterLineArtifact)artifact;
+        WaterLineArtifact lineArtifact = (WaterLineArtifact) artifact;
 
-        return winfo.getWaterLines(this.getIndex(), (CrossSectionLine) crossSection);
+        if (crossSection != null) {
+            return lineArtifact.getWaterLines(this.getIndex(),
+                (FastCrossSectionLine) crossSection, (Double) nextKm, (Double) prevKm);
+        }
+        else {
+            return new Lines.LineData(new double[][] {}, 0d,0d);
+        }
     }
 
 
     /** Do a deep copy. */
-    @Override 
+    @Override
     public Facet deepCopy() {
         CrossSectionWaterLineFacet copy = new CrossSectionWaterLineFacet(
             this.getIndex(),
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DataFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DataFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,7 +3,6 @@
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
 
-import de.intevation.artifactdatabase.state.DefaultFacet;
 import de.intevation.artifactdatabase.state.Facet;
 
 import de.intevation.flys.artifacts.FLYSArtifact;
@@ -11,7 +10,7 @@
 import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
 
 public class DataFacet
-extends      DefaultFacet
+extends      BlackboardDataFacet
 {
     protected ComputeType type;
     protected String      hash;
@@ -31,10 +30,12 @@
         this(name, description, ComputeType.ADVANCE);
     }
 
+
     public DataFacet(String name, String description, ComputeType type) {
         this(name, description, type, null);
     }
 
+
     public DataFacet(
         String      name,
         String      description,
@@ -61,6 +62,21 @@
     }
 
 
+    public DataFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      hash,
+        String      stateId
+    ) {
+        super(index, name, description);
+        this.type    = type;
+        this.hash    = hash;
+        this.stateId = stateId;
+    }
+
+
     /**
      * Return computation result.
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DateRange.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,51 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class DateRange
+implements   Serializable
+{
+    private static final long serialVersionUID = -2553914795388094818L;
+
+    protected Date from;
+    protected Date to;
+
+    public DateRange(Date from, Date to) {
+        this.from = from;
+        this.to   = to;
+    }
+
+    public Date getFrom() {
+        return from;
+    }
+
+    public void setFrom(Date from) {
+        this.from = from;
+    }
+
+    public Date getTo() {
+        return to;
+    }
+
+    public void setTo(Date to) {
+        this.to = to;
+    }
+
+    private static final boolean equalDates(Date a, Date b) {
+        if (a == null && b != null) return false;
+        if (a != null && b == null) return false;
+        if (a == null) return true;
+        return a.equals(b);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof DateRange)) {
+            return false;
+        }
+        DateRange o = (DateRange)other;
+        return equalDates(from, o.from) && equalDates(to, o.to);
+    }
+}
+// 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/DifferenceCurveFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,68 @@
+package de.intevation.flys.artifacts.model;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Facet with the curve of a subtraction of two waterlevel-lines.
+ * TODO inherit directly from DataFacet? Check whether this Facet is obsolete.
+ */
+public class DifferenceCurveFacet extends WaterlevelFacet {
+
+    private static Logger logger = Logger.getLogger(DifferenceCurveFacet.class);
+
+
+    public DifferenceCurveFacet() {
+    }
+
+    public DifferenceCurveFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateID,
+        String      hash
+
+    ) {
+        super(index, name, description, type, stateID, hash);
+    }
+
+    /**
+     * Get difference curve data.
+     * @return a WKms at given index.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        WINFOArtifact winfo = (WINFOArtifact)artifact;
+
+        CalculationResult res = (CalculationResult)
+            winfo.compute(context, hash, stateId, type, false);
+
+        WKms [] wkms = (WKms [])res.getData();
+
+        WKms result = wkms[index];
+        logger.debug("Got difference curve data (" + result.getName()
+            + ") at index: " + index);
+
+        return result;
+    }
+
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        WaterlevelFacet copy = new DifferenceCurveFacet();
+        copy.set(this);
+        copy.type    = type;
+        copy.stateId = stateId;
+        copy.hash    = hash;
+        return copy;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DischargeTables.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,7 +4,6 @@
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Arrays;
-import java.util.Comparator;
 
 import java.io.Serializable;
 
@@ -18,9 +17,13 @@
 import de.intevation.flys.model.DischargeTable;
 import de.intevation.flys.model.DischargeTableValue;
 
+import gnu.trove.TDoubleArrayList;
+
+/** Documentation goes here. */
 public class DischargeTables
 implements   Serializable
 {
+    /** Private logger. */
     private static Logger log = Logger.getLogger(DischargeTables.class);
 
     public static final double DEFAULT_SCALE = 100.0;
@@ -124,114 +127,109 @@
             // TODO: Filter by time interval
             DischargeTable table = tables.get(0);
 
-            List<DischargeTableValue> dtvs =
-                table.getDischargeTableValues();
-
-            final double [][] vs = new double[2][dtvs.size()];
-
-            boolean qSorted = true;
-
-            double lastQ = -Double.MAX_VALUE;
-
-            int idx = 0;
-            for (DischargeTableValue dtv: dtvs) {
-                double q = dtv.getQ().doubleValue();
-                vs[0][idx] = q * scale;
-                vs[1][idx] = dtv.getW().doubleValue() * scale;
-                ++idx;
-
-                if (qSorted && lastQ > q) {
-                    qSorted = false;
-                }
-                lastQ = q;
-            }
+            double [][] vs = loadDischargeTableValues(table, scale);
 
-            if (!qSorted) {
-                log.debug("need to sort by q values");
-                // TODO: Do this db level.
-                // XXX: This is so ugly :-(
-                Integer [] indices = new Integer[vs[0].length];
-                for (int i = 0; i < indices.length; ++i) {
-                    indices[i] = i;
-                }
-
-                Arrays.sort(indices, new Comparator<Integer>() {
-                    public int compare(Integer a, Integer b) {
-                        double va = vs[1][a];
-                        double vb = vs[1][b];
-                        double d = va - vb;
-                        if (d < 0.0) return -1;
-                        if (d > 0.0) return +1;
-                        return 0;
-                    }
-                });
-
-                double [][] vs2 = new double[2][vs[0].length];
-                for (int i = 0; i < indices.length; ++i) {
-                    vs2[0][i] = vs[0][indices[i]];
-                    vs2[1][i] = vs[1][indices[i]];
-                }
-                values.put(gaugeName, vs2);
-            }
-            else {
-                values.put(gaugeName, vs);
-            }
-
+            values.put(gaugeName, vs);
         }
 
         return values;
     }
 
-    public static double getQForW(double [][] values, double w) {
+
+    /**
+     * @param table The discharge table
+     * @param scale The scale factor to adjust W and Q values.
+     *
+     * @return the values of a discharge table.
+     */
+    public static double[][] loadDischargeTableValues(
+        DischargeTable table,
+        double         scale
+    ) {
+        List<DischargeTableValue> dtvs = table.getDischargeTableValues();
+
+        final double [][] vs = new double[2][dtvs.size()];
+
+        int idx = 0;
+        for (DischargeTableValue dtv: dtvs) {
+            double q = dtv.getQ().doubleValue();
+            vs[0][idx] = q * scale;
+            vs[1][idx] = dtv.getW().doubleValue() * scale;
+            ++idx;
+        }
+
+        return vs;
+    }
+
+    private static final double EPSILON = 1e-5;
+
+    private static final boolean epsEquals(double a, double b) {
+        return Math.abs(a - b) < EPSILON;
+    }
+
+    private static final boolean between(double a, double b, double x) {
+        if (a > b) { double t = a; a = b; b = t; }
+        return x > a && x < b;
+    }
+
+    public static double [] getQsForW(double [][] values, double w) {
 
         boolean debug = log.isDebugEnabled();
 
         if (debug) {
-            log.debug("calculating getQForW(" + w + ")");
-        }
-
-        int index = Arrays.binarySearch(values[1], w);
-        if (index >= 0) {
-            return values[0][index];
-        }
-
-        index = -index - 1; // insert position
-
-        if (index < 1 || index >= values[0].length) {
-            // do not extraploate
-            if (debug) {
-                log.debug("we do not extrapolate: NaN");
-            }
-            return Double.NaN;
+            log.debug("getQsForW: W = " + w);
         }
 
-        double w1 = values[1][index-1];
-        double w2 = values[1][index  ];
-        double q1 = values[0][index-1];
-        double q2 = values[0][index  ];
+        double [] qs = values[0];
+        double [] ws = values[1];
 
-        // q1 = m*w1 + b
-        // q2 = m*w2 + b
-        // q2 - q1 = m*(w2 - w1)
-        // m = (q2 - q1)/(w2 - w1) # w2 != w1
-        // b = q1 - m*w1
+        int N = Math.min(qs.length, ws.length);
 
-        double q;
-        if (w1 == w2) {
-            q = 0.5*(q1 + q2);
+        if (N == 0) {
             if (debug) {
-                log.debug("same w1 and w2: " + w1);
+                log.debug("Q(" + w + ") = []");
+            }
+            return new double [0];
+        }
+
+        TDoubleArrayList outQs = new TDoubleArrayList();
+
+        if (epsEquals(ws[0], w)) {
+            outQs.add(qs[0]);
+        }
+
+        for (int i = 1; i < N; ++i) {
+            if (epsEquals(ws[i], w)) {
+                outQs.add(qs[i]);
+            }
+            else if (between(ws[i-1], ws[i], w)) {
+                double w1 = ws[i-1];
+                double w2 = ws[i];
+                double q1 = qs[i-1];
+                double q2 = qs[i];
+
+                // q1 = m*w1 + b
+                // q2 = m*w2 + b
+                // q2 - q1 = m*(w2 - w1)
+                // m = (q2 - q1)/(w2 - w1) # w2 != w1
+                // b = q1 - m*w1
+                // w1 != w2
+
+                double m = (q2 - q1)/(w2 - w1);
+                double b = q1 - m*w1;
+                double q = w*m + b;
+
+                outQs.add(q);
             }
         }
-        else {
-            double m = (q2 - q1)/(w2 - w1);
-            double b = q1 - m*w1;
-            q = w*m + b;
+
+        double [] result = outQs.toNativeArray();
+
+        if (debug) {
+            log.debug("Q(" + w + ") = " + Arrays.toString(result));
         }
-        if (debug) {
-            log.debug("Q(" + w + ") = " + q);
-        }
-        return q;
+
+        return result;
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/DurationCurveFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,8 @@
 package de.intevation.flys.artifacts.model;
 
+import java.util.List;
+import java.util.ArrayList;
+
 import org.apache.log4j.Logger;
 
 import de.intevation.artifacts.Artifact;
@@ -8,15 +11,25 @@
 import de.intevation.artifactdatabase.state.DefaultFacet;
 import de.intevation.artifactdatabase.state.Facet;
 
+import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.WINFOArtifact;
 
 import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
 
 
+/**
+ * Data of a duration curve.
+ */
 public class DurationCurveFacet extends DefaultFacet {
 
     private static Logger logger = Logger.getLogger(DurationCurveFacet.class);
 
+    /** Blackboard data provider key for durationcurve (wqday) data. */
+    public static String BB_DURATIONCURVE = "durationcurve";
+
+    /** Blackboard data provider key for km of durationcurve. */
+    public static String BB_DURATIONCURVE_KM = "durationcurve.km";
+
     public DurationCurveFacet() {
     }
 
@@ -25,6 +38,9 @@
     }
 
 
+    /**
+     * Expose state computation from WINFOArtifact.
+     */
     public Object getData(Artifact artifact, CallContext context) {
         logger.debug("Get data for duration curve data");
 
@@ -36,7 +52,43 @@
         return cr.getData();
     }
 
-    @Override 
+
+    @Override
+    public List getStaticDataProviderKeys(Artifact art) {
+        List list = new ArrayList();
+        list.add(BB_DURATIONCURVE);
+        list.add(BB_DURATIONCURVE_KM);
+        return list;
+    }
+
+
+    /**
+     * Can provide whatever getData returns and additionally the location.
+     * @param key      will respond on BB_DURATIONCURVE +KM
+     * @param param    ignored
+     * @param context  ignored
+     * @return whatever getData delivers or location.
+     */
+    @Override
+    public Object provideBlackboardData(Artifact artifact,
+        Object key,
+        Object param,
+        CallContext context
+    ) {
+        if (key.equals(BB_DURATIONCURVE)) {
+            return getData(artifact, context);
+        }
+        else if (key.equals(BB_DURATIONCURVE_KM)) {
+            return ((FLYSArtifact)artifact).getDataAsString("ld_locations");
+        }
+        else {
+            return null;
+        }
+    }
+
+
+    /** Create a deep copy. */
+    @Override
     public Facet deepCopy() {
         DurationCurveFacet copy = new DurationCurveFacet();
         copy.set(this);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/EmptyFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,33 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifactdatabase.state.DefaultFacet;
+import de.intevation.artifactdatabase.state.Facet;
+
+public class EmptyFacet
+extends      DefaultFacet
+{
+    /** Trivial constructor. */
+    public EmptyFacet() {
+        super(0, "empty.facet", "empty.facet");
+    }
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        return null;
+    }
+
+
+    /**
+     * Return a deep copy.
+     */
+    @Override
+    public Facet deepCopy() {
+        EmptyFacet copy = new EmptyFacet();
+        copy.set(this);
+        return copy;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FacetTypes.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,6 @@
 package de.intevation.flys.artifacts.model;
 
+/** 'Types' of facets. */
 public interface FacetTypes {
 
     public class IS {
@@ -17,25 +18,142 @@
                 || type.equals(CROSS_SECTION_AREA)
                 || type.equals(LONGITUDINAL_SECTION_AREA);
         }
+        public static boolean W(String type) {
+            return type.equals(LONGITUDINAL_W)
+                || type.equals(DISCHARGE_LONGITUDINAL_W)
+                || type.equals(DURATION_W)
+                || type.equals(STATIC_WKMS)
+                || type.equals(STATIC_WQKMS_W);
+        }
+        public static boolean Q(String type) {
+            return type.equals(LONGITUDINAL_Q)
+                || type.equals(DISCHARGE_LONGITUDINAL_Q)
+                || type.equals(DURATION_Q)
+                || type.equals(STATIC_WQKMS_Q);
+        }
+        public static boolean V(String type) {
+            return type.equals(FLOW_VELOCITY_MAINCHANNEL)
+                || type.equals(FLOW_VELOCITY_TOTALCHANNEL);
+        }
+        public static boolean T(String type) {
+            return type.equals(FLOW_VELOCITY_TAU);
+        }
+        public static boolean H(String type) {
+            return type.equals(MIDDLE_BED_HEIGHT_SINGLE)
+                || type.equals(MIDDLE_BED_HEIGHT_EPOCH);
+        }
+        public static boolean MANUALPOINTS(String type) {
+            return type.endsWith("manualpoints");
+        }
+        public static boolean MANUALLINE(String type) {
+            return type.endsWith("manualline");
+        }
+        public static boolean SQ_CURVE(String type) {
+            if (type.equals(SQ_A_CURVE)
+                || type.equals(SQ_B_CURVE)
+                || type.equals(SQ_C_CURVE)
+                || type.equals(SQ_D_CURVE)
+                || type.equals(SQ_E_CURVE)
+                || type.equals(SQ_F_CURVE)
+                || type.equals(SQ_A_OUTLIER_CURVE)
+                || type.equals(SQ_B_OUTLIER_CURVE)
+                || type.equals(SQ_C_OUTLIER_CURVE)
+                || type.equals(SQ_D_OUTLIER_CURVE)
+                || type.equals(SQ_E_OUTLIER_CURVE)
+                || type.equals(SQ_F_OUTLIER_CURVE)
+                )
+            {
+                return true;
+            }
+
+            return false;
+        }
+        public static boolean SQ_MEASUREMENT(String type) {
+            if (type.equals(SQ_A_MEASUREMENT)
+                || type.equals(SQ_B_MEASUREMENT)
+                || type.equals(SQ_C_MEASUREMENT)
+                || type.equals(SQ_D_MEASUREMENT)
+                || type.equals(SQ_E_MEASUREMENT)
+                || type.equals(SQ_F_MEASUREMENT)
+                || type.equals(SQ_A_OUTLIER_MEASUREMENT)
+                || type.equals(SQ_B_OUTLIER_MEASUREMENT)
+                || type.equals(SQ_C_OUTLIER_MEASUREMENT)
+                || type.equals(SQ_D_OUTLIER_MEASUREMENT)
+                || type.equals(SQ_E_OUTLIER_MEASUREMENT)
+                || type.equals(SQ_F_OUTLIER_MEASUREMENT)
+                )
+            {
+                return true;
+            }
+
+            return false;
+        }
+        public static boolean SQ_OUTLIER(String type) {
+            if (type.equals(SQ_A_OUTLIER)
+                || type.equals(SQ_B_OUTLIER)
+                || type.equals(SQ_C_OUTLIER)
+                || type.equals(SQ_D_OUTLIER)
+                || type.equals(SQ_E_OUTLIER)
+                || type.equals(SQ_F_OUTLIER))
+            {
+                return true;
+            }
+
+            return false;
+        }
     };
 
-    String AREA                   = "area";
-    String CROSS_SECTION_AREA     = "cross_section.area";
-    String LONGITUDINAL_SECTION_AREA = "longitudinal_section.area";
+    public enum ChartType {
+        FD("fix_derivate_curve"),
+        LS("longitudinal_section"),
+        CS("cross_section"),
+        DLS("discharge_longitudinal_section"),
+        CDC("computed_discharge_curve"),
+        DUC("duration_curve"),
+        DIC("discharge_curve"),
+        RC("reference_curve"),
+        RCN("reference_curve_normalized"),
+        WD("wdifferences"),
+        FWQC("fix_wq_curve"),
+        FDWC("fix_deltawt_curve"),
+        FLSC("fix_longitudinal_section_curve"),
+        FDC("fix_derivate_curve"),
+        HD("historical_discharge");
 
-    String FLOODMAP_WSPLGEN       = "floodmap.wsplgen";
-    String FLOODMAP_BARRIERS      = "floodmap.barriers";
-    String FLOODMAP_RIVERAXIS     = "floodmap.riveraxis";
-    String FLOODMAP_WMSBACKGROUND = "floodmap.wmsbackground";
-    String FLOODMAP_KMS           = "floodmap.kms";
-    String FLOODMAP_QPS           = "floodmap.qps";
-    String FLOODMAP_HWS           = "floodmap.hws";
-    String FLOODMAP_CATCHMENT     = "floodmap.catchment";
-    String FLOODMAP_FLOODPLAIN    = "floodmap.floodplain";
-    String FLOODMAP_LINES         = "floodmap.lines";
-    String FLOODMAP_BUILDINGS     = "floodmap.buildings";
-    String FLOODMAP_FIXPOINTS     = "floodmap.fixpoints";
-    String FLOODMAP_EXTERNAL_WMS  = "floodmap.externalwms";
+        private String chartTypeString;
+
+        ChartType(String description) {
+            this.chartTypeString = description;
+        }
+
+        @Override
+        public String toString() {
+            return chartTypeString;
+        }
+    }
+
+    String AREA                        = "area";
+    String CROSS_SECTION_AREA          = "cross_section.area";
+    String LONGITUDINAL_SECTION_AREA   = "longitudinal_section.area";
+
+    String FLOODMAP_WSPLGEN            = "floodmap.wsplgen";
+    String FLOODMAP_BARRIERS           = "floodmap.barriers";
+    String FLOODMAP_USERSHAPE          = "floodmap.usershape";
+    String FLOODMAP_RIVERAXIS          = "floodmap.riveraxis";
+    String FLOODMAP_WMSBACKGROUND      = "floodmap.wmsbackground";
+    String FLOODMAP_KMS                = "floodmap.kms";
+    String FLOODMAP_QPS                = "floodmap.qps";
+    String FLOODMAP_HWS                = "floodmap.hws";
+    String FLOODMAP_HYDR_BOUNDARY      = "floodmap.hydr_boundaries";
+    String FLOODMAP_HYDR_BOUNDARY_POLY = "floodmap.hydr_boundaries_poly";
+    String FLOODMAP_CATCHMENT          = "floodmap.catchment";
+    String FLOODMAP_FLOODPLAIN         = "floodmap.floodplain";
+    String FLOODMAP_LINES              = "floodmap.lines";
+    String FLOODMAP_BUILDINGS          = "floodmap.buildings";
+    String FLOODMAP_FIXPOINTS          = "floodmap.fixpoints";
+    String FLOODMAP_FLOODMAPS          = "floodmap.floodmaps";
+    String FLOODMAP_GAUGE_LOCATION     = "floodmap.gauge_location";
+    String FLOODMAP_EXTERNAL_WMS       = "floodmap.externalwms";
 
     String DISCHARGE_LONGITUDINAL_W = "discharge_longitudinal_section.w";
     String DISCHARGE_LONGITUDINAL_Q = "discharge_longitudinal_section.q";
@@ -43,7 +161,8 @@
 
     String LONGITUDINAL_W = "longitudinal_section.w";
     String LONGITUDINAL_Q = "longitudinal_section.q";
-    String LONGITUDINAL_ANNOTATION = "longitudinal_section.annotations";
+    String LONGITUDINAL_ANNOTATION   = "longitudinal_section.annotations";
+    String LONGITUDINAL_MANUALPOINTS = "longitudinal_section.manualpoints";
 
     String W_DIFFERENCES = "w_differences";
 
@@ -57,15 +176,23 @@
     String CROSS_SECTION = "cross_section";
     String CROSS_SECTION_WATER_LINE = "cross_section_water_line";
 
+    String HYK = "hyk";
+
     String DISCHARGE_CURVE = "discharge_curve.curve";
 
     String DURATION_W = "duration_curve.w";
     String DURATION_Q = "duration_curve.q";
+    String DURATION_MAINVALUES_Q = "duration_curve.mainvalues.q";
 
-    String STATIC_WQ    = "other.wq";
+    String MANUALPOINTS = "manualpoints";
+    String MANUALLINE = "manualline";
+
+    String QSECTOR        = "qsectors";
+
+    String STATIC_WQ      = "other.wq";
     String STATIC_WQ_ANNOTATIONS = "other.wq.annotations";
-    String STATIC_WKMS  = "other.wkms";
-    String STATIC_WQKMS = "other.wqkms";
+    String STATIC_WKMS    = "other.wkms";
+    String STATIC_WQKMS   = "other.wqkms";
     String STATIC_WQKMS_W = "other.wqkms.w";
     String STATIC_WQKMS_Q = "other.wqkms.q";
     String STATIC_WKMS_INTERPOL = "other.wkms.interpol";
@@ -75,7 +202,111 @@
     String CSV = "csv";
     String WST = "wst";
     String AT  = "at";
+    String PDF = "pdf";
 
     String REPORT = "report";
+
+    String HISTORICAL_DISCHARGE_Q      = "historical_discharge.historicalq";
+    String HISTORICAL_DISCHARGE_Q_DIFF = "historical_discharge.historicalq.diff";
+
+    String REFERENCE_CURVE = "reference_curve";
+    String REFERENCE_CURVE_NORMALIZED = "reference_curve_normalized";
+
+    String FLOW_VELOCITY_MAINCHANNEL  = "flow_velocity.mainchannel";
+    String FLOW_VELOCITY_TOTALCHANNEL = "flow_velocity.totalchannel";
+    String FLOW_VELOCITY_TAU          = "flow_velocity.tau";
+    String FLOW_VELOCITY_ANNOTATION   = "flow_velocity.annotation";
+
+    String MIDDLE_BED_HEIGHT_SINGLE     = "bedheight_middle.single";
+    String MIDDLE_BED_HEIGHT_EPOCH      = "bedheight_middle.epoch";
+    String MIDDLE_BED_HEIGHT_ANNOTATION = "bedheight_middle.annotation";
+
+    String BED_QUALITY_POROSITY_TOPLAYER         = "bed_longitudinal_section.porosity_toplayer";
+    String BED_QUALITY_POROSITY_SUBLAYER         = "bed_longitudinal_section.porosity_sublayer";
+    String BED_QUALITY_BED_DIAMETER_TOPLAYER     = "bed_longitudinal_section.bed_diameter_toplayer";
+    String BED_QUALITY_BED_DIAMETER_SUBLAYER     = "bed_longitudinal_section.bed_diameter_sublayer";
+    String BED_QUALITY_SEDIMENT_DENSITY_TOPLAYER = "bed_longitudinal_section.sediment_density_toplayer";
+    String BED_QUALITY_SEDIMENT_DENSITY_SUBLAYER = "bed_longitudinal_section.sediment_density_sublayer";
+    String BED_QUALITY_BEDLOAD_DIAMETER          = "bed_longitudinal_section.bedload_diameter";
+
+    String BED_DIFFERENCE_YEAR          = "bedheight_difference.year";
+    String BED_DIFFERENCE_HEIGHT_YEAR   = "bedheight_difference.height_year";
+    String BED_DIFFERENCE_EPOCH         = "bedheight_difference.epoch";
+    String BED_DIFFERENCE_MORPH_WIDTH   = "bedheight_difference.morph_width";
+    String BED_DIFFERENCE_YEAR_HEIGHT1  = "bedheight_difference.year.height1";
+    String BED_DIFFERENCE_YEAR_HEIGHT2  = "bedheight_difference.year.height2";
+    String BED_DIFFERENCE_EPOCH_HEIGHT1 = "bedheight_difference.epoch.height1";
+    String BED_DIFFERENCE_EPOCH_HEIGHT2 = "bedheight_difference.epoch.height2";
+
+    String SQ_OVERVIEW       = "sq_overview";
+
+    String SQ_A_CURVE       = "sq_a_curve";
+    String SQ_A_MEASUREMENT = "sq_a_measurement";
+    String SQ_A_OUTLIER     = "sq_a_outlier";
+    String SQ_A_OUTLIER_CURVE = "sq_a_outlier_curve";
+    String SQ_A_OUTLIER_MEASUREMENT = "sq_a_outlier_measurement";
+
+    String SQ_B_CURVE       = "sq_b_curve";
+    String SQ_B_MEASUREMENT = "sq_b_measurement";
+    String SQ_B_OUTLIER     = "sq_b_outlier";
+    String SQ_B_OUTLIER_CURVE  = "sq_b_outlier_curve";
+    String SQ_B_OUTLIER_MEASUREMENT  = "sq_b_outlier_measurement";
+
+    String SQ_C_CURVE       = "sq_c_curve";
+    String SQ_C_MEASUREMENT = "sq_c_measurement";
+    String SQ_C_OUTLIER     = "sq_c_outlier";
+    String SQ_C_OUTLIER_CURVE = "sq_c_outlier_curve";
+    String SQ_C_OUTLIER_MEASUREMENT = "sq_c_outlier_measurement";
+
+    String SQ_D_CURVE       = "sq_d_curve";
+    String SQ_D_MEASUREMENT = "sq_d_measurement";
+    String SQ_D_OUTLIER     = "sq_d_outlier";
+    String SQ_D_OUTLIER_CURVE = "sq_d_outlier_curve";
+    String SQ_D_OUTLIER_MEASUREMENT = "sq_d_outlier_measurement";
+
+    String SQ_E_CURVE       = "sq_e_curve";
+    String SQ_E_MEASUREMENT = "sq_e_measurement";
+    String SQ_E_OUTLIER     = "sq_e_outlier";
+    String SQ_E_OUTLIER_CURVE = "sq_e_outlier_curve";
+    String SQ_E_OUTLIER_MEASUREMENT = "sq_e_outlier_curve_measurement";
+
+    String SQ_F_CURVE       = "sq_f_curve";
+    String SQ_F_MEASUREMENT = "sq_f_measurement";
+    String SQ_F_OUTLIER     = "sq_f_outlier";
+    String SQ_F_OUTLIER_CURVE = "sq_f_outlier_curve";
+    String SQ_F_OUTLIER_MEASUREMENT = "sq_f_outlier_measurement";
+
+    String RELATIVE_POINT = "relativepoint";
+
+    String FIX_ANALYSIS_EVENTS_DWT = "fix_analysis_events_dwt";
+    String FIX_ANALYSIS_EVENTS_LS = "fix_analysis_events_ls";
+    String FIX_ANALYSIS_EVENTS_WQ = "fix_analysis_events_wq";
+
+    String FIX_REFERENCE_EVENTS_DWT = "fix_reference_events_dwt";
+    String FIX_REFERENCE_EVENTS_LS = "fix_reference_events_ls";
+    String FIX_REFERENCE_EVENTS_WQ = "fix_reference_events_wq";
+    String FIX_REFERENCE_PERIOD_DWT = "fix_reference_period_dwt";
+
+    // Note that AVERAGE_DWT will get a postfix (e.g. ..._dwt_1)
+    String FIX_SECTOR_AVERAGE_DWT = "fix_sector_average_dwt";
+    String FIX_SECTOR_AVERAGE_LS = "fix_sector_average_ls";
+    String FIX_SECTOR_AVERAGE_WQ = "fix_sector_average_wq";
+    String FIX_SECTOR_AVERAGE_LS_DEVIATION = "fix_sector_average_ls_deviation";
+
+    String FIX_WQ_CURVE = "fix_wq_curve";
+    String FIX_OUTLIER = "fix_outlier";
+
+    String FIX_ANALYSIS_PERIODS_DWT = "fix_analysis_periods_dwt";
+    String FIX_ANALYSIS_PERIODS_LS = "fix_analysis_periods_ls";
+    String FIX_ANALYSIS_PERIODS_WQ = "fix_analysis_periods_wq";
+
+    String FIX_DERIVATE_CURVE = "fix_derivate_curve";
+
+    String FIX_DEVIATION_DWT = "fix_deviation_dwt";
+    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/FastCrossSectionChunk.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,83 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.List;
+import java.util.Collections;
+
+import java.io.Serializable;
+
+import de.intevation.flys.model.CrossSection;
+
+import de.intevation.flys.model.FastCrossSectionLine;
+
+import org.apache.log4j.Logger;
+
+public class FastCrossSectionChunk
+implements   Serializable
+{
+    private static Logger log = Logger.getLogger(FastCrossSectionChunk.class);
+
+    public static final String PREFIX = "FCSC:";
+    public static final double KM_RANGE = 1.0;
+
+    protected double startKm;
+    protected int    crossSectionId;
+
+    protected List<FastCrossSectionLine> crossSectionLines;
+
+    public FastCrossSectionChunk() {
+    }
+
+    public FastCrossSectionChunk(CrossSection cs, double km) {
+
+        crossSectionId = cs.getId();
+        startKm = Math.floor(km);
+        double stopKm = startKm + KM_RANGE;
+
+        long startTime = System.currentTimeMillis();
+
+        crossSectionLines = cs.getFastLines(startKm, stopKm);
+
+        long stopTime = System.currentTimeMillis();
+
+        if (log.isDebugEnabled()) {
+            log.debug("Fetching cross section lines took " +
+                (float)(stopTime-startTime)/1000f + " secs.");
+        }
+    }
+
+    public FastCrossSectionLine getCrossSectionLine(double km) {
+        FastCrossSectionLine key = new FastCrossSectionLine(km);
+        int pos = Collections.binarySearch(
+            crossSectionLines, key, FastCrossSectionLine.KM_CMP);
+        return pos < 0 ? null : crossSectionLines.get(pos);
+    }
+
+    public static String createHashKey(CrossSection cs, double km) {
+        return PREFIX + cs.getId() + ":" + (int)Math.floor(km);
+    }
+
+    public String getHashKey() {
+        return PREFIX + crossSectionId + ":" + (int)Math.floor(startKm);
+    }
+
+    public double getStartKm() {
+        return startKm;
+    }
+
+    public void setStartKm(double startKm) {
+        this.startKm = startKm;
+    }
+
+    public double getStopKm() {
+        return startKm + KM_RANGE;
+    }
+
+    public int getCrossSectionId() {
+        return crossSectionId;
+    }
+
+    public void setCrossSectionId(int crossSectionId) {
+        this.crossSectionId = crossSectionId;
+    }
+}
+// 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/FastCrossSectionLineFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,69 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+
+import de.intevation.flys.model.CrossSection;
+
+import de.intevation.flys.model.FastCrossSectionLine;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class FastCrossSectionLineFactory
+{
+    private static Logger log =
+        Logger.getLogger(FastCrossSectionLineFactory.class);
+
+    public static final String CACHE_NAME = "fast-cross-section-lines";
+
+    private FastCrossSectionLineFactory() {
+    }
+
+    public static FastCrossSectionLine getCrossSectionLine(
+        CrossSection cs,
+        double       km
+    ) {
+        Cache cache = CacheFactory.getCache(CACHE_NAME);
+
+        boolean debug = log.isDebugEnabled();
+
+        if (cache == null) {
+            if (debug) {
+                log.debug("No cross section chunk cache configured.");
+            }
+            List<FastCrossSectionLine> lines = cs.getFastLines(km, km);
+            return lines.isEmpty() ? null : lines.get(0);
+        }
+
+        String cacheKey = FastCrossSectionChunk.createHashKey(cs, km);
+
+        Element element = cache.get(cacheKey);
+
+        FastCrossSectionChunk fcsc;
+
+        if (element != null) {
+            if (debug) {
+                log.debug("Found cross section chunk in cache id: " +
+                    cs.getId() + " km: " + km);
+            }
+
+            fcsc = (FastCrossSectionChunk)element.getValue();
+        }
+        else {
+            if (debug) {
+                log.debug("Not found cross section chunk in cache id: " +
+                    cs.getId() + " km: " + km + " -> loading");
+            }
+            fcsc = new FastCrossSectionChunk(cs, km);
+            element = new Element(cacheKey, fcsc);
+            cache.put(element);
+        }
+
+        return fcsc.getCrossSectionLine(km);
+    }
+}
+// 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/FixingsColumn.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,62 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.math.Linear;
+
+import java.util.Arrays;
+
+import java.io.Serializable;
+
+public class FixingsColumn
+implements   Serializable
+{
+    protected double [] kms;
+    protected double [] ws;
+
+    protected QRangeTree qs;
+
+    public FixingsColumn() {
+    }
+
+    public FixingsColumn(
+        double []  kms,
+        double []  ws,
+        QRangeTree qs
+    ) {
+        this.kms = kms;
+        this.ws  = ws;
+        this.qs  = qs;
+    }
+
+    public boolean getW(double km, double [] w) {
+        return getW(km, w, 0);
+    }
+
+    public boolean getW(double km, double [] w, int index) {
+
+        if (kms.length == 0 || km < kms[0] || km > kms[kms.length-1]) {
+            w[index] = Double.NaN;
+            return true;
+        }
+
+        int idx = Arrays.binarySearch(kms, km);
+
+        if (idx >= 0) {
+            w[index] = ws[idx];
+            return true;
+        }
+
+        idx = -idx - 1;
+
+        w[index] = Linear.linear(km, kms[idx-1], kms[idx], ws[idx-1], ws[idx]);
+        return false;
+    }
+
+    public double getQ(double km) {
+        return qs.findQ(km);
+    }
+
+    public QRangeTree getQRanges() {
+        return qs;
+    }
+}
+// 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/FixingsColumnFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,131 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.Fixing;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+
+import de.intevation.flys.backend.SessionHolder;
+
+import java.util.List;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.hibernate.Session;
+import org.hibernate.SQLQuery;
+
+import org.hibernate.type.StandardBasicTypes;
+
+import org.apache.log4j.Logger;
+
+public class FixingsColumnFactory
+{
+    private static Logger log = Logger.getLogger(FixingsColumnFactory.class);
+
+    public static final String CACHE_NAME = "fixings-columns";
+
+    public static final String SQL_COLUMN_WS =
+        "SELECT wcv.position AS km, wcv.w AS w " +
+        "FROM wst_column_values wcv " +
+        "WHERE wst_column_id = :column_id " +
+        "ORDER by wcv.position";
+
+    public static final String SQL_COLUMN_QS =
+        "SELECT wqr.q AS q, r.a AS a, r.b AS b " +
+        "FROM wst_column_q_ranges wcqr " +
+        "JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id " +
+        "JOIN ranges r         ON wqr.range_id        = r.id " +
+        "WHERE wcqr.wst_column_id = :column_id ORDER by r.a";
+
+    public static final FixingsColumnFactory INSTANCE =
+        new FixingsColumnFactory();
+
+    private FixingsColumnFactory() {
+    }
+
+    public static FixingsColumnFactory getInstance() {
+        return INSTANCE;
+    }
+
+    public FixingsColumn getColumnData(Fixing.Column column) {
+
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("FixingsColumnFactory.getColumnData");
+        }
+
+        Cache cache = CacheFactory.getCache(CACHE_NAME);
+
+        if (cache == null) {
+            if (debug) {
+                log.debug("Cache unconfigured.");
+            }
+            return getUncached(column);
+        }
+
+        Integer cacheKey = Integer.valueOf(column.getId());
+        Element element  = cache.get(cacheKey);
+
+        if (element != null) {
+            if (debug) {
+                log.debug("Column " + cacheKey + " found in cache.");
+            }
+            return (FixingsColumn)element.getValue();
+        }
+        else {
+            FixingsColumn result = getUncached(column);
+            if (result != null) {
+                if (debug) {
+                    log.debug("Store column " + cacheKey + " into cache.");
+                }
+                cache.put(new Element(cacheKey, result));
+            }
+            return result;
+        }
+    }
+
+    protected FixingsColumn getUncached(Fixing.Column column) {
+        Session session = SessionHolder.HOLDER.get();
+
+        SQLQuery sqlQuery = session.createSQLQuery(SQL_COLUMN_WS)
+            .addScalar("km", StandardBasicTypes.DOUBLE)
+            .addScalar("w",  StandardBasicTypes.DOUBLE);
+
+        sqlQuery.setInteger("column_id", column.getId());
+
+        List<Object []> results = sqlQuery.list();
+
+        if (results.isEmpty()) {
+            return null;
+        }
+
+        double [] kms = new double[results.size()];
+        double [] ws  = new double[kms.length];
+
+        for (int i = 0; i < kms.length; ++i) {
+            Object [] row = results.get(i);
+            kms[i] = ((Double)row[0]).doubleValue();
+            ws [i] = ((Double)row[1]).doubleValue();
+        }
+
+        sqlQuery = session.createSQLQuery(SQL_COLUMN_QS)
+            .addScalar("q", StandardBasicTypes.DOUBLE)
+            .addScalar("a", StandardBasicTypes.DOUBLE)
+            .addScalar("b", StandardBasicTypes.DOUBLE);
+
+        sqlQuery.setInteger("column_id", column.getId());
+
+        results = sqlQuery.list();
+
+        if (results.isEmpty()) {
+            return null;
+        }
+
+        QRangeTree qs = new QRangeTree(
+            results, QRangeTree.WITHOUT_COLUMN, 0, results.size());
+
+        return new FixingsColumn(kms, ws, qs);
+    }
+}
+// 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/FixingsFilterBuilder.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,247 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.AndFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.DateFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.DateRangeFilter;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.IdFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.IdsFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.KmFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.NotFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.OrFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.SectorFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.SectorRangeFilter;
+
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class FixingsFilterBuilder
+{
+    private static Logger log = Logger.getLogger(FixingsFilterBuilder.class);
+
+    protected Filter   filter;
+    protected Range    range;
+
+    protected Document document;
+
+    public FixingsFilterBuilder() {
+    }
+
+    public FixingsFilterBuilder(Document document) {
+        this.document = document;
+    }
+
+    public Filter getFilter() {
+        if (filter == null) {
+            filter = buildFilter();
+        }
+        return filter;
+    }
+
+    public Range getRange() {
+        if (range == null) {
+            range = buildRange();
+        }
+        return range;
+    }
+
+    public Document getDocument() {
+        return document;
+    }
+
+    protected Range buildRange() {
+
+        NodeList ranges = document.getElementsByTagName("range");
+
+        if (ranges.getLength() < 1) {
+            return FixingsOverview.FULL_EXTENT;
+        }
+
+        Element range = (Element)ranges.item(0);
+
+        String from = range.getAttribute("from").trim();
+        String to   = range.getAttribute("to"  ).trim();
+
+        double start = -Double.MAX_VALUE;
+        double end   =  Double.MAX_VALUE;
+
+        if (from.length() > 0) {
+            try {
+                start = Double.parseDouble(from);
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("Invalid from value: " + from);
+            }
+        }
+
+        if (to.length() > 0) {
+            try {
+                end = Double.parseDouble(to);
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("Invalid to value: " + to);
+            }
+        }
+
+        if (start > end) {
+            double t = start;
+            start = end;
+            end = t;
+        }
+
+        return new Range(start, end);
+    }
+
+    protected Filter buildFilter() {
+        NodeList filters = document.getElementsByTagName("filter");
+
+        return filters.getLength() < 1
+            ? FixingsOverview.ACCEPT
+            : buildFilter((Element)filters.item(0));
+    }
+
+    protected static Filter buildFilter(Element root) {
+        List<Filter> filters = buildRecursiveFilter(root);
+        switch (filters.size()) {
+            case  0: return FixingsOverview.ACCEPT;
+            case  1: return filters.get(0);
+            default: return new AndFilter(filters);
+        }
+    }
+
+    protected static final Date parseDate(String text) {
+        SimpleDateFormat format =
+            new SimpleDateFormat(FixingsOverview.DATE_FORMAT);
+        return format.parse(text, new ParsePosition(0));
+    }
+
+    protected static List<Filter> buildRecursiveFilter(Element root) {
+        List<Filter> filters = new ArrayList<Filter>();
+
+        NodeList children = root.getChildNodes();
+
+        for (int i = 0, N = children.getLength(); i < N; ++i) {
+            Node child = children.item(i);
+            if (child.getNodeType() != Node.ELEMENT_NODE) {
+                continue;
+            }
+
+            Element element = (Element)child;
+            String name = element.getLocalName();
+
+            if ("and".equals(name)) {
+                filters.add(new AndFilter(buildRecursiveFilter(element)));
+            }
+            else if ("or".equals(name)) {
+                filters.add(new OrFilter(buildRecursiveFilter(element)));
+            }
+            else if ("not".equals(name)) {
+                List<Filter> childrenFilters = buildRecursiveFilter(element);
+                if (!childrenFilters.isEmpty()) {
+                    filters.add(new NotFilter(childrenFilters.get(0)));
+                }
+            }
+            else if ("column".equals(name)) {
+                String cid = element.getAttribute("cid").trim();
+                if (cid.length() > 0) {
+                    try {
+                        filters.add(new IdFilter(Integer.parseInt(cid)));
+                    }
+                    catch (NumberFormatException nfe) {
+                        log.warn(nfe);
+                    }
+                }
+            }
+            else if ("columns".equals(name)) {
+                String cidsS = element.getAttribute("cids").trim();
+                String [] parts = cidsS.split("\\s+");
+                List<Integer> ids = new ArrayList<Integer>();
+                for (String part: parts) {
+                    try {
+                        ids.add(Integer.valueOf(part));
+                    }
+                    catch (NumberFormatException nfe) {
+                        log.warn(nfe);
+                    }
+                }
+                int [] cids = new int[ids.size()];
+                for (int j = 0; j < cids.length; ++j) {
+                    cids[j] = ids.get(j);
+                }
+                filters.add(new IdsFilter(cids));
+            }
+            else if ("date".equals(name)) {
+                String when = element.getAttribute("when").trim();
+                if (when.length() > 0) {
+                    Date date = parseDate(when);
+                    if (date != null) {
+                        filters.add(new DateFilter(date));
+                    }
+                }
+            }
+            else if ("date-range".equals(name)) {
+                String from = element.getAttribute("from").trim();
+                String to   = element.getAttribute("to"  ).trim();
+                if (from.length() > 0 && to.length() > 0) {
+                    Date start = parseDate(from);
+                    Date end   = parseDate(to);
+                    if (start != null && end != null) {
+                        filters.add(new DateRangeFilter(start, end));
+                    }
+                }
+            }
+            else if ("sector-range".equals(name)) {
+                String from = element.getAttribute("from").trim();
+                String to   = element.getAttribute("to"  ).trim();
+                if (from.length() > 0 && to.length() > 0) {
+                    try {
+                        filters.add(new SectorRangeFilter(
+                            Integer.parseInt(from),
+                            Integer.parseInt(to)));
+                    }
+                    catch (NumberFormatException nfe) {
+                        log.warn(nfe);
+                    }
+                }
+            }
+            else if ("sector".equals(name)) {
+                String value = element.getAttribute("value").trim();
+                if (value.length() > 0) {
+                    try {
+                        filters.add(new SectorFilter(Integer.parseInt(value)));
+                    }
+                    catch (NumberFormatException nfe) {
+                        log.warn(nfe);
+                    }
+                }
+            }
+            else if ("position".equals(name)) {
+                String km = element.getAttribute("km").trim();
+                if (km.length() > 0) {
+                    try {
+                        filters.add(new KmFilter(Double.parseDouble(km)));
+                    }
+                    catch (NumberFormatException nfe) {
+                        log.warn(nfe);
+                    }
+                }
+            }
+        }
+
+        return filters;
+    }
+}
+// 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/FixingsOverview.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,788 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+import java.text.SimpleDateFormat;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+
+import org.hibernate.type.StandardBasicTypes;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class FixingsOverview
+implements   Serializable
+{
+    private static Logger log = Logger.getLogger(FixingsOverview.class);
+
+    public static final double EPSILON = 1e-2;
+
+    public static final String DATE_FORMAT = "dd.MM.yyyy";
+
+    public static final String SQL_RIVER_ID =
+        "SELECT" +
+        "    id AS river_id," +
+        "    km_up " +
+        "FROM rivers " +
+        "WHERE" +
+        "    name = :name";
+
+    public static final String SQL_FIXINGS =
+        "SELECT" +
+        "    id AS wst_id," +
+        "    description " +
+        "FROM wsts " +
+        "WHERE" +
+        "    river_id = :river_id AND kind = 2";
+
+    public static final String SQL_FIXING_COLUMNS =
+        "SELECT" +
+        "    wc.id         AS wst_column_id," +
+        "    ti.start_time AS start_time," +
+        "    wc.name       AS name " +
+        "FROM wst_columns wc" +
+        "    JOIN time_intervals ti ON wc.time_interval_id = ti.id " +
+        "WHERE" +
+        "    wc.wst_id = :wst_id " +
+        "ORDER BY position";
+
+    public static final String SQL_FIXING_COLUMN_Q_RANGES =
+        "SELECT" +
+        "    wqr.q AS q," +
+        "    r.a   AS start_km," +
+        "    r.b   AS stop_km " +
+        "FROM wst_column_q_ranges wcqr" +
+        "    JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id" +
+        "    JOIN ranges       r   ON wqr.range_id        = r.id " +
+        "WHERE" +
+        "    wcqr.wst_column_id = :column_id " +
+        "ORDER BY r.a";
+
+    public static final String SQL_FIXING_COLUMN_KM_RANGE =
+        "SELECT" +
+        "    MIN(position) AS start_km," +
+        "    MAX(position) AS stop_km " +
+        "FROM" +
+        "    wst_column_values " +
+        "WHERE" +
+        "    wst_column_id = :column_id";
+
+
+    public static class QRange extends Range {
+
+        protected double q;
+
+        public QRange() {
+        }
+
+        public QRange(double start, double end, double q) {
+            super(start, end);
+            this.q = q;
+        }
+    } // class QRange
+
+    public static class SectorRange extends Range {
+
+        protected int sector;
+
+        public SectorRange() {
+        }
+
+        public SectorRange(SectorRange other) {
+            start  = other.start;
+            end    = other.end;
+            sector = other.sector;
+        }
+
+        public SectorRange(Range range) {
+            super(range);
+        }
+
+        public SectorRange(double start, double end, int sector) {
+            super(start, end);
+            this.sector = sector;
+        }
+
+        public int getSector() {
+            return sector;
+        }
+
+        public void setSector(int sector) {
+            this.sector = sector;
+        }
+
+        public boolean enlarge(SectorRange other) {
+            if (sector == other.sector
+            && Math.abs(end-other.start) < FixingsOverview.EPSILON) {
+                end = other.end;
+                return true;
+            }
+            return false;
+        }
+    } // class SectorRange
+
+    public static class Fixing implements Serializable {
+
+        public static final Comparator<Column> DATE_CMP =
+            new Comparator<Column>() {
+                @Override
+                public int compare(Column a, Column b) {
+                    return a.startTime.compareTo(b.startTime);
+                }
+            };
+
+        public interface Filter {
+
+            boolean accept(Column column);
+
+        } // interface Filter
+
+        public class Column extends Range {
+
+            protected int    columnId;
+            protected Date   startTime;
+            protected String name;
+
+            protected List<SectorRange> sectors;
+
+            public Column() {
+            }
+
+            public Column(int columnId, Date startTime, String name) {
+                this.columnId  = columnId;
+                this.startTime = startTime;
+                this.name      = name;
+
+                sectors = new ArrayList<SectorRange>();
+            }
+
+            public int getId() {
+                return columnId;
+            }
+
+            public Fixing getFixing() {
+                return Fixing.this;
+            }
+
+            public Date getStartTime() {
+                return startTime;
+            }
+
+            public String getName() {
+                return name;
+            }
+
+            public String getDescription() {
+                return Fixing.this.description + "/" + name;
+            }
+
+            public List<SectorRange> getSectors() {
+                return sectors;
+            }
+
+            public List<SectorRange> getSectors(Range range) {
+
+                List<SectorRange> result =
+                    new ArrayList<SectorRange>(sectors.size());
+
+                for (SectorRange src: sectors) {
+                    SectorRange dst = new SectorRange(src);
+                    if (range == null || dst.clip(range)) {
+                        result.add(dst);
+                    }
+                }
+
+                return result;
+            }
+
+            public int findQSector(double km) {
+                for (SectorRange sector: sectors) {
+                    if (sector.inside(km)) {
+                        return sector.getSector();
+                    }
+                }
+                return -1;
+            }
+
+            public void buildSectors(
+                GaugeFinder  gaugeFinder,
+                List<QRange> qRanges
+            ) {
+                for (QRange qRange: qRanges) {
+                    for (GaugeRange gRange: gaugeFinder.getGauges()) {
+                        SectorRange sector = new SectorRange(qRange);
+                        if (!sector.clip(gRange)) {
+                            continue;
+                        }
+                        sector.setSector(gRange.classify(qRange.q));
+
+                        if (sectors.isEmpty()
+                        || !sectors.get(sectors.size()-1).enlarge(sector)) {
+                            sectors.add(sector);
+                        }
+                    } // for all gauges
+                } // for all Q ranges
+            }
+
+            public void loadKmRange(SQLQuery query) {
+                query.setInteger("column_id", columnId);
+
+                List<Object []> kms = query.list();
+
+                if (kms.isEmpty()) {
+                    log.warn("No km range for column " + columnId + ".");
+                }
+                else {
+                    Object [] obj = kms.get(0);
+                    start = (Double)obj[0];
+                    end   = (Double)obj[1];
+                }
+            }
+
+            public void loadQRanges(
+                SQLQuery    query,
+                GaugeFinder gaugeFinder
+            ) {
+                query.setInteger("column_id", columnId);
+                List<Object []> list = query.list();
+
+                List<QRange> qRanges = new ArrayList<QRange>(list.size());
+
+                for (Object [] row: list) {
+                    double q     = (Double)row[0];
+                    double start = (Double)row[1];
+                    double end   = (Double)row[2];
+                    QRange qRange = new QRange(start, end, q);
+                    if (qRange.clip(this)) {
+                        qRanges.add(qRange);
+                    }
+                }
+
+                buildSectors(gaugeFinder, qRanges);
+            }
+        } // class Column
+
+        protected int          wstId;
+        protected String       description;
+        protected List<Column> columns;
+
+        public Fixing() {
+        }
+
+        public int getId() {
+            return wstId;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public Fixing(int wstId, String description) {
+            this.wstId       = wstId;
+            this.description = description;
+            columns = new ArrayList<Column>();
+        }
+
+        public void loadColumns(SQLQuery query) {
+            query.setInteger("wst_id", wstId);
+            List<Object []> list = query.list();
+            for (Object [] row: list) {
+                int    columnId  = (Integer)row[0];
+                Date   startTime = (Date)   row[1];
+                String name      = (String) row[2];
+                columns.add(new Column(columnId, startTime, name));
+            }
+        }
+
+        public void loadColumnsKmRange(SQLQuery query) {
+            for (Column column: columns) {
+                column.loadKmRange(query);
+            }
+        }
+
+        public void adjustExtent(Range extent) {
+            for (Column column: columns) {
+                extent.extend(column);
+            }
+        }
+
+        public void loadColumnsQRanges(
+            SQLQuery    query,
+            GaugeFinder gaugeFinder
+        ) {
+            for (Column column: columns) {
+                column.loadQRanges(query, gaugeFinder);
+            }
+        }
+
+        public void addAllColumns(
+            List<Column> allColumns,
+            Range        range,
+            Filter       filter
+        ) {
+            for (Column column: columns) {
+                if ((range == null || column.intersects(range))
+                && (filter == null || filter.accept(column))) {
+                    allColumns.add(column);
+                }
+            }
+        }
+    } // class Fixing
+
+
+    protected String       riverName;
+    protected int          riverId;
+    protected boolean      isKmUp;
+    protected List<Fixing> fixings;
+    protected Range        extent;
+
+    public FixingsOverview() {
+        fixings = new ArrayList<Fixing>();
+        extent  = new Range(Double.MAX_VALUE, -Double.MAX_VALUE);
+    }
+
+    public FixingsOverview(String riverName) {
+        this();
+        this.riverName = riverName;
+    }
+
+    protected boolean loadRiver(Session session) {
+        SQLQuery query = session.createSQLQuery(SQL_RIVER_ID)
+            .addScalar("river_id", StandardBasicTypes.INTEGER)
+            .addScalar("km_up",    StandardBasicTypes.BOOLEAN);
+
+        query.setString("name", riverName);
+
+        List<Object []> list = query.list();
+
+        if (list.isEmpty()) {
+            log.warn("No river '" + riverName + "' found.");
+            return false;
+        }
+
+        Object [] row = list.get(0);
+
+        riverId = (Integer)row[0];
+        isKmUp  = (Boolean)row[1];
+
+        return true;
+    }
+
+    protected void loadFixings(Session session) {
+        SQLQuery query = session.createSQLQuery(SQL_FIXINGS)
+            .addScalar("wst_id",      StandardBasicTypes.INTEGER)
+            .addScalar("description", StandardBasicTypes.STRING);
+
+        query.setInteger("river_id", riverId);
+
+        List<Object []> list = query.list();
+
+        if (list.isEmpty()) {
+            log.warn("River " + riverId + " has no fixings.");
+            // Its pretty fine to have no fixings.
+        }
+
+        for (Object [] row: list) {
+            int    wstId       = (Integer)row[0];
+            String description = (String) row[1];
+            Fixing fixing = new Fixing(wstId, description);
+            fixings.add(fixing);
+        }
+    }
+
+    protected void loadFixingsColumns(Session session) {
+        SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMNS)
+            .addScalar("wst_column_id", StandardBasicTypes.INTEGER)
+            .addScalar("start_time",    StandardBasicTypes.DATE)
+            .addScalar("name",          StandardBasicTypes.STRING);
+
+        for (Fixing fixing: fixings) {
+            fixing.loadColumns(query);
+        }
+    }
+
+    protected void loadFixingsColumnsKmRange(Session session) {
+        SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_KM_RANGE)
+            .addScalar("start_km", StandardBasicTypes.DOUBLE)
+            .addScalar("stop_km",  StandardBasicTypes.DOUBLE);
+
+        for (Fixing fixing: fixings) {
+            fixing.loadColumnsKmRange(query);
+        }
+    }
+
+    protected void loadFixingsColumnsQRanges(
+        Session     session,
+        GaugeFinder gaugeFinder
+    ) {
+        SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES)
+            .addScalar("q",        StandardBasicTypes.DOUBLE)
+            .addScalar("start_km", StandardBasicTypes.DOUBLE)
+            .addScalar("stop_km",  StandardBasicTypes.DOUBLE);
+
+        for (Fixing fixing: fixings) {
+            fixing.loadColumnsQRanges(query, gaugeFinder);
+        }
+    }
+
+    protected void adjustExtent() {
+        for (Fixing fixing: fixings) {
+            fixing.adjustExtent(extent);
+        }
+    }
+
+    public boolean load(Session session) {
+
+        if (!loadRiver(session)) {
+            return false;
+        }
+
+        GaugeFinderFactory gff = GaugeFinderFactory.getInstance();
+
+        GaugeFinder gaugeFinder = gff.getGaugeFinder(riverId, isKmUp);
+
+        if (gaugeFinder == null) {
+            return false;
+        }
+
+        loadFixings(session);
+        loadFixingsColumns(session);
+        loadFixingsColumnsKmRange(session);
+
+        adjustExtent();
+
+        loadFixingsColumnsQRanges(session, gaugeFinder);
+
+        return true;
+    }
+
+    public static final Range FULL_EXTENT =
+        new Range(-Double.MAX_VALUE, Double.MAX_VALUE);
+
+    public static final Fixing.Filter ACCEPT = new Fixing.Filter() {
+        @Override
+        public boolean accept(Fixing.Column column) {
+            return true;
+        }
+    };
+
+    public static class NotFilter implements Fixing.Filter {
+        protected Fixing.Filter child;
+
+        public NotFilter(Fixing.Filter child) {
+            this.child = child;
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            return !child.accept(column);
+        }
+    } // class NotFilter
+
+    public static abstract class ComponentFilter implements Fixing.Filter {
+        protected List<Fixing.Filter> children;
+
+        public ComponentFilter() {
+            children = new ArrayList<Fixing.Filter>();
+        }
+
+        public ComponentFilter(List<Fixing.Filter> children) {
+            this.children = children;
+        }
+
+        public ComponentFilter add(Fixing.Filter filter) {
+            children.add(filter);
+            return this;
+        }
+    } // class ComponentFilter
+
+    public static class OrFilter extends ComponentFilter {
+
+        public OrFilter() {
+        }
+
+        public OrFilter(List<Fixing.Filter> children) {
+            super(children);
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            for (Fixing.Filter child: children) {
+                if (child.accept(column)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    } // class OrFilter
+
+    public static class AndFilter extends ComponentFilter {
+
+        public AndFilter() {
+        }
+
+        public AndFilter(List<Fixing.Filter> children) {
+            super(children);
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            for (Fixing.Filter child: children) {
+                if (!child.accept(column)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    } // class AndFilter
+
+    public static class IdFilter implements Fixing.Filter {
+
+        protected int columnId;
+
+        public IdFilter(int columnId) {
+            this.columnId = columnId;
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            return column.getId() == columnId;
+        }
+    } // class IdFilter
+
+    public static class IdsFilter implements Fixing.Filter {
+
+        protected int [] columnIds;
+
+        public IdsFilter(int [] columnIds) {
+            this.columnIds = columnIds;
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            int cid = column.getId();
+            for (int i = columnIds.length-1; i >= 0; --i) {
+                if (columnIds[i] == cid) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    } // class IdFilter
+
+    public static class DateFilter implements Fixing.Filter {
+
+        protected Date date;
+
+        public DateFilter(Date date) {
+            this.date = date;
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            return date.equals(column.getStartTime());
+        }
+    } // class DateFilter
+
+    public static class DateRangeFilter implements Fixing.Filter {
+
+        protected Date start;
+        protected Date end;
+
+        public DateRangeFilter(Date start, Date end) {
+            this.start = start;
+            this.end   = end;
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            Date date = column.getStartTime();
+            return start.compareTo(date) <= 0 && end.compareTo(date) >= 0;
+        }
+    } // class DateRangeFilter
+
+    public static class SectorFilter implements Fixing.Filter {
+
+        protected int sector;
+
+        public SectorFilter(int sector) {
+            this.sector = sector;
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            for (SectorRange s: column.getSectors()) {
+                if (s.getSector() == sector) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    } // class SectorFilter
+
+    public static class SectorRangeFilter implements Fixing.Filter {
+
+        protected int min;
+        protected int max;
+
+        public SectorRangeFilter(int min, int max) {
+            this.min = Math.min(min, max);
+            this.max = Math.max(min, max);
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            for (SectorRange s: column.getSectors()) {
+                int v = s.getSector();
+                if (v >= min && v <= max) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    } // class SectorRangeFilter
+
+    public static class KmFilter implements Fixing.Filter {
+
+        protected double km;
+
+        public KmFilter(double km) {
+            this.km = km;
+        }
+
+        @Override
+        public boolean accept(Fixing.Column column) {
+            for (SectorRange s: column.getSectors()) {
+                if (s.inside(km)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    } // class KmFilter
+
+    public void generateOverview(Document document) {
+        generateOverview(document, FULL_EXTENT, ACCEPT);
+    }
+
+    public List<Fixing.Column> filter(Range range, Fixing.Filter filter) {
+        List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>();
+
+        for (Fixing fixing: fixings) {
+            fixing.addAllColumns(allColumns, range, filter);
+        }
+
+        Collections.sort(allColumns, Fixing.DATE_CMP);
+
+        return allColumns;
+    }
+
+    protected static Range realRange(List<Fixing.Column> columns) {
+        Range range = null;
+        for (Fixing.Column column: columns) {
+            if (range == null) {
+                range = new Range(column);
+            }
+            else {
+                range.extend(column);
+            }
+        }
+        return range;
+    }
+
+    protected Element intersectingGauges(Document document, Range range) {
+        Element gauges = document.createElement("gauges");
+
+        if (range == null) {
+            return gauges;
+        }
+
+        GaugeFinderFactory gff = GaugeFinderFactory.getInstance();
+
+        GaugeFinder gf = gff.getGaugeFinder(riverId, isKmUp);
+
+        if (gf == null) {
+            return gauges;
+        }
+
+        for (GaugeRange gr: gf.getGauges()) {
+            if (gr.intersects(range)) {
+                Element gauge = document.createElement("gauge");
+                gauge.setAttribute("from", String.valueOf(gr.getStart()));
+                gauge.setAttribute("to",   String.valueOf(gr.getEnd()));
+                gauge.setAttribute("name", gr.getName());
+                gauges.appendChild(gauge);
+            }
+        }
+
+        return gauges;
+    }
+
+    public void generateOverview(
+        Document      document,
+        Range         range,
+        Fixing.Filter filter
+    ) {
+        List<Fixing.Column> allColumns = filter(range, filter);
+
+        Element fixingsElement = document.createElement("fixings");
+
+        Element riverElement = document.createElement("river");
+
+        riverElement.setAttribute("from", String.valueOf(extent.start));
+        riverElement.setAttribute("to",   String.valueOf(extent.end));
+        riverElement.setAttribute("rid",  String.valueOf(riverId));
+        riverElement.setAttribute("name", riverName);
+
+        fixingsElement.appendChild(riverElement);
+
+        fixingsElement.appendChild(
+            intersectingGauges(
+                document,
+                realRange(allColumns)));
+
+        SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
+
+        Element esE = document.createElement("events");
+
+        for (Fixing.Column column: allColumns) {
+
+            List<SectorRange> sectors = column.getSectors(range);
+
+            if (!sectors.isEmpty()) {
+                Element eE = document.createElement("event");
+                eE.setAttribute("description",
+                    String.valueOf(column.getDescription()));
+                eE.setAttribute("cid", String.valueOf(column.columnId));
+                eE.setAttribute("date", df.format(column.startTime));
+
+                for (SectorRange sector: sectors) {
+                    Element sE = document.createElement("sector");
+
+                    sE.setAttribute("from",  String.valueOf(sector.start));
+                    sE.setAttribute("to",    String.valueOf(sector.end));
+                    sE.setAttribute("class", String.valueOf(sector.sector));
+
+                    eE.appendChild(sE);
+                }
+
+                esE.appendChild(eE);
+            }
+        }
+
+        fixingsElement.appendChild(esE);
+
+        document.appendChild(fixingsElement);
+    }
+}
+// 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/FixingsOverviewFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,73 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+
+import de.intevation.flys.backend.SessionHolder;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+
+public class FixingsOverviewFactory
+{
+    private static Logger log = Logger.getLogger(FixingsOverviewFactory.class);
+
+    public static final String CACHE_NAME = "fixings-overviews";
+
+    private FixingsOverviewFactory() {
+    }
+
+
+    public static FixingsOverview getOverview(String river) {
+
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug(
+                "Looking for fixings overview for river '" + river + "'");
+        }
+
+        Cache cache = CacheFactory.getCache(CACHE_NAME);
+
+        if (cache == null) {
+            if (debug) {
+                log.debug("Cache not configured.");
+            }
+            return getUncached(river);
+        }
+
+        String key = "fix-over-" + river;
+
+        Element element = cache.get(key);
+
+        if (element != null) {
+            if (debug) {
+                log.debug("Overview found in cache");
+            }
+            return (FixingsOverview)element.getValue();
+        }
+
+        FixingsOverview overview = getUncached(river);
+
+        if (overview != null) {
+            if (debug) {
+                log.debug("Store overview in cache.");
+            }
+            cache.put(new Element(key, overview));
+        }
+
+        return overview;
+    }
+
+    public static FixingsOverview getUncached(String river) {
+        FixingsOverview overview = new FixingsOverview(river);
+
+        Session session = SessionHolder.HOLDER.get();
+
+        return overview.load(session) ? overview : null;
+    }
+}
+// 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/FlowVelocityCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,169 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import de.intevation.artifacts.Artifact;
+
+import de.intevation.flys.artifacts.access.FlowVelocityAccess;
+
+import de.intevation.flys.artifacts.model.RiverFactory;
+
+import de.intevation.flys.model.DischargeZone;
+import de.intevation.flys.model.FlowVelocityModel;
+import de.intevation.flys.model.FlowVelocityModelValue;
+import de.intevation.flys.model.River;
+
+import org.apache.log4j.Logger;
+
+
+public class FlowVelocityCalculation extends Calculation {
+
+    private static final Logger logger =
+        Logger.getLogger(FlowVelocityCalculation.class);
+
+
+    public CalculationResult calculate(FlowVelocityAccess access) {
+        logger.info("FlowVelocityCalculation.calculate");
+
+        int[] mainIds  = access.getMainChannels();
+        int[] totalIds = access.getTotalChannels();
+
+        if (logger.isDebugEnabled()) {
+            Artifact a = access.getArtifact();
+            logger.debug("Artifact '" + a.identifier() + "' contains:");
+            if (mainIds != null) {
+                logger.debug("   " + mainIds.length + " main channel ids");
+            }
+
+            if (totalIds != null) {
+                logger.debug("   " + totalIds.length + " total channel ids");
+            }
+        }
+
+        List<DischargeZone>     zones  = getDischargeZones(mainIds, totalIds);
+        List<FlowVelocityModel> models = getFlowVelocityModels(access, zones);
+
+        return buildCalculationResult(access, models);
+    }
+
+
+    protected List<DischargeZone> getDischargeZones(
+        int[] mainIds,
+        int[] totalIds
+    ) {
+        List<DischargeZone> zones = new ArrayList<DischargeZone>();
+
+        if (mainIds != null) {
+            for (int id: mainIds) {
+                DischargeZone zone = DischargeZone.getDischargeZoneById(id);
+
+                if (zone != null) {
+                    zones.add(zone);
+                }
+            }
+        }
+
+        if (totalIds != null) {
+            for (int id: totalIds) {
+                DischargeZone zone = DischargeZone.getDischargeZoneById(id);
+
+                if (zone != null) {
+                    zones.add(zone);
+                }
+            }
+        }
+
+        return zones;
+    }
+
+
+    protected List<FlowVelocityModel> getFlowVelocityModels(
+        FlowVelocityAccess  access,
+        List<DischargeZone> zones
+    ) {
+        String riverName = access.getRiver();
+        if (riverName == null) {
+            logger.warn("No river name found");
+            return Collections.<FlowVelocityModel>emptyList();
+        }
+
+        River river = RiverFactory.getRiver(riverName);
+        if (river == null) {
+            logger.warn("No such river: " + riverName);
+            return Collections.<FlowVelocityModel>emptyList();
+        }
+
+        List<FlowVelocityModel> models = new ArrayList<FlowVelocityModel>();
+
+        for (DischargeZone zone: zones) {
+            List<FlowVelocityModel> model =
+                FlowVelocityModel.getModels(river, zone);
+
+            if (model != null) {
+                models.addAll(model);
+            }
+        }
+
+        return models;
+    }
+
+
+    protected void prepareData(
+        FlowVelocityData  data,
+        FlowVelocityModel model,
+        double kmLo,
+        double kmHi
+    ) {
+        List<FlowVelocityModelValue> values =
+            FlowVelocityModelValue.getValues(model, kmLo, kmHi);
+
+        logger.debug("Found " + values.size() + " values for model.");
+
+        for (FlowVelocityModelValue value: values) {
+            data.addKM(value.getStation().doubleValue());
+            data.addQ(value.getQ().doubleValue());
+            data.addVTotal(value.getTotalChannel().doubleValue());
+            data.addVMain(value.getMainChannel().doubleValue());
+            data.addTauMain(value.getShearStress().doubleValue());
+        }
+
+        DischargeZone zone = model.getDischargeZone();
+        String        lo   = zone.getLowerDischarge();
+        String        hi   = zone.getUpperDischarge();
+
+        if (lo.equals(hi)) {
+            data.setZone(lo);
+        }
+        else {
+            data.setZone(lo + " - " + hi);
+        }
+    }
+
+
+    protected CalculationResult buildCalculationResult(
+        FlowVelocityAccess         access,
+        List<FlowVelocityModel> models
+    ) {
+        double kmLo = access.getLowerKM();
+        double kmHi = access.getUpperKM();
+
+        logger.debug("Prepare data for km range: " + kmLo + " - " + kmHi);
+
+        FlowVelocityData[] data = new FlowVelocityData[models.size()];
+
+        for (int i = 0, n = models.size(); i < n; i++) {
+            FlowVelocityData d = new FlowVelocityData();
+
+            prepareData(d, models.get(i), kmLo, kmHi);
+
+            data[i] = d;
+        }
+
+        logger.debug("Calculation contains " + data.length + " data items.");
+
+        return new CalculationResult(data, this);
+    }
+}
+// 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/FlowVelocityData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,115 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+import gnu.trove.TDoubleArrayList;
+
+
+public class FlowVelocityData implements Serializable {
+
+    private TDoubleArrayList km;
+    private TDoubleArrayList vMain;
+    private TDoubleArrayList vTotal;
+    private TDoubleArrayList tauMain;
+    private TDoubleArrayList q;
+    private String zone;
+
+
+    protected FlowVelocityData() {
+        this.km      = new TDoubleArrayList();
+        this.vMain   = new TDoubleArrayList();
+        this.vTotal  = new TDoubleArrayList();
+        this.tauMain = new TDoubleArrayList();
+        this.q       = new TDoubleArrayList();
+    }
+
+
+    public void addKM(double km) {
+        this.km.add(km);
+    }
+
+    public double getKM(int idx) {
+        return km.get(idx);
+    }
+
+    public void addVMain(double vMain) {
+        this.vMain.add(vMain);
+    }
+
+    public double getVMain(int idx) {
+        return vMain.get(idx);
+    }
+
+    public void addVTotal(double vTotal) {
+        this.vTotal.add(vTotal);
+    }
+
+    public double getVTotal(int idx) {
+        return vTotal.get(idx);
+    }
+
+    public void addTauMain(double tauMain) {
+        this.tauMain.add(tauMain);
+    }
+
+    public double getTauMain(int idx) {
+        return tauMain.get(idx);
+    }
+
+    public void addQ(double q) {
+        this.q.add(q);
+    }
+
+    public double getQ(int idx) {
+        return q.get(idx);
+    }
+
+    public void setZone(String zone) {
+        this.zone = zone;
+    }
+
+    public String getZone() {
+        return zone;
+    }
+
+    public int size() {
+        return km.size();
+    }
+
+
+    public double[][] getMainChannelPoints() {
+        double[][] points = new double[2][size()];
+
+        for (int i = 0, n = size(); i < n; i++) {
+            points[0][i] = getKM(i);
+            points[1][i] = getVMain(i);
+        }
+
+        return points;
+    }
+
+
+    public double[][] getTotalChannelPoints() {
+        double[][] points = new double[2][size()];
+
+        for (int i = 0, n = size(); i < n; i++) {
+            points[0][i] = getKM(i);
+            points[1][i] = getVTotal(i);
+        }
+
+        return points;
+    }
+
+
+    public double[][] getTauPoints() {
+        double[][] points = new double[2][size()];
+
+        for (int i = 0, n = size(); i < n; i++) {
+            points[0][i] = getKM(i);
+            points[1][i] = getTauMain(i);
+        }
+
+        return points;
+    }
+}
+// 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/FlowVelocityFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Facet of a FlowVelocity curve.
+ */
+public class FlowVelocityFacet extends DataFacet {
+
+    private static Logger logger = Logger.getLogger(FlowVelocityFacet.class);
+
+
+    public FlowVelocityFacet() {
+        // required for clone operation deepCopy()
+    }
+
+
+    public FlowVelocityFacet(
+        int         idx,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateId,
+        String      hash
+    ) {
+        super(idx, name, description, type, hash, stateId);
+    }
+
+
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("Get data for flow velocity at index: " + index);
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult)
+            flys.compute(context, hash, stateId, type, false);
+
+        FlowVelocityData[] data = (FlowVelocityData[]) res.getData();
+
+        return data[index];
+    }
+
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        FlowVelocityFacet copy = new FlowVelocityFacet();
+        copy.set(this);
+        copy.type    = type;
+        copy.hash    = hash;
+        copy.stateId = stateId;
+        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/GaugeDischargeCurveFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,57 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifactdatabase.state.DefaultFacet;
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.model.WQKms;
+
+import de.intevation.flys.model.Gauge;
+
+/**
+ * A Facet that returns discharge curve data at a gauge
+ *
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public class GaugeDischargeCurveFacet
+extends      DefaultFacet
+{
+    private Gauge gauge;
+    private String river;
+
+    public GaugeDischargeCurveFacet(String river, Gauge gauge) {
+        super(0, "facet.gauge.discharge_curve", "facet.gauge.discharge_curve");
+        this.river = river;
+        this.gauge = gauge;
+    }
+
+    @Override
+    public Object getData(Artifact art, CallContext context) {
+
+        DischargeTables dt = new DischargeTables(river, gauge.getName());
+
+        Map<String, double [][]> map = dt.getValues(100d);
+
+        double [][] values = map.get(name);
+        if (values == null) {
+            return null;
+        }
+        double [] kms = new double[values[0].length];
+        Arrays.fill(kms, gauge.getStation().doubleValue());
+        return new WQKms(kms, values[0], values[1], gauge.getName());
+    }
+
+    @Override
+    public Facet deepCopy() {
+        GaugeDischargeCurveFacet copy =
+            new GaugeDischargeCurveFacet(this.river, this.gauge);
+        copy.set(this);
+        return copy;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/GaugeDischargeFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,86 @@
+package de.intevation.flys.artifacts.model;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Access Discharge Curve of a gauge.
+ */
+public class GaugeDischargeFacet extends DataFacet {
+
+    /** Private logger. */
+    private static final Logger logger =
+        Logger.getLogger(GaugeDischargeFacet.class);
+
+
+    public GaugeDischargeFacet() {
+    }
+
+
+    /**
+     * @param index Index translates to index of WQ-array.
+     * @param name Name of the facet.
+     * @param desc Description of the facet (visible in client).
+     */
+    public GaugeDischargeFacet(int index, String name, String desc) {
+        super(index, name, desc, ComputeType.ADVANCE, null,
+            "state.gaugedischarge.init");
+    }
+
+
+    public GaugeDischargeFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateID,
+        String      hash
+
+    ) {
+        super(index, name, description, type, hash, stateID);
+    }
+
+
+    @Override
+    public Facet deepCopy() {
+        GaugeDischargeFacet copy = new GaugeDischargeFacet();
+        copy.set(this);
+        copy.type    = type;
+        copy.hash    = hash;
+        copy.stateId = stateId;
+        return copy;
+    }
+
+
+    /**
+     * @return wqkms corresponding to gauge of artifact and index of facet.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Get data for discharge curves at index: " +
+                index + " / stateId: " + stateId);
+        }
+
+        if (stateId == null) {
+            logger.error("GaugeDischargeFacet.getData: stateId is null.");
+        }
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult)
+            flys.compute(context, hash, stateId, type, true);
+
+        WQKms[] discharge = (WQKms[]) res.getData();
+
+        return discharge[index];
+    }
+}
+// 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/GaugeFinder.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,131 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+
+import org.hibernate.type.StandardBasicTypes;
+
+public class GaugeFinder
+implements   Serializable
+{
+    private static Logger log = Logger.getLogger(GaugeFinder.class);
+
+    public static final String SQL_DISCHARGE_SECTORS =
+        "SELECT" +
+        "    g.id                            AS gauge_id," +
+        "    nmv.name                        AS name," +
+        "    CAST(mv.value AS NUMERIC(38,2)) AS value " +
+        "FROM gauges g" +
+        "    JOIN main_values       mv  ON g.id = mv.gauge_id" +
+        "    JOIN named_main_values nmv ON nmv.id = mv.named_value_id" +
+        "    JOIN main_value_types  mvt ON nmv.type_id = mvt.id " +
+        "WHERE" +
+        "    mvt.name = 'Q' AND (" +
+        "        nmv.name = 'MNQ'      OR" +
+        "        nmv.name LIKE 'MNQ(%' OR" +
+        "        nmv.name = 'MQ'       OR" +
+        "        nmv.name LIKE 'MQ(%'  OR" +
+        "        nmv.name = 'MHQ'      OR" +
+        "        nmv.name LIKE 'MHQ(%' OR" +
+        "        nmv.name = 'HQ5'      OR" +
+        "        nmv.name LIKE 'HQ5(%') AND" +
+        "    g.river_id = :river_id " +
+        "ORDER BY" +
+        "    g.id";
+
+    protected List<GaugeRange> gauges;
+    protected boolean          isKmUp;
+
+    public GaugeFinder(List<GaugeRange> gauges) {
+        this(gauges, true);
+    }
+
+    public GaugeFinder(
+        List<GaugeRange> gauges,
+        boolean          isKmUp
+    ) {
+        this.gauges = gauges;
+        this.isKmUp = isKmUp;
+    }
+
+    public boolean getIsKmUp() {
+        return isKmUp;
+    }
+
+    public void setIsKmUp(boolean isKmUp) {
+        this.isKmUp = isKmUp;
+    }
+
+    public GaugeRange find(double km) {
+        for (GaugeRange gauge: gauges) {
+            if (gauge.inside(km)) {
+                return gauge;
+            }
+        }
+        return null;
+    }
+
+    public GaugeRange find(Range range) {
+        return find(isKmUp ? range.start : range.end);
+    }
+
+    public GaugeRange find(int gaugeId) {
+        for (GaugeRange gauge: gauges) {
+            if (gauge.gaugeId == gaugeId) {
+                return gauge;
+            }
+        }
+        return null;
+    }
+
+    public List<GaugeRange> getGauges() {
+        return gauges;
+    }
+
+    public boolean loadDischargeSectors(Session session, int riverId) {
+
+        SQLQuery query = session.createSQLQuery(SQL_DISCHARGE_SECTORS)
+            .addScalar("gauge_id", StandardBasicTypes.INTEGER)
+            .addScalar("name",     StandardBasicTypes.STRING)
+            .addScalar("value",    StandardBasicTypes.DOUBLE);
+
+        query.setInteger("river_id", riverId);
+
+        List<Object []> list = query.list();
+
+        if (list.isEmpty()) {
+            log.warn("River " + riverId + " has no discharge sectors.");
+            return false;
+        }
+
+        GaugeRange gauge = null;
+
+        for (Object [] row: list) {
+            int    gaugeId = (Integer)row[0];
+            String label   = (String) row[1];
+            Double value   = (Double) row[2];
+
+            if (gauge == null || gauge.gaugeId != gaugeId) {
+                if ((gauge = find(gaugeId)) == null) {
+                    log.warn("Cannot find gauge for id " + gaugeId + ".");
+                    continue;
+                }
+            }
+
+            gauge.addMainValue(label, value);
+        }
+
+        for (GaugeRange g: gauges) {
+            g.buildClasses();
+        }
+
+        return true;
+    }
+}
+// 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/GaugeFinderFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,133 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+
+import de.intevation.flys.backend.SessionHolder;
+
+import de.intevation.flys.model.River;
+
+import java.util.ArrayList;
+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;
+
+public class GaugeFinderFactory
+{
+    private static Logger log = Logger.getLogger(GaugeFinderFactory.class);
+
+    public static final String CACHE_NAME = "gauge-finders";
+
+    public static final String SQL_GAUGES =
+        "SELECT" +
+        "    g.id AS gauge_id," +
+        "    g.name AS name," +
+        "    r.a  AS a," +
+        "    r.b  AS b " +
+        "FROM gauges g" +
+        "    JOIN ranges r ON g.range_id = r.id " +
+        "WHERE" +
+        "    g.river_id = :river_id " +
+        "ORDER BY r.a";
+
+    private static GaugeFinderFactory INSTANCE;
+
+    protected GaugeFinderFactory() {
+    }
+
+    public static synchronized GaugeFinderFactory getInstance() {
+        if (INSTANCE == null) {
+            INSTANCE = new GaugeFinderFactory();
+        }
+
+        return INSTANCE;
+    }
+
+    public GaugeFinder getGaugeFinder(String riverName) {
+        River river = RiverFactory.getRiver(riverName);
+        return river != null
+            ? getGaugeFinder(river.getId(), river.getKmUp())
+            : null;
+    }
+
+    public synchronized GaugeFinder getGaugeFinder(
+        int     riverId,
+        boolean isKmUp
+    ) {
+        Cache cache = CacheFactory.getCache(CACHE_NAME);
+
+        if (cache == null) {
+            return getUncached(riverId, isKmUp);
+        }
+
+        String cacheKey = riverId + "-" + isKmUp;
+        Element element = cache.get(cacheKey);
+
+        if (element != null) {
+            return (GaugeFinder)element.getValue();
+        }
+
+        GaugeFinder finder = getUncached(riverId, isKmUp);
+
+        if (finder != null) {
+            cache.put(new Element(cacheKey, finder));
+        }
+
+        return finder;
+    }
+
+    protected GaugeFinder loadGauges(
+        Session session,
+        int     riverId,
+        boolean isKmUp
+    ) {
+        SQLQuery query = session.createSQLQuery(SQL_GAUGES)
+            .addScalar("gauge_id", StandardBasicTypes.INTEGER)
+            .addScalar("name",     StandardBasicTypes.STRING)
+            .addScalar("a",        StandardBasicTypes.DOUBLE)
+            .addScalar("b",        StandardBasicTypes.DOUBLE);
+
+        query.setInteger("river_id", riverId);
+
+        List<Object []> list = query.list();
+
+        if (list.isEmpty()) {
+            log.warn("River " + riverId + " has no gauges.");
+            return null;
+        }
+
+        List<GaugeRange> gauges = new ArrayList<GaugeRange>();
+
+        for (Object [] row: list) {
+            int    gaugeId = (Integer)row[0];
+            String name    = (String) row[1];
+            double start   = (Double) row[2];
+            double end     = (Double) row[3];
+            GaugeRange gauge = new GaugeRange(start, end, name, gaugeId);
+            gauges.add(gauge);
+        }
+
+        return new GaugeFinder(gauges, isKmUp);
+    }
+
+    protected GaugeFinder getUncached(int riverId, boolean isKmUp) {
+        Session session = SessionHolder.HOLDER.get();
+
+        GaugeFinder finder = loadGauges(session, riverId, isKmUp);
+
+        if (finder == null
+        || !finder.loadDischargeSectors(session, riverId)) {
+            return null;
+        }
+
+        return finder;
+    }
+}
+// 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/GaugeRange.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,132 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+public class GaugeRange
+extends      Range
+{
+    private static Logger log = Logger.getLogger(GaugeRange.class);
+
+    private static final class Sector implements Serializable {
+
+        int    sector;
+        double value;
+
+        Sector(int sector, double value) {
+            this.sector = sector;
+            this.value  = value;
+        }
+    } // class Sector
+
+    protected String name;
+
+    protected int gaugeId;
+
+    protected Map<String, Double> mainValues;
+    protected List<Sector> sectors;
+
+    public GaugeRange() {
+    }
+
+    public GaugeRange(double start, double end, int gaugeId) {
+        this(start, end, null, gaugeId);
+    }
+
+    public GaugeRange(
+        double start,
+        double end,
+        String name,
+        int    gaugeId
+    ) {
+        super(start, end);
+        this.name = name;
+        this.gaugeId = gaugeId;
+        mainValues = new HashMap<String, Double>();
+        sectors = new ArrayList<Sector>(3);
+    }
+
+    public void addMainValue(String label, Double value) {
+        int idx = label.indexOf('(');
+        if (idx >= 0) {
+            label = label.substring(0, idx);
+        }
+        mainValues.put(label, value);
+    }
+
+    protected Double getMainValue(String label) {
+        Double v = mainValues.get(label);
+        if (v == null) {
+            log.warn("Missing main value '"
+                + label + "' for gauge " + gaugeId);
+        }
+        return v;
+    }
+
+    public void buildClasses() {
+        Double mnq = getMainValue("MNQ");
+        Double mq  = getMainValue("MQ");
+        Double mhq = getMainValue("MHQ");
+        Double hq5 = getMainValue("HQ5");
+
+        Double [][] pairs = {
+            { mnq,  mq },
+            {  mq, mhq },
+            { hq5, hq5 } };
+
+        for (int c = 0; c < pairs.length; ++c) {
+            Double [] pair = pairs[c];
+            if (pair[0] != null && pair[1] != null) {
+                double value = 0.5*(pair[0] + pair[1]);
+                sectors.add(new Sector(c, value));
+            }
+        }
+    }
+
+    public double getSectorBorder(int sector) {
+        for (Sector s: sectors) {
+            if (s.sector == sector) {
+                return s.value;
+            }
+        }
+        return Double.NaN;
+    }
+
+    public int classify(double value) {
+        for (Sector sector: sectors) {
+            if (value < sector.value) {
+                return sector.sector;
+            }
+        }
+        return sectors.size();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder("sectors: [");
+
+        for (int i = 0, S = sectors.size(); i < S; ++i) {
+            if (i > 0) sb.append(", ");
+            Sector s = sectors.get(i);
+            sb.append(s.sector).append(": ").append(s.value);;
+        }
+
+        sb.append("] mainvalues: ").append(mainValues);
+
+        return sb.toString();
+    }
+}
+// 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/HYKFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,78 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.DataProvider;
+import de.intevation.flys.artifacts.HYKArtifact;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.model.FastCrossSectionLine;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * Trival Facet for HYKs
+ */
+public class HYKFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(HYKFacet.class);
+
+    /** Trivial constructor, set (maybe localized) description. */
+    public HYKFacet(int idx, String description) {
+        super(idx, HYK, description, ComputeType.FEED, null, null);
+    }
+
+
+    /**
+     * Set km from cross section- master to HYKArtifact, then fire up
+     * computation.
+     *
+     * @param art artifact to get data from.
+     * @param context ignored
+     */
+     @Override
+    public Object getData(Artifact art, CallContext context) {
+        logger.debug("HYKFacet.getData");
+
+        String dataKey = CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA;
+
+        List<DataProvider> providers = context.getDataProvider(dataKey);
+        if (providers.size() < 1) {
+            logger.warn("Could not find Cross-Section data provider to get master cs km.");
+            return null;
+        }
+
+        FastCrossSectionLine crossSection = (FastCrossSectionLine) providers.get(0)
+            .provideData(dataKey, null, context);
+
+        if(crossSection == null) {
+            logger.debug("getData: crossSection is null");
+            return null;
+        }
+
+        double km = crossSection.getKm();
+        logger.debug("HYKFacet.getData: Master Cross Section is at km: " + km);
+
+        // Set this km at hyk artifact to be evaluated.
+        HYKArtifact hyk = (HYKArtifact) art;
+        hyk.setKm(km);
+
+        return hyk.compute(context, hash, stateId, type, false);
+    }
+
+
+    /** Do a deep copy. */
+    @Override
+    public Facet deepCopy() {
+        HYKFacet copy = new HYKFacet(this.index, this.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/HYKFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,211 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+import de.intevation.flys.backend.SessionHolder;
+import de.intevation.flys.model.HYK;
+import de.intevation.flys.model.HYKFlowZone;
+import de.intevation.flys.model.HYKFormation;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.apache.log4j.Logger;
+import org.hibernate.Query;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.type.StandardBasicTypes;
+
+
+/**
+ * Factory to access HYKs (hydrographic values).
+ */
+public class HYKFactory
+{
+    private static Logger logger = Logger.getLogger(HYKFactory.class);
+
+    public static String HYK_CACHE_NAME = "hykache";
+
+
+    /** Do not instantiate a HYKFactory. */
+    private HYKFactory() {
+    }
+
+
+    /**
+     * Get List of Zones for given river and km.
+     */
+    public static Object getHYKs(int hykid, double km) {
+        logger.debug("HYKFactory.getHYKs");
+
+        Cache cache = CacheFactory.getCache(HYK_CACHE_NAME);
+
+        String cacheKey;
+
+        if (cache != null) {
+            cacheKey = "" + hykid + "_" + km;
+            Element element = cache.get(cacheKey);
+            if (element != null) {
+                logger.debug("Got hyk from cache");
+                return element.getValue();
+            }
+        }
+        else {
+            cacheKey = null;
+        }
+
+        List<Zone> zones = getZonesUncached(hykid, km);
+
+        if (zones != null && cacheKey != null) {
+            logger.debug("Store hykzones in cache.");
+            Element element = new Element(cacheKey, zones);
+            cache.put(element);
+        }
+
+        return zones;
+    }
+
+
+    /** Return name for hyk with given id. */
+    public static String getHykName(int hykid) {
+        logger.debug("HYKFactory.getHykName " + hykid);
+
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "select description from HYK where id = :hykid ");
+        query.setParameter("hykid", hykid);
+
+        return (String) query.uniqueResult();
+    }
+
+
+    /**
+     * Ask DB for hyk zones.
+     * @param hykid ID of the 'main' HYK to query.
+     * @param km for which to get the hyk-zones.
+     * @return according zones.
+     */
+    public static List<Zone> getZonesUncached(int hykid, double km) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("HYKFactory.getZoneUncached " + hykid + " km " + km);
+        }
+
+        Session session = SessionHolder.HOLDER.get();
+
+        // Find out flow-direction of river.
+        // OPTIMIZE: 1) query kmUp directly 2) merge queries.
+        Query rQuery = session.createQuery("from HYK where id = :hykid");
+        rQuery.setParameter("hykid", hykid);
+        rQuery.setMaxResults(1);
+        HYK hyk = (HYK) rQuery.uniqueResult();
+
+        double flowDir = hyk.getRiver().getKmUp() ? 1 : -1;
+
+        List<HYKFormation> forms = getHYKFormations(hykid, km, flowDir);
+        List<Zone>         zones = new ArrayList<Zone>();
+
+        // Take the first one.
+        if (forms.size() >= 1) {
+            HYKFormation form = forms.get(0);
+            // Create respective zones.
+            for (HYKFlowZone flowZone: form.getZones()) {
+                Zone z = new Zone(flowZone.getA().doubleValue(),
+                    flowZone.getB().doubleValue(),
+                    flowZone.getType().getName());
+                zones.add(z);
+            }
+        }
+
+        return zones;
+    }
+
+
+    protected static List<HYKFormation> getHYKFormations(
+        int        hykid,
+        double     km,
+        double     flowDir
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        String SQL = "SELECT " +
+            "   f.id          AS FID, " +
+            "   f.distance_vl AS DIST, " +
+            "   e.hyk_id      AS HID, " +
+            "   e.km          AS KM " +
+            " FROM hyk_formations f INNER JOIN hyk_entries e " +
+            "   ON e.id = f.hyk_entry_id " +
+            " WHERE e.hyk_id = :hykid " +
+            "   AND :km between " +
+            "     LEAST(e.km, e.km + :flowDir*(f.distance_vl/1000.0+0.001)) " +
+            "   AND " +
+            "     GREATEST(e.km, e.km + :flowDir*(f.distance_vl/1000.0+0.001))";
+
+        SQLQuery sqlQuery = session.createSQLQuery(SQL)
+            .addScalar("FID", StandardBasicTypes.INTEGER)
+            .addScalar("DIST", StandardBasicTypes.DOUBLE)
+            .addScalar("HID", StandardBasicTypes.INTEGER)
+            .addScalar("KM", StandardBasicTypes.DOUBLE);
+
+        sqlQuery.setInteger("hykid", hykid);
+        sqlQuery.setDouble("flowDir", flowDir);
+        sqlQuery.setDouble("km", km);
+
+        logger.debug("HYK SQL: " + sqlQuery.getQueryString());
+
+        List<Object[]> results = sqlQuery.list();
+
+        logger.debug("Found " + results.size() + " HYKFormation IDs in DB.");
+
+        if (results == null || results.isEmpty()) {
+            logger.debug("No HYK found for ID " + hykid + " at km " + km);
+            return new ArrayList<HYKFormation>();
+        }
+
+        Object[] resultSet      = results.get(0);
+        Integer  hykFormationId = (Integer) resultSet[0];
+
+        Query query = session.createQuery("from HYKFormation where id = :id");
+        query.setParameter("id", hykFormationId);
+        query.setMaxResults(1);
+
+        return query.list();
+    }
+
+
+    /** Labeled section. */
+    public static class Zone implements Serializable {
+        /** Lower end of segment. */
+        protected double  from;
+        /** Upper end of segment. */
+        protected double  to;
+        /** The label. */
+        protected String name;
+
+        /** Constructor for labelled section. */
+        public Zone (double from, double to, String name) {
+            this.from = from;
+            this.to   = to;
+            this.name = name;
+        }
+
+        /** Get upper value. */
+        public double getTo() {
+            return to;
+        }
+
+        /** Get lower value. */
+        public double getFrom() {
+            return from;
+        }
+
+        /** Get name (type). */
+        public String getName() {
+            return name;
+        }
+    } // public static class Zone
+}
+// 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/HistoricalDischargeDifferenceFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,61 @@
+package de.intevation.flys.artifacts.model;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalDischargeDifferenceFacet
+extends      HistoricalDischargeFacet
+{
+    private static final Logger logger =
+        Logger.getLogger(HistoricalDischargeDifferenceFacet.class);
+
+
+    public HistoricalDischargeDifferenceFacet(
+        int    index,
+        String name,
+        String desc
+    ) {
+        super(index, name, desc, ComputeType.ADVANCE, null, null);
+    }
+
+
+    public HistoricalDischargeDifferenceFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateID,
+        String      hash
+
+    ) {
+        super(index, name, description, type, hash, stateID);
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Get data for historical discharge difference curves" +
+                " at index: " + index + " / stateId: " + stateId);
+        }
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult)
+            flys.compute(context, hash, stateId, type,  false);
+
+        HistoricalWQTimerange[] wqts = (HistoricalWQTimerange[]) res.getData();
+
+        return wqts[index];
+    }
+}
+// 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/HistoricalDischargeFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,73 @@
+package de.intevation.flys.artifacts.model;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalDischargeFacet extends DataFacet {
+
+    private static final Logger logger =
+        Logger.getLogger(HistoricalDischargeFacet.class);
+
+
+    public HistoricalDischargeFacet() {
+    }
+
+
+    public HistoricalDischargeFacet(int index, String name, String desc) {
+        super(index, name, desc, ComputeType.ADVANCE, null, null);
+    }
+
+
+    public HistoricalDischargeFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateID,
+        String      hash
+
+    ) {
+        super(index, name, description, type, hash, stateID);
+    }
+
+
+    @Override
+    public Facet deepCopy() {
+        WaterlevelFacet copy = new WaterlevelFacet();
+        copy.set(this);
+        copy.type    = type;
+        copy.hash    = hash;
+        copy.stateId = stateId;
+        return copy;
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Get data for historical discharge curves at index: " +
+                index + " / stateId: " + stateId);
+        }
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult)
+            flys.compute(context, hash, stateId, type,  false);
+
+        WQTimerange[] wqts = (WQTimerange[]) res.getData();
+
+        return wqts[index];
+    }
+}
+// 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/HistoricalWQTimerange.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,49 @@
+package de.intevation.flys.artifacts.model;
+
+import gnu.trove.TDoubleArrayList;
+
+
+/**
+ * A subclass of WQTimerange that stores besides W, Q and Timerange values
+ * another double value.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalWQTimerange extends WQTimerange {
+
+    protected TDoubleArrayList diffs;
+
+
+    public HistoricalWQTimerange(String name) {
+        super(name);
+
+        diffs = new TDoubleArrayList();
+    }
+
+
+    public void add(double w, double q, double diff, Timerange t) {
+        ws.add(w);
+        qs.add(q);
+        ts.add(t);
+        diffs.add(diff);
+    }
+
+
+    /**
+     * This method requires a 3dim double array for <i>res</i>!
+     */
+    @Override
+    public double[] get(int idx, double[] res) {
+        res[0] = ws.getQuick(idx);
+        res[1] = qs.getQuick(idx);
+        res[2] = diffs.getQuick(idx);
+
+        return res;
+    }
+
+
+    public double[] getDiffs() {
+        return diffs.toNativeArray();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/LayerInfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -10,6 +10,7 @@
     protected String connection;
     protected String connectionType;
     protected String extent;
+    protected String srid;
     protected String group;
     protected String groupTitle;
     protected String title;
@@ -122,6 +123,16 @@
     }
 
 
+    public void setSrid(String srid) {
+        this.srid = srid;
+    }
+
+
+    public String getSrid() {
+        return srid;
+    }
+
+
     public void setStyle(String style) {
         this.style = style;
     }
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/LocationProvider.java	Fri Sep 28 12:15:52 2012 +0200
@@ -6,84 +6,95 @@
 import org.apache.log4j.Logger;
 
 import de.intevation.flys.model.Annotation;
-import de.intevation.flys.model.Position;
+import de.intevation.flys.model.FastAnnotations;
 
 import de.intevation.flys.artifacts.cache.CacheFactory;
-import de.intevation.flys.artifacts.model.AnnotationsFactory;
-
 
 public class LocationProvider {
 
+    private static final Logger log =
+        Logger.getLogger(LocationProvider.class);
+
+
     public static final String CACHE_KEY = "location-provider";
 
-
-    private static final Logger logger =
-        Logger.getLogger(LocationProvider.class);
+    public static final String PREFIX = "lp-";
 
 
     private LocationProvider() {
     }
 
+    public static String getLocation(String river, double km) {
 
-    public static String getLocation(String river, double km) {
-        return getLocation(getLocationHash(river, km), river, km);
+        FastAnnotations fas = getAnnotations(river, km);
+
+        FastAnnotations.Annotation an = fas.findByKm(km);
+
+        return an != null ? an.getPosition() : null;
     }
 
+    public static FastAnnotations getAnnotations(String river) {
+        return getAnnotations(river, Double.MAX_VALUE);
+    }
 
-    public static String getLocation(String hash, String river, double km) {
-        logger.debug("Fetch location for '" + river + "' at '" + km + "'");
+    protected static FastAnnotations getAnnotations(String river, double km) {
 
         Cache cache = CacheFactory.getCache(CACHE_KEY);
 
-        if (cache != null) {
-            return getCachedLocation(cache, hash, river, km);
+        if (cache == null) {
+            return uncachedAnnotations(river, km);
         }
-        else {
-            logger.info("No Cache for Locations configured.");
-            return getUncachedLocation(river, km);
+
+        String key = PREFIX + river;
+
+        Element element = cache.get(key);
+
+        if (element != null) {
+            return (FastAnnotations)element.getValue();
         }
+
+        FastAnnotations fas = uncachedAnnotations(river, Double.MAX_VALUE);
+
+        cache.put(new Element(key, fas));
+
+        return fas;
     }
 
-
-    protected static String getCachedLocation(
-        Cache cache,
-        String hash,
+    protected static FastAnnotations uncachedAnnotations(
         String river,
         double km
     ) {
-        logger.debug("Fetch location from cache.");
-
-        Element element = cache.get(hash);
+        if (km != Double.MAX_VALUE) {
+            // XXX Fake it by using a standard Annotation.
 
-        if (element == null) {
-            logger.debug("Element is not in cache yet.");
+            Annotation annotation =
+                AnnotationsFactory.getAnnotation(river, km);
 
-            String location = getUncachedLocation(river, km);
-            element = new Element(hash, location);
-            cache.put(element);
+            if (annotation != null) {
+                FastAnnotations.Annotation fa =
+                    new FastAnnotations.Annotation(
+                        km, Double.NaN,
+                        annotation.getPosition().getValue(), null, null,
+                        Double.NaN, Double.NaN);
+                return new FastAnnotations(
+                    new FastAnnotations.Annotation [] { fa });
+            }
+
+            return new FastAnnotations(new FastAnnotations.Annotation[0]);
         }
 
-        return (String) element.getValue();
-    }
-
+        long startTime = System.currentTimeMillis();
 
-    protected static String getUncachedLocation(String river, double km) {
-        logger.debug("Fetch location from backend.");
+        FastAnnotations fas = new FastAnnotations(river);
 
-        Annotation annotation = AnnotationsFactory.getAnnotation(river, km);
+        long stopTime = System.currentTimeMillis();
 
-        if (annotation != null) {
-            logger.debug("Found an annotation.");
-            Position pos = annotation.getPosition();
-            return pos.getValue();
+        if (log.isDebugEnabled()) {
+            log.debug("Loading locations took " +
+                (stopTime-startTime)/1000f + " secs.");
         }
 
-        return "";
-    }
-
-
-    protected static String getLocationHash(String river, double km) {
-        return river + "#" + km;
+        return fas;
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-package de.intevation.flys.artifacts.model;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import org.hibernate.Session;
-import org.hibernate.Query;
-
-import de.intevation.flys.backend.SessionHolder;
-
-import de.intevation.flys.model.Gauge;
-import de.intevation.flys.model.MainValue;
-
-
-/**
- * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
- */
-public class MainValuesFactory {
-
-    private static Logger logger = Logger.getLogger(MainValuesFactory.class);
-
-    public static List<MainValue> getMainValues(Gauge gauge) {
-        Session session = SessionHolder.HOLDER.get();
-
-        Query query = session.createQuery(
-            "from MainValue where gauge=:gauge");
-        query.setParameter("gauge", gauge);
-
-        return query.list();
-    }
-
-
-    /**
-     * Returns an array of [days, qs] necessary to create duration curves.
-     *
-     * @param gauge The selected gauge.
-     *
-     * @return a 2dim array of [days, qs] where days is an int[] and qs is
-     * an double[].
-     */
-    public static Object[] getDurationCurveData(Gauge gauge) {
-        Session session = SessionHolder.HOLDER.get();
-
-        Query query = session.createQuery(
-            "select cast(nmv.name as integer) as days, mv.value as q " +
-            "from MainValue as mv " +
-            "join mv.mainValue as nmv " +
-            "join nmv.type mvt " +
-            "where mvt.name = 'D' and mv.gauge.id = :gauge_id " +
-            "order by days");
-
-        query.setParameter("gauge_id", gauge.getId());
-
-        List<Object> results = query.list();
-        int[]        days    = new int[results.size()];
-        double[]     qs      = new double[results.size()];
-
-        int idx = 0;
-
-        for (Object obj: results) {
-            Object[] arr = (Object[]) obj;
-
-            try {
-                int  day = ((Integer)    arr[0]).intValue();
-                double q = ((BigDecimal) arr[1]).doubleValue();
-
-                days[idx] = day;
-                qs[idx++] = q;
-            }
-            catch (NumberFormatException nfe) {
-                logger.warn(nfe, nfe);
-            }
-        }
-
-        return new Object[] { days, qs };
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesQFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,34 +3,77 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.jfree.chart.annotations.XYTextAnnotation;
+import org.apache.log4j.Logger;
 
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.DataProvider;
 
 import de.intevation.artifactdatabase.state.DefaultFacet;
 
 import de.intevation.flys.artifacts.MainValuesArtifact;
-import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.math.Linear;
 import de.intevation.flys.jfree.FLYSAnnotation;
 import de.intevation.flys.jfree.StickyAxisAnnotation;
 
+import de.intevation.flys.exports.DurationCurveGenerator;
+
+
 /**
  * Facet to show Main Q Values.
+ * TODO Join with W implementation.
  */
 public class MainValuesQFacet
 extends      DefaultFacet
 implements   FacetTypes {
 
+    /** Own logger. */
+    private static Logger logger = Logger.getLogger(MainValuesQFacet.class);
+
     /** Do we want MainValues at Gauge (not interpolated)? */
     protected boolean isAtGauge;
 
+
     /** Trivial Constructor. */
     public MainValuesQFacet(String name, String description, boolean atGauge) {
         this.description = description;
-        this.name = name;
-        this.index = 0;
-        this.isAtGauge = atGauge;
+        this.name        = name;
+        this.index       = 0;
+        this.isAtGauge   = atGauge;
+    }
+
+
+    /**
+     * Set the hit-point in Q where a line drawn from the axis would hit the
+     * curve in WQDay (if hit).
+     * Employ linear interpolation.
+     */
+    protected static void setHitPoint(WQDay wqday, StickyAxisAnnotation annotation) {
+        int idx = 0;
+        float q = annotation.getPos();
+        boolean qIncreases = wqday.getQ(0) < wqday.getQ(wqday.size()-1);
+        if (qIncreases) {
+            while (idx < wqday.size() && wqday.getQ(idx) < q) {
+                idx++;
+            }
+        }
+        else {
+            idx = wqday.size() -1;
+            while (idx > 0 && wqday.getQ(idx) > q) {
+                idx--;
+            }
+        }
+
+        double day = 0d;
+        int mod = (qIncreases) ? -1 : +1;
+        if (idx != 0 && idx <= wqday.size()-1) {
+            day = Linear.linear(q, wqday.getQ(idx +mod), wqday.getQ(idx),
+                wqday.getDay(idx+mod), wqday.getDay(idx));
+            annotation.setHitPoint((float)day);
+        }
+        else {
+            logger.debug("StickyAnnotation does not hit wqday curve");
+        }
     }
 
 
@@ -46,14 +89,50 @@
     public Object getData(Artifact artifact, CallContext context) {
         MainValuesArtifact mvArtifact = (MainValuesArtifact) artifact;
 
-        List<NamedDouble>      qs = mvArtifact.getMainValuesQ(isAtGauge);
-        List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
+        List<NamedDouble>          qs = mvArtifact.getMainValuesQ(isAtGauge);
+        List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>();
 
-        for (NamedDouble q: qs) {
-            xy.add(new StickyAxisAnnotation(
-                q.getName(),
-                (float) q.getValue(),
-                StickyAxisAnnotation.SimpleAxis.X_AXIS));
+        WQDay wqdays = null;
+        List<DataProvider> providers = context.
+            getDataProvider(DurationCurveFacet.BB_DURATIONCURVE);
+        if (providers.size() < 1) {
+            logger.warn("Could not find durationcurve data provider.");
+        }
+        else {
+            wqdays = (WQDay) providers.get(0).provideData(
+                DurationCurveFacet.BB_DURATIONCURVE,
+                null,
+                context);
+        }
+
+        // Rather specific case, Q-Annotations at a maybe second yaxis.
+        StickyAxisAnnotation annotation = null;
+        if (this.name.equals(DURATION_MAINVALUES_Q)) {
+            for (NamedDouble q: qs) {
+                annotation =
+                    new StickyAxisAnnotation(
+                        q.getName(),
+                        (float) q.getValue(),
+                        StickyAxisAnnotation.SimpleAxis.Y_AXIS,
+                        DurationCurveGenerator.YAXIS.Q.idx);
+                xy.add(annotation);
+                if (wqdays != null) {
+                    setHitPoint(wqdays, annotation);
+                }
+            }
+        }
+        else {
+            for (NamedDouble q: qs) {
+                annotation =
+                    new StickyAxisAnnotation(
+                        q.getName(),
+                        (float) q.getValue(),
+                        StickyAxisAnnotation.SimpleAxis.X_AXIS);
+                xy.add(annotation);
+                if (wqdays != null) {
+                    setHitPoint(wqdays, annotation);
+                }
+            }
         }
 
         return new FLYSAnnotation(description, xy);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MainValuesWFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,18 +3,20 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.jfree.chart.annotations.XYTextAnnotation;
+import org.apache.log4j.Logger;
 
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.DataProvider;
 
 import de.intevation.artifactdatabase.state.DefaultFacet;
 
 import de.intevation.flys.artifacts.MainValuesArtifact;
-import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.math.Linear;
 import de.intevation.flys.jfree.FLYSAnnotation;
 import de.intevation.flys.jfree.StickyAxisAnnotation;
 
+
 /**
  * Facet to show Main W Values.
  */
@@ -22,6 +24,9 @@
 extends      DefaultFacet
 implements   FacetTypes {
 
+    /** Own logger. */
+    private static Logger logger = Logger.getLogger(MainValuesWFacet.class);
+
     /** Do we want MainValues at Gauge (not interpolated)? */
     protected boolean isAtGauge;
 
@@ -35,6 +40,40 @@
 
 
     /**
+     * Set the hit-point in W where a line drawn from the axis would hit the
+     * curve in WQDay (if hit).
+     * Employ linear interpolation.
+     */
+    protected static void setHitPoint(WQDay wqday, StickyAxisAnnotation annotation) {
+        int idx = 0;
+        float w = annotation.getPos();
+        boolean wIncreases = wqday.getW(0) < wqday.getW(wqday.size()-1);
+        if (wIncreases) {
+            while (idx < wqday.size() && wqday.getW(idx) < w) {
+                idx++;
+            }
+        }
+        else {
+            idx = wqday.size() -1;
+            while (idx > 0 && wqday.getW(idx) > w) {
+                idx--;
+            }
+        }
+
+        double day = 0d;
+        int mod = (wIncreases) ? -1 : +1;
+        if (idx != 0 && idx < wqday.size()-1-mod) {
+            day = Linear.linear(w, wqday.getW(idx +mod), wqday.getW(idx),
+                wqday.getDay(idx+mod), wqday.getDay(idx));
+            annotation.setHitPoint((float)day);
+        }
+        else {
+            logger.debug("StickyAnnotation does not hit wqday curve");
+        }
+    }
+
+
+    /**
      * Returns the data this facet requires.
      *
      * @param artifact the owner artifact.
@@ -47,13 +86,32 @@
         MainValuesArtifact mvArtifact = (MainValuesArtifact) artifact;
 
         List<NamedDouble>      ws = mvArtifact.getMainValuesW(isAtGauge);
-        List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
+        List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>();
+
+        // Find whether a duration curve is on the blackboard.
+        WQDay wqdays = null;
+        List<DataProvider> providers = context.
+            getDataProvider(DurationCurveFacet.BB_DURATIONCURVE);
+        if (providers.size() < 1) {
+            logger.warn("Could not find durationcurve data provider.");
+        }
+        else {
+            wqdays = (WQDay) providers.get(0).provideData(
+                DurationCurveFacet.BB_DURATIONCURVE,
+                null,
+                context);
+        }
 
         for (NamedDouble w: ws) {
-            xy.add(new StickyAxisAnnotation(
-                w.getName(),
-                (float) w.getValue(),
-                StickyAxisAnnotation.SimpleAxis.Y_AXIS));
+            StickyAxisAnnotation annotation =
+                new StickyAxisAnnotation(
+                    w.getName(),
+                    (float) w.getValue(),
+                    StickyAxisAnnotation.SimpleAxis.Y_AXIS);
+            xy.add(annotation);
+            if (wqdays != null) {
+                setHitPoint(wqdays, annotation);
+            }
         }
 
         return new FLYSAnnotation(description, xy);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManagedDomFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManagedDomFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -9,7 +9,7 @@
 import de.intevation.artifacts.ArtifactNamespaceContext;
 
 
-/** 
+/**
  * Use an Element (DOM) to store the information about a facet.
  * The intent of this facet type is to represent a facet
  * stored in an Collection attribute. Different facets can have different
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManagedFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -123,7 +123,7 @@
         active   = other.active;
     }
 
-    @Override 
+    @Override
     public Facet deepCopy() {
         ManagedFacet copy = new ManagedFacet();
         copy.set((DefaultFacet)this);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManagedFacetAdapter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ManagedFacetAdapter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -70,3 +70,4 @@
         return facet;
     }
 }
+// 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/ManualPointsFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.artifacts.model;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.ManualPointsArtifact;
+
+import de.intevation.artifactdatabase.state.DefaultFacet;
+import de.intevation.artifactdatabase.state.Facet;
+
+
+/**
+ * Facet to access ManualPoints that where added by user.
+ */
+public class ManualPointsFacet
+extends      DefaultFacet
+{
+    /** Logger for this class. */
+    private static final Logger logger = Logger.getLogger(ManualPointsFacet.class);
+
+
+    /**
+     * Trivial Constructor.
+     */
+    public ManualPointsFacet() {
+    }
+
+
+    /**
+     * Trivial Constructor for a ManualPointsFacet.
+     *
+     * @param index       Database-Index to use.
+     * @param name        Name (~type) of Facet.
+     * @param description Description of Facet.
+     */
+    public ManualPointsFacet(int index, String name, String description) {
+        super(index, name, description);
+    }
+
+
+    /**
+     * Get List of ManualPoints for river from Artifact.
+     *
+     * @param artifact (ManualPoints-)Artifact to query for list of ManualPoints.
+     * @param context  Ignored.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        ManualPointsArtifact pointsArtifact = (ManualPointsArtifact) artifact;
+        return pointsArtifact.getPointsData(this.name);
+    }
+
+
+    /** Do a deep copy. */
+    @Override
+    public Facet deepCopy() {
+        ManualPointsFacet copy = new ManualPointsFacet();
+        copy.set(this);
+        return copy;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MapserverStyle.java	Fri Sep 28 12:15:52 2012 +0200
@@ -31,7 +31,7 @@
                 item.toString(sb);
             }
 
-            sb.append("END");
+            sb.append("END\n");
 
             return sb.toString();
         }
@@ -68,7 +68,10 @@
         public void toString(StringBuilder sb) {
             sb.append("STYLE\n");
             sb.append("WIDTH " + String.valueOf(size) + "\n");
-            sb.append("OUTLINECOLOR " + outlinecolor + "\n");
+
+            if (outlinecolor != null) {
+                sb.append("OUTLINECOLOR " + outlinecolor + "\n");
+            }
 
             if (color != null) {
                 sb.append("COLOR " + color + "\n");
@@ -108,6 +111,20 @@
         }
     }
 
+    public static class Expression implements ClazzItem {
+        protected String value;
+
+        public Expression(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public void toString(StringBuilder sb) {
+            sb.append("EXPRESSION " + value);
+            sb.append("\n");
+        }
+    }
+
 
     protected List<Clazz> classes;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/MiddleBedHeightCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,212 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.common.utils.DateUtils;
+
+import de.intevation.flys.model.BedHeightEpoch;
+import de.intevation.flys.model.BedHeightEpochValue;
+import de.intevation.flys.model.BedHeightSingle;
+import de.intevation.flys.model.BedHeightSingleValue;
+import de.intevation.flys.model.TimeInterval;
+
+import de.intevation.flys.artifacts.access.BedHeightAccess;
+
+
+public class MiddleBedHeightCalculation extends Calculation {
+
+    private static final Logger logger =
+        Logger.getLogger(MiddleBedHeightCalculation.class);
+
+
+    public CalculationResult calculate(BedHeightAccess access) {
+        logger.info("MiddleBedHeightCalculation.calculate");
+
+        int[] singleIds = access.getBedHeightSingleIDs();
+        int[] epochIds  = access.getBedHeightEpochIDs();
+
+
+        if (logger.isDebugEnabled()) {
+            Artifact artifact = access.getArtifact();
+
+            logger.debug("Artifact '" + artifact.identifier() + "' contains:");
+            if (singleIds != null) {
+                logger.debug("   " + singleIds.length + " single bedheight ids");
+            }
+
+            if (epochIds != null) {
+                logger.debug("   " + epochIds.length + " epoch bedheight ids");
+            }
+        }
+
+        List<BedHeightSingle> singles = getSingles(access, singleIds);
+        List<BedHeightEpoch>  epochs  = getEpochs(access, epochIds);
+
+        return buildCalculationResult(access, singles, epochs);
+    }
+
+
+    protected List<BedHeightSingle> getSingles(
+        BedHeightAccess access,
+        int[] ids
+    ) {
+        List<BedHeightSingle> singles = new ArrayList<BedHeightSingle>();
+
+        for (int id: ids) {
+            BedHeightSingle s = BedHeightSingle.getBedHeightSingleById(id);
+
+            if (s != null) {
+                singles.add(s);
+            }
+            else {
+                logger.warn("Cannot find Single by id: " + id);
+                // TODO ADD WARNING
+            }
+        }
+
+        return singles;
+    }
+
+
+    protected List<BedHeightEpoch> getEpochs(
+        BedHeightAccess access,
+        int[] ids
+    ) {
+        List<BedHeightEpoch> epochs = new ArrayList<BedHeightEpoch>();
+
+        for (int id: ids) {
+            BedHeightEpoch e = BedHeightEpoch.getBedHeightEpochById(id);
+
+            if (e != null) {
+                epochs.add(e);
+            }
+            else {
+                logger.warn("Cannot find Epoch by id: " + id);
+                // TODO ADD WARNING
+            }
+        }
+
+        return epochs;
+    }
+
+
+    protected CalculationResult buildCalculationResult(
+        BedHeightAccess       access,
+        List<BedHeightSingle> singles,
+        List<BedHeightEpoch>  epochs
+    ) {
+        logger.info("MiddleBedHeightCalculation.buildCalculationResult");
+
+        double kmLo = access.getLowerKM();
+        double kmHi = access.getUpperKM();
+
+        List<MiddleBedHeightData> data = new ArrayList<MiddleBedHeightData>();
+
+        for (BedHeightSingle single: singles) {
+            MiddleBedHeightData d = prepareSingleData(single, kmLo, kmHi);
+
+            if (d != null) {
+                data.add(d);
+            }
+        }
+
+        for (BedHeightEpoch epoch: epochs) {
+            MiddleBedHeightData d = prepareEpochData(epoch, kmLo, kmHi);
+
+            if (d != null) {
+                data.add(d);
+            }
+        }
+
+        logger.debug("Calculation results in " + data.size() + " data objects.");
+
+        return new CalculationResult((MiddleBedHeightData[])
+            data.toArray(new MiddleBedHeightData[data.size()]), this);
+    }
+
+
+    protected MiddleBedHeightData prepareSingleData(
+        BedHeightSingle single,
+        double kmLo,
+        double kmHi
+    ) {
+        logger.debug("Prepare data for single: " + single.getDescription());
+
+        List<BedHeightSingleValue> values =
+            BedHeightSingleValue.getBedHeightSingleValues(single, kmLo, kmHi);
+
+        MiddleBedHeightData data = new MiddleBedHeightData(
+            single.getYear(),
+            single.getYear(),
+            single.getEvaluationBy(),
+            single.getDescription());
+
+        for (BedHeightSingleValue value: values) {
+            if (value.getHeight() != null) {
+                data.addAll(value.getStation().doubleValue(),
+                    value.getHeight().doubleValue(),
+                    value.getUncertainty().doubleValue(),
+                    value.getSoundingWidth().doubleValue(),
+                    value.getDataGap().doubleValue(),
+                    value.getWidth().doubleValue(),
+                    false);
+             }
+            else {
+                data.addAll(value.getStation().doubleValue(),
+                    0,
+                    0,
+                    0,
+                    0,
+                    0,
+                    true);
+            }
+        }
+
+        logger.debug("Single contains " + values.size() + " values");
+
+        return data;
+    }
+
+
+    /** Create MiddleBedHeightData to return. */
+    protected MiddleBedHeightData prepareEpochData(
+        BedHeightEpoch epoch,
+        double kmLo,
+        double kmHi
+    ) {
+        logger.debug("Prepare data for epoch: " + epoch.getDescription());
+
+        TimeInterval ti = epoch.getTimeInterval();
+
+        List<BedHeightEpochValue> values =
+            BedHeightEpochValue.getBedHeightEpochValues(epoch, kmLo, kmHi);
+
+        MiddleBedHeightData data = new MiddleBedHeightData(
+            DateUtils.getYearFromDate(ti.getStartTime()),
+            DateUtils.getYearFromDate(ti.getStopTime()),
+            epoch.getEvaluationBy(),
+            epoch.getDescription()
+        );
+
+        for (BedHeightEpochValue value: values) {
+            data.addKM(value.getStation().doubleValue());
+            if (value.getHeight() != null) {
+                data.addMiddleHeight(value.getHeight().doubleValue());
+                data.addIsEmpty(false);
+            }
+            else {
+                data.addMiddleHeight(Double.NaN);
+                data.addIsEmpty(true);
+            }
+        }
+
+        logger.debug("Epoch contains " + values.size() + " values");
+
+        return data;
+    }
+}
+// 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/MiddleBedHeightData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,185 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+import java.util.ArrayList;
+
+import gnu.trove.TDoubleArrayList;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import org.apache.log4j.Logger;
+
+
+public class MiddleBedHeightData implements Serializable {
+
+    /** Very private logger. */
+    private static final Logger logger = Logger.getLogger(MiddleBedHeightData.class);
+
+    public static final String I18N_SINGLE_NAME = "facet.bedheight_middle.single";
+    public static final String I18N_EPOCH_NAME  = "facet.bedheight_middle.epoch";
+
+    private int    startYear;
+    private int    endYear;
+    private String evaluatedBy;
+    private String description;
+
+    private TDoubleArrayList km;
+    private TDoubleArrayList middleHeight;
+    private TDoubleArrayList uncertainty;
+    private TDoubleArrayList soundingWidth;
+    private TDoubleArrayList dataGap;
+    private TDoubleArrayList width;
+    private ArrayList empty;
+
+
+    protected MiddleBedHeightData(int start, int end, String eval, String desc) {
+        this.startYear   = start;
+        this.endYear     = end;
+        this.evaluatedBy = eval;
+        this.description = desc;
+
+        this.km            = new TDoubleArrayList();
+        this.middleHeight  = new TDoubleArrayList();
+        this.uncertainty   = new TDoubleArrayList();
+        this.soundingWidth = new TDoubleArrayList();
+        this.dataGap       = new TDoubleArrayList();
+        this.width         = new TDoubleArrayList();
+        this.empty         = new ArrayList();
+    }
+
+    public void addAll(double station, double height, double uncertainty,
+        double soundingWidth, double dataGap, double width, boolean isEmpty) {
+        addKM(station);
+        addMiddleHeight(height);
+        addUncertainty(uncertainty);
+        addSoundingWidth(soundingWidth);
+        addDataGap(dataGap);
+        addWidth(width);
+        addIsEmpty(isEmpty);
+    }
+
+
+    public int getStartYear() {
+        return startYear;
+    }
+
+    public int getEndYear() {
+        return endYear;
+    }
+
+    public String getEvaluatedBy() {
+        return evaluatedBy;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+
+    protected void addKM(double km) {
+        this.km.add(km);
+    }
+
+    public double getKM(int idx) {
+        return km.get(idx);
+    }
+
+    protected void addMiddleHeight(double middleHeight) {
+        this.middleHeight.add(middleHeight);
+    }
+
+    public double getMiddleHeight(int idx) {
+        return middleHeight.get(idx);
+    }
+
+    protected void addUncertainty(double uncertainty) {
+        this.uncertainty.add(uncertainty);
+    }
+
+    public double getUncertainty(int idx) {
+        return uncertainty.get(idx);
+    }
+
+    protected void addSoundingWidth(double soundingWidth) {
+        this.soundingWidth.add(soundingWidth);
+    }
+
+    public double getSoundingWidth(int idx) {
+        return soundingWidth.get(idx);
+    }
+
+    protected void addDataGap(double gap) {
+        this.dataGap.add(gap);
+    }
+
+    public double getDataGap(int idx) {
+        return dataGap.get(idx);
+    }
+
+    protected void addIsEmpty(boolean empty) {
+        this.empty.add(empty);
+    }
+
+    public boolean isEmpty(int idx) {
+        return (Boolean) empty.get(idx);
+    }
+
+
+    protected void addWidth(double width) {
+        this.width.add(width);
+    }
+
+    public double getWidth(int idx) {
+        return width.get(idx);
+    }
+
+    public int size() {
+        return km.size();
+    }
+
+
+    /**
+     * Get the points, ready to be drawn
+     * @return [[km1, km2,...],[height1,height2,...]]
+     */
+    public double[][] getMiddleHeightsPoints() {
+        double[][] points = new double[2][size()];
+
+        for (int i = 0, n = size(); i < n; i++) {
+            if (isEmpty(i)) {
+                points[0][i] = getKM(i);
+                points[1][i] = Double.NaN;
+            }
+            else {
+                points[0][i] = getKM(i);
+                points[1][i] = getMiddleHeight(i);
+            }
+        }
+
+        return points;
+    }
+
+
+    public String getSoundingName(CallContext context) {
+        if (getStartYear() == getEndYear()) {
+            return Resources.getMsg(
+                context.getMeta(),
+                I18N_SINGLE_NAME,
+                I18N_SINGLE_NAME,
+                new Object[] { getStartYear() }
+            );
+        }
+        else {
+            return Resources.getMsg(
+                context.getMeta(),
+                I18N_EPOCH_NAME,
+                I18N_EPOCH_NAME,
+                new Object[] { getStartYear(), getEndYear() }
+            );
+        }
+    }
+}
+// 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/MiddleBedHeightFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Facet of a MiddleBedHeight curve.
+ */
+public class MiddleBedHeightFacet extends DataFacet {
+
+    private static Logger logger = Logger.getLogger(MiddleBedHeightFacet.class);
+
+
+    public MiddleBedHeightFacet() {
+        // required for clone operation deepCopy()
+    }
+
+
+    public MiddleBedHeightFacet(
+        int         idx,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateId,
+        String      hash
+    ) {
+        super(idx, name, description, type, hash, stateId);
+    }
+
+
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("Get data for middle bed height at index: " + index);
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult)
+            flys.compute(context, hash, stateId, type, false);
+
+        MiddleBedHeightData[] data = (MiddleBedHeightData[]) res.getData();
+
+        return data[index];
+    }
+
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        MiddleBedHeightFacet copy = new MiddleBedHeightFacet();
+        copy.set(this);
+        copy.type    = type;
+        copy.hash    = hash;
+        copy.stateId = stateId;
+        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/Module.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,25 @@
+package de.intevation.flys.artifacts.model;
+
+/**
+ * Represents a Module as is is loaded from the config
+ */
+public class Module {
+
+    private String name;
+    private boolean selected;
+
+    public Module(String name, boolean selected) {
+        this.name = name;
+        this.selected = selected;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public boolean isSelected() {
+        return this.selected;
+    }
+}
+
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80:
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/NamedDouble.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/NamedDouble.java	Fri Sep 28 12:15:52 2012 +0200
@@ -27,3 +27,4 @@
         return this.value;
     }
 }
+// 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/Parameters.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,334 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.math.Linear;
+
+import gnu.trove.TDoubleArrayList;
+
+import java.io.Serializable;
+
+import org.apache.log4j.Logger;
+
+public class Parameters
+implements   Serializable
+{
+    private static Logger log = Logger.getLogger(Parameters.class);
+
+    public interface Visitor {
+
+        void visit(double [] row);
+
+    } // interface Visitor
+
+    public static final double EPSILON = 1e-4;
+
+    protected String []           columnNames;
+    protected TDoubleArrayList [] columns;
+
+    public Parameters() {
+    }
+
+    public Parameters(String [] columnNames) {
+        if (columnNames == null || columnNames.length < 1) {
+            throw new IllegalArgumentException("columnNames too short.");
+        }
+        this.columnNames = columnNames;
+        columns = new TDoubleArrayList[columnNames.length];
+        for (int i = 0; i < columns.length; ++i) {
+            columns[i] = new TDoubleArrayList();
+        }
+    }
+
+    public int columnIndex(String name) {
+        for (int i = 0; i < columnNames.length; ++i) {
+            if (columnNames[i].equals(name)) {
+                return i;
+            }
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("columnIndex: " + name + " not found in columnNames");
+        }
+        return -1;
+    }
+
+    public int newRow() {
+
+        int N = columns[0].size();
+
+        for (int i = 0; i < columns.length; ++i) {
+            columns[i].add(Double.NaN);
+        }
+
+        return N;
+    }
+
+    public double get(int row, int index) {
+        return columns[index].getQuick(row);
+    }
+
+    public double get(int i, String columnName) {
+        int index = columnIndex(columnName);
+        return index >= 0
+            ? columns[index].getQuick(i)
+            : Double.NaN;
+    }
+
+    public void set(int row, int index, double value) {
+        columns[index].setQuick(row, value);
+    }
+
+    public void set(int i, String columnName, double value) {
+        int idx = columnIndex(columnName);
+        if (idx >= 0) {
+            columns[idx].setQuick(i, value);
+        }
+    }
+
+    public boolean set(int row, int [] indices, double [] values) {
+        boolean invalid = false;
+        for (int i = 0; i < indices.length; ++i) {
+            double v = values[i];
+            if (Double.isNaN(v)) {
+                invalid = true;
+            }
+            else {
+                columns[indices[i]].setQuick(row, v);
+            }
+        }
+        return invalid;
+    }
+
+    public boolean set(int row, String [] names, double [] values) {
+        boolean success = true;
+        for (int i = 0; i < names.length; ++i) {
+            int idx = columnIndex(names[i]);
+            if (idx >= 0) {
+                columns[idx].setQuick(row, values[i]);
+            }
+            else {
+                success = false;
+            }
+        }
+        return success;
+    }
+
+    public int size() {
+        return columns[0].size();
+    }
+
+    public int getNumberColumns() {
+        return columnNames.length;
+    }
+
+    public String [] getColumnNames() {
+        return columnNames;
+    }
+
+    public void removeNaNs() {
+        W.removeNaNs(columns);
+    }
+
+    public int [] columnIndices(String [] columns) {
+        int [] indices = new int[columns.length];
+        for (int i = 0; i < columns.length; ++i) {
+            indices[i] = columnIndex(columns[i]);
+        }
+        return indices;
+    }
+
+    public double getValue(int row, String column) {
+        int idx = columnIndex(column);
+        return idx >= 0
+            ? columns[idx].getQuick(row)
+            : Double.NaN;
+    }
+
+    public double [] get(int row, String [] columns) {
+        return get(row, columns, new double[columns.length]);
+    }
+
+    public double [] get(int row, String [] columns, double [] values) {
+        for (int i = 0; i < columns.length; ++i) {
+            int idx = columnIndex(columns[i]);
+            values[i] = idx < 0
+                ? Double.NaN
+                : this.columns[idx].getQuick(row);
+        }
+
+        return values;
+    }
+
+    public void get(int row, int [] columnIndices, double [] values) {
+        for (int i = 0; i < columnIndices.length; ++i) {
+            int index = columnIndices[i];
+            values[i] = index >= 0 && index < columns.length
+                ? columns[index].getQuick(row)
+                : Double.NaN;
+        }
+    }
+
+    public int binarySearch(String columnName, double value) {
+        return binarySearch(columnIndex(columnName), value);
+    }
+
+    /**
+     * Performes a binary search in the column identified by its
+     * index.
+     * @return Index of found element or negative insertion point (shifted by one)
+     */
+    public int binarySearch(int columnIndex, double value) {
+        TDoubleArrayList column = columns[columnIndex];
+        return column.binarySearch(value);
+    }
+
+    public int binarySearch(String columnName, double value, double epsilon) {
+        return binarySearch(columnIndex(columnName), value, epsilon);
+    }
+
+    public int binarySearch(int columnIndex, double value, double epsilon) {
+        if (epsilon < 0d) epsilon = -epsilon;
+        double vl = value - epsilon;
+        double vh = value + epsilon;
+
+        TDoubleArrayList column = columns[columnIndex];
+        int lo = 0, hi = column.size()-1;
+        while (hi >= lo) {
+            int mid = (lo + hi) >> 1;
+            double v = column.getQuick(mid);
+            if      (v < vl) lo = mid + 1;
+            else if (v > vh) hi = mid - 1;
+            else             return mid;
+        }
+
+        return -(lo + 1);
+    }
+
+    public double [] interpolate(int columnIndex, double key) {
+        return interpolate(columnIndex, key, new double[columns.length]);
+    }
+
+    public double [] interpolate(String columnName, double key) {
+        return interpolate(
+            columnIndex(columnName), key, new double[columns.length]);
+    }
+
+    public double [] interpolate(
+        String    columnName,
+        double    key,
+        double [] values
+    ) {
+        return interpolate(columnIndex(columnName), key, values);
+    }
+
+    public double [] interpolate(
+        int       columnIndex,
+        double    key,
+        double [] values
+    ) {
+        int row = binarySearch(columnIndex, key, EPSILON);
+
+        if (row >= 0) { // direct hit
+            for (int i = 0; i < values.length; ++i) {
+                values[i] = columns[i].getQuick(row);
+            }
+        }
+        else {
+            row = -row - 1;
+            if (row < 1 || row >= size()) {
+                return null;
+            }
+            double v1 = columns[columnIndex].getQuick(row-1);
+            double v2 = columns[columnIndex].getQuick(row);
+            double factor = Linear.factor(key, v1, v2);
+            for (int i = 0; i < values.length; ++i) {
+                values[i] = Linear.weight(
+                    factor,
+                    columns[i].getQuick(row-1),
+                    columns[i].getQuick(row));
+            }
+        }
+        return values;
+    }
+
+
+    public double [] interpolate(
+        String    keyName,
+        double    key,
+        String [] columnNames
+    ) {
+        int keyIndex = columnIndex(keyName);
+        return keyIndex < 0
+            ? null
+            : interpolate(keyIndex, key, columnNames);
+    }
+
+    public double [] interpolate(
+        int       keyIndex,
+        double    key,
+        String [] columnNames
+    ) {
+        int row = binarySearch(keyIndex, key, EPSILON);
+
+        if (row >= 0) { // direct match
+            double [] values = new double[columnNames.length];
+            for (int i = 0; i < values.length; ++i) {
+                int ci = columnIndex(columnNames[i]);
+                values[i] = ci < 0
+                    ? Double.NaN
+                    : columns[ci].getQuick(row);
+            }
+            return values;
+        }
+
+        row = -row - 1;
+        if (row < 1 || row >= size()) {
+            log.debug("interpolate: row is out of bounds");
+            return null;
+        }
+
+        double v1 = columns[keyIndex].getQuick(row-1);
+        double v2 = columns[keyIndex].getQuick(row);
+        double factor = Linear.factor(key, v1, v2);
+
+        double [] values = new double[columnNames.length];
+
+        for (int i = 0; i < values.length; ++i) {
+            int ci = columnIndex(columnNames[i]);
+            values[i] = ci < 0
+                ? Double.NaN
+                : Linear.weight(
+                    factor,
+                    columns[ci].getQuick(row-1),
+                    columns[ci].getQuick(row));
+        }
+
+        return values;
+    }
+
+    public boolean isSorted(String columnName) {
+        return isSorted(columnIndex(columnName));
+    }
+
+    public boolean isSorted(int columnIndex) {
+        TDoubleArrayList column = columns[columnIndex];
+        for (int i = 1, N = column.size(); i < N; ++i) {
+            if (column.getQuick(i-1) > column.getQuick(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void visit(Visitor visitor) {
+        visit(visitor, new double[columns.length]);
+    }
+
+    public void visit(Visitor visitor, double [] data) {
+        for (int i = 0, R = size(); i < R; ++i) {
+            for (int j = 0; j < data.length; ++j) {
+                data[j] = columns[j].getQuick(i);
+            }
+            visitor.visit(data);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,6 +3,7 @@
 import java.io.Serializable;
 
 import java.util.List;
+import java.util.ArrayList;
 
 import org.apache.log4j.Logger;
 
@@ -11,6 +12,8 @@
 {
     private static Logger log = Logger.getLogger(QRangeTree.class);
 
+    public static final double EPSILON = 1e-4;
+
     public static class Node
     implements          Serializable
     {
@@ -105,47 +108,99 @@
     public QRangeTree() {
     }
 
+    public static final class AccessQAB {
+        private int startIndex;
+
+        public AccessQAB(int startIndex) {
+            this.startIndex = startIndex;
+        }
+
+        public Double getQ(Object [] row) {
+            return (Double)row[startIndex];
+        }
+
+        public Double getA(Object [] row) {
+            return (Double)row[startIndex+1];
+        }
+
+        public Double getB(Object [] row) {
+            return (Double)row[startIndex+2];
+        }
+    }
+
+    public static final AccessQAB WITH_COLUMN    = new AccessQAB(1);
+    public static final AccessQAB WITHOUT_COLUMN = new AccessQAB(0);
+
     /** wstQRanges need to be sorted by range.a */
     public QRangeTree(List<Object []> qRanges, int start, int stop) {
+        this(qRanges, WITH_COLUMN, start, stop);
+    }
 
+    public QRangeTree(
+        List<Object []> qRanges,
+        AccessQAB       accessQAB,
+        int             start,
+        int             stop
+    ) {
         if (stop <= start) {
             return;
         }
 
-        Node [] nodes = new Node[stop-start];
-        for (int i = 0; i < nodes.length; ++i) {
+        int N = stop-start;
+
+        List<Node> nodes = new ArrayList<Node>(N);
+
+        Node last = null;
+
+        for (int i = 0; i < N; ++i) {
             Object [] qRange = qRanges.get(start + i);
-            Double q = (Double)qRange[1];
-            Double a = (Double)qRange[2];
-            Double b = (Double)qRange[3];
+            Double q = accessQAB.getQ(qRange);
+            Double a = accessQAB.getA(qRange);
+            Double b = accessQAB.getB(qRange);
 
-            nodes[i] = new Node(
-                a != null ? a.doubleValue() : -Double.MAX_VALUE,
-                b != null ? b.doubleValue() :  Double.MAX_VALUE,
-                q.doubleValue());
+            double av = a != null ? a.doubleValue() : -Double.MAX_VALUE;
+            double bv = b != null ? b.doubleValue() :  Double.MAX_VALUE;
+            double qv = q.doubleValue();
+
+            // If nodes are directly neighbored and Qs are the same
+            // join them.
+            if (last != null
+            && Math.abs(last.b - av) < EPSILON
+            && Math.abs(last.q - qv) < EPSILON) {
+                last.b = bv;
+            }
+            else {
+                nodes.add(last = new Node(av, bv, qv));
+            }
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("Before/after nodes join: " +
+                N + "/" + nodes.size());
         }
 
         root = wireTree(nodes);
     }
 
-    protected static Node wireTree(Node [] nodes) {
-        for (int i = 0; i < nodes.length; ++i) {
-            Node node = nodes[i];
-            if (i > 0             ) node.prev = nodes[i-1];
-            if (i < nodes.length-1) node.next = nodes[i+1];
+    protected static Node wireTree(List<Node> nodes) {
+        int N = nodes.size();
+        for (int i = 0; i < N; ++i) {
+            Node node = nodes.get(i);
+            if (i > 0  ) node.prev = nodes.get(i-1);
+            if (i < N-1) node.next = nodes.get(i+1);
         }
 
-        return buildTree(nodes, 0, nodes.length-1);
+        return buildTree(nodes, 0, N-1);
     }
 
-    protected static Node buildTree(Node [] nodes, int lo, int hi) {
+    protected static Node buildTree(List<Node> nodes, int lo, int hi) {
 
         if (lo > hi) {
             return null;
         }
 
         int mid = (lo + hi) >> 1;
-        Node parent = nodes[mid];
+        Node parent = nodes.get(mid);
 
         parent.left  = buildTree(nodes, lo, mid-1);
         parent.right = buildTree(nodes, mid+1, hi);
@@ -157,6 +212,56 @@
         return root != null ? root.findQ(pos) : Double.NaN;
     }
 
+    protected Node head() {
+        Node head = root;
+        while (head.left != null) {
+            head = head.left;
+        }
+        return head;
+    }
+
+    public List<Range> findSegments(double a, double b) {
+        if (a > b) { double t = a; a = b; b = t; }
+        return findSegments(new Range(a, b));
+    }
+
+    public List<Range> findSegments(Range range) {
+        List<Range> segments = new ArrayList<Range>();
+
+        // Linear scan should be good enough here.
+        for (Node curr = head(); curr != null; curr = curr.next) {
+            if (!range.disjoint(curr.a, curr.b)) {
+                Range r = new Range(curr.a, curr.b);
+                if (r.clip(range)) {
+                    segments.add(r);
+                }
+            }
+        }
+
+        return segments;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        inorder(root, sb);
+        return sb.toString();
+    }
+
+    protected static void inorder(Node node, StringBuilder sb) {
+        if (node != null) {
+            inorder(node.left, sb);
+            sb.append('[')
+              .append(node.a)
+              .append(", ")
+              .append(node.b)
+              .append(": ")
+              .append(node.q)
+              .append(']');
+            inorder(node.right, sb);
+        }
+    }
+
     private static final String name(Object o) {
         return String.valueOf(System.identityHashCode(o) & 0xffffffffL);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QSectorFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,66 @@
+package de.intevation.flys.artifacts.model;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.QSectorArtifact;
+
+import de.intevation.artifactdatabase.state.DefaultFacet;
+import de.intevation.artifactdatabase.state.Facet;
+
+
+/**
+ * Facet to access QSector that where added by user.
+ */
+public class QSectorFacet
+extends      DefaultFacet
+{
+    /** Logger for this class. */
+    private static final Logger logger = Logger.getLogger(QSectorFacet.class);
+
+
+    /**
+     * Trivial Constructor.
+     */
+    public QSectorFacet() {
+    }
+
+
+    /**
+     * Trivial Constructor for a QSectorFacet.
+     *
+     * @param index       Database-Index to use.
+     * @param name        Name (~type) of Facet.
+     * @param description Description of Facet.
+     */
+    public QSectorFacet(int index, String name, String description) {
+        super(index, name, description);
+    }
+
+
+    /**
+     * Get List of QSector for river from Artifact.
+     *
+     * @param artifact (QSector-)Artifact to query for list of QSector.
+     * @param context  Ignored.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        QSectorArtifact qsectorArtifact = (QSectorArtifact) artifact;
+        double currentKm =
+            ((Double)context.getContextValue("currentKm")).doubleValue();
+        return qsectorArtifact.getQSectors(currentKm, context);
+    }
+
+
+    /** Do a deep copy. */
+    @Override
+    public Facet deepCopy() {
+        QSectorFacet copy = new QSectorFacet();
+        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/QW.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,35 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+public class QW
+implements   Serializable
+{
+    protected double q;
+    protected double w;
+
+    public QW() {
+    }
+
+    public QW(double q, double w) {
+        this.q = q;
+        this.w = w;
+    }
+
+    public double getQ() {
+        return q;
+    }
+
+    public void setQ(double q) {
+        this.q = q;
+    }
+
+    public double getW() {
+        return w;
+    }
+
+    public void setW(double w) {
+        this.w = w;
+    }
+}
+// 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/QWDDateRange.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,24 @@
+package de.intevation.flys.artifacts.model;
+
+
+import java.io.Serializable;
+
+import de.intevation.flys.artifacts.model.fixings.QWD;
+
+public class QWDDateRange
+implements   Serializable
+{
+
+    public QWD qwd;
+    public DateRange dateRange;
+
+    public QWDDateRange(QWD qwd, DateRange dr) {
+        this.qwd = qwd;
+        this.dateRange = dr;
+    }
+
+    public QWD getQWD() {
+        return qwd;
+    }
+}
+// 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/Range.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,63 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+public class Range implements Serializable {
+
+    public static final double EPSILON  = 1e-5;
+
+    protected double start;
+    protected double end;
+
+    public Range() {
+    }
+
+    public Range(Range other) {
+        start = other.start;
+        end   = other.end;
+    }
+
+    public Range(double start, double end) {
+        this.start = start;
+        this.end   = end;
+    }
+
+    public double getStart() {
+        return start;
+    }
+
+    public double getEnd() {
+        return end;
+    }
+
+    public boolean disjoint(double ostart, double oend) {
+        return start > oend || ostart > end;
+    }
+
+    public boolean disjoint(Range other) {
+        return start > other.end || other.start > end;
+    }
+
+    public boolean intersects(Range other) {
+        return !disjoint(other);
+    }
+
+    public void extend(Range other) {
+        if (other.start < start) start = other.start;
+        if (other.end   > end  ) end   = other.end;
+    }
+
+    public boolean clip(Range other) {
+        if (disjoint(other)) return false;
+
+        if (other.start > start) start = other.start;
+        if (other.end   < end  ) end   = other.end;
+
+        return true;
+    }
+
+    public boolean inside(double x) {
+        return x > start-EPSILON && x < end+EPSILON;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/RangeWithValues.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/RangeWithValues.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,41 +1,32 @@
 package de.intevation.flys.artifacts.model;
 
-import java.io.Serializable;
-
+import java.util.Arrays;
 
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
-public class RangeWithValues implements Serializable {
+public class RangeWithValues extends Range {
 
-    protected double   lower;
-    protected double   upper;
     protected double[] values;
 
-
     public RangeWithValues() {
     }
 
-
     public RangeWithValues(double lower, double upper, double[] values) {
-        this.lower  = lower;
-        this.upper  = upper;
+        super(lower, upper);
         this.values = values;
     }
 
-
-    public double getLower() {
-        return lower;
-    }
-
-
-    public double getUpper() {
-        return upper;
-    }
-
-
     public double[] getValues() {
         return values;
     }
+
+    @Override
+    public String toString() {
+        return new StringBuilder("start=").append(start)
+            .append(" end=" ).append(end)
+            .append(" values=[").append(Arrays.toString(values)).append(']')
+            .toString();
+    }
 }
 // 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/ReferenceCurveFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,150 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collections;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.WINFOArtifact;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import org.apache.log4j.Logger;
+
+
+/** Facet for W-over-Ws. */
+public class ReferenceCurveFacet
+extends      DataFacet
+{
+    private static Logger log = Logger.getLogger(ReferenceCurveFacet.class);
+
+    public static final String CONTEXT_KEY = "reference.curve.axis.scale";
+
+    /** Blackboard data provider key for reference curves start km. */
+    public static final String BB_REFERENCECURVE_STARTKM =
+        "reference_curve.startkm";
+
+    /** Blackboard data provider key for reference curves end kms. */
+    public static final String BB_REFERENCECURVE_ENDKMS =
+        "reference_curve.endkms";
+
+
+    public ReferenceCurveFacet() {
+    }
+
+
+    public ReferenceCurveFacet(int index, String name, String description) {
+        super(index, name, description, ComputeType.ADVANCE, null, null);
+    }
+
+
+    public ReferenceCurveFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateID,
+        String      hash
+    ) {
+        super(index, name, description, type, hash, stateID);
+    }
+
+
+    public Object getData(Artifact artifact, CallContext context) {
+
+        if (log.isDebugEnabled()) {
+            log.debug("Get data for reference curve at index: " + index +
+                " /stateId: " + stateId);
+        }
+
+        return getWWQQ(artifact, context);
+    }
+
+
+   /**
+     * Can provide parameters of reference curve
+     * @param key      will respond on BB_REFERENCECURVE START/ENDKMS
+     * @param param    ignored
+     * @param context  ignored
+     * @return whatever parameters for reference curve
+     */
+    @Override
+    public Object provideBlackboardData(Artifact artifact,
+        Object key,
+        Object param,
+        CallContext context
+    ) {
+        WINFOArtifact winfo = (WINFOArtifact) artifact;
+        if (key.equals(BB_REFERENCECURVE_STARTKM)) {
+            return winfo.getReferenceStartKm();
+        }
+        else if (key.equals(BB_REFERENCECURVE_ENDKMS)) {
+            return winfo.getReferenceEndKms();
+        }
+        else {
+            return null;
+        }
+    }
+
+
+    protected WWQQ getWWQQ(Artifact artifact, CallContext context) {
+        FLYSArtifact winfo = (FLYSArtifact)artifact;
+
+        CalculationResult res = (CalculationResult)
+            winfo.compute(context, hash, stateId, type, false);
+
+        return ((WWQQ [])res.getData())[index];
+    }
+
+
+    @Override
+    public void set(Facet other) {
+        super.set(other);
+        ReferenceCurveFacet o = (ReferenceCurveFacet)other;
+        type                  = o.type;
+        hash                  = o.hash;
+        stateId               = o.stateId;
+    }
+
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        ReferenceCurveFacet copy = new ReferenceCurveFacet();
+        copy.set(this);
+        return copy;
+    }
+
+
+    @Override
+    public List getStaticDataProviderKeys(Artifact art) {
+        List list = new ArrayList();
+        list.add(BB_REFERENCECURVE_STARTKM);
+        list.add(BB_REFERENCECURVE_ENDKMS);
+        return list;
+    }
+
+
+    @Override
+    public List getDataProviderKeys(Artifact art, CallContext context) {
+
+        // compute / get data
+        Object obj = context.getContextValue(CONTEXT_KEY);
+
+        if (!(obj instanceof WWAxisTypes)) {
+            obj = new WWAxisTypes(getWWQQ(art, context));
+            context.putContextValue(CONTEXT_KEY, obj);
+        }
+        else {
+            ((WWAxisTypes)obj).classify(getWWQQ(art, context));
+        }
+
+        return getStaticDataProviderKeys(art);//Collections.emptyList();
+    }
+}
+// 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/RelativePointFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,179 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.List;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.DataProvider;
+
+import de.intevation.flys.artifacts.StaticWKmsArtifact;
+import de.intevation.flys.artifacts.math.Linear;
+
+/**
+ * Facet to access a point.
+ */
+public class RelativePointFacet
+extends      BlackboardDataFacet
+implements   FacetTypes {
+
+    /** Own logger. */
+    private static Logger logger = Logger.getLogger(RelativePointFacet.class);
+
+    /** Trivial Constructor. */
+    public RelativePointFacet(String description) {
+        this(RELATIVE_POINT, description);
+    }
+
+
+    public RelativePointFacet(String name, String description) {
+        this.name        = name;
+        this.description = description;
+        this.index       = 0;
+    }
+
+
+    protected Point2D calculateDurationCurvePoint(CallContext context,
+        StaticWKmsArtifact artifact)
+    {
+        // TODO here and in reference curve calc: Do warn if more than 1
+        // provider found or (way better) handle it.
+        Object wqdays = null;
+        double km     = 0d;
+        List<DataProvider> providers = context.
+            getDataProvider(DurationCurveFacet.BB_DURATIONCURVE);
+        if (providers.size() < 1) {
+            logger.warn("Could not find durationcurve data provider.");
+        }
+        else {
+            wqdays = providers.get(0).provideData(
+                DurationCurveFacet.BB_DURATIONCURVE,
+                null,
+                context);
+        }
+        List<DataProvider> kmproviders = context.
+            getDataProvider(DurationCurveFacet.BB_DURATIONCURVE_KM);
+        if (kmproviders.size() < 1) {
+            logger.warn("Could not find durationcurve.km data provider.");
+        }
+        else {
+            logger.debug("Found durationcurve.km data provider.");
+            String dckm = providers.get(0).provideData(
+                DurationCurveFacet.BB_DURATIONCURVE_KM,
+                null,
+                context).toString();
+            km = Double.valueOf(dckm);
+        }
+
+        if (wqdays != null) {
+            // Which W at this km?
+            double w = artifact.getWAtKmLin(artifact.getWKms(0), km);
+            if (w == -1) {
+                logger.warn("w is -1, already bad sign!");
+            }
+            // Where is this W passed by in the wq-curve?
+            WQDay wqday = (WQDay) wqdays;
+            // Doing a linear Day Of KM.
+            int idx = 0;
+            boolean wIncreases = wqday.getW(0) < wqday.getW(wqday.size()-1);
+            if (wIncreases) {
+                while (idx < wqday.size() && wqday.getW(idx) < w) {
+                    idx++;
+                }
+            }
+            else {
+                idx = wqday.size() -1;
+                while (idx > 0 && wqday.getW(idx) > w) {
+                    idx--;
+                }
+            }
+
+            double day = 0d;
+            int mod = (wIncreases) ? -1 : +1;
+            if (idx != 0 && idx <= wqday.size()-1) {
+                day = Linear.linear(w, wqday.getW(idx+mod), wqday.getW(idx),
+                    wqday.getDay(idx+mod), wqday.getDay(idx));
+            }
+
+            return new Point2D.Double((double) day, w);
+        }
+        logger.warn("not wqkms / w / day found");
+        // TODO better signal failure.
+        return new Point2D.Double(0d, 0d);
+    }
+
+
+    /**
+     * Calculate a reference curve point, that is, a point made of
+     * the Ws from start and end km param of the reference curve.
+     */
+    public Point2D calculateReferenceCurvePoint(CallContext context,
+        StaticWKmsArtifact artifact) {
+        List<DataProvider> providers = context.
+            getDataProvider(ReferenceCurveFacet.BB_REFERENCECURVE_STARTKM);
+        if (providers.size() < 1) {
+            logger.warn("Could not find reference curve startkm data provider.");
+        }
+
+        Double start = (Double) providers.get(0).
+            provideData(ReferenceCurveFacet.BB_REFERENCECURVE_STARTKM, null, context);
+
+        providers = context.
+            getDataProvider(ReferenceCurveFacet.BB_REFERENCECURVE_ENDKMS);
+        if (providers.size() < 1) {
+            logger.warn("Could not find reference curve endkms data provider.");
+        }
+        double[] ends = (double[]) providers.get(0).
+            provideData(ReferenceCurveFacet.BB_REFERENCECURVE_ENDKMS, null, context);
+
+        logger.debug("Got s " + start + " e " + ends);
+        double startW = artifact.getWAtKmLin(artifact.getWKms(0), start.doubleValue());
+        // TODO handle multiple ends.
+        double endW = artifact.getWAtKmLin(artifact.getWKms(0), ends[0]);
+        logger.debug("Gotw s " + startW + " e " + endW);
+        return new Point2D.Double(startW, endW);
+    }
+
+
+    /**
+     * 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) {
+        StaticWKmsArtifact staticData = (StaticWKmsArtifact) artifact;
+        // Find out whether we live in a duration curve context, there we would
+        // provide only a single point.
+
+        if (context.getDataProvider(
+            DurationCurveFacet.BB_DURATIONCURVE_KM).size() > 0) {
+            return calculateDurationCurvePoint(context, staticData);
+        }
+        else if (context.getDataProvider(
+            ReferenceCurveFacet.BB_REFERENCECURVE_STARTKM).size() > 0) {
+            return calculateReferenceCurvePoint(context, staticData);
+        }
+
+        // TODO better signal failure.
+        return new Point2D.Double(0d, 0d);
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public RelativePointFacet deepCopy() {
+        RelativePointFacet copy = new RelativePointFacet(description);
+        copy.set(this);
+        return copy;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/ReportFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,7 +8,7 @@
 
 import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
 
-import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.FLYSArtifact;
 
 
 import org.apache.log4j.Logger;
@@ -43,9 +43,9 @@
     public Object getData(Artifact artifact, CallContext context) {
         logger.debug("get report data");
 
-        WINFOArtifact winfo = (WINFOArtifact)artifact;
+        FLYSArtifact flys = (FLYSArtifact)artifact;
 
-        CalculationResult cr = (CalculationResult)winfo.compute(
+        CalculationResult cr = (CalculationResult)flys.compute(
             context, hash, stateId, type, false);
 
         return cr.getReport();
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/RiverFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -45,7 +45,7 @@
 
         List<River> rivers = query.list();
 
-        return (rivers != null && rivers.size() > 0) ? rivers.get(0) : null;
+        return rivers.isEmpty() ? null : rivers.get(0);
     }
 
 
@@ -65,7 +65,7 @@
 
         List<River> rivers = query.list();
 
-        return (rivers != null && rivers.size() > 0) ? rivers.get(0) : null;
+        return rivers.isEmpty() ? null : rivers.get(0);
     }
 }
 // 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/SQOverview.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,209 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+import java.text.SimpleDateFormat;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+
+import org.hibernate.type.StandardBasicTypes;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import de.intevation.flys.utils.KMIndex;
+
+public class SQOverview
+implements   Serializable
+{
+    private static Logger log = Logger.getLogger(SQOverview.class);
+
+    /**
+     * Serial version UId.
+     */
+    private static final long serialVersionUID = -8934372438968398508L;
+
+    public interface Filter {
+
+        boolean accept(KMIndex<List<Date>> entry);
+
+    } // interface Filter
+
+
+    public static final Filter ACCEPT = new Filter() {
+        @Override
+        public boolean accept(KMIndex<List<Date>> entry) {
+            return true;
+        }
+    };
+
+    public static class KmFilter implements Filter {
+
+        protected double km;
+
+        public KmFilter (double km) {
+            this.km = km;
+        }
+        @Override
+        public boolean accept(KMIndex<List<Date>> list) {
+            for (KMIndex.Entry<List<Date>> e: list){
+                if (e.getKm() == km) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    public static class DateFilter implements Filter {
+
+        protected Date date;
+
+        public DateFilter (Date date) {
+            this.date = date;
+        }
+        @Override
+        public boolean accept(KMIndex<List<Date>> list) {
+            for (KMIndex.Entry<List<Date>> e: list){
+                if (e.getValue().equals(this.date)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    public static final double EPSILON = 1e-4;
+
+    public static final String DATE_FORMAT = "dd.MM.yyyy";
+
+    public static final String SQL_SQ =
+        "SELECT" +
+        "    s.km    AS km," +
+        "    m.datum AS datum " +
+        "FROM messung m " +
+        "    JOIN station s" +
+        "       ON m.stationid = s.stationid " +
+        "    JOIN gewaesser g " +
+        "       ON s.gewaesserid = g.gewaesserid " +
+        "WHERE" +
+        "    m.q_bpegel IS NOT NULL AND" +
+        "    g.name = :name " +
+        "ORDER by" +
+        "    s.km, m.datum";
+
+    protected String       riverName;
+
+    protected KMIndex<List<Date>> entries;
+
+    public SQOverview() {
+        entries = new KMIndex<List<Date>>();
+    }
+
+    public SQOverview(String riverName) {
+        this();
+        this.riverName = riverName;
+    }
+
+    private static final boolean epsilonEquals(double a, double b) {
+        return Math.abs(a - b) < EPSILON;
+    }
+
+    protected void loadData(Session session) {
+        SQLQuery query = session.createSQLQuery(SQL_SQ)
+            .addScalar("km",    StandardBasicTypes.DOUBLE)
+            .addScalar("datum", StandardBasicTypes.DATE);
+
+        query.setString("name", riverName);
+
+        List<Object []> list = query.list();
+
+        if (list.isEmpty()) {
+            log.warn("No river '" + riverName + "' found.");
+        }
+
+        Double prevKm = -Double.MAX_VALUE;
+        List<Date> dates = new ArrayList<Date>();
+
+        for (Object [] row: list) {
+            Double km = (Double)row[0];
+            if (!epsilonEquals(km, prevKm) && !dates.isEmpty()) {
+                entries.add(prevKm, dates);
+                dates = new ArrayList<Date>();
+            }
+            dates.add((Date)row[1]);
+            prevKm = km;
+        }
+
+        if (!dates.isEmpty()) {
+            entries.add(prevKm, dates);
+        }
+    }
+
+    public boolean load(Session session) {
+
+        loadData(session);
+
+        return true;
+    }
+
+
+    public void generateOverview(Document document) {
+        generateOverview(document, ACCEPT);
+    }
+
+    public KMIndex<List<Date>> filter(Filter f) {
+        // TODO: Apply filter
+        return entries;
+    }
+
+    public void generateOverview(
+        Document document,
+        Filter   filter
+    ) {
+        KMIndex<List<Date>> filtered = filter(ACCEPT);
+
+        Element sqElement = document.createElement("sq");
+
+        Element riverElement = document.createElement("river");
+
+        riverElement.setAttribute("name", riverName);
+
+        sqElement.appendChild(riverElement);
+
+        SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
+
+        Element kmE = document.createElement("km");
+
+        for (KMIndex.Entry<List<Date>> e: filtered) {
+
+            List<Date> dates = e.getValue();
+
+            if (!dates.isEmpty()) {
+                Element dEs = document.createElement("dates");
+
+                for (Date d: dates) {
+                    Element dE = document.createElement("date");
+
+                    dE.setAttribute("value", df.format(d));
+
+                    dEs.appendChild(dE);
+                }
+
+                kmE.appendChild(dEs);
+            }
+        }
+
+        sqElement.appendChild(kmE);
+
+        document.appendChild(sqElement);
+    }
+}
+// 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/SQOverviewFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,73 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+
+import de.intevation.flys.backend.SedDBSessionHolder;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+
+public class SQOverviewFactory {
+
+    private static Logger log = Logger.getLogger(SQOverviewFactory.class);
+
+    public static final String CACHE_NAME = "sq-overviews";
+
+    private SQOverviewFactory() {
+    }
+
+
+    public static SQOverview getOverview(String river) {
+
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug(
+                "Looking for sq overview for river '" + river + "'");
+        }
+
+        Cache cache = CacheFactory.getCache(CACHE_NAME);
+
+        if (cache == null) {
+            if (debug) {
+                log.debug("Cache not configured.");
+            }
+            return getUncached(river);
+        }
+
+        String key = "sq-over-" + river;
+
+        Element element = cache.get(key);
+
+        if (element != null) {
+            if (debug) {
+                log.debug("Overview found in cache");
+            }
+            return (SQOverview)element.getValue();
+        }
+
+        SQOverview overview = getUncached(river);
+
+        if (overview != null) {
+            if (debug) {
+                log.debug("Store overview in cache.");
+            }
+            cache.put(new Element(key, overview));
+        }
+
+        return overview;
+    }
+
+    public static SQOverview getUncached(String river) {
+        SQOverview overview = new SQOverview(river);
+
+        Session session = SedDBSessionHolder.HOLDER.get();
+
+        return overview.load(session) ? overview : null;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Segment.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Segment.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,20 +1,34 @@
 package de.intevation.flys.artifacts.model;
 
-import java.util.List;
-import java.util.ArrayList;
+import de.intevation.flys.model.DischargeTable;
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.River;
+
+import de.intevation.flys.utils.DoubleUtil;
 
 import java.io.Serializable;
 
-import org.apache.log4j.Logger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
 
-import gnu.trove.TDoubleArrayList;
-
-import de.intevation.flys.utils.DoubleUtil;
+import org.apache.log4j.Logger;
 
 public class Segment
 implements   Serializable
 {
-    private static Logger logger = Logger.getLogger(Segment.class);
+    private static Logger log = Logger.getLogger(Segment.class);
+
+    public static final Comparator<Segment> REF_CMP =
+        new Comparator<Segment>() {
+            @Override
+            public int compare(Segment a, Segment b) {
+                double d = a.referencePoint - b.referencePoint;
+                if (d < 0d) return -1;
+                return d > 0d ? +1 : 0;
+            }
+        };
 
     protected double    from;
     protected double    to;
@@ -39,6 +53,13 @@
         return from < to;
     }
 
+    public boolean inside(double km) {
+        return from < to
+            ? km >= from && km <= to
+            : km >= to   && km <= from;
+    }
+
+    @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("Segment: [");
         sb.append("from: ").append(from).append("; to: ")
@@ -58,7 +79,13 @@
     }
 
     public void backup() {
-        backup = (double [])values.clone();
+        backup = values != null
+            ? (double [])values.clone()
+            : null;
+    }
+
+    public double [] getBackup() {
+        return backup;
     }
 
     public double getFrom() {
@@ -81,6 +108,10 @@
         return values;
     }
 
+    public int numValues() {
+        return values.length;
+    }
+
     public void setReferencePoint(double referencePoint) {
         this.referencePoint = referencePoint;
     }
@@ -91,36 +122,89 @@
 
     public static List<Segment> parseSegments(String input) {
 
-        ArrayList<Segment> segments = new ArrayList<Segment>();
-
-        TDoubleArrayList vs = new TDoubleArrayList();
+        final List<Segment> segments = new ArrayList<Segment>();
 
-        for (String segmentStr: input.split(":")) {
-            String [] parts = segmentStr.split(";");
-            if (parts.length < 3) {
-                logger.warn("invalid segment: '" + segmentStr + "'");
-                continue;
-            }
-            try {
-                double from = Double.parseDouble(parts[0].trim());
-                double to   = Double.parseDouble(parts[1].trim());
-
-                vs.clear();
-
-                for (String valueStr: parts[2].split(",")) {
-                    vs.add(DoubleUtil.round(
-                        Double.parseDouble(valueStr.trim())));
-                }
-
-                double [] values = vs.toNativeArray();
+        DoubleUtil.parseSegments(input, new DoubleUtil.SegmentCallback() {
+            @Override
+            public void newSegment(double from, double to, double [] values) {
                 segments.add(new Segment(from, to, values));
             }
-            catch (NumberFormatException nfe) {
-                logger.warn("invalid segment: '" + segmentStr + "'");
-            }
-        }
+        });
 
         return segments;
     }
+
+    public static boolean setReferencePointConvertQ(
+        List<Segment> segments,
+        River         river,
+        boolean       isQ,
+        Calculation   report
+    ) {
+        int numResults = -1;
+
+        boolean success = true;
+
+        // assign reference points
+        for (Segment segment: segments) {
+            Gauge gauge = river.maxOverlap(segment.getFrom(), segment.getTo());
+
+            if (gauge == null) {
+                log.warn("no gauge found. Defaults to mid point.");
+                segment.setReferencePoint(
+                    0.5*(segment.getFrom()+segment.getTo()));
+            }
+            else {
+                double ref = gauge.getStation().doubleValue();
+                log.debug(
+                    "reference gauge: " + gauge.getName() +
+                    " (km " + ref + ")");
+                segment.setReferencePoint(ref);
+            }
+
+            double [] values = segment.values;
+
+            if (numResults == -1) {
+                numResults = values.length;
+            }
+            else if (numResults != values.length) {
+                log.warn("wrong length of values");
+                return false;
+            }
+
+            // convert to Q if needed
+            if (!isQ && gauge != null) {
+
+                DischargeTable dt = gauge.fetchMasterDischargeTable();
+
+                double [][] table =
+                    DischargeTables.loadDischargeTableValues(dt, 1);
+
+                // need the original values for naming
+                segment.backup();
+
+                for (int i = 0; i < values.length; ++i) {
+                    double w = values[i] / 100.0;
+                    double [] qs = DischargeTables.getQsForW(table, w);
+                    if (qs.length == 0) {
+                        log.warn("No Qs found for W = " + values[i]);
+                        report.addProblem("cannot.find.w.for.q", values[i]);
+                        values[i] = Double.NaN;
+                        success = false;
+                    }
+                    else {
+                        values[i] = qs[0];
+                        if (qs.length > 1) {
+                            log.warn(
+                                "More than one Q found for W = " + values[i]);
+                        }
+                    }
+                }
+            }
+        } // for all segments
+
+        Collections.sort(segments, Segment.REF_CMP);
+
+        return success;
+    }
 }
 // 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/StaticBedHeightCacheKey.java	Fri Sep 28 12:15:52 2012 +0200
@@ -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 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/StaticWQKmsCacheKey.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/StaticWQKmsCacheKey.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,7 +8,7 @@
 public final class StaticWQKmsCacheKey
 implements         Serializable
 {
-    public static final String CACHE_NAME = "wst-wq--value-table-static";
+    public static final String CACHE_NAME = "wst-wq-value-table-static";
 
     private int column;
     private int wst_id;
@@ -27,7 +27,7 @@
             return false;
         }
         StaticWQKmsCacheKey o = (StaticWQKmsCacheKey) other;
-        return wst_id == o.wst_id && this.column == o.column;
+        return this.wst_id == o.wst_id && this.column == o.column;
     }
 }
 // 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/Timerange.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,41 @@
+package de.intevation.flys.artifacts.model;
+
+import java.io.Serializable;
+
+import java.util.Date;
+
+
+/**
+ * This class represents time ranges specified by start and end time. Start and
+ * end times are stored as long (number of milliseconds since january 1, 1970).
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class Timerange implements Serializable {
+
+    private long start;
+    private long end;
+
+
+    public Timerange(long start, long end) {
+        this.start = start;
+        this.end   = end;
+    }
+
+
+    public Timerange(Date start, Date stop) {
+        this.start = start.getTime();
+        this.end   = stop != null ? stop.getTime() : System.currentTimeMillis();
+    }
+
+
+    public long getStart() {
+        return start;
+    }
+
+
+    public long getEnd() {
+        return end;
+    }
+}
+// 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/W.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,149 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.utils.DataUtil;
+
+import gnu.trove.TDoubleArrayList;
+
+import org.apache.log4j.Logger;
+
+public class W
+extends      NamedObjectImpl
+{
+    private static Logger log = Logger.getLogger(W.class);
+
+    protected TDoubleArrayList ws;
+
+    public W() {
+        ws = new TDoubleArrayList();
+    }
+
+    public W(String name) {
+        super(name);
+        ws = new TDoubleArrayList();
+    }
+
+    public W(int capacity) {
+        this(capacity, "");
+    }
+
+    public W(int capacity, String name) {
+        super(name);
+        ws = new TDoubleArrayList(capacity);
+    }
+
+    public void add(double value) {
+        ws.add(value);
+    }
+
+    public int size() {
+        return ws.size();
+    }
+
+    public double getW(int idx) {
+        return ws.getQuick(idx);
+    }
+
+    public double [] getWs() {
+        return ws.toNativeArray();
+    }
+
+    public double [] get(int idx) {
+        return get(idx, new double [1]);
+    }
+
+    public double [] get(int idx, double [] dst) {
+        dst[0] = ws.getQuick(idx);
+        return dst;
+    }
+
+    public double minWs() {
+        return ws.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 [] { ws });
+    }
+
+    public boolean guessWaterIncreasing() {
+        return guessWaterIncreasing(0.05f);
+    }
+
+    public boolean guessWaterIncreasing(float factor) {
+        return DataUtil.guessWaterIncreasing(ws, factor);
+    }
+
+    public int [] longestIncreasingWRangeIndices() {
+        return longestIncreasingWRangeIndices(new int[2]);
+    }
+
+    public int [] longestIncreasingWRangeIndices(int [] bounds) {
+
+        int N = size();
+        int start = 0;
+        int stop  = 0;
+
+        double lastW = Double.MAX_VALUE;
+
+        for (int i = 0; i < N; ++i) {
+            double v = ws.getQuick(i);
+            if (v <= lastW) {
+                if (stop-start > bounds[1]-bounds[0]) {
+                    bounds[0] = start;
+                    bounds[1] = stop;
+                    if (log.isDebugEnabled()) {
+                        log.debug("new range: " +
+                            bounds[0] + " - " + bounds[1] + " (" +
+                            ws.getQuick(bounds[0]) + ", " +
+                            ws.getQuick(bounds[1]) + ")");
+
+                    }
+                }
+                start = stop = i;
+            }
+            else {
+                stop = i;
+            }
+            lastW = v;
+        }
+
+        if (stop-start > bounds[1]-bounds[0]) {
+            bounds[0] = start;
+            bounds[1] = stop;
+            if (log.isDebugEnabled()) {
+                log.debug("new range @end: " +
+                    bounds[0] + " - " + bounds[1] + " (" +
+                    ws.getQuick(bounds[0]) + ", " +
+                    ws.getQuick(bounds[1]) + ")");
+            }
+        }
+
+        return bounds;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKms.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKms.java	Fri Sep 28 12:15:52 2012 +0200
@@ -14,5 +14,7 @@
     TDoubleArrayList allKms();
 
     TDoubleArrayList allWs();
+
+    public boolean guessWaterIncreasing();
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,7 +4,6 @@
 import de.intevation.artifacts.CallContext;
 
 import de.intevation.flys.artifacts.StaticWKmsArtifact;
-import de.intevation.flys.artifacts.model.FacetTypes;
 
 /**
  * Facet to show W|km Values.
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -12,19 +12,18 @@
 import org.hibernate.SQLQuery;
 import org.hibernate.type.StandardBasicTypes;
 
-import de.intevation.flys.artifacts.model.WKms;
-import de.intevation.flys.artifacts.model.WKmsImpl;
-
 import de.intevation.flys.artifacts.cache.CacheFactory;
 
 import de.intevation.flys.backend.SessionHolder;
 
+
 /**
- * Factory to access ready-made WKms for other (than computed) 'kinds' of 
+ * Factory to access ready-made WKms for other (than computed) 'kinds' of
  * WST-data.
  */
 public class WKmsFactory
 {
+    /** Private logger to use here. */
     private static Logger log = Logger.getLogger(WKmsFactory.class);
 
     /** Query to get km and ws for wst_id and column_pos. */
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,6 +2,9 @@
 
 import gnu.trove.TDoubleArrayList;
 
+import de.intevation.flys.utils.DataUtil;
+
+
 public class WKmsImpl
 extends      NamedObjectImpl
 implements   WKms
@@ -69,6 +72,14 @@
         return kms.getQuick(index);
     }
 
+    @Override
+    public boolean guessWaterIncreasing() {
+        return guessWaterIncreasing(0.05f);
+    }
+
+    protected boolean guessWaterIncreasing(float factor) {
+        return DataUtil.guessWaterIncreasing(ws, factor);
+    }
 
     @Override
     public int size() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WKmsJRDataSource.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,115 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.log4j.Logger;
+
+import net.sf.jasperreports.engine.JRDataSource;
+import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JRField;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class WKmsJRDataSource implements JRDataSource
+{
+    /** The logger used in this exporter.*/
+    private static Logger logger = Logger.getLogger(WKmsJRDataSource.class);
+
+    /**
+     *
+     */
+    private ArrayList<String[]> data;
+    private HashMap<String, String> metaData;
+
+    private int index = -1;
+
+    /**
+     *
+     */
+    public WKmsJRDataSource()
+    {
+        data = new ArrayList<String[]>();
+        metaData = new HashMap<String, String>();
+    }
+
+
+    /**
+     *
+     */
+    public void addData(String[] data) {
+        this.data.add(data);
+    }
+
+
+    /**
+     *
+     */
+    public void addMetaData(String key, String value) {
+        this.metaData.put(key, value);
+    }
+
+
+    /**
+     *
+     */
+    public boolean next() throws JRException
+    {
+        index++;
+
+        return (index < data.size());
+    }
+
+
+    /**
+     *
+     */
+    public Object getFieldValue(JRField field) throws JRException
+    {
+        Object value = "";
+        String fieldName = field.getName();
+        if ("river".equals(fieldName)) {
+            value = metaData.get("river");
+        }
+        else if ("date".equals(fieldName)) {
+            value = metaData.get("date");
+        }
+        else if ("range".equals(fieldName)) {
+            value = metaData.get("range");
+        }
+        else if ("gauge".equals(fieldName)) {
+            value = metaData.get("gauge");
+        }
+        else if ("calculation".equals(fieldName)) {
+            value = metaData.get("calculation");
+        }
+        else if ("differences".equals(fieldName)) {
+            value = metaData.get("differences");
+        }
+        else if ("km".equals(fieldName)) {
+            value = data.get(index)[0];
+        }
+        else if ("W".equals(fieldName)) {
+            value = data.get(index)[1];
+        }
+        else if ("Q".equals(fieldName)) {
+            value = data.get(index)[2];
+        }
+        else if ("description".equals(fieldName)) {
+            value = data.get(index)[3];
+        }
+        else if ("location".equals(fieldName)) {
+            value = data.get(index)[4];
+        }
+        else if ("gaugename".equals(fieldName)) {
+            value = data.get(index)[5];
+        }
+        else if ("day".equals(fieldName)) {
+            value = data.get(index)[6];
+        }
+        return value;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WMSDBLayerFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-package de.intevation.flys.artifacts.model;
-
-import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
-
-
-public class WMSDBLayerFacet extends WMSLayerFacet {
-
-    protected String data;
-    protected String filter;
-    protected String labelItem;
-    protected String geometryType;
-    protected String connection;
-    protected String connectionType;
-
-
-    public WMSDBLayerFacet() {
-        super();
-    }
-
-
-    public WMSDBLayerFacet(int index, String name, String description) {
-        this(index, name, description, ComputeType.FEED, null, null);
-    }
-
-
-    public WMSDBLayerFacet(
-        int         index,
-        String      name,
-        String      description,
-        ComputeType type,
-        String      stateId,
-        String      hash
-
-    ) {
-        super(index, name, description, type, stateId, hash);
-    }
-
-
-    public WMSDBLayerFacet(
-        int         index,
-        String      name,
-        String      description,
-        ComputeType type,
-        String      stateId,
-        String      hash,
-        String      url
-    ) {
-        super(index, name, description, type, stateId, hash, url);
-    }
-
-
-    public void setFilter(String filter) {
-        this.filter = filter;
-    }
-
-    public String getFilter() {
-        return filter;
-    }
-
-    public void setData(String data) {
-        this.data = data;
-    }
-
-    public String getData() {
-        return data;
-    }
-
-    public void setGeometryType(String geometryType) {
-        this.geometryType = geometryType;
-    }
-
-    public String getGeometryType() {
-        return geometryType;
-    }
-
-    public void setConnection(String connection) {
-        this.connection = connection;
-    }
-
-    public String getConnection() {
-        return connection;
-    }
-
-    public void setConnectionType(String connectionType) {
-        this.connectionType = connectionType;
-    }
-
-    public String getConnectionType() {
-        return connectionType;
-    }
-
-    public void setLabelItem(String labelItem) {
-        this.labelItem = labelItem;
-    }
-
-    public String getLabelItem() {
-        return labelItem;
-    }
-
-
-    @Override
-    public boolean isQueryable() {
-        return true;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WMSLayerFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-package de.intevation.flys.artifacts.model;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.ArtifactNamespaceContext;
-import de.intevation.artifacts.CallContext;
-
-import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
-
-import de.intevation.artifactdatabase.state.DefaultFacet;
-import de.intevation.artifactdatabase.state.Facet;
-
-import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
-import de.intevation.flys.utils.GeometryUtils;
-
-
-public class WMSLayerFacet
-extends      DefaultFacet
-{
-    protected ComputeType  type;
-    protected List<String> layers;
-    protected String       stateId;
-    protected String       hash;
-    protected String       url;
-    protected Envelope     extent;
-    protected String       srid;
-
-
-    private static final Logger logger = Logger.getLogger(WMSLayerFacet.class);
-
-    public WMSLayerFacet() {
-    }
-
-
-    public WMSLayerFacet(int index, String name, String description) {
-        this(index, name, description, ComputeType.FEED, null, null);
-    }
-
-
-    public WMSLayerFacet(
-        int         index,
-        String      name,
-        String      description,
-        ComputeType type,
-        String      stateId,
-        String      hash
-
-    ) {
-        super(index, name, description);
-        this.layers  = new ArrayList<String>();
-        this.type    = type;
-        this.stateId = stateId;
-        this.hash    = hash;
-    }
-
-
-    public WMSLayerFacet(
-        int         index,
-        String      name,
-        String      description,
-        ComputeType type,
-        String      stateId,
-        String      hash,
-        String      url
-    ) {
-        this(index, name, description, type, stateId, hash);
-        this.url = url;
-    }
-
-
-    public void addLayer(String name) {
-        if (name != null && name.length() > 0) {
-            layers.add(name);
-        }
-    }
-
-
-    public void setExtent(Envelope extent) {
-        if (extent != null) {
-            this.extent = extent;
-        }
-    }
-
-
-    public Envelope getExtent() {
-        return extent;
-    }
-
-
-    public void setSrid(String srid) {
-        if (srid != null) {
-            this.srid = srid;
-        }
-    }
-
-
-    public String getSrid() {
-        return srid;
-    }
-
-
-    public Object getData(Artifact artifact, CallContext context) {
-        return null;
-    }
-
-
-    @Override
-    public Node toXML(Document doc) {
-        ElementCreator ec = new ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Element facet = ec.create("facet");
-        ec.addAttr(facet, "description", description, true);
-        ec.addAttr(facet, "index", String.valueOf(index), true);
-        ec.addAttr(facet, "name", name, true);
-        ec.addAttr(facet, "url", url, true);
-        ec.addAttr(facet, "layers", layers.get(0), true);
-        ec.addAttr(facet, "srid", srid != null ? srid : "", true);
-        ec.addAttr(facet, "extent", extent != null
-            ? GeometryUtils.jtsBoundsToOLBounds(extent)
-            : "", true);
-        ec.addAttr(facet, "queryable", String.valueOf(isQueryable()), true);
-
-        return facet;
-    }
-
-
-    public boolean isQueryable() {
-        return false;
-    }
-
-
-    @Override
-    public Facet deepCopy() {
-        WMSLayerFacet copy = new WMSLayerFacet();
-        copy.set(this);
-
-        copy.type    = type;
-        copy.layers  = new ArrayList<String>(layers);
-        copy.stateId = stateId;
-        copy.hash    = hash;
-        copy.url     = url;
-        copy.extent  = extent;
-        copy.srid    = srid;
-
-        return copy;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQ.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQ.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,29 +1,29 @@
 package de.intevation.flys.artifacts.model;
 
-import de.intevation.flys.utils.DataUtil;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import gnu.trove.TDoubleArrayList;
 
 import org.apache.log4j.Logger;
 
 public class WQ
-extends      NamedObjectImpl
+extends      W
 {
-    private static Logger logger = Logger.getLogger(WQ.class);
+    public static final Pattern NUMBERS_PATTERN =
+        Pattern.compile("\\D*(\\d++.\\d*)\\D*");
 
-    // TODO: s/w/ws/g
-    protected TDoubleArrayList w;
+    private static Logger log = Logger.getLogger(WQ.class);
 
-    // TODO: s/q/qs/g
-    protected TDoubleArrayList q;
+    protected TDoubleArrayList qs;
 
     public WQ() {
         this("");
     }
 
     public WQ(String name) {
-        w = new TDoubleArrayList();
-        q = new TDoubleArrayList();
+        super(name);
+        qs = new TDoubleArrayList();
     }
 
     public WQ(int capacity) {
@@ -32,9 +32,8 @@
 
 
     public WQ(int capacity, String name) {
-        super(name);
-        w = new TDoubleArrayList(capacity);
-        q = new TDoubleArrayList(capacity);
+        super(capacity, name);
+        qs = new TDoubleArrayList(capacity);
     }
 
     public WQ(double [] qs, double [] ws) {
@@ -43,130 +42,61 @@
 
     public WQ(double [] qs, double [] ws, String name) {
         super(name);
-        w = new TDoubleArrayList(ws);
-        q = new TDoubleArrayList(qs);
+        this.ws = new TDoubleArrayList(ws);
+        this.qs = new TDoubleArrayList(qs);
+    }
+
+
+    public Double getRawValue() {
+        if (name == null || name.length() == 0) {
+            // this should never happen
+            return null;
+        }
+
+        Matcher m = NUMBERS_PATTERN.matcher(name);
+
+        if (m.matches()) {
+            String raw = m.group(1);
+
+            try {
+                return Double.valueOf(raw);
+            }
+            catch (NumberFormatException nfe) {
+                // do nothing
+            }
+        }
+
+        return null;
     }
 
     public void add(double w, double q) {
-        this.w.add(w);
-        this.q.add(q);
-    }
-
-    public int size() {
-        return w.size();
-    }
-
-    public double getW(int idx) {
-        return w.getQuick(idx);
+        ws.add(w);
+        qs.add(q);
     }
 
     public double getQ(int idx) {
-        return q.getQuick(idx);
+        return qs.getQuick(idx);
     }
 
+    @Override
     public double [] get(int idx) {
         return get(idx, new double [2]);
     }
 
+    @Override
     public double [] get(int idx, double [] dst) {
-        dst[0] = w.getQuick(idx);
-        dst[1] = q.getQuick(idx);
+        dst[0] = ws.getQuick(idx);
+        dst[1] = qs.getQuick(idx);
         return dst;
     }
 
-    public double [] getWs() {
-        return w.toNativeArray();
-    }
-
     public double [] getQs() {
-        return q.toNativeArray();
-    }
-
-    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 [] { w, q });
-    }
-
-    public boolean guessWaterIncreasing() {
-        return guessWaterIncreasing(0.05f);
-    }
-
-    public boolean guessWaterIncreasing(float factor) {
-        return DataUtil.guessWaterIncreasing(w, factor);
+        return qs.toNativeArray();
     }
 
-    public int [] longestIncreasingWRangeIndices() {
-        return longestIncreasingWRangeIndices(new int[2]);
-    }
-
-    public int [] longestIncreasingWRangeIndices(int [] bounds) {
-
-        int N = size();
-        int start = 0;
-        int stop  = 0;
-
-        double lastW = Double.MAX_VALUE;
-
-        for (int i = 0; i < N; ++i) {
-            double v = w.getQuick(i);
-            if (v <= lastW) {
-                if (stop-start > bounds[1]-bounds[0]) {
-                    bounds[0] = start;
-                    bounds[1] = stop;
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("new range: " +
-                            bounds[0] + " - " + bounds[1] + " (" +
-                            w.getQuick(bounds[0]) + ", " +
-                            w.getQuick(bounds[1]) + ")");
-
-                    }
-                }
-                start = stop = i;
-            }
-            else {
-                stop = i;
-            }
-            lastW = v;
-        }
-
-        if (stop-start > bounds[1]-bounds[0]) {
-            bounds[0] = start;
-            bounds[1] = stop;
-            if (logger.isDebugEnabled()) {
-                logger.debug("new range @end: " +
-                    bounds[0] + " - " + bounds[1] + " (" +
-                    w.getQuick(bounds[0]) + ", " +
-                    w.getQuick(bounds[1]) + ")");
-
-            }
-        }
-
-        return bounds;
+    @Override
+    public void removeNaNs() {
+        removeNaNs(new TDoubleArrayList [] { ws, qs });
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQCKms.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQCKms.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,40 +2,39 @@
 
 import gnu.trove.TDoubleArrayList;
 
-
 /**
  * This class represents a pool of data triples that consists of 'W', 'Q' and
  * 'KM' data with corrected 'W' values computed by a BackJumpCorrector.
  *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
-public class WQCKms extends WQKms {
-
-    protected TDoubleArrayList cw;
+public class WQCKms
+extends      WQKms
+{
+    protected TDoubleArrayList cws;
 
     public WQCKms() {
     }
 
     public WQCKms(WQKms other, double [] cws) {
-        this.w   = other.w;
-        this.q   = other.q;
+        this.ws  = other.ws;
+        this.qs  = other.qs;
         this.kms = other.kms;
-        this.cw  = new TDoubleArrayList(cws);
+        this.cws = new TDoubleArrayList(cws);
     }
 
 
     public WQCKms(double[] kms, double[] qs, double[] ws, double[] cws) {
         super(kms, qs, ws);
 
-        this.cw = new TDoubleArrayList(cws);
+        this.cws = new TDoubleArrayList(cws);
     }
 
     @Override
     public void removeNaNs() {
-        removeNaNs(new TDoubleArrayList [] { w, q, cw, kms });
+        removeNaNs(new TDoubleArrayList [] { ws, qs, cws, kms });
     }
 
-
     /**
      * Adds a new row to this data pool with corrected W.
      *
@@ -45,10 +44,14 @@
      * @param cw The corrected W.
      */
     public void add(double w, double q, double kms, double cw) {
-        add(w, q, kms);
-        this.cw.add(cw);
+        super.add(w, q, kms);
+        cws.add(cw);
     }
 
+    @Override
+    public double[] get(int idx) {
+        return get(idx, new double[4]);
+    }
 
     /**
      * This method returns a 4dim array of W, Q,Kms and corrected W.
@@ -66,15 +69,15 @@
             return dst;
         }
 
-        if (cw != null && cw.size() > idx) {
-            dst[3] = cw.getQuick(idx);
+        if (cws != null && cws.size() > idx) {
+            dst[3] = cws.getQuick(idx);
         }
 
         return dst;
     }
 
     public double getC(int idx) {
-        return cw.getQuick(idx);
+        return cws.getQuick(idx);
     }
 
 
@@ -84,7 +87,7 @@
      * @return the double array of corrected W values.
      */
     public double[] getCWs() {
-        return cw.toNativeArray();
+        return cws.toNativeArray();
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQDay.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQDay.java	Fri Sep 28 12:15:52 2012 +0200
@@ -19,6 +19,7 @@
     }
 
     public WQDay(int capacity) {
+        super(capacity);
         days = new TIntArrayList(capacity);
     }
 
@@ -50,26 +51,26 @@
     public void removeNaNs() {
 
         int dest = 0;
-        int N = w.size();
+        int N = ws.size();
 
         for (int i = 0; i < N; ++i) {
-            double wi = w.getQuick(i);
-            double qi = q.getQuick(i);
+            double wi = ws.getQuick(i);
+            double qi = qs.getQuick(i);
 
             if (Double.isNaN(wi) || Double.isNaN(qi)) {
                 continue;
             }
 
             days.setQuick(dest, days.getQuick(i));
-            w.setQuick(dest, wi);
-            q.setQuick(dest, qi);
+            ws.setQuick(dest, wi);
+            qs.setQuick(dest, qi);
             ++dest;
         }
 
         if (dest < N) {
             days.remove(dest, N-dest);
-            w   .remove(dest, N-dest);
-            q   .remove(dest, N-dest);
+            ws  .remove(dest, N-dest);
+            qs  .remove(dest, N-dest);
         }
     }
 }
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -6,7 +6,6 @@
 import de.intevation.artifactdatabase.state.DefaultFacet;
 
 import de.intevation.flys.artifacts.WQKmsInterpolArtifact;
-import de.intevation.flys.artifacts.model.FacetTypes;
 
 /**
  * Facet to show W|Q Values.
@@ -43,7 +42,8 @@
     public Object getData(Artifact artifact, CallContext context) {
         WQKmsInterpolArtifact interpolData =
             (WQKmsInterpolArtifact) artifact;
-        return interpolData.getWQAtKm(10);
+        Double currentKm = (Double)context.getContextValue("currentKm");
+        return interpolData.getWQAtKm(currentKm);
     }
 
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKms.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKms.java	Fri Sep 28 12:15:52 2012 +0200
@@ -38,7 +38,7 @@
 
 
     public WQKms(int capacity, String name) {
-        super(name);
+        super(capacity, name);
         this.kms = new TDoubleArrayList(capacity);
     }
 
@@ -54,7 +54,7 @@
 
     @Override
     public void removeNaNs() {
-        removeNaNs(new TDoubleArrayList [] { w, q, kms });
+        removeNaNs(new TDoubleArrayList [] { ws, qs, kms });
     }
 
     /**
@@ -62,13 +62,18 @@
      *
      * @param w a W.
      * @param q a Q.
-     * @param kms a Kms.
+     * @param km a kms.
      */
     public void add(double w, double q, double km) {
         super.add(w, q);
         kms.add(km);
     }
 
+    @Override
+    public double [] get(int idx) {
+        return get(idx, new double [3]);
+    }
+
     /**
      * This method returns a triple of W, Q and Kms in a single 3dim array.
      *
@@ -78,9 +83,9 @@
      * @return a triple of [W, Q, Kms] in dst.
      */
     @Override
-    public double[] get(int idx, double [] dst) {
-        dst[0] = w  .getQuick(idx);
-        dst[1] = q  .getQuick(idx);
+    public double [] get(int idx, double [] dst) {
+        dst[0] = ws .getQuick(idx);
+        dst[1] = qs .getQuick(idx);
         dst[2] = kms.getQuick(idx);
         return dst;
     }
@@ -97,7 +102,7 @@
 
     @Override
     public TDoubleArrayList allWs() {
-        return w;
+        return ws;
     }
 
     public double[] getKms() {
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKmsFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,29 +1,40 @@
 package de.intevation.flys.artifacts.model;
 
+import org.apache.log4j.Logger;
+
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
 
-import de.intevation.artifactdatabase.state.DefaultFacet;
+import de.intevation.flys.artifacts.StaticWQKmsArtifact;
 
-import de.intevation.flys.artifacts.StaticWQKmsArtifact;
-import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
 
 /**
  * Facet to show W|Q|km Values.
+ * We have following 'Types' (from FacetTypes):
+ *   String STATIC_WQKMS = "other.wqkms";
+ *   String STATIC_WQMS_W = "other.wqkms.w";
+ *   String STATIC_WQKMS_Q = "other.wqkms.q";
  */
 public class WQKmsFacet
-extends      DefaultFacet
+extends      DataFacet
 implements   FacetTypes {
 
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(WQKmsFacet.class);
+
     /** Trivial Constructor. */
     public WQKmsFacet(String description) {
         this(STATIC_WQKMS, description);
     }
 
+
+    /**
+     * @param name Name of this facet (we have at least two flavors (w and q).
+     */
     public WQKmsFacet(String name, String description) {
-        this.name        = name;
-        this.description = description;
-        this.index       = 0;
+        super(0, name, description, ComputeType.FEED, null, null);
     }
 
 
@@ -37,9 +48,13 @@
      */
     @Override
     public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("WQKmsFacet.getData");
+
         StaticWQKmsArtifact staticData =
             (StaticWQKmsArtifact) artifact;
-        return staticData.getWQKms(0);
+        Object res = staticData.compute(context, hash, stateId, type, false);
+
+        return res;
     }
 
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKmsFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQKmsFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -12,14 +12,12 @@
 import org.hibernate.SQLQuery;
 import org.hibernate.type.StandardBasicTypes;
 
-import de.intevation.flys.artifacts.model.WQKms;
-
 import de.intevation.flys.artifacts.cache.CacheFactory;
 
 import de.intevation.flys.backend.SessionHolder;
 
 /**
- * Factory to access ready-made WQKms for other (than computed) 'kinds' of 
+ * Factory to access ready-made WQKms for other (than computed) 'kinds' of
  * WST-data.
  */
 public class WQKmsFactory
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WQTJRDataSource.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,100 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.log4j.Logger;
+
+import net.sf.jasperreports.engine.JRDataSource;
+import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JRField;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class WQTJRDataSource implements JRDataSource
+{
+    /** The logger used in this exporter.*/
+    private static Logger logger = Logger.getLogger(WQTJRDataSource.class);
+
+    /**
+     *
+     */
+    private ArrayList<String[]> data;
+    private HashMap<String, String> metaData;
+
+    private int index = -1;
+
+    /**
+     *
+     */
+    public WQTJRDataSource()
+    {
+        data = new ArrayList<String[]>();
+        metaData = new HashMap<String, String>();
+    }
+
+
+    /**
+     *
+     */
+    public void addData(String[] data) {
+        this.data.add(data);
+    }
+
+
+    /**
+     *
+     */
+    public void addMetaData(String key, String value) {
+        this.metaData.put(key, value);
+    }
+
+
+    /**
+     *
+     */
+    public boolean next() throws JRException
+    {
+        index++;
+
+        return (index < data.size());
+    }
+
+
+    /**
+     *
+     */
+    public Object getFieldValue(JRField field) throws JRException
+    {
+        Object value = "";
+        String fieldName = field.getName();
+        if ("river".equals(fieldName)) {
+            value = metaData.get("river");
+        }
+        else if ("date".equals(fieldName)) {
+            value = metaData.get("date");
+        }
+        else if ("calculation".equals(fieldName)) {
+            value = metaData.get("calculation");
+        }
+        else if ("range".equals(fieldName)) {
+            value = data.get(index)[0];
+        }
+        else if ("W".equals(fieldName)) {
+            value = data.get(index)[1];
+        }
+        else if ("Q".equals(fieldName)) {
+            value = data.get(index)[2];
+        }
+        else if ("delta".equals(fieldName)) {
+            value = data.get(index)[3];
+        }
+        else if ("gaugename".equals(fieldName)) {
+            value = data.get(index)[4];
+        }
+        return value;
+    }
+}
+// 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/WQTimerange.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class WQTimerange extends WQ {
+
+    protected List<Timerange> ts;
+
+
+    public WQTimerange() {
+        super("");
+    }
+
+
+    public WQTimerange(String name) {
+        super(name);
+        ts = new ArrayList<Timerange>();
+    }
+
+
+    public void add(double w, double q, Timerange t) {
+        ws.add(w);
+        qs.add(q);
+        ts.add(t);
+    }
+
+
+    public Timerange getTimerange(int idx) {
+        return ts.get(idx);
+    }
+
+
+    public Timerange[] getTimeranges() {
+        return ts.toArray(new Timerange[ts.size()]);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WSPLGENCalculation.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-package de.intevation.flys.artifacts.model;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import org.apache.log4j.Logger;
-
-import de.intevation.artifacts.CallMeta;
-
-
-public class WSPLGENCalculation extends Calculation {
-
-    private static final Logger log = Logger.getLogger(WSPLGENCalculation.class);
-
-    protected Map<Integer, String> errors;
-    protected Map<Integer, String> warnings;
-
-
-    public WSPLGENCalculation() {
-        errors   = new HashMap<Integer, String>();
-        warnings = new HashMap<Integer, String>();
-    }
-
-
-    public void addError(Integer key, String msg) {
-        log.debug("New error: (" + key + ") " + msg);
-        errors.put(key, msg);
-    }
-
-
-    public void addWarning(Integer key, String msg) {
-        log.debug("New warning: (" + key + ") " + msg);
-        warnings.put(key, msg);
-    }
-
-
-    public int numErrors() {
-        return errors.size();
-    }
-
-
-    public int numWarnings() {
-        return warnings.size();
-    }
-
-
-    public void toXML(Document document, CallMeta meta) {
-        Element root = document.createElement("problems");
-
-        if (numErrors() > 0) {
-            Set<Map.Entry<Integer, String>> entrySet = errors.entrySet();
-
-            for (Map.Entry<Integer, String> entry: entrySet) {
-                Element problem = document.createElement("problem");
-                problem.setAttribute("error", String.valueOf(entry.getKey()));
-                problem.setTextContent(entry.getValue());
-
-                root.appendChild(problem);
-            }
-        }
-
-        if (numWarnings() > 0) {
-            Set<Map.Entry<Integer, String>> entrySet = warnings.entrySet();
-
-            for (Map.Entry<Integer, String> entry: entrySet) {
-                Element problem = document.createElement("problem");
-                problem.setAttribute("error", String.valueOf(entry.getKey()));
-                problem.setTextContent(entry.getValue());
-
-                root.appendChild(problem);
-            }
-        }
-
-        document.appendChild(root);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WSPLGENJob.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,473 +0,0 @@
-package de.intevation.flys.artifacts.model;
-
-import java.io.IOException;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-import de.intevation.artifacts.CallContext;
-
-import de.intevation.flys.artifacts.FLYSArtifact;
-import de.intevation.flys.wsplgen.FacetCreator;
-
-
-public class WSPLGENJob {
-
-    public static final String GEL_SPERRE   = "SPERRE";
-    public static final String GEL_NOSPERRE = "NOSPERRE";
-
-
-    protected FLYSArtifact artifact;
-
-    protected CallContext callContext;
-
-    protected WSPLGENCalculation calculation;
-
-    protected FacetCreator facetCreator;
-
-    protected File workingDir;
-
-    protected String dgm;
-    protected String pro;
-    protected String wsp;
-    protected String wspTag;
-    protected String axis;
-    protected String area;
-    protected String gel;
-    protected String outFile;
-
-    protected List<String> lin;
-
-    protected int out;
-
-    protected double start;
-    protected double end;
-    protected double from;
-    protected double to;
-    protected double diff;
-    protected double dist;
-
-
-
-    public WSPLGENJob(
-        FLYSArtifact       flys,
-        File               workingDir,
-        FacetCreator       facetCreator,
-        CallContext        context,
-        WSPLGENCalculation calculation)
-    {
-        this.artifact     = flys;
-        this.workingDir   = workingDir;
-        this.facetCreator = facetCreator;
-        this.callContext  = context;
-        this.calculation  = calculation;
-
-        out   = -1;
-        start = Double.NaN;
-        end   = Double.NaN;
-        from  = Double.NaN;
-        to    = Double.NaN;
-        diff  = Double.NaN;
-        dist  = Double.NaN;
-        lin   = new ArrayList<String>(2);
-    }
-
-
-    public File getWorkingDir() {
-        return workingDir;
-    }
-
-
-    public FLYSArtifact getArtifact() {
-        return artifact;
-    }
-
-
-    public FacetCreator getFacetCreator() {
-        return facetCreator;
-    }
-
-
-    public WSPLGENCalculation getCalculation() {
-        return calculation;
-    }
-
-
-    public CallContext getCallContext() {
-        return callContext;
-    }
-
-
-    public void setWsp(String wsp) {
-        this.wsp = wsp;
-    }
-
-
-    public String getWsp() {
-        return wsp;
-    }
-
-
-    public void setWspTag(String wspTag) {
-        this.wspTag = wspTag;
-    }
-
-
-    public String getWspTag() {
-        return wspTag;
-    }
-
-
-    public void addLin(String lin) {
-        this.lin.add(lin);
-    }
-
-
-    public List<String> getLin() {
-        return lin;
-    }
-
-
-    public void setAxis(String axis) {
-        this.axis = axis;
-    }
-
-
-    public String getAxis() {
-        return axis;
-    }
-
-
-    public void setArea(String area) {
-        this.area = area;
-    }
-
-
-    public String getArea() {
-        return area;
-    }
-
-
-    public void setOut(int out) {
-        this.out = out;
-    }
-
-
-    public int getOut() {
-        return out;
-    }
-
-
-    public void setOutFile(String outFile) {
-        this.outFile = outFile;
-    }
-
-
-    public String getOutFile() {
-        return outFile;
-    }
-
-
-    public void setStart(double start) {
-        this.start = start;
-    }
-
-
-    public double getStart() {
-        return start;
-    }
-
-
-    public void setEnd(double end) {
-        this.end = end;
-    }
-
-
-    public double getEnd() {
-        return end;
-    }
-
-
-    public void setPro(String pro) {
-        this.pro = pro;
-    }
-
-
-    public String getPro() {
-        return pro;
-    }
-
-
-    public void setDgm(String dgm) {
-        this.dgm = dgm;
-    }
-
-
-    public String getDgm() {
-        return dgm;
-    }
-
-
-    public void setFrom(double from) {
-        this.from = from;
-    }
-
-
-    public double getFrom() {
-        return from;
-    }
-
-
-    public void setTo(double to) {
-        this.to = to;
-    }
-
-
-    public double getTo() {
-        return to;
-    }
-
-
-    public void setDiff(double diff) {
-        this.diff = diff;
-    }
-
-
-    public double getDiff() {
-        return diff;
-    }
-
-
-    public void setDist(double dist) {
-        this.dist = dist;
-    }
-
-
-    public double getDist() {
-        return dist;
-    }
-
-
-    public void setGel(String gel) {
-        if (gel == null || gel.length() == 0) {
-            return;
-        }
-
-        if (gel.equals(GEL_SPERRE) || gel.equals(GEL_NOSPERRE)) {
-            this.gel = gel;
-        }
-    }
-
-
-    public String getGel() {
-        return gel;
-    }
-
-
-    public void toFile(File file)
-    throws IOException, IllegalArgumentException
-    {
-        PrintWriter writer = null;
-
-        try {
-            writer =
-                new PrintWriter(
-                    new OutputStreamWriter(
-                        new FileOutputStream(file)));
-
-            write(writer);
-        }
-        finally {
-            if (writer != null) {
-                writer.flush();
-                writer.close();
-            }
-        }
-    }
-
-
-    protected void write(PrintWriter writer)
-    throws IOException, IllegalArgumentException
-    {
-        writeWsp(writer);    // required
-        writeWspTag(writer); // required
-        writeLin(writer);
-        writeAxis(writer);
-        writeArea(writer);
-        writeOut(writer);
-        writeOutFile(writer);
-        writeRange(writer);
-        writeDelta(writer);
-        writeGel(writer);
-        writeDist(writer);
-        writePro(writer);
-        writeDgm(writer);    // required
-    }
-
-
-    protected void writeWsp(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        String wsp = getWsp();
-
-        if (wsp != null && wsp.length() > 0) {
-            writer.println("-WSP=\"" + wsp + "\"");
-            return;
-        }
-
-        throw new IllegalArgumentException("Required WSP missing!");
-    }
-
-    protected void writeWspTag(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        String wspTag = getWspTag();
-
-        if (wspTag != null && wspTag.length() > 0) {
-            writer.println("-WSPTAG=\"" + wspTag + "\"");
-            return;
-        }
-
-        throw new IllegalArgumentException("Required WSPTAG missing!");
-    }
-
-    protected void writeLin(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        List<String> lins = getLin();
-
-        if (lins != null && !lins.isEmpty()) {
-            for (String lin: lins) {
-                writer.println("-LIN=\"" + lin + "\"");
-            }
-        }
-    }
-
-    protected void writeAxis(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        String axis = getAxis();
-
-        if (axis != null && axis.length() > 0) {
-            writer.println("-ACHSE=\"" + axis + "\"");
-        }
-    }
-
-    protected void writeGel(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        if (area != null && area.length() > 0) {
-            writer.println("-GEL=" + getGel());
-        }
-    }
-
-    protected void writeArea(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        String area = getArea();
-
-        if (area != null && area.length() > 0) {
-            writer.println("-GEBIET=\"" + area + "\"");
-        }
-    }
-
-
-    protected void writeOut(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        int out = getOut();
-
-        if (out >= 0) {
-            writer.println("-OUTPUT=" + String.valueOf(out));
-        }
-    }
-
-    protected void writeOutFile(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        String outFile = getOutFile();
-
-        if (outFile != null && outFile.length() > 0) {
-            writer.println("-AUSGABE=\""+ outFile + "\"");
-        }
-    }
-
-    protected void writeRange(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        StringBuilder sb = new StringBuilder("-STRECKE=");
-
-        double start = getStart();
-        double end   = getEnd();
-
-        if (Double.isNaN(start) && Double.isNaN(end)) {
-            return;
-        }
-
-        if (! Double.isNaN(getStart())) {
-            sb.append(getStart());
-        }
-
-        sb.append(",");
-
-        if (! Double.isNaN(getEnd())) {
-            sb.append(getEnd());
-        }
-
-        writer.println(sb.toString());
-    }
-
-    protected void writeDelta(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        StringBuilder sb = new StringBuilder("-DELTA=");
-        if (! Double.isNaN(from)) {
-            sb.append(from);
-        }
-
-        sb.append(",");
-
-        if (! Double.isNaN(to)) {
-            sb.append(to);
-        }
-
-        sb.append(",");
-
-        if (! Double.isNaN(diff)) {
-            sb.append(diff);
-        }
-
-        writer.println(sb.toString());
-    }
-
-    protected void writeDist(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        if (! Double.isNaN(getDist())) {
-            writer.println("-DIST=" + String.valueOf(getDist()));
-        }
-    }
-
-    protected void writePro(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        if (pro != null && pro.length() > 0) {
-            writer.println("-PRO=\"" + getPro() + "\"");
-        }
-    }
-
-    protected void writeDgm(PrintWriter writer)
-    throws IllegalArgumentException
-    {
-        if (dgm != null && dgm.length() > 0) {
-            writer.println("-DGM=\"" + getDgm() + "\"");
-            return;
-        }
-
-        throw new IllegalArgumentException("Required DGM missing!");
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WSPLGENReportFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-package de.intevation.flys.artifacts.model;
-
-import org.apache.log4j.Logger;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.CallContext;
-
-import de.intevation.artifactdatabase.state.Facet;
-
-import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
-
-
-/**
- * This facet is used to provide WSPLGEN reports <b>only</b>.
- */
-public class WSPLGENReportFacet extends ReportFacet {
-
-    private static Logger logger = Logger.getLogger(WSPLGENReportFacet.class);
-
-
-    protected CalculationResult result;
-
-
-    public WSPLGENReportFacet() {
-    }
-
-
-    public WSPLGENReportFacet(
-        ComputeType       type,
-        String            hash,
-        String            stateId,
-        CalculationResult result
-    ) {
-        super(type, hash, stateId);
-        this.result = result;
-    }
-
-
-    @Override
-    public Object getData(Artifact artifact, CallContext context) {
-        return result.getReport();
-    }
-
-
-    @Override
-    public Facet deepCopy() {
-        WSPLGENReportFacet copy = new WSPLGENReportFacet();
-        copy.set(this);
-        copy.type    = type;
-        copy.hash    = hash;
-        copy.stateId = stateId;
-        copy.result  = result;
-        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/WW.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,200 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.math.Function;
+import de.intevation.flys.artifacts.math.Identity;
+
+import gnu.trove.TDoubleArrayList;
+
+public class WW
+extends      W
+{
+    public static class ApplyFunctionIterator
+    {
+        protected Function function1;
+        protected Function function2;
+        protected int      pos;
+        protected WW       ww;
+
+        public ApplyFunctionIterator(WW ww) {
+            this(ww, Identity.IDENTITY, Identity.IDENTITY);
+        }
+
+        public ApplyFunctionIterator(
+            WW       ww,
+            Function function1,
+            Function function2
+        ) {
+            this.ww        = ww;
+            this.function1 = function1;
+            this.function2 = function2;
+        }
+
+        public boolean hasNext() {
+            return pos < ww.size();
+        }
+
+        public int size() {
+            return ww.size();
+        }
+
+        public void reset() {
+            pos = 0;
+        }
+
+        public WW getWW() {
+            return ww;
+        }
+
+        public void get(int idx, double [] wwPair) {
+            wwPair[0] = function1.value(ww.getW(idx));
+            wwPair[1] = function2.value(ww.getW2(idx));
+        }
+
+        public void next(double [] wwPair) {
+            get(pos++, wwPair);
+        }
+    } // class FunctionIterator
+
+    protected TDoubleArrayList ws2;
+
+    protected double startKm;
+    protected double endKm;
+
+    protected Double startDatum;
+    protected Double endDatum;
+
+    public WW() {
+        this("");
+    }
+
+    public WW(String name) {
+        super(name);
+    }
+
+    public WW(int capacity) {
+        this(capacity, "");
+    }
+
+    public WW(int capacity, String name) {
+        super(capacity, name);
+        ws2 = new TDoubleArrayList(capacity);
+    }
+
+    public WW(
+        String    name,
+        double    startKm,
+        Double    startDatum,
+        double [] ws,
+        double    endKm,
+        Double    endDatum,
+        double [] ws2
+    ) {
+        this.name       = name;
+        this.ws         = new TDoubleArrayList(ws);
+        this.ws2        = new TDoubleArrayList(ws2);
+        this.startKm    = startKm;
+        this.startDatum = startDatum;
+        this.endKm      = endKm;
+        this.endDatum   = endDatum;
+    }
+
+    public WW(String name, TDoubleArrayList ws, TDoubleArrayList ws2) {
+        this.name = name;
+        this.ws  = ws;
+        this.ws2 = ws2;
+    }
+
+    public void add(double w1, double w2) {
+        ws .add(w1);
+        ws2.add(w2);
+    }
+
+    public double getW1(int idx) {
+        return ws.getQuick(idx);
+    }
+
+    public double getW2(int idx) {
+        return ws2.getQuick(idx);
+    }
+
+    public double [] getWs2() {
+        return ws2.toNativeArray();
+    }
+
+    @Override
+    public double [] get(int idx) {
+        return get(idx, new double[2]);
+    }
+
+    @Override
+    public double [] get(int idx, double [] dst) {
+        dst[0] = ws .getQuick(idx);
+        dst[1] = ws2.getQuick(idx);
+        return dst;
+    }
+
+    public double getStartKm() {
+        return startKm;
+    }
+
+    public void setStartKm(double startKm) {
+        this.startKm = startKm;
+    }
+
+    public double getEndKm() {
+        return endKm;
+    }
+
+    public void setEndKm(double endKm) {
+        this.endKm = endKm;
+    }
+
+    public Double getStartDatum() {
+        return startDatum;
+    }
+
+    public boolean startAtGauge() {
+        return startDatum != null;
+    }
+
+    public boolean endAtGauge() {
+        return endDatum != null;
+    }
+
+    public void setStartDatum(Double startDatum) {
+        this.startDatum = startDatum;
+    }
+
+    public Double getEndDatum() {
+        return endDatum;
+    }
+
+    public void setEndDatum(Double endDatum) {
+        this.endDatum = endDatum;
+    }
+
+    @Override
+    public void removeNaNs() {
+        removeNaNs(new TDoubleArrayList [] { ws, ws2 });
+    }
+
+    public double minWs2() {
+        return ws2.min();
+    }
+
+    // Note that we can also easily define a Function to do so.
+    public double getRelHeight1Cm(int idx) {
+        if (this.startAtGauge()) {
+            return (ws.getQuick(idx) - getStartDatum())*100d;
+        }
+        else return ws.getQuick(idx)*100d;
+    }
+
+    public double getRelHeight2Cm(int idx) {
+        if (this.endAtGauge()) {
+            return (ws2.getQuick(idx) - getEndDatum())*100d;
+        }
+        else return ws2.getQuick(idx)*100d;
+    }
+}
+// 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/WWAxisTypes.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,84 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.math.Function;
+import de.intevation.flys.artifacts.math.Identity;
+import de.intevation.flys.artifacts.math.AddScaleFunction;
+
+public class WWAxisTypes
+{
+    protected boolean inCm1;
+    protected boolean inCm2;
+
+    public WWAxisTypes() {
+        inCm1 = inCm2 = true;
+    }
+
+    public WWAxisTypes(WW ww) {
+        this();
+        classify(ww);
+    }
+
+    public void classify(WW ww) {
+        if (!ww.startAtGauge()) inCm1 = false;
+        if (!ww.endAtGauge())   inCm2 = false;
+    }
+
+    public boolean getInCm(int index) {
+        switch (index) {
+            case 0:  return inCm1;
+            case 1:  return inCm2;
+            default: return false;
+        }
+    }
+
+    public boolean getInCm1() {
+        return inCm1;
+    }
+
+    public void setInCm1(boolean inCm1) {
+        this.inCm1 = inCm1;
+    }
+
+    public boolean getInCm2() {
+        return inCm2;
+    }
+
+    public void setInCm2(boolean inCm2) {
+        this.inCm2 = inCm2;
+    }
+
+    public WW.ApplyFunctionIterator transform(WW ww) {
+        return transform(ww, false);
+    }
+
+    private static final double zero(Double d) {
+        return d == null ? 0 : d;
+    }
+
+    public WW.ApplyFunctionIterator transform(WW ww, boolean normalized) {
+
+        Function function1;
+        Function function2;
+
+        if (!normalized) {
+            function1 = inCm1
+                ? new AddScaleFunction(-ww.getStartDatum(), 100d)
+                : Identity.IDENTITY;
+
+            function2 = inCm2
+                ? new AddScaleFunction(-ww.getEndDatum(), 100d)
+                : Identity.IDENTITY;
+        }
+        else {
+            double minW1 = ww.minWs();
+            double minW2 = ww.minWs2();
+            double scale1 = inCm1 ? 100d : 1d;
+            double scale2 = inCm2 ? 100d : 1d;
+            function1 = new AddScaleFunction(-minW1, scale1);
+            function2 = new AddScaleFunction(-minW2, scale2);
+        }
+
+        return new WW.ApplyFunctionIterator(ww, function1, function2);
+    }
+}
+// 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/WWQQ.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,97 @@
+package de.intevation.flys.artifacts.model;
+
+import de.intevation.flys.artifacts.math.Identity;
+
+import gnu.trove.TDoubleArrayList;
+
+public class WWQQ
+extends      WW
+{
+    public static class ApplyFunctionIterator
+    extends             WW.ApplyFunctionIterator
+    {
+        public ApplyFunctionIterator(WWQQ ww) {
+            super(ww, Identity.IDENTITY, Identity.IDENTITY);
+        }
+
+        @Override
+        public void get(int idx, double [] wwqqPair) {
+            WWQQ wwqq = (WWQQ)ww;
+            wwqqPair[0] = function1.value(wwqq.getW(idx));
+            wwqqPair[1] = function2.value(wwqq.getW2(idx));
+            wwqqPair[2] = wwqq.getQ1(idx);
+            wwqqPair[3] = wwqq.getQ2(idx);
+        }
+    } // class ApplyFunctionIterator
+
+    protected TDoubleArrayList qs1;
+    protected TDoubleArrayList qs2;
+
+    public WWQQ() {
+        this("");
+    }
+
+    public WWQQ(String name) {
+        super(name);
+    }
+
+    public WWQQ(int capacity) {
+        this(capacity, "");
+    }
+
+    public WWQQ(int capacity, String name) {
+        super(capacity, name);
+    }
+
+    public WWQQ(
+        String    name,
+        double    startKm,
+        Double    startDatum,
+        double [] ws1,
+        double [] qs1,
+        double    endKm,
+        Double    endDatum,
+        double [] ws2,
+        double [] qs2
+    ) {
+        super(name, startKm, startDatum, ws1, endKm, endDatum, ws2);
+        this.qs1 = new TDoubleArrayList(qs1);
+        this.qs2 = new TDoubleArrayList(qs2);
+    }
+
+    public double getQ1(int idx) {
+        return qs1.getQuick(idx);
+    }
+
+    public double getQ2(int idx) {
+        return qs2.getQuick(idx);
+    }
+
+    public double [] getQs1() {
+        return qs1.toNativeArray();
+    }
+
+    public double [] getQs2() {
+        return qs2.toNativeArray();
+    }
+
+    @Override
+    public double [] get(int idx) {
+        return get(idx, new double[4]);
+    }
+
+    @Override
+    public double [] get(int idx, double [] dst) {
+        dst[0] = ws .getQuick(idx);
+        dst[1] = ws2.getQuick(idx);
+        dst[2] = qs1.getQuick(idx);
+        dst[3] = qs2.getQuick(idx);
+        return dst;
+    }
+
+    @Override
+    public void removeNaNs() {
+        removeNaNs(new TDoubleArrayList [] { ws, ws2, qs1, qs2 });
+    }
+}
+// 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/WWQQJRDataSource.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,121 @@
+package de.intevation.flys.artifacts.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.log4j.Logger;
+
+import net.sf.jasperreports.engine.JRDataSource;
+import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JRField;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class WWQQJRDataSource implements JRDataSource
+{
+    /** The logger used in this exporter.*/
+    private static Logger logger = Logger.getLogger(WWQQJRDataSource.class);
+
+    /**
+     *
+     */
+    private ArrayList<String[]> data;
+    private HashMap<String, String> metaData;
+
+    private int index = -1;
+
+    /**
+     *
+     */
+    public WWQQJRDataSource()
+    {
+        data = new ArrayList<String[]>();
+        metaData = new HashMap<String, String>();
+    }
+
+
+    /**
+     *
+     */
+    public void addData(String[] data) {
+        this.data.add(data);
+    }
+
+
+    /**
+     *
+     */
+    public void addMetaData(String key, String value) {
+        this.metaData.put(key, value);
+    }
+
+
+    /**
+     *
+     */
+    public boolean next() throws JRException
+    {
+        index++;
+
+        return (index < data.size());
+    }
+
+
+    /**
+     *
+     */
+    public Object getFieldValue(JRField field) throws JRException
+    {
+        Object value = "";
+        String fieldName = field.getName();
+        if ("river".equals(fieldName)) {
+            value = metaData.get("river");
+        }
+        else if ("date".equals(fieldName)) {
+            value = metaData.get("date");
+        }
+        else if ("calculation".equals(fieldName)) {
+            value = metaData.get("calculation");
+        }
+        else if ("reference".equals(fieldName)) {
+            value = metaData.get("reference");
+        }
+        else if ("location".equals(fieldName)) {
+            value = metaData.get("location");
+        }
+        else if ("km1".equals(fieldName)) {
+            value = data.get(index)[0];
+        }
+        else if ("location1".equals(fieldName)) {
+            value = data.get(index)[1];
+        }
+        else if ("W1".equals(fieldName)) {
+            value = data.get(index)[2];
+        }
+        else if ("Q1".equals(fieldName)) {
+            value = data.get(index)[3];
+        }
+        else if ("km2".equals(fieldName)) {
+            value = data.get(index)[4];
+        }
+        else if ("location2".equals(fieldName)) {
+            value = data.get(index)[5];
+        }
+        else if ("W2".equals(fieldName)) {
+            value = data.get(index)[6];
+        }
+        else if ("Q2".equals(fieldName)) {
+            value = data.get(index)[7];
+        }
+        else if ("Wcm1".equals(fieldName)) {
+            value = data.get(index)[8];
+        }
+        else if ("Wcm2".equals(fieldName)) {
+            value = data.get(index)[9];
+        }
+        return value;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WaterlevelFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,38 +1,28 @@
 package de.intevation.flys.artifacts.model;
 
-import org.apache.log4j.Logger;
+import de.intevation.artifactdatabase.state.Facet;
 
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
 
-import de.intevation.artifactdatabase.state.Facet;
-
-import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.FLYSArtifact;
 
 import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.artifacts.math.Linear;
 
+import org.apache.log4j.Logger;
 
 /**
  * Facet of a Waterlevel (WQKms).
  */
-public class WaterlevelFacet extends BlackboardDataFacet {
+public class WaterlevelFacet extends DataFacet {
 
     private static Logger logger = Logger.getLogger(WaterlevelFacet.class);
 
-    protected ComputeType type;
-    protected String      stateID;
-    protected String      hash;
-
-
     public WaterlevelFacet(int index, String name, String description) {
-        this(index, name, description, ComputeType.ADVANCE, null, null);
+        super(index, name, description, ComputeType.ADVANCE, null, null);
     }
 
-
-    public WaterlevelFacet() {
-    }
-
-
     public WaterlevelFacet(
         int         index,
         String      name,
@@ -40,30 +30,84 @@
         ComputeType type,
         String      stateID,
         String      hash
-
     ) {
-        super(index, name, description);
-        this.type    = type;
-        this.stateID = stateID;
-        this.hash    = hash;
+        super(index, name, description, type, hash, stateID);
     }
 
+    public WaterlevelFacet() {
+    }
+
+    protected WQKms [] getWQKms(CalculationResult res) {
+        return (WQKms [])res.getData();
+    }
 
     /**
      * Get waterlevel data.
      * @return a WQKms at given index.
      */
     public Object getData(Artifact artifact, CallContext context) {
-        logger.debug("Get data for waterlevels at index: " + index);
 
-        WINFOArtifact winfo = (WINFOArtifact)artifact;
+        if (logger.isDebugEnabled()) {
+            logger.debug("Get data for waterlevels at index: " + index +
+                " /stateId: " + stateId);
+        }
+
+        FLYSArtifact winfo = (FLYSArtifact) artifact;
 
         CalculationResult res = (CalculationResult)
-            winfo.compute(context, hash, stateID, type, false);
+            winfo.compute(context, hash, stateId, type, false);
 
-        WQKms [] wqkms = (WQKms [])res.getData();
+        if (res == null) {
+            logger.error("WaterlevelFacet.getData: null result");
+            return null;
+        }
 
-        return wqkms[index];
+        if (winfo == null) {
+            logger.error("WaterlevelFacet.getData: artifact is null");
+            return null;
+        }
+
+        WQKms [] wqkms = getWQKms(res);
+        Object KM = context.getContextValue("currentKm");
+        if (KM != null) {
+            logger.debug("interpolate at given km");
+            // TODO handle exact match.
+
+            WQKms wqkmsI = wqkms[index];
+            double km = (Double)KM;
+
+            // TODO employ DataUtils interface to TDoubleArraList
+            int size = wqkmsI.size();
+            boolean kmIncreasing = wqkmsI.getKm(0) < wqkmsI.getKm(size-1);
+            int mod = kmIncreasing ? +1 : -1;
+            int idx = 0;
+            if (!kmIncreasing) {
+                while (idx < size && wqkmsI.getKm(idx) < km) {
+                    idx++;
+                }
+            }
+            else {
+                idx = size-1;
+                while (idx > 0 && wqkmsI.getKm(idx) > km) {
+                    idx--;
+                }
+            }
+            WQKms resultWQKms = new WQKms();
+            if (idx != -1 && idx < size) {
+                double inW = Linear.linear(
+                    km,
+                    wqkmsI.getKm(idx), wqkmsI.getKm(idx-mod),
+                    wqkmsI.getW(idx), wqkmsI.getW(idx-mod));
+                double inQ = Linear.linear(
+                    km,
+                    wqkmsI.getKm(idx), wqkmsI.getKm(idx-mod),
+                    wqkmsI.getQ(idx), wqkmsI.getQ(idx-mod));
+                resultWQKms.add(inW, inQ, km);
+            }
+            return resultWQKms;
+        }
+
+        return wqkms != null ? wqkms[index] : null;
     }
 
 
@@ -73,8 +117,8 @@
         WaterlevelFacet copy = new WaterlevelFacet();
         copy.set(this);
         copy.type    = type;
-        copy.stateID = stateID;
         copy.hash    = hash;
+        copy.stateId = stateId;
         return copy;
     }
 }
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java	Fri Sep 28 12:15:52 2012 +0200
@@ -32,6 +32,8 @@
 
     public static final int DEFAULT_Q_STEPS = 500;
 
+    public static final int RELATE_WS_SAMPLES = 200;
+
     /**
      * A Column in the table, typically representing one measurement session.
      */
@@ -98,7 +100,7 @@
 
         public SplineFunction(
             PolynomialSplineFunction spline,
-            double []                splineQs, 
+            double []                splineQs,
             double []                splineWs
         ) {
             this.spline   = spline;
@@ -107,8 +109,8 @@
         }
 
         public double [][] sample(
-            int         numSamples, 
-            double      km, 
+            int         numSamples,
+            double      km,
             Calculation errors
         ) {
             double minQ = getQMin();
@@ -130,8 +132,7 @@
             }
             catch (ArgumentOutsideDomainException aode) {
                 if (errors != null) {
-                    // TODO: I18N
-                    errors.addProblem(km, "spline interpolation failed");
+                    errors.addProblem(km, "spline.interpolation.failed");
                 }
                 log.error("spline interpolation failed.", aode);
             }
@@ -222,9 +223,8 @@
                     double wo = other.getW(qPosition);
                     if (Double.isNaN(wt) || Double.isNaN(wo)) {
                         if (errors != null) {
-                            // TODO: I18N
                             errors.addProblem(
-                                km, "cannot find w for q = " + iqs[i]);
+                                km, "cannot.find.w.for.q", iqs[i]);
                         }
                         ows[i] = Double.NaN;
                     }
@@ -234,8 +234,7 @@
                 }
                 else {
                     if (errors != null) {
-                        // TODO: I18N
-                        errors.addProblem(km, "cannot find q = " + iqs[i]);
+                        errors.addProblem(km, "cannot.find.q", iqs[i]);
                     }
                     ows[i] = Double.NaN;
                 }
@@ -251,8 +250,7 @@
 
             if (W < 1) {
                 if (errors != null) {
-                    // TODO: I18N
-                    errors.addProblem(km, "no ws found");
+                    errors.addProblem(km, "no.ws.found");
                 }
                 return null;
             }
@@ -262,9 +260,8 @@
             for (int i = 0; i < W; ++i) {
                 double sq = table.getQIndex(i, km);
                 if (Double.isNaN(sq) && errors != null) {
-                    // TODO: I18N
                     errors.addProblem(
-                        km, "no q found in " + (i+1) + " column");
+                        km, "no.q.found.in.column", (i+1));
                 }
                 splineQs[i] = sq;
             }
@@ -278,8 +275,7 @@
             }
             catch (MathIllegalArgumentException miae) {
                 if (errors != null) {
-                    // TODO: I18N
-                    errors.addProblem(km, "spline creation failed");
+                    errors.addProblem(km, "spline.creation.failed");
                 }
                 log.error("spline creation failed", miae);
             }
@@ -296,8 +292,7 @@
 
             if (W < 1) {
                 if (errors != null) {
-                    // TODO: I18N
-                    errors.addProblem("no ws found");
+                    errors.addProblem("no.ws.found");
                 }
                 return null;
             }
@@ -316,8 +311,7 @@
 
                 if (Double.isNaN(wws) || Double.isNaN(wqs)) {
                     if (errors != null) {
-                        // TODO: I18N
-                        errors.addProblem(km, "cannot find w or q");
+                        errors.addProblem(km, "cannot.find.w.or.q");
                     }
                 }
 
@@ -335,8 +329,7 @@
             }
             catch (MathIllegalArgumentException miae) {
                 if (errors != null) {
-                    // TODO: I18N
-                    errors.addProblem(km, "spline creation failed");
+                    errors.addProblem(km, "spline.creation.failed");
                 }
                 log.error("spline creation failed", miae);
             }
@@ -453,7 +446,7 @@
         public double [] findQsForW(
             Row           other,
             double        w,
-            double        km, 
+            double        km,
             WstValueTable table
         ) {
             TDoubleArrayList qs = new TDoubleArrayList();
@@ -503,6 +496,28 @@
 
             return qs.toNativeArray();
         }
+
+        public double [] getMinMaxW(double [] result) {
+            double minW =  Double.MAX_VALUE;
+            double maxW = -Double.MAX_VALUE;
+            for (int i = 0; i < ws.length; ++i) {
+                double w = ws[i];
+                if (w < minW) minW = w;
+                if (w > maxW) maxW = w;
+            }
+            result[0] = minW;
+            result[1] = maxW;
+            return result;
+        }
+
+        public double [] getMinMaxW(Row other, double km, double [] result) {
+            double [] m1 = this .getMinMaxW(new double [2]);
+            double [] m2 = other.getMinMaxW(new double [2]);
+            double factor = Linear.factor(km, this.km, other.km);
+            result[0] = Linear.weight(factor, m1[0], m2[0]);
+            result[1] = Linear.weight(factor, m1[1], m2[1]);
+            return result;
+        }
     } // class Row
 
     /** Rows in table. */
@@ -559,17 +574,15 @@
             for (int i = 0; i < qs.length; ++i) {
                 if (getQPosition(km, qs[i], qPosition) == null) {
                     if (errors != null) {
-                        // TODO: I18N
-                        errors.addProblem(km, "cannot find q = " + qs[i]);
+                        errors.addProblem(km, "cannot.find.q", qs[i]);
                     }
                     ws[i] = Double.NaN;
                 }
                 else {
                     if (Double.isNaN(ws[i] = row.getW(qPosition))
                     && errors != null) {
-                        // TODO: I18N
                         errors.addProblem(
-                            km, "cannot find w for q = " + qs[i]);
+                            km, "cannot.find.w.for.q", qs[i]);
                     }
                 }
             }
@@ -581,8 +594,7 @@
                 // do not extrapolate
                 Arrays.fill(ws, Double.NaN);
                 if (errors != null) {
-                    // TODO: I18N
-                    errors.addProblem(km, "km not found");
+                    errors.addProblem(km, "km.not.found");
                 }
             }
             else {
@@ -595,6 +607,123 @@
         return ws;
     }
 
+    public double [] getMinMaxQ(double km) {
+        return getMinMaxQ(km, new double [2]);
+    }
+
+    public double [] getMinMaxQ(double km, double [] result) {
+        double minQ =  Double.MAX_VALUE;
+        double maxQ = -Double.MAX_VALUE;
+
+        for (int i = 0; i < columns.length; ++i) {
+            double q = columns[i].getQRangeTree().findQ(km);
+            if (!Double.isNaN(q)) {
+                if (q < minQ) minQ = q;
+                if (q > maxQ) maxQ = q;
+            }
+        }
+
+        if (minQ < Double.MAX_VALUE) {
+            result[0] = minQ;
+            result[1] = maxQ;
+            return result;
+        }
+
+        return null;
+    }
+
+    public double [] getMinMaxQ(double from, double to, double step) {
+        double [] result = new double[2];
+
+        double minQ =  Double.MAX_VALUE;
+        double maxQ = -Double.MAX_VALUE;
+
+        if (from > to) {
+            double tmp = from;
+            from = to;
+            to = tmp;
+        }
+
+        step = Math.max(Math.abs(step), 0.0001);
+
+        double d = from;
+        for (; d <= to; d += step) {
+            if (getMinMaxQ(d, result) != null) {
+                if (result[0] < minQ) minQ = result[0];
+                if (result[1] > maxQ) maxQ = result[1];
+            }
+        }
+
+        if (d != to) {
+            if (getMinMaxQ(to, result) != null) {
+                if (result[0] < minQ) minQ = result[0];
+                if (result[1] > maxQ) maxQ = result[1];
+            }
+        }
+
+        return minQ < Double.MAX_VALUE
+            ? new double [] { minQ, maxQ }
+            : null;
+    }
+
+    public double [] getMinMaxW(double km) {
+        return getMinMaxW(km, new double [2]);
+
+    }
+    public double [] getMinMaxW(double km, double [] result) {
+        int rowIndex = Collections.binarySearch(rows, new Row(km));
+
+        if (rowIndex >= 0) {
+            return rows.get(rowIndex).getMinMaxW(result);
+        }
+
+        rowIndex = -rowIndex -1;
+
+        if (rowIndex < 1 || rowIndex >= rows.size()) {
+            // do not extrapolate
+            return null;
+        }
+
+        Row r1 = rows.get(rowIndex-1);
+        Row r2 = rows.get(rowIndex);
+
+        return r1.getMinMaxW(r2, km, result);
+    }
+
+    public double [] getMinMaxW(double from, double to, double step) {
+        double [] result = new double[2];
+
+        double minW =  Double.MAX_VALUE;
+        double maxW = -Double.MAX_VALUE;
+
+        if (from > to) {
+            double tmp = from;
+            from = to;
+            to = tmp;
+        }
+
+        step = Math.max(Math.abs(step), 0.0001);
+
+        double d = from;
+        for (; d <= to; d += step) {
+            if (getMinMaxW(d, result) != null) {
+                if (result[0] < minW) minW = result[0];
+                if (result[1] > maxW) maxW = result[1];
+            }
+        }
+
+        if (d != to) {
+            if (getMinMaxW(to, result) != null) {
+                if (result[0] < minW) minW = result[0];
+                if (result[1] > maxW) maxW = result[1];
+            }
+        }
+
+        return minW < Double.MAX_VALUE
+            ? new double [] { minW, maxW }
+            : null;
+    }
+
     /**
      * Interpolate W and Q values at a given km.
      */
@@ -604,11 +733,16 @@
 
     /**
      * Interpolate W and Q values at a given km.
+     *
+     * @param errors where to store errors.
+     *
+     * @return double double array, first index Ws, second Qs.
      */
     public double [][] interpolateWQ(double km, Calculation errors) {
         return interpolateWQ(km, DEFAULT_Q_STEPS, errors);
     }
 
+
     /**
      * Interpolate W and Q values at a given km.
      */
@@ -626,8 +760,7 @@
         if (rowIndex < 1 || rowIndex >= rows.size()) {
             // do not extrapolate
             if (errors != null) {
-                // TODO: I18N
-                errors.addProblem(km, "km not found");
+                errors.addProblem(km, "km.not.found");
             }
             return new double[2][0];
         }
@@ -719,7 +852,7 @@
             Arrays.fill(ws, Double.NaN);
             Arrays.fill(qs, Double.NaN);
             if (errors != null) {
-                errors.addProblem(referenceKm, "cannot find q");
+                errors.addProblem(referenceKm, "cannot.find.q", q);
             }
             return null;
         }
@@ -732,7 +865,7 @@
 
             if (Double.isNaN(qs[i] = getQ(qPosition, kms[i]))) {
                 if (errors != null) {
-                    errors.addProblem(kms[i], "cannot find q");
+                    errors.addProblem(kms[i], "cannot.find.q", q);
                 }
                 ws[i] = Double.NaN;
                 continue;
@@ -745,7 +878,7 @@
                 // direct row match
                 if (Double.isNaN(ws[i] = rows.get(rowIndex).getW(qPosition))
                 && errors != null) {
-                    errors.addProblem(kms[i], "cannot find w");
+                    errors.addProblem(kms[i], "cannot.find.w.for.q", q);
                 }
                 continue;
             }
@@ -755,7 +888,7 @@
             if (rowIndex < 1 || rowIndex > R1) {
                 // do not extrapolate
                 if (errors != null) {
-                    errors.addProblem(kms[i], "cannot find km");
+                    errors.addProblem(kms[i], "km.not.found");
                 }
                 ws[i] = Double.NaN;
                 continue;
@@ -765,7 +898,7 @@
 
             if (Double.isNaN(ws[i] = r1.getW(r2, kms[i], qPosition))
             && errors != null) {
-                errors.addProblem(kms[i], "cannot find w");
+                errors.addProblem(kms[i], "cannot.find.w.for.q", q);
             }
         }
 
@@ -809,6 +942,8 @@
         if (rowIndex < 0) {
             rowIndex = -rowIndex -1;
         }
+
+        // TODO Beyond definition, we could stop more clever.
         if (rowIndex >= rows.size()) {
             rowIndex = rows.size() -1;
         }
@@ -832,10 +967,12 @@
                     break;
                 }
             }
-            for (int after = rowIndex, R = rows.size(); after < R; after++) {
-                if (!Double.isNaN(rows.get(after).ws[col])) {
-                    rowAfter = rows.get(after);
-                    break;
+            if (rowBefore != null) {
+                for (int after = rowIndex, R = rows.size(); after < R; after++) {
+                    if (!Double.isNaN(rows.get(after).ws[col])) {
+                        rowAfter = rows.get(after);
+                        break;
+                    }
                 }
             }
 
@@ -874,8 +1011,7 @@
         if (rowIndex >= 0) {
             SplineFunction sf = rows.get(rowIndex).createSpline(this, errors);
             if (sf == null && errors != null) {
-                // TODO: I18N
-                errors.addProblem(km, "cannot create w/q relation");
+                errors.addProblem(km, "cannot.create.wq.relation");
             }
             return sf;
         }
@@ -885,8 +1021,7 @@
         if (rowIndex < 1 || rowIndex >= rows.size()) {
             // Do not extrapolate.
             if (errors != null) {
-                // TODO: I18N
-                errors.addProblem(km, "km not found");
+                errors.addProblem(km, "km.not.found");
             }
             return null;
         }
@@ -897,8 +1032,7 @@
 
         SplineFunction sf = r1.createSpline(r2, km, this, errors);
         if (sf == null && errors != null) {
-            // TODO: I18N
-            errors.addProblem(km, "cannot create w/q relation");
+            errors.addProblem(km, "cannot.create.wq.relation");
         }
 
         return sf;
@@ -906,7 +1040,37 @@
 
     /** 'Bezugslinienverfahren' */
     public double [][] relateWs(
-        double      km1, 
+        double      km1,
+        double      km2,
+        Calculation errors
+    ) {
+        return relateWs(km1, km2, RELATE_WS_SAMPLES, errors);
+    }
+
+    private static class ErrorHandler {
+
+        boolean     hasErrors;
+        Calculation errors;
+
+        ErrorHandler(Calculation errors) {
+            this.errors = errors;
+        }
+
+        void error(double km, String key, Object ... args) {
+            if (errors != null && !hasErrors) {
+                hasErrors = true;
+                errors.addProblem(km, key, args);
+            }
+        }
+    } // class ErrorHandler
+
+
+    /* TODO: Add optimized methods of relateWs to relate one
+     *       start km to many end kms. The index generation/spline stuff for
+     *       the start km is always the same.
+     */
+    public double [][] relateWs(
+        double      km1,
         double      km2,
         int         numSamples,
         Calculation errors
@@ -916,7 +1080,7 @@
             return new double[2][0];
         }
 
-        SplineFunction sf2 = createSpline(km1, errors);
+        SplineFunction sf2 = createSpline(km2, errors);
         if (sf2 == null) {
             return new double[2][0];
         }
@@ -924,60 +1088,82 @@
         PolynomialSplineFunction iQ1 = sf1.createIndexQRelation();
         if (iQ1 == null) {
             if (errors != null) {
-                // TODO: I18N
-                errors.addProblem(km1, "cannot create index/q relation");
+                errors.addProblem(km1, "cannot.create.index.q.relation");
             }
             return new double[2][0];
         }
 
-        PolynomialSplineFunction iQ2 = sf1.createIndexQRelation();
+        PolynomialSplineFunction iQ2 = sf2.createIndexQRelation();
         if (iQ2 == null) {
             if (errors != null) {
-                // TODO: I18N
-                errors.addProblem(km2, "cannot create index/q relation");
+                errors.addProblem(km2, "cannot.create.index.q.relation");
             }
             return new double[2][0];
         }
 
-        int N = sf1.splineQs.length;
+        int N = Math.min(sf1.splineQs.length, sf2.splineQs.length);
         double stepWidth = N/(double)numSamples;
 
         PolynomialSplineFunction qW1 = sf1.spline;
         PolynomialSplineFunction qW2 = sf2.spline;
 
-        double [] ws1 = new double[numSamples];
-        double [] ws2 = new double[numSamples];
-
-        Arrays.fill(ws1, Double.NaN);
-        Arrays.fill(ws2, Double.NaN);
-
-        boolean hadErrors = false;
+        TDoubleArrayList ws1 = new TDoubleArrayList(numSamples);
+        TDoubleArrayList ws2 = new TDoubleArrayList(numSamples);
+        TDoubleArrayList qs1 = new TDoubleArrayList(numSamples);
+        TDoubleArrayList qs2 = new TDoubleArrayList(numSamples);
 
-        double p = 0d;
-        for (int i = 0; i < numSamples; ++i, p += stepWidth) {
+        ErrorHandler err = new ErrorHandler(errors);
+
+        int i = 0;
+        for (double p = 0d; p <= N-1; p += stepWidth, ++i) {
+
+            double q1;
             try {
-                double q1 = iQ1.value(p);
-                double w1 = qW1.value(q1);
-                double q2 = iQ2.value(p);
-                double w2 = qW2.value(q2);
-                ws1[i] = w1;
-                ws2[i] = w2;
+                q1 = iQ1.value(p);
             }
             catch (ArgumentOutsideDomainException aode) {
-                if (!hadErrors) {
-                    // XXX: I'm not sure if this really can happen
-                    //      and if we should report this more than once.
-                    hadErrors = true;
-                    if (errors != null) {
-                        // TODO: I18N
-                        log.debug("W~W failed", aode);
-                        errors.addProblem("W~W failed");
-                    }
-                }
+                err.error(km1, "w.w.qkm1.failed", p);
+                continue;
             }
+
+            double w1;
+            try {
+                w1 = qW1.value(q1);
+            }
+            catch (ArgumentOutsideDomainException aode) {
+                err.error(km1, "w.w.wkm1.failed", q1, p);
+                continue;
+            }
+
+            double q2;
+            try {
+                q2 = iQ2.value(p);
+            }
+            catch (ArgumentOutsideDomainException aode) {
+                err.error(km2, "w.w.qkm2.failed", p);
+                continue;
+            }
+
+            double w2;
+            try {
+                w2 = qW2.value(q2);
+            }
+            catch (ArgumentOutsideDomainException aode) {
+                err.error(km2, "w.w.wkm2.failed", q2, p);
+                continue;
+            }
+
+            ws1.add(w1);
+            ws2.add(w2);
+            qs1.add(q1);
+            qs2.add(q2);
         }
 
-        return new double [][] { ws1, ws2 };
+        return new double [][] {
+            ws1.toNativeArray(),
+            qs1.toNativeArray(),
+            ws2.toNativeArray(),
+            qs2.toNativeArray() };
     }
 
     public QPosition getQPosition(double km, double q) {
@@ -1031,5 +1217,46 @@
         double q2 = columns[index  ].getQRangeTree().findQ(km);
         return Linear.weight(weight, q1, q2);
     }
+
+    public double [][] interpolateTabulated(double km) {
+        return interpolateTabulated(km, new double[2][columns.length]);
+    }
+
+    public double [][] interpolateTabulated(double km, double [][] result) {
+
+        int rowIndex = Collections.binarySearch(rows, new Row(km));
+
+        if (rowIndex >= 0) {
+            // Direct hit -> copy ws.
+            Row row = rows.get(rowIndex);
+            System.arraycopy(
+                row.ws, 0, result[0], 0,
+                Math.min(row.ws.length, result[0].length));
+        }
+        else {
+            rowIndex = -rowIndex -1;
+            if (rowIndex < 1 || rowIndex >= rows.size()) {
+                // Out of bounds.
+                return null;
+            }
+            // Interpolate ws.
+            Row r1 = rows.get(rowIndex-1);
+            Row r2 = rows.get(rowIndex);
+            double factor = Linear.factor(km, r1.km, r2.km);
+            Linear.weight(factor, r1.ws, r2.ws, result[0]);
+        }
+
+        double [] qs = result[1];
+        for (int i = Math.min(qs.length, columns.length)-1; i >= 0; --i) {
+            qs[i] = columns[i].getQRangeTree().findQ(km);
+        }
+        return result;
+    }
+
+    public List<Range> findSegments(double km1, double km2) {
+        return columns.length != 0
+            ? columns[columns.length-1].getQRangeTree().findSegments(km1, km2)
+            : Collections.<Range>emptyList();
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTableFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -53,7 +53,7 @@
 
     /** Statement to query qranges of a single column. */
     public static final String SQL_SELECT_QS_AT_COL =
-        "SELECT column_pos, q, a, b FROM wst_q_values " +
+        "SELECT q, a, b FROM wst_q_values " +
         "WHERE wst_id = :wst_id AND column_pos = :column_pos";
 
     // (sorted by km)
@@ -96,7 +96,7 @@
         Session session = SessionHolder.HOLDER.get();
 
         // Fetch data for one column only.
-        
+
         WstValueTable.Column [] columns = loadColumns(session, wst_id);
         loadQRanges(session, columns, wst_id);
         List<WstValueTable.Row> rows = loadRows(session, wst_id, columns.length);
@@ -138,7 +138,7 @@
         Session session = SessionHolder.HOLDER.get();
 
         // Fetch data for one column only.
-        
+
         WstValueTable.Column [] columns = loadColumn(session, wst_id, col_pos);
         loadQRanges(session, columns, wst_id, col_pos);
         List<WstValueTable.Row> rows = loadRowsOneColumn(session, wst_id, col_pos);
@@ -228,29 +228,32 @@
 
     /**
      * Load rows with a single columns result.
+     *
      * @param session    session to use for querying db.
-     * @param wst_id     id of wst (in db).
+     * @param wstId     id of wst (in db).
      * @param column_pos the column_pos (within the db) of the wst_value_table
      *                   of which the values shall be fetched.
+     *
      * @return resultant rows.
      */
     protected static List<WstValueTable.Row> loadRowsOneColumn(
         Session session,
-        int     wst_id,
+        int     wstId,
         int     column_pos
     ) {
         SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_WS_AT_COL)
-            .addScalar("km",         StandardBasicTypes.DOUBLE)
-            .addScalar("w",          StandardBasicTypes.DOUBLE);
+            .addScalar("km", StandardBasicTypes.DOUBLE)
+            .addScalar("w",  StandardBasicTypes.DOUBLE);
 
-        sqlQuery.setInteger("wst_id", wst_id);
+        sqlQuery.setInteger("wst_id", wstId);
         sqlQuery.setInteger("column_pos", column_pos);
 
         List<Object []> results = sqlQuery.list();
 
         double [] ws = null;
 
-        ArrayList<WstValueTable.Row> rows = new ArrayList<WstValueTable.Row>();
+        List<WstValueTable.Row> rows =
+            new ArrayList<WstValueTable.Row>(results.size());
 
         // Walk over rows.
         for (Object [] result: results) {
@@ -263,7 +266,6 @@
             ws[0] = w != null ? w : Double.NaN;
         }
 
-        rows.trimToSize();
         return rows;
     }
 
@@ -369,10 +371,9 @@
         int                     column_pos
     ) {
         SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_QS_AT_COL)
-            .addScalar("column_pos", StandardBasicTypes.INTEGER) // keep to maintain order.
-            .addScalar("q",          StandardBasicTypes.DOUBLE)
-            .addScalar("a",          StandardBasicTypes.DOUBLE)
-            .addScalar("b",          StandardBasicTypes.DOUBLE);
+            .addScalar("q", StandardBasicTypes.DOUBLE)
+            .addScalar("a", StandardBasicTypes.DOUBLE)
+            .addScalar("b", StandardBasicTypes.DOUBLE);
 
         sqlQuery.setInteger("wst_id",     wst_id);
         sqlQuery.setInteger("column_pos", column_pos);
@@ -381,7 +382,8 @@
 
         int qSize = qRanges.size();
 
-        QRangeTree qRangeTree = new QRangeTree(qRanges, 0, qSize);
+        QRangeTree qRangeTree = new QRangeTree(
+            qRanges, QRangeTree.WITHOUT_COLUMN, 0, qSize);
         columns[0].setQRangeTree(qRangeTree);
     }
 
@@ -452,7 +454,7 @@
             }
         }
         */
-    
+
     }
 
     protected static void loadQRanges(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/extreme/Curve.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,107 @@
+package de.intevation.flys.artifacts.model.extreme;
+
+import de.intevation.flys.artifacts.math.Function;
+import de.intevation.flys.artifacts.math.NaNFunction;
+import de.intevation.flys.artifacts.math.UnivariateRealFunctionFunction;
+
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+
+import java.io.Serializable;
+
+import java.lang.ref.SoftReference;
+
+import org.apache.commons.math.analysis.interpolation.SplineInterpolator;
+
+import org.apache.commons.math.exception.MathIllegalArgumentException;
+
+import org.apache.log4j.Logger;
+
+public class Curve
+implements   Serializable, Function
+{
+    private static Logger log = Logger.getLogger(Curve.class);
+
+    protected double [] qs;
+    protected double [] ws;
+    protected String    function;
+    protected double [] coeffs;
+
+    // The spline is pretty heavy weight so cache it with a soft ref only.
+    protected transient SoftReference<Function> spline;
+    protected transient Function                extrapolation;
+
+    public Curve() {
+    }
+
+    public Curve(
+        double [] qs,
+        double [] ws,
+        String    function,
+        double [] coeffs
+    ) {
+        this.qs       = qs;
+        this.ws       = ws;
+        this.function = function;
+        this.coeffs   = coeffs;
+    }
+
+    public double [] getQs() {
+        return qs;
+    }
+
+    public double [] getWs() {
+        return ws;
+    }
+
+    public String getFunction() {
+        return function;
+    }
+
+    public double [] getCoeffs() {
+        return coeffs;
+    }
+
+    @Override
+    public double value(double x) {
+        if (x < qs[0]) return Double.NaN;
+        return (x <= qs[qs.length-1]
+            ? getSpline()
+            : getExtrapolation()).value(x);
+    }
+
+    protected synchronized Function getExtrapolation() {
+        if (extrapolation == null) {
+            de.intevation.flys.artifacts.math.fitting.Function
+                f = FunctionFactory.getInstance().getFunction(function);
+
+            extrapolation = f != null
+                ? f.instantiate(coeffs)
+                : NaNFunction.INSTANCE;
+        }
+        return extrapolation;
+    }
+
+    protected synchronized Function getSpline() {
+        Function sp;
+        if (spline != null) {
+            if ((sp = spline.get()) != null) {
+                return sp;
+            }
+        }
+        spline = new SoftReference<Function>(sp = createSpline());
+        return sp;
+    }
+
+    protected Function createSpline() {
+        SplineInterpolator interpolator = new SplineInterpolator();
+        try {
+            return new UnivariateRealFunctionFunction(
+                interpolator.interpolate(qs, ws));
+        }
+        catch (MathIllegalArgumentException miae) {
+            log.debug("creation on spline failed", miae);
+            return NaNFunction.INSTANCE;
+        }
+    }
+}
+// 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/extreme/ExtremeCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,162 @@
+package de.intevation.flys.artifacts.model.extreme;
+
+import de.intevation.flys.artifacts.access.ExtremeAccess;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+
+import de.intevation.flys.artifacts.model.Calculation;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.RangeWithValues;
+import de.intevation.flys.artifacts.model.RiverFactory;
+import de.intevation.flys.artifacts.model.WstValueTable;
+import de.intevation.flys.artifacts.model.WstValueTableFactory;
+
+import de.intevation.flys.model.River;
+
+import de.intevation.flys.utils.DoubleUtil;
+
+import java.util.List;
+
+public class ExtremeCalculation
+extends      Calculation
+{
+    protected String                river;
+    protected String                function;
+    protected double                from;
+    protected double                to;
+    protected double                step;
+    protected double                percent;
+    protected List<RangeWithValues> ranges;
+
+    public ExtremeCalculation() {
+    }
+
+    public ExtremeCalculation(ExtremeAccess access) {
+        String                river    = access.getRiver();
+        String                function = access.getFunction();
+        Double                from     = access.getFrom();
+        Double                to       = access.getTo();
+        Double                step     = access.getStep();
+        Double                percent  = access.getPercent();
+        List<RangeWithValues> ranges   = access.getRanges();
+
+        if (river == null) {
+            // TODO: i18n
+            addProblem("extreme.no.river");
+        }
+
+        if (function == null) {
+            // TODO: i18n
+            addProblem("extreme.no.function");
+        }
+
+        if (from == null) {
+            // TODO: i18n
+            addProblem("extreme.no.from");
+        }
+
+        if (to == null) {
+            // TODO: i18n
+            addProblem("extreme.no.to");
+        }
+
+        if (step == null) {
+            // TODO: i18n
+            addProblem("extreme.no.step");
+        }
+
+        if (percent == null) {
+            // TODO: i18n
+            addProblem("extreme.no.percent");
+        }
+
+        if (ranges == null) {
+            // TODO: i18n
+            addProblem("extreme.no.ranges");
+        }
+
+        if (!hasProblems()) {
+            this.river    = river;
+            this.function = function;
+            this.from     = Math.min(from, to);
+            this.to       = Math.max(from, to);
+            this.step     = Math.max(0.001d, Math.abs(step)/1000d);
+            this.percent  = Math.max(0d, Math.min(100d, percent));
+            this.ranges   = ranges;
+        }
+    }
+
+    public CalculationResult calculate() {
+
+        WstValueTable wst = null;
+
+        River river = RiverFactory.getRiver(this.river);
+        if (river == null) {
+            // TODO: i18n
+            addProblem("extreme.no.such.river", this.river);
+        }
+        else {
+            wst = WstValueTableFactory.getTable(river);
+            if (wst == null) {
+                // TODO: i18n
+                addProblem("extreme.no.wst.table");
+            }
+        }
+
+        Function function =
+            FunctionFactory.getInstance().getFunction(this.function);
+        if (function == null) {
+            // TODO: i18n
+            addProblem("extreme.no.such.function", this.function);
+        }
+
+        return hasProblems()
+            ? new CalculationResult(this)
+            : innerCalculate(wst, function);
+    }
+
+    protected CalculationResult innerCalculate(
+        WstValueTable wst,
+        Function      function
+    ) {
+        RangeWithValues range = null;
+
+        KMs: for (double km = from; km <= to; km += step) {
+            double currentKm = DoubleUtil.round(km);
+
+            if (range == null || !range.inside(currentKm)) {
+                for (RangeWithValues r: ranges) {
+                    if (r.inside(currentKm)) {
+                        range = r;
+                        break;
+                    }
+                }
+                // TODO: i18n
+                addProblem(currentKm, "extreme.no.range");
+                continue KMs;
+            }
+
+            double [][] wqs = wst.interpolateTabulated(currentKm);
+            if (wqs == null) {
+                // TODO: i18n
+                addProblem(currentKm, "extreme.no.raw.data");
+                continue;
+            }
+
+            // XXX: This should not be necessary for model data.
+            if (!DoubleUtil.isValid(wqs)) {
+                // TODO: i18n
+                addProblem(currentKm, "extreme.invalid.data");
+                continue;
+            }
+            // TODO: Implement extraction of points for curve fitting.
+            // TODO: Implement curve fitting.
+            // TODO: Implement generating Curve object per km.
+        }
+
+        ExtremeResult result = new ExtremeResult();
+        return new CalculationResult(result, this);
+    }
+}
+// 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/extreme/ExtremeResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,11 @@
+package de.intevation.flys.artifacts.model.extreme;
+
+import java.io.Serializable;
+
+public class ExtremeResult
+implements   Serializable
+{
+    public ExtremeResult() {
+    }
+}
+// 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/fixings/AnalysisPeriod.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,98 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.flys.artifacts.model.DateRange;
+
+import java.io.Serializable;
+
+public class AnalysisPeriod
+implements   Serializable
+{
+    protected DateRange dateRange;
+    protected QWD []    qwds;
+    protected QWD []    qSectorAverages;
+    protected double [] qSectorStdDevs;
+
+    public AnalysisPeriod() {
+    }
+
+    public AnalysisPeriod(DateRange dateRange) {
+        this.dateRange = dateRange;
+    }
+
+    public AnalysisPeriod(DateRange dateRange, QWD [] qwds) {
+        this(dateRange);
+        this.dateRange = dateRange;
+        this.qwds      = qwds;
+    }
+
+    public AnalysisPeriod(
+        DateRange dateRange,
+        QWD []    qwds,
+        QWD []    qSectorAverages,
+        double [] qSectorStdDevs
+    ) {
+        this(dateRange, qwds);
+        this.qSectorAverages = qSectorAverages;
+        this.qSectorStdDevs  = qSectorStdDevs;
+    }
+
+    public DateRange getDateRange() {
+        return dateRange;
+    }
+
+    public void setDateRange(DateRange dateRange) {
+        this.dateRange = dateRange;
+    }
+
+    public QWD [] getQWDs() {
+        return qwds;
+    }
+
+    public void setQWDs(QWD [] qwds) {
+        this.qwds = qwds;
+    }
+
+    public QWD [] getQSectorAverages() {
+        return qSectorAverages;
+    }
+
+    public void setQSectorAverages(QWD [] qSectorAverages) {
+        this.qSectorAverages = qSectorAverages;
+    }
+
+    public QWD getQSectorAverage(int i) {
+        return qSectorAverages[i];
+    }
+
+    public double [] getQSectorStdDevs() {
+        return qSectorStdDevs;
+    }
+
+    public void setQSectorStdDevs(double [] qSectorStdDevs) {
+        this.qSectorStdDevs = qSectorStdDevs;
+    }
+
+    public double getQSectorStdDev(int i) {
+        return qSectorStdDevs[i];
+    }
+
+    public double getMaxQ() {
+        double maxQ = -Double.MAX_VALUE;
+        if (qwds != null) {
+            for (QWD qwd: qwds) {
+                if (qwd.getQ() > maxQ) {
+                    maxQ = qwd.getQ();
+                }
+            }
+        }
+        if (qSectorAverages != null) {
+            for (QWD qwd: qSectorAverages) {
+                if (qwd != null && qwd.getQ() > maxQ) {
+                    maxQ = qwd.getQ();
+                }
+            }
+        }
+        return maxQ;
+    }
+}
+// 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/fixings/Fitting.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,247 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.flys.artifacts.math.Outlier;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+
+import gnu.trove.TDoubleArrayList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math.MathException;
+
+import org.apache.commons.math.optimization.fitting.CurveFitter;
+
+import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer;
+
+import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
+
+import org.apache.log4j.Logger;
+
+public class Fitting
+{
+    private static Logger log = Logger.getLogger(Fitting.class);
+
+    /** Use instance of this factory to find meta infos for outliers. */
+    public interface QWDFactory {
+
+        QWD create(double q, double w);
+
+    } // interface QWFactory
+
+    public static final QWDFactory QWD_FACTORY = new QWDFactory() {
+        @Override
+        public QWD create(double q, double w) {
+            return new QWD(q, w);
+        }
+    };
+
+    protected boolean        checkOutliers;
+    protected Function       function;
+    protected QWDFactory     qwdFactory;
+    protected double         chiSqr;
+    protected double []      parameters;
+    protected ArrayList<QWI> removed;
+    protected QWD []         referenced;
+    protected double         standardDeviation;
+
+
+    public Fitting() {
+        removed = new ArrayList<QWI>();
+    }
+
+    public Fitting(Function function) {
+        this(function, QWD_FACTORY);
+    }
+
+    public Fitting(Function function, QWDFactory qwdFactory) {
+        this(function, qwdFactory, false);
+    }
+
+    public Fitting(
+        Function   function,
+        QWDFactory qwdFactory,
+        boolean    checkOutliers
+    ) {
+        this();
+        this.function      = function;
+        this.qwdFactory    = qwdFactory;
+        this.checkOutliers = checkOutliers;
+    }
+
+    public Function getFunction() {
+        return function;
+    }
+
+    public void setFunction(Function function) {
+        this.function = function;
+    }
+
+    public boolean getCheckOutliers() {
+        return checkOutliers;
+    }
+
+    public void setCheckOutliers(boolean checkOutliers) {
+        this.checkOutliers = checkOutliers;
+    }
+
+    public double getChiSquare() {
+        return chiSqr;
+    }
+
+    public void reset() {
+        chiSqr     = 0.0;
+        parameters = null;
+        removed.clear();
+        referenced = null;
+        standardDeviation = 0.0;
+    }
+
+    public boolean hasOutliers() {
+        return !removed.isEmpty();
+    }
+
+    public List<QWI> getOutliers() {
+        return removed;
+    }
+
+    public QWI [] outliersToArray() {
+        return removed.toArray(new QWI[removed.size()]);
+    }
+
+    public QWD [] referencedToArray() {
+        return referenced != null ? (QWD [])referenced.clone() : null;
+    }
+
+    public double getMaxQ() {
+        double maxQ = -Double.MAX_VALUE;
+        if (referenced != null) {
+            for (QWI qw: referenced) {
+                if (qw.getQ() > maxQ) {
+                    maxQ = qw.getQ();
+                }
+            }
+        }
+        return maxQ;
+    }
+
+    public double [] getParameters() {
+        return parameters;
+    }
+
+    public double getStandardDeviation() {
+        return standardDeviation;
+    }
+
+    public boolean fit(double [] qs, double [] ws) {
+
+        TDoubleArrayList xs = new TDoubleArrayList(qs.length);
+        TDoubleArrayList ys = new TDoubleArrayList(ws.length);
+
+        for (int i = 0; i < qs.length; ++i) {
+            if (!Double.isNaN(qs[i]) && !Double.isNaN(ws[i])) {
+                xs.add(qs[i]);
+                ys.add(ws[i]);
+            }
+            else {
+                log.warn("remove invalid value " + qs[i] + " " + ws[i]);
+            }
+        }
+
+        if (xs.size() < 2) {
+            log.warn("Too less points.");
+            return false;
+        }
+
+        List<Double> inputs = new ArrayList<Double>(xs.size());
+
+        de.intevation.flys.artifacts.math.Function instance = null;
+
+        LevenbergMarquardtOptimizer lmo = null;
+
+        for (;;) {
+            parameters = null;
+            for (double tolerance = 1e-10; tolerance < 1e-3; tolerance *= 10d) {
+
+                lmo = new LevenbergMarquardtOptimizer();
+                lmo.setCostRelativeTolerance(tolerance);
+                lmo.setOrthoTolerance(tolerance);
+                lmo.setParRelativeTolerance(tolerance);
+
+                CurveFitter cf = new CurveFitter(lmo);
+
+                for (int i = 0, N = xs.size(); i < N; ++i) {
+                    cf.addObservedPoint(xs.getQuick(i), ys.getQuick(i));
+                }
+
+                try {
+                    parameters = cf.fit(function, function.getInitialGuess());
+                    break;
+                }
+                catch (MathException me) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("tolerance " + tolerance + " + failed.");
+                    }
+                }
+            }
+            if (parameters == null) {
+                return false;
+            }
+
+            // This is the paraterized function for a given km.
+            instance = function.instantiate(parameters);
+
+            if (!checkOutliers) {
+                break;
+            }
+
+            inputs.clear();
+
+            for (int i = 0, N = xs.size(); i < N; ++i) {
+                double y = instance.value(xs.getQuick(i));
+                if (Double.isNaN(y)) {
+                    y = Double.MAX_VALUE;
+                }
+                inputs.add(Double.valueOf(ys.getQuick(i) - y));
+            }
+
+            Integer outlier = Outlier.findOutlier(inputs);
+
+            if (outlier == null) {
+                break;
+            }
+
+            int idx = outlier.intValue();
+            removed.add(
+                qwdFactory.create(
+                    xs.getQuick(idx), ys.getQuick(idx)));
+            xs.remove(idx);
+            ys.remove(idx);
+        }
+
+        StandardDeviation stdDev = new StandardDeviation();
+
+        referenced = new QWD[xs.size()];
+        for (int i = 0; i < referenced.length; ++i) {
+            QWD qwd = qwdFactory.create(xs.getQuick(i), ys.getQuick(i));
+
+            if (qwd == null) {
+                log.warn("QW creation failed!");
+            }
+            else {
+                referenced[i] = qwd;
+                double dw = (qwd.getW() - instance.value(qwd.getQ()))*100.0;
+                qwd.setDeltaW(dw);
+                stdDev.increment(dw);
+            }
+        }
+
+        standardDeviation = stdDev.getResult();
+
+        chiSqr = lmo.getChiSquare();
+
+        return true;
+    }
+}
+// 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/fixings/FixAnalysisCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,293 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DateRange;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.AndFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.DateRangeFilter;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.Fixing;
+import de.intevation.flys.artifacts.model.FixingsOverview.IdsFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.KmFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.SectorFilter;
+
+import de.intevation.flys.artifacts.model.FixingsOverview;
+import de.intevation.flys.artifacts.model.Parameters;
+import de.intevation.flys.artifacts.model.Range;
+
+import de.intevation.flys.utils.DateAverager;
+import de.intevation.flys.utils.KMIndex;
+
+import gnu.trove.TIntIntHashMap;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
+
+import org.apache.log4j.Logger;
+
+public class FixAnalysisCalculation
+extends      FixCalculation
+{
+    private static Logger log = Logger.getLogger(FixAnalysisCalculation.class);
+
+    protected DateRange    referencePeriod;
+    protected DateRange [] analysisPeriods;
+
+    public FixAnalysisCalculation() {
+    }
+
+    public FixAnalysisCalculation(FixAnalysisAccess access) {
+        super(access);
+
+        DateRange    referencePeriod = access.getReferencePeriod();
+        DateRange [] analysisPeriods = access.getAnalysisPeriods();
+
+        if (referencePeriod == null) {
+            addProblem("fix.missing.reference.period");
+        }
+
+        if (analysisPeriods == null || analysisPeriods.length < 1) {
+            addProblem("fix.missing.analysis.periods");
+        }
+
+        if (!hasProblems()) {
+            this.referencePeriod = referencePeriod;
+            this.analysisPeriods = analysisPeriods;
+        }
+    }
+
+    @Override
+    public CalculationResult innerCalculate(
+        FixingsOverview overview,
+        Function        func
+    ) {
+        ColumnCache cc = new ColumnCache();
+
+        FitResult fitResult = doFitting(overview, cc, func);
+
+        if (fitResult == null) {
+            return new CalculationResult(this);
+        }
+
+        KMIndex<AnalysisPeriod []> analysisPeriods =
+            calculateAnalysisPeriods(
+                func,
+                fitResult.getParameters(),
+                overview,
+                cc);
+
+        analysisPeriods.sort();
+
+        FixAnalysisResult far = new FixAnalysisResult(
+            fitResult.getParameters(),
+            fitResult.getReferenced(),
+            fitResult.getOutliers(),
+            analysisPeriods);
+
+        return new CalculationResult(far, this);
+    }
+
+    @Override
+    protected Filter createFilter() {
+        Filter ids = super.createFilter();
+        DateRangeFilter rdf = new DateRangeFilter(
+            referencePeriod.getFrom(),
+            referencePeriod.getTo());
+        return new AndFilter().add(rdf).add(ids);
+    }
+
+    protected KMIndex<AnalysisPeriod []> calculateAnalysisPeriods(
+        Function        function,
+        Parameters      parameters,
+        FixingsOverview overview,
+        ColumnCache cc
+    ) {
+        Range range = new Range(from, to);
+
+        int kmIndex   = parameters.columnIndex("km");
+        int maxQIndex = parameters.columnIndex("max_q");
+
+        double [] wq = new double[2];
+
+        int [] parameterIndices =
+            parameters.columnIndices(function.getParameterNames());
+
+        double [] parameterValues = new double[parameterIndices.length];
+
+        DateAverager dateAverager = new DateAverager();
+
+        KMIndex<AnalysisPeriod []> results =
+            new KMIndex<AnalysisPeriod []>(parameters.size());
+
+        IdsFilter idsFilter = new IdsFilter(events);
+
+        TIntIntHashMap [] col2indices =
+            new TIntIntHashMap[analysisPeriods.length];
+
+        for (int i = 0; i < analysisPeriods.length; ++i) {
+            col2indices[i] = new TIntIntHashMap();
+        }
+
+        for (int row = 0, R = parameters.size(); row < R; ++row) {
+            double km = parameters.get(row, kmIndex);
+            parameters.get(row, parameterIndices, parameterValues);
+
+            // This is the paraterized function for a given km.
+            de.intevation.flys.artifacts.math.Function instance =
+                function.instantiate(parameterValues);
+
+            KmFilter kmFilter = new KmFilter(km);
+
+            ArrayList<AnalysisPeriod> periodResults =
+                new ArrayList<AnalysisPeriod>(analysisPeriods.length);
+
+            for (int ap = 0; ap < analysisPeriods.length; ++ap) {
+                DateRange analysisPeriod = analysisPeriods[ap];
+                TIntIntHashMap col2index = col2indices[ap];
+
+                DateRangeFilter drf = new DateRangeFilter(
+                    analysisPeriod.getFrom(),
+                    analysisPeriod.getTo());
+
+                QWD []    qSectorAverages = new QWD[4];
+                double [] qSectorStdDevs  = new double[4];
+
+                ArrayList<QWD> allQWDs = new ArrayList<QWD>();
+
+                // for all Q sectors.
+                for (int qSector = qSectorStart; qSector < qSectorEnd; ++qSector) {
+
+                    Filter filter = new AndFilter()
+                        .add(kmFilter)
+                        .add(new SectorFilter(qSector))
+                        .add(drf)
+                        .add(idsFilter);
+
+                    List<Fixing.Column> metas = overview.filter(range, filter);
+
+                    if (metas.isEmpty()) {
+                        // No fixings for km and analysis period
+                        continue;
+                    }
+
+                    double sumQ = 0.0;
+                    double sumW = 0.0;
+
+                    StandardDeviation stdDev = new StandardDeviation();
+
+                    List<QWD> qwds = new ArrayList<QWD>(metas.size());
+
+                    dateAverager.clear();
+
+                    for (Fixing.Column meta: metas) {
+                        if (meta.findQSector(km) != qSector) {
+                            // Ignore not matching sectors.
+                            continue;
+                        }
+
+                        Column column = cc.getColumn(meta);
+                        if (column == null || !column.getQW(km, wq)) {
+                            continue;
+                        }
+
+                        double fw = instance.value(wq[1]);
+                        if (Double.isNaN(fw)) {
+                            continue;
+                        }
+
+                        double dw = (wq[0] - fw)*100.0;
+
+                        stdDev.increment(dw);
+
+                        Date date = column.getDate();
+                        String description = column.getDescription();
+
+                        QWD qwd = new QWD(
+                            wq[1], wq[0],
+                            description,
+                            date, true,
+                            dw, getIndex(col2index, column.getIndex()));
+
+                        qwds.add(qwd);
+
+                        sumW += wq[0];
+                        sumQ += wq[1];
+
+                        dateAverager.add(date);
+                    }
+
+                    // Calulate average per Q sector.
+                    int N = qwds.size();
+                    if (N > 0) {
+                        allQWDs.addAll(qwds);
+                        double avgW = sumW / N;
+                        double avgQ = sumQ / N;
+
+                        double avgFw = instance.value(avgQ);
+                        if (!Double.isNaN(avgFw)) {
+                            double avgDw = (avgW - avgFw)*100.0;
+                            Date avgDate = dateAverager.getAverage();
+
+                            String avgDescription = "avg.deltawt." + qSector;
+
+                            QWD avgQWD = new QWD(
+                                avgQ, avgW, avgDescription, avgDate, true, avgDw, 0);
+
+                            qSectorAverages[qSector] = avgQWD;
+                        }
+                        qSectorStdDevs[qSector] = stdDev.getResult();
+                    }
+                    else {
+                        qSectorStdDevs[qSector] = Double.NaN;
+                    }
+                } // for all Q sectors
+
+                QWD [] aqwds = allQWDs.toArray(new QWD[allQWDs.size()]);
+
+                AnalysisPeriod periodResult = new AnalysisPeriod(
+                    analysisPeriod,
+                    aqwds,
+                    qSectorAverages,
+                    qSectorStdDevs);
+                periodResults.add(periodResult);
+            }
+
+            double maxQ = -Double.MAX_VALUE;
+            for (AnalysisPeriod ap: periodResults) {
+                double q = ap.getMaxQ();
+                if (q > maxQ) {
+                    maxQ = q;
+                }
+            }
+
+            double oldMaxQ = parameters.get(row, maxQIndex);
+            if (oldMaxQ < maxQ) {
+                parameters.set(row, maxQIndex, maxQ);
+            }
+
+            results.add(km, periodResults.toArray(
+                new AnalysisPeriod[periodResults.size()]));
+        }
+
+        return results;
+    }
+
+    private static final int getIndex(TIntIntHashMap map, int colIdx) {
+        if (map.containsKey(colIdx)) {
+            return map.get(colIdx);
+        }
+        int index = map.size();
+        map.put(colIdx, index);
+        return index;
+    }
+}
+// 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/fixings/FixAnalysisEventsFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,117 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import de.intevation.flys.utils.KMIndex;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Facet to show W values for Q values at km for a date.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixAnalysisEventsFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixAnalysisEventsFacet.class);
+
+    /** Trivial Constructor. */
+    public FixAnalysisEventsFacet() {
+    }
+
+
+    /**
+     * @param name
+     */
+    public FixAnalysisEventsFacet(int index, String name, String description) {
+        super(index,
+             name,
+             description,
+             ComputeType.ADVANCE,
+             null,
+             null);
+    }
+
+
+    /**
+     * 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) {
+        logger.debug("FixAnalysisEventsFacet.getData");
+
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixAnalysisResult result = (FixAnalysisResult) res.getData();
+            double currentKm =
+                ((Double)context.getContextValue("currentKm")).doubleValue();
+
+            KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods();
+            KMIndex.Entry<AnalysisPeriod []> kmPeriodsEntry =
+                kmPeriods.binarySearch(currentKm);
+
+            if(kmPeriodsEntry == null) {
+                logger.debug("getData: kmPeriodsEntry == null");
+                return null;
+            }
+
+            AnalysisPeriod[] periods = kmPeriodsEntry.getValue();
+            if (periods == null) {
+                logger.debug("getData: periods == null");
+                return null;
+            }
+            int ndx = index >> 8;
+            QWD[] qwdData = periods[ndx].getQWDs();
+            if (qwdData == null) {
+                return null;
+            }
+            int ndy = index & 255;
+            for (int i = 0; i < qwdData.length; i++) {
+                if (qwdData[i].getIndex() == ndy) {
+                    return qwdData[i];
+                }
+            }
+            return null;
+        }
+        else {
+            logger.debug("Not an instance of FixationArtifact.");
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixAnalysisEventsFacet deepCopy() {
+        FixAnalysisEventsFacet copy = new FixAnalysisEventsFacet();
+        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/fixings/FixAnalysisPeriodsFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,113 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.DateRange;
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import de.intevation.flys.utils.KMIndex;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Facet to show W values for Q values at km for a date.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixAnalysisPeriodsFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixAnalysisPeriodsFacet.class);
+
+    /** Trivial Constructor. */
+    public FixAnalysisPeriodsFacet() {
+    }
+
+
+    /**
+     * @param name
+     */
+    public FixAnalysisPeriodsFacet(int index, String name, String description) {
+        super(index,
+            name,
+            description,
+            ComputeType.ADVANCE,
+            null,
+            null);
+    }
+
+
+    /**
+     * 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) {
+        logger.debug("FixAnalysisPeriodsFacet.getData");
+
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+            FixAnalysisAccess access = new FixAnalysisAccess(flys);
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixAnalysisResult result = (FixAnalysisResult) res.getData();
+            double currentKm =
+                ((Double)context.getContextValue("currentKm")).doubleValue();
+
+            KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods();
+            KMIndex.Entry<AnalysisPeriod []> kmPeriodsEntry =
+                kmPeriods.binarySearch(currentKm);
+
+            if (kmPeriodsEntry == null) {
+                return null;
+            }
+
+            AnalysisPeriod[] periods = kmPeriodsEntry.getValue();
+
+            if (periods == null) {
+                return null;
+            }
+            DateRange[] dates = new DateRange[periods.length];
+            for (int i = 0; i < periods.length; i++) {
+                dates[i] = periods[i].getDateRange();
+            }
+            return dates;
+        }
+        else {
+            logger.debug("Not an instance of FixationArtifact.");
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixAnalysisPeriodsFacet deepCopy() {
+        FixAnalysisPeriodsFacet copy = new FixAnalysisPeriodsFacet();
+        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/fixings/FixAnalysisResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,77 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.TreeSet;
+
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.utils.KMIndex;
+
+public class FixAnalysisResult
+extends      FixResult
+{
+    protected KMIndex<AnalysisPeriod []> analysisPeriods;
+
+    public FixAnalysisResult() {
+    }
+
+    public FixAnalysisResult(
+        Parameters                 parameters,
+        KMIndex<QWD []>            referenced,
+        KMIndex<QWI []>            outliers,
+        KMIndex<AnalysisPeriod []> analysisPeriods
+    ) {
+        super(parameters, referenced, outliers);
+        this.analysisPeriods = analysisPeriods;
+    }
+
+    public int getUsedSectorsInAnalysisPeriods() {
+        int result = 0;
+        for (KMIndex.Entry<AnalysisPeriod []> entry: analysisPeriods) {
+            for (AnalysisPeriod period: entry.getValue()) {
+                for (int i = 0; i < 4; ++i) {
+                    result |= period.getQSectorAverage(i) != null
+                        ? (1 << i)
+                        : 0;
+                }
+                // XXX: Stop early on result == ~(~0 << 4)) ?
+            }
+        }
+        return result;
+    }
+
+    public Collection<Date> getReferenceEventsDates() {
+        TreeSet<Date> dates = new TreeSet<Date>();
+        for (KMIndex.Entry<QWD []> entry: referenced) {
+            QWD [] values = entry.getValue();
+            for (int i = 0; i < values.length; i++) {
+                dates.add(values[i].date);
+            }
+        }
+        return dates;
+    }
+
+    public Collection<Date> getAnalysisEventsDates(int analysisPeriod) {
+        TreeSet<Date> dates = new TreeSet<Date>();
+        for (KMIndex.Entry<AnalysisPeriod []> entry: analysisPeriods) {
+            QWD [] qwds = entry.getValue()[analysisPeriod].getQWDs();
+            if (qwds == null) {
+                continue;
+            }
+            for (int i = 0; i < qwds.length; i++) {
+                dates.add(qwds[i].date);
+            }
+        }
+        return dates;
+    }
+
+    public KMIndex<AnalysisPeriod []> getAnalysisPeriods() {
+        return analysisPeriods;
+    }
+
+    public void setAnalysisPeriods(KMIndex<AnalysisPeriod []> analysisPeriods) {
+        this.analysisPeriods = analysisPeriods;
+    }
+}
+// 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/fixings/FixAvSectorFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,128 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+import de.intevation.flys.artifacts.model.QWDDateRange;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import de.intevation.flys.utils.KMIndex;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * Facet to show average W values for Q sectors.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixAvSectorFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixAvSectorFacet.class);
+
+    /** Trivial Constructor. */
+    public FixAvSectorFacet() {
+    }
+
+
+    public FixAvSectorFacet(int ndx, String name, String description) {
+        super(
+            ndx,
+            name,
+            description,
+            ComputeType.ADVANCE,
+            null,
+            null);
+    }
+
+
+    /**
+     * Returns the data this facet requires.
+     *
+     * @param artifact the owner artifact.
+     * @param context  the CallContext.
+     *
+     * @return the data as QWD array (QWD[]).
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("FixAvSectorFacet.getData");
+
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+            FixAnalysisAccess access = new FixAnalysisAccess(flys);
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixAnalysisResult result = (FixAnalysisResult) res.getData();
+
+            double currentKm =
+                ((Double)context.getContextValue("currentKm")).doubleValue();
+            KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods();
+            KMIndex.Entry<AnalysisPeriod []> kmPeriodsEntry =
+                kmPeriods.binarySearch(currentKm);
+
+            if (kmPeriodsEntry == null) {
+                logger.warn("No analysis periods found for km '" + currentKm + "'");
+                return null;
+            }
+
+            AnalysisPeriod[] periods = kmPeriodsEntry.getValue();
+
+            if (periods == null) {
+                logger.warn("No analysis periods specified!");
+                return null;
+            }
+
+            QWD[] qwdData = null;
+            int sectorNdx = index & 3;
+            int periodNdx = index >> 2;
+
+            if (periodNdx < periods.length) {
+                qwdData = periods[periodNdx].getQSectorAverages();
+            }
+
+            if (logger.isDebugEnabled()) {
+                int resSize = qwdData != null ? qwdData.length : -1;
+                logger.debug("Found " + resSize + " result elements.");
+            }
+
+            if (qwdData == null) {
+                return null;
+            }
+            return new QWDDateRange(qwdData[sectorNdx], periods[periodNdx].getDateRange());
+        }
+        else {
+            logger.warn("Artifact is no instance of FLYSArtifact.");
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixAvSectorFacet deepCopy() {
+        FixAvSectorFacet copy = new FixAvSectorFacet();
+        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/fixings/FixCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,419 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifacts.common.utils.StringUtils;
+
+import de.intevation.flys.artifacts.access.FixAccess;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+
+import de.intevation.flys.artifacts.model.Calculation;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.FixingsColumn;
+import de.intevation.flys.artifacts.model.FixingsColumnFactory;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.Fixing;
+import de.intevation.flys.artifacts.model.FixingsOverview.IdsFilter;
+
+import de.intevation.flys.artifacts.model.FixingsOverview;
+import de.intevation.flys.artifacts.model.FixingsOverviewFactory;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.utils.DoubleUtil;
+import de.intevation.flys.utils.KMIndex;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+public abstract class FixCalculation
+extends               Calculation
+{
+    private static Logger log = Logger.getLogger(FixCalculation.class);
+
+    public static final double EPSILON = 1e-4;
+
+    public static final String [] STANDARD_COLUMNS = {
+        "km", "chi_sqr", "max_q", "std-dev"
+    };
+
+    protected static class FitResult {
+
+        protected Parameters      parameters;
+        protected KMIndex<QWD []> referenced;
+        protected KMIndex<QWI []> outliers;
+
+        public FitResult() {
+        }
+
+        public FitResult(
+            Parameters      parameters,
+            KMIndex<QWD []> referenced,
+            KMIndex<QWI []> outliers
+        ) {
+            this.parameters = parameters;
+            this.referenced = referenced;
+            this.outliers   = outliers;
+        }
+
+        public Parameters getParameters() {
+            return parameters;
+        }
+
+        public KMIndex<QWD []> getReferenced() {
+            return referenced;
+        }
+
+        public KMIndex<QWI []> getOutliers() {
+            return outliers;
+        }
+    } // class FitResult
+
+    /** Helper class to bundle the meta information of a column
+     *  and the real data.
+     */
+    protected static class Column {
+
+        protected Fixing.Column meta;
+        protected FixingsColumn data;
+        protected int           index;
+
+        public Column() {
+        }
+
+        public Column(Fixing.Column meta, FixingsColumn data, int index) {
+            this.meta  = meta;
+            this.data  = data;
+            this.index = index;
+        }
+
+        public Date getDate() {
+            return meta.getStartTime();
+        }
+
+        public String getDescription() {
+            return meta.getDescription();
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        public boolean getQW(
+            double    km,
+            double [] qs,
+            double [] ws,
+            int       index
+        ) {
+            qs[index] = data.getQ(km);
+            return data.getW(km, ws, index);
+        }
+
+        public boolean getQW(double km, double [] wq) {
+            data.getW(km, wq, 0);
+            if (Double.isNaN(wq[0])) return false;
+            wq[1] = data.getQ(km);
+            return !Double.isNaN(wq[1]);
+        }
+    } // class Column
+
+    /**
+     * Helper class to find the data belonging to meta info more quickly.
+     */
+    protected static class ColumnCache {
+
+        protected Map<Integer, Column> columns;
+
+        public ColumnCache() {
+            columns = new HashMap<Integer, Column>();
+        }
+
+        public Column getColumn(Fixing.Column meta) {
+            Integer key = meta.getId();
+            Column column = columns.get(key);
+            if (column == null) {
+                FixingsColumn data = FixingsColumnFactory
+                    .getInstance()
+                    .getColumnData(meta);
+                if (data != null) {
+                    column = new Column(meta, data, columns.size());
+                    columns.put(key, column);
+                }
+            }
+            return column;
+        }
+    } // class ColumnCache
+
+
+    protected String  river;
+    protected double  from;
+    protected double  to;
+    protected double  step;
+    protected boolean preprocessing;
+    protected String  function;
+    protected int []  events;
+    protected int     qSectorStart;
+    protected int     qSectorEnd;
+
+    public FixCalculation() {
+    }
+
+    public FixCalculation(FixAccess access) {
+        String  river         = access.getRiver();
+        Double  from          = access.getFrom();
+        Double  to            = access.getTo();
+        Double  step          = access.getStep();
+        String  function      = access.getFunction();
+        int []  events        = access.getEvents();
+        Integer qSectorStart  = access.getQSectorStart();
+        Integer qSectorEnd    = access.getQSectorEnd();
+        Boolean preprocessing = access.getPreprocessing();
+
+        if (river == null) {
+            addProblem("fix.missing.river");
+        }
+
+        if (from == null) {
+            addProblem("fix.missing.from");
+        }
+
+        if (to == null) {
+            addProblem("fix.missing.to");
+        }
+
+        if (step == null) {
+            addProblem("fix.missing.step");
+        }
+
+        if (function == null) {
+            addProblem("fix.missing.function");
+        }
+
+        if (events == null || events.length < 1) {
+            addProblem("fix.missing.events");
+        }
+
+        if (qSectorStart == null) {
+            addProblem("fix.missing.qstart.sector");
+        }
+
+        if (qSectorEnd == null) {
+            addProblem("fix.missing.qend.sector");
+        }
+
+        if (preprocessing == null) {
+            addProblem("fix.missing.preprocessing");
+        }
+
+        if (!hasProblems()) {
+            this.river         = river;
+            this.from          = from;
+            this.to            = to;
+            this.step          = step;
+            this.function      = function;
+            this.events        = events;
+            this.qSectorStart  = qSectorStart;
+            this.qSectorEnd    = qSectorEnd;
+            this.preprocessing = preprocessing;
+        }
+    }
+
+    protected static String toString(
+        String [] parameterNames,
+        double [] values
+    ) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < parameterNames.length; ++i) {
+            if (i > 0) sb.append(", ");
+            sb.append(parameterNames[i]).append(": ").append(values[i]);
+        }
+        return sb.toString();
+    }
+
+    protected Filter createFilter() {
+        return new IdsFilter(events);
+    }
+
+    protected List<Column> getEventColumns(
+        FixingsOverview overview,
+        ColumnCache     cc
+    ) {
+        FixingsColumnFactory fcf = FixingsColumnFactory.getInstance();
+
+        Filter filter = createFilter();
+
+        List<Fixing.Column> metas = overview.filter(null, filter);
+
+        List<Column> columns = new ArrayList<Column>(metas.size());
+
+        for (Fixing.Column meta: metas) {
+
+            Column data = cc.getColumn(meta);
+            if (data == null) {
+                addProblem("fix.cannot.load.data");
+            }
+            else {
+                columns.add(data);
+            }
+        }
+
+        return columns;
+    }
+
+    protected FitResult doFitting(
+        FixingsOverview overview,
+        ColumnCache     cc,
+        Function        func
+    ) {
+        boolean debug = log.isDebugEnabled();
+
+        final List<Column> eventColumns = getEventColumns(overview, cc);
+
+        if (eventColumns.size() < 2) {
+            addProblem("fix.too.less.data.columns");
+            return null;
+        }
+
+        final double  [] qs = new double[eventColumns.size()];
+        final double  [] ws = new double[qs.length];
+        final boolean [] interpolated = new boolean[ws.length];
+
+        Fitting.QWDFactory qwdFactory = new Fitting.QWDFactory() {
+            @Override
+            public QWD create(double q, double w) {
+                // Check all the event columns for close match
+                // and take the description and the date from meta.
+                for (int i = 0; i < qs.length; ++i) {
+                    if (Math.abs(qs[i]-q) < EPSILON
+                    &&  Math.abs(ws[i]-w) < EPSILON) {
+                        Column column = eventColumns.get(i);
+                        return new QWD(
+                            qs[i], ws[i],
+                            column.getDescription(),
+                            column.getDate(),
+                            interpolated[i],
+                            0d,
+                            column.getIndex());
+                    }
+                }
+                log.warn("cannot find column for (" + q + ", " + w + ")");
+                return new QWD(q, w);
+            }
+        };
+
+        Fitting fitting = new Fitting(func, qwdFactory, preprocessing);
+
+        String [] parameterNames = func.getParameterNames();
+
+        Parameters results =
+            new Parameters(
+                StringUtils.join(STANDARD_COLUMNS, parameterNames));
+
+        boolean invalid = false;
+
+        double [] kms = DoubleUtil.explode(from, to, step / 1000.0);
+
+        if (debug) {
+            log.debug("number of kms: " + kms.length);
+        }
+
+        KMIndex<QWI []> outliers   = new KMIndex<QWI []>();
+        KMIndex<QWD []> referenced = new KMIndex<QWD []>(kms.length);
+
+        int kmIndex             = results.columnIndex("km");
+        int chiSqrIndex         = results.columnIndex("chi_sqr");
+        int maxQIndex           = results.columnIndex("max_q");
+        int stdDevIndex         = results.columnIndex("std-dev");
+        int [] parameterIndices = results.columnIndices(parameterNames);
+
+        int numFailed = 0;
+
+        for (int i = 0; i < kms.length; ++i) {
+            double km = kms[i];
+
+            // Fill Qs and Ws from event columns.
+            for (int j = 0; j < ws.length; ++j) {
+                interpolated[j] = !eventColumns.get(j).getQW(km, qs, ws, j);
+            }
+
+            fitting.reset();
+
+            if (!fitting.fit(qs, ws)) {
+                ++numFailed;
+                addProblem(km, "fix.fitting.failed");
+                continue;
+            }
+
+            referenced.add(km, fitting.referencedToArray());
+
+            if (fitting.hasOutliers()) {
+                outliers.add(km, fitting.outliersToArray());
+            }
+
+            int row = results.newRow();
+            double [] values = fitting.getParameters();
+
+            results.set(row, kmIndex, km);
+            results.set(row, chiSqrIndex, fitting.getChiSquare());
+            results.set(row, stdDevIndex, fitting.getStandardDeviation());
+            results.set(row, maxQIndex,   fitting.getMaxQ());
+            invalid |= results.set(row, parameterIndices, values);
+
+            if (debug) {
+                log.debug("km: "+km+" " + toString(parameterNames, values));
+            }
+        }
+
+        if (debug) {
+            log.debug("success: " + (kms.length - numFailed));
+            log.debug("failed: " + numFailed);
+        }
+
+        if (invalid) {
+            addProblem("fix.invalid.values");
+            results.removeNaNs();
+        }
+
+        outliers.sort();
+        referenced.sort();
+
+        return new FitResult(
+            results,
+            referenced,
+            outliers);
+    }
+
+    public CalculationResult calculate() {
+        FixingsOverview overview =
+            FixingsOverviewFactory.getOverview(river);
+
+        if (overview == null) {
+            addProblem("fix.no.overview.available");
+        }
+
+        Function func = FunctionFactory.getInstance()
+            .getFunction(function);
+
+        if (func == null) {
+            addProblem("fix.invalid.function.name");
+        }
+
+        if (hasProblems()) {
+            return new CalculationResult(this);
+        }
+
+        return innerCalculate(overview, func);
+    }
+
+    protected abstract CalculationResult innerCalculate(
+        FixingsOverview overview,
+        Function        function
+    );
+}
+// 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/fixings/FixDerivateFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,121 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * Facet to show the W|Q values.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixDerivateFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixDerivateFacet.class);
+
+
+    /** Trivial Constructor. */
+    public FixDerivateFacet() {
+    }
+
+
+    /**
+     * @param name
+     */
+    public FixDerivateFacet(String name, String description) {
+        super(0, name, description, ComputeType.ADVANCE, null, null);
+    }
+
+    public FixDerivateFacet(int index, String name, String description) {
+        super(index, name, description, ComputeType.ADVANCE, null, null);
+    }
+
+
+    /**
+     * 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) {
+
+        logger.debug("FixDerivateFacet.getData");
+        if (!(artifact instanceof FLYSArtifact)) {
+            logger.debug("Not an instance of FixationArtifact.");
+            return null;
+        }
+
+        FLYSArtifact flys = (FLYSArtifact)artifact;
+        FixAnalysisAccess access = new FixAnalysisAccess(flys);
+
+        CalculationResult res =
+            (CalculationResult) flys.compute(context,
+                                             ComputeType.ADVANCE,
+                                             false);
+
+        FixAnalysisResult result = (FixAnalysisResult) res.getData();
+        double currentKm =
+            ((Double)context.getContextValue("currentKm")).doubleValue();
+
+        String function = access.getFunction();
+        Function ff = FunctionFactory.getInstance().getFunction(function);
+        Function.Derivative fd = ff.getDerivative();
+
+        Parameters params = result.getParameters();
+        double maxQ = FixFacetUtils.getMaxQ(params, currentKm);
+
+        String[] paramNames = ff.getParameterNames();
+
+        double[] coeffs = params.interpolate("km", currentKm, paramNames);
+        if (coeffs == null) {
+            logger.warn("getData: coeffs == null");
+            return null;
+        }
+
+        de.intevation.flys.artifacts.math.Function mf =
+            fd.instantiate(coeffs);
+
+        FixFunction fix = new FixFunction(
+            "",
+            fd.getDescription(),
+            mf,
+            maxQ);
+
+        return fix;
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixDerivateFacet deepCopy() {
+        FixDerivateFacet copy = new FixDerivateFacet();
+        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/fixings/FixDeviationFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,104 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * Facet to show the W|Q values.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixDeviationFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixDeviationFacet.class);
+
+    public static final String [] STD_DEV_COLUMN = { "std-dev" };
+
+    /** Trivial Constructor. */
+    public FixDeviationFacet() {
+    }
+
+
+    /**
+     * @param name
+     */
+    public FixDeviationFacet(String name, String description) {
+        super(0, name, description, ComputeType.ADVANCE, null, null);
+    }
+
+    public FixDeviationFacet(int index, String name, String description) {
+        super(index, name, description, ComputeType.ADVANCE, null, null);
+    }
+
+
+    /**
+     * 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) {
+        logger.debug("FixDeviationFacet.getData");
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+            FixAnalysisAccess access = new FixAnalysisAccess(flys);
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixAnalysisResult result = (FixAnalysisResult) res.getData();
+            double currentKm =
+                ((Double)context.getContextValue("currentKm")).doubleValue();
+
+            Parameters params = result.getParameters();
+
+            double[] stdDev =
+                params.interpolate("km", currentKm, STD_DEV_COLUMN);
+
+            if (stdDev == null) {
+                logger.warn("getData: stdDev == null at km " + currentKm);
+                return null;
+            }
+
+            return stdDev;
+        }
+        else {
+            logger.debug("Not an instance of FixationArtifact.");
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixDerivateFacet deepCopy() {
+        FixDerivateFacet copy = new FixDerivateFacet();
+        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/fixings/FixFacetUtils.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,18 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.flys.artifacts.model.Parameters;
+
+public final class FixFacetUtils {
+
+    public static final String [] MAX_Q_COLUMN = { "max_q" };
+
+    public static double getMaxQ(Parameters params, double km) {
+        double [] maxQ = params.interpolate("km", km, MAX_Q_COLUMN);
+        if (maxQ == null) {
+            return 1000d;
+        }
+        double mQ = Math.min(10000d, Math.abs(maxQ[0]));
+        return mQ + 0.05*mQ;
+    }
+}
+// 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/fixings/FixFunction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,40 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.flys.artifacts.math.Function;
+
+public class FixFunction
+{
+    protected String   name;
+    protected String   description;
+    protected Function function;
+    protected double   maxQ;
+
+    public FixFunction (
+        String   name,
+        String   description,
+        Function function,
+        double   maxQ
+    ) {
+        this.name        = name;
+        this.description = description;
+        this.function    = function;
+        this.maxQ        = maxQ;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public Function getFunction() {
+        return function;
+    }
+
+    public double getMaxQ() {
+        return maxQ;
+    }
+}
+// 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/fixings/FixLongitudinalAnalysisFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,108 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.utils.KMIndex;
+
+/**
+ * Facet to show average W values for Q sectors.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixLongitudinalAnalysisFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixLongitudinalAnalysisFacet.class);
+
+    /** Trivial Constructor. */
+    public FixLongitudinalAnalysisFacet() {
+    }
+
+
+    public FixLongitudinalAnalysisFacet(
+        int ndx,
+        String name,
+        String description)
+    {
+        super(
+            ndx,
+            name,
+            description,
+            ComputeType.ADVANCE,
+            null,
+            null);
+    }
+
+
+    /**
+     * Returns the data this facet requires.
+     *
+     * @param artifact the owner artifact.
+     * @param context  the CallContext.
+     *
+     * @return the data as KMIndex.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("FixLongitudinalAnalysisFacet.getData");
+
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixAnalysisResult result = (FixAnalysisResult) res.getData();
+
+            KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods();
+            if (kmPeriods == null) {
+                logger.warn("No analysis periods found.");
+                return null;
+            }
+            int periodNdx = index >> 8;
+            int qwdNdx = index & 255;
+            KMIndex<QWD> resPeriods =
+                    new KMIndex<QWD>();
+            for (KMIndex.Entry<AnalysisPeriod[]> entry: kmPeriods) {
+                AnalysisPeriod ap = entry.getValue()[periodNdx];
+                QWD[] qwds = ap.qwds;
+                for(int i = 0; i < qwds.length; i++) {
+                    if(qwds[i].getIndex() == qwdNdx) {
+                        resPeriods.add(entry.getKm(), qwds[i]);
+                    }
+                }
+            }
+
+
+            return resPeriods;
+        }
+        else {
+            logger.warn("Artifact is no instance of FLYSArtifact.");
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixLongitudinalAnalysisFacet deepCopy() {
+        FixLongitudinalAnalysisFacet copy = new FixLongitudinalAnalysisFacet();
+        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/fixings/FixLongitudinalAvSectorFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,97 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.utils.KMIndex;
+
+public class FixLongitudinalAvSectorFacet
+extends DataFacet
+implements FacetTypes {
+
+    /** House logger. */
+    private static Logger logger =
+        Logger.getLogger(FixLongitudinalAvSectorFacet.class);
+
+    /** Trivial Constructor. */
+    public FixLongitudinalAvSectorFacet() {
+    }
+
+
+    public FixLongitudinalAvSectorFacet(
+        int ndx,
+        String name,
+        String description)
+    {
+        super(
+            ndx,
+            name,
+            description,
+            ComputeType.ADVANCE,
+            null,
+            null);
+    }
+
+
+    /**
+     * Returns the data this facet requires.
+     *
+     * @param artifact the owner artifact.
+     * @param context  the CallContext.
+     *
+     * @return the data as KMIndex.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("FixLongitudinalAvSectorFacet.getData");
+
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixAnalysisResult result = (FixAnalysisResult) res.getData();
+
+            KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods();
+            if (kmPeriods == null) {
+                logger.warn("No analysis periods found.");
+                return null;
+            }
+            int periodNdx = index >> 2;
+            KMIndex<AnalysisPeriod> resPeriods =
+                    new KMIndex<AnalysisPeriod>();
+            for (KMIndex.Entry<AnalysisPeriod[]> entry: kmPeriods) {
+                AnalysisPeriod ap = entry.getValue()[periodNdx];
+                resPeriods.add(entry.getKm(), ap);
+            }
+
+            return resPeriods;
+        }
+        else {
+            logger.warn("Artifact is no instance of FLYSArtifact.");
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixLongitudinalAvSectorFacet deepCopy() {
+        FixLongitudinalAvSectorFacet copy = new FixLongitudinalAvSectorFacet();
+        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/fixings/FixLongitudinalDeviationFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,118 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import de.intevation.flys.utils.KMIndex;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Facet to show average W values for Q sectors.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixLongitudinalDeviationFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixLongitudinalDeviationFacet.class);
+
+    /** Trivial Constructor. */
+    public FixLongitudinalDeviationFacet() {
+    }
+
+
+    public FixLongitudinalDeviationFacet(
+        int ndx,
+        String name,
+        String description)
+    {
+        super(
+            ndx,
+            name,
+            description,
+            ComputeType.ADVANCE,
+            null,
+            null);
+    }
+
+
+    /**
+     * Returns the data this facet requires.
+     *
+     * @param artifact the owner artifact.
+     * @param context  the CallContext.
+     *
+     * @return the data as KMIndex.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("FixLongitudinalDeviationFacet.getData");
+
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+            FixAnalysisAccess access = new FixAnalysisAccess(flys);
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixAnalysisResult result = (FixAnalysisResult) res.getData();
+
+            KMIndex<AnalysisPeriod []> kmPeriods = result.getAnalysisPeriods();
+
+            if (kmPeriods == null) {
+                logger.warn("No analysis periods found.");
+                return null;
+            }
+
+            Parameters params = result.getParameters();
+
+            KMIndex<double[]> kmIndex = new KMIndex<double[]>();
+            for (KMIndex.Entry<AnalysisPeriod[]> entry: kmPeriods) {
+                double km = entry.getKm();
+                double[] stdDev =
+                    params.interpolate("km", km, new String[] {"std-dev"});
+
+                if(stdDev == null) {
+                    logger.warn("getData: stdDev == null");
+                    continue;
+                }
+                kmIndex.add(km, stdDev);
+            }
+
+            return kmIndex;
+        }
+        else {
+            logger.warn("Artifact is no instance of FLYSArtifact.");
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixLongitudinalDeviationFacet deepCopy() {
+        FixLongitudinalDeviationFacet copy = new FixLongitudinalDeviationFacet();
+        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/fixings/FixLongitudinalReferenceFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,115 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import de.intevation.flys.utils.KMIndex;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * Facet to show average W values for Q sectors.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixLongitudinalReferenceFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixLongitudinalReferenceFacet.class);
+
+    /** Trivial Constructor. */
+    public FixLongitudinalReferenceFacet() {
+    }
+
+
+    public FixLongitudinalReferenceFacet(
+        int ndx,
+        String name,
+        String description)
+    {
+        super(
+            ndx,
+            name,
+            description,
+            ComputeType.ADVANCE,
+            null,
+            null);
+    }
+
+
+    /**
+     * Returns the data this facet requires.
+     *
+     * @param artifact the owner artifact.
+     * @param context  the CallContext.
+     *
+     * @return the data as KMIndex.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("FixLongitudinalReferenceFacet.getData");
+
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+            FixAnalysisAccess access = new FixAnalysisAccess(flys);
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixAnalysisResult result = (FixAnalysisResult) res.getData();
+
+            KMIndex<QWD []> kmReference = result.getReferenced();
+
+            if (kmReference == null) {
+                logger.warn("No references found.");
+                return null;
+            }
+
+            int qwdNdx = index & 255;
+            KMIndex<QWD> resReference =
+                    new KMIndex<QWD>();
+            for (KMIndex.Entry<QWD[]> entry: kmReference) {
+                QWD[] qwds = entry.getValue();
+                for(int i = 0; i < qwds.length; i++) {
+                    if(qwds[i].getIndex() == qwdNdx) {
+                        resReference.add(entry.getKm(), qwds[i]);
+                    }
+                }
+            }
+            return resReference;
+        }
+        else {
+            logger.warn("Artifact is no instance of FLYSArtifact.");
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixLongitudinalReferenceFacet deepCopy() {
+        FixLongitudinalReferenceFacet copy =
+            new FixLongitudinalReferenceFacet();
+        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/fixings/FixOutlierFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,103 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.utils.KMIndex;
+
+/**
+ * Facet to show the outliers in a fix calculation.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixOutlierFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixOutlierFacet.class);
+
+    /** Trivial Constructor. */
+    public FixOutlierFacet() {
+    }
+
+
+    /**
+     * @param name
+     */
+    public FixOutlierFacet(String name, String description) {
+        super(0, name, description, ComputeType.ADVANCE, null, null);
+    }
+
+    public FixOutlierFacet(int index, String name, String description) {
+        super(index, name, description, ComputeType.ADVANCE, null, null);
+    }
+
+
+    /**
+     * Returns the data this facet requires.
+     *
+     * @param artifact the owner artifact; needs to be a FLYSArtifact.
+     * @param context  the CallContext; required to retrieve the value of
+     * <i>currentKm</i>.
+     *
+     * @return an array of QW objects or null.
+     */
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("FixOutlierFacet.getData");
+
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixResult result = (FixResult) res.getData();
+            double currentKm =
+                ((Double)context.getContextValue("currentKm")).doubleValue();
+
+            KMIndex<QWI []>       kmQWs    = result.getOutliers();
+            KMIndex.Entry<QWI []> qwsEntry = kmQWs.binarySearch(currentKm);
+
+            QWI [] qws = null;
+            if (qwsEntry != null) {
+                qws = qwsEntry.getValue();
+
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Found " + (qws != null ? qws.length : 0)
+                        + " KMIndex.Entry for km " + currentKm);
+                }
+            }
+            else {
+                logger.debug("Found no KMIndex.Entry for km " + currentKm);
+            }
+
+            return qws;
+        }
+
+        logger.warn("Not an instance of FLYSArtifact.");
+        return null;
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixOutlierFacet deepCopy() {
+        FixOutlierFacet copy = new FixOutlierFacet();
+        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/fixings/FixRealizingCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,162 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.flys.artifacts.access.FixRealizingAccess;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.FixingsOverview;
+import de.intevation.flys.artifacts.model.RiverFactory;
+import de.intevation.flys.artifacts.model.Segment;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.model.River;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class FixRealizingCalculation
+extends      FixCalculation
+{
+    private static Logger log =
+        Logger.getLogger(FixRealizingCalculation.class);
+
+    protected boolean       isQ;
+    protected List<Segment> segments;
+
+    public FixRealizingCalculation() {
+    }
+
+    public FixRealizingCalculation(FixRealizingAccess access) {
+        super(access);
+
+        Boolean       isQ      = access.isQ();
+        List<Segment> segments = access.getSegments();
+
+        if (isQ == null) {
+            // TODO: i18n
+            addProblem("fix.realize.missing.is.q");
+        }
+
+        if (segments == null || segments.isEmpty()) {
+            // TODO: i18n
+            addProblem("fix.realize.missing.segments");
+        }
+
+        River r = RiverFactory.getRiver(river);
+
+        if (r == null) {
+            // TODO: i18n
+            addProblem("fix.no.such.river");
+        }
+
+        if (!hasProblems()) {
+            this.isQ      = isQ;
+            this.segments = segments;
+
+            // Convert from W to Q
+            Segment.setReferencePointConvertQ(segments, r, isQ, this);
+        }
+    }
+
+    @Override
+    protected CalculationResult innerCalculate(
+        FixingsOverview overview,
+        Function        func
+    ) {
+        ColumnCache cc = new ColumnCache();
+        FitResult fitResult = doFitting(overview, cc, func);
+
+        if (fitResult == null) {
+            return new CalculationResult(this);
+        }
+
+        Segment segment = segments.get(0);
+        int numResults = segment.numValues();
+
+        WQKms [] results = new WQKms[numResults];
+        for (int i = 0; i < results.length; ++i) {
+            results[i] = new WQKms();
+        }
+
+        Parameters parameters = fitResult.getParameters();
+
+        int kmIndex = parameters.columnIndex("km");
+        int [] parameterIndices =
+            parameters.columnIndices(func.getParameterNames());
+
+        double [] parameterValues = new double[parameterIndices.length];
+
+        for (int row = 0, R = parameters.size(); row < R; ++row) {
+            double km = parameters.get(row, kmIndex);
+
+            if (!segment.inside(km)) {
+                Segment nextSeg = null;
+                for (Segment seg: segments) {
+                    if (seg.inside(km)) {
+                        nextSeg = seg;
+                        break;
+                    }
+                }
+                if (nextSeg == null) {
+                    // TODO: i18n
+                    addProblem(km, "fix.cannot.find.segment");
+                    continue;
+                }
+                segment = nextSeg;
+            }
+
+            parameters.get(row, parameterIndices, parameterValues);
+
+            de.intevation.flys.artifacts.math.Function instance =
+                func.instantiate(parameterValues);
+
+            double [] values = segment.getValues();
+            for (int i = 0; i < numResults; ++i) {
+                double q = values[i];
+                double w = instance.value(q);
+
+                if (Double.isNaN(w)) {
+                    // TODO: i18n
+                    addProblem(km, "fix.cannot.calculate.function", q);
+                }
+                else {
+                    results[i].add(w, q, km);
+                }
+            }
+        }
+
+        // name the curves
+        for (int i = 0; i < results.length; ++i) {
+            results[i].setName(createName(i));
+        }
+
+        FixRealizingResult frr = new FixRealizingResult(
+            parameters,
+            fitResult.getReferenced(),
+            fitResult.getOutliers(),
+            results);
+
+        return new CalculationResult(frr, this);
+    }
+
+    protected String createName(int index) {
+        // TODO: i18n
+        StringBuilder sb = new StringBuilder(isQ ? "Q" : "W");
+        sb.append(" benutzerdefiniert (");
+        for (int i = 0, N = segments.size(); i < N; ++i) {
+            if (i > 0) {
+                sb.append("; ");
+            }
+            Segment segment = segments.get(i);
+            double [] backup = segment.getBackup();
+            double [] values = segment.getValues();
+            sb.append((backup != null ? backup : values)[index]);
+        }
+        sb.append(')');
+        return sb.toString();
+    }
+}
+// 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/fixings/FixRealizingResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,35 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.flys.artifacts.model.WQKms;
+
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.utils.KMIndex;
+
+public class FixRealizingResult
+extends      FixResult
+{
+    public WQKms [] wqkms;
+
+    public FixRealizingResult() {
+    }
+
+    public FixRealizingResult(
+        Parameters      parameters,
+        KMIndex<QWD []> referenced,
+        KMIndex<QWI []> outliers,
+        WQKms []        wqkms
+    ) {
+        super(parameters, referenced, outliers);
+        this.wqkms = wqkms;
+    }
+
+    public WQKms [] getWQKms() {
+        return wqkms;
+    }
+
+    public void setWQKms(WQKms [] wqkms) {
+        this.wqkms = wqkms;
+    }
+}
+// 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/fixings/FixReferenceEventsFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,102 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.utils.KMIndex;
+
+
+/**
+ * Facet to show W values for Q values at km for a date.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixReferenceEventsFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixReferenceEventsFacet.class);
+
+    /** Trivial Constructor. */
+    public FixReferenceEventsFacet() {
+    }
+
+
+    /**
+     * @param name
+     */
+    public FixReferenceEventsFacet(int index, String name, String description) {
+        super(index,
+             name,
+             description,
+             ComputeType.ADVANCE,
+             null,
+             null);
+    }
+
+
+    /**
+     * 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) {
+        logger.debug("FixReferenceEventsFacet.getData");
+
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixResult result = (FixResult) res.getData();
+            double currentKm =
+                ((Double)context.getContextValue("currentKm")).doubleValue();
+
+            KMIndex<QWD []> kmQWs = result.getReferenced();
+            KMIndex.Entry<QWD []> kmQWsEntry = kmQWs.binarySearch(currentKm);
+            QWD[] qwds = null;
+            if (kmQWsEntry != null) {
+                int ndx = index & 255;
+                qwds = kmQWsEntry.getValue();
+                for (int i = 0; i < qwds.length; i++) {
+                    if (qwds[i].getIndex() == ndx) {
+                        return qwds[i];
+                    }
+                }
+                return null;
+            }
+            return null;
+        }
+        else {
+            logger.debug("Not an instance of FixationArtifact.");
+            return null;
+        }
+    }
+
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixReferenceEventsFacet deepCopy() {
+        FixReferenceEventsFacet copy = new FixReferenceEventsFacet();
+        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/fixings/FixResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,53 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.utils.KMIndex;
+
+import java.io.Serializable;
+
+public class FixResult
+implements   Serializable
+{
+    protected Parameters      parameters;
+    protected KMIndex<QWD []> referenced;
+    protected KMIndex<QWI []> outliers;
+
+    public FixResult() {
+    }
+
+    public FixResult(
+        Parameters      parameters,
+        KMIndex<QWD []> referenced,
+        KMIndex<QWI []> outliers
+    ) {
+        this.parameters = parameters;
+        this.referenced = referenced;
+        this.outliers   = outliers;
+    }
+
+    public KMIndex<QWD []> getReferenced() {
+        return referenced;
+    }
+
+    public void setReferenced(KMIndex<QWD []> referenced) {
+        this.referenced = referenced;
+    }
+
+    public KMIndex<QWI []> getOutliers() {
+        return outliers;
+    }
+
+    public void setOutliers(KMIndex<QWI []> outliers) {
+        this.outliers = outliers;
+    }
+
+    public Parameters getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(Parameters parameters) {
+        this.parameters = parameters;
+    }
+}
+// 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/fixings/FixWQCurveFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,126 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Facet to show the W|Q values.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixWQCurveFacet
+extends      DataFacet
+implements   FacetTypes {
+
+    /** House logger. */
+    private static Logger logger = Logger.getLogger(FixWQCurveFacet.class);
+
+    /** Trivial Constructor. */
+    public FixWQCurveFacet() {
+    }
+
+
+    /**
+     * @param description Description of the facet.
+     */
+    public FixWQCurveFacet(String description) {
+        super(0, FIX_WQ_CURVE, description, ComputeType.ADVANCE, null, null);
+    }
+
+    public FixWQCurveFacet(int index, String description) {
+        super(index, FIX_WQ_CURVE, description, ComputeType.ADVANCE, null, null);
+    }
+
+
+    /**
+     * 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) {
+        logger.debug("FixWQCurveFacet.getData");
+        if (artifact instanceof FLYSArtifact) {
+            FLYSArtifact flys = (FLYSArtifact)artifact;
+            FixAnalysisAccess access = new FixAnalysisAccess(flys);
+
+            CalculationResult res =
+                (CalculationResult) flys.compute(context,
+                                                 ComputeType.ADVANCE,
+                                                 false);
+
+            FixResult result = (FixResult) res.getData();
+            double currentKm =
+                ((Double)context.getContextValue("currentKm")).doubleValue();
+
+            logger.debug("getData: km = " + currentKm);
+
+            String function = access.getFunction();
+            Function ff = FunctionFactory.getInstance().getFunction(function);
+
+            if (ff == null) {
+                logger.warn("getData: ff == null");
+                return null;
+            }
+
+            Parameters params = result.getParameters();
+            String[] paramNames = ff.getParameterNames();
+
+            double [] coeffs = params.interpolate("km", currentKm, paramNames);
+
+            if (coeffs == null) {
+                logger.warn("getData: coeffs == null");
+                return null;
+            }
+
+            de.intevation.flys.artifacts.math.Function mf =
+                ff.instantiate(coeffs);
+
+            double maxQ = FixFacetUtils.getMaxQ(params, currentKm);
+            logger.debug("getData: maxQ = " + maxQ);
+
+            FixFunction fix = new FixFunction(
+                ff.getName(),
+                ff.getDescription(),
+                mf,
+                maxQ);
+
+            return fix;
+        }
+        else {
+            logger.debug("Not an instance of FixationArtifact.");
+            return null;
+        }
+    }
+
+    /**
+     * Create a deep copy of this Facet.
+     * @return a deep copy.
+     */
+    @Override
+    public FixWQCurveFacet deepCopy() {
+        FixWQCurveFacet copy = new FixWQCurveFacet();
+        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/fixings/FixWaterlevelFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,49 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.WaterlevelFacet;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+public class FixWaterlevelFacet
+extends      WaterlevelFacet
+{
+    public FixWaterlevelFacet() {
+    }
+
+    public FixWaterlevelFacet(int index, String name, String description) {
+        super(index, name, description, ComputeType.ADVANCE, null, null);
+    }
+
+    public FixWaterlevelFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateID,
+        String      hash
+    ) {
+        super(index, name, description, type, hash, stateID);
+    }
+
+    @Override
+    protected WQKms [] getWQKms(CalculationResult res) {
+        FixRealizingResult fr = (FixRealizingResult)res.getData();
+        return fr != null ? fr.getWQKms() : null;
+    }
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        FixWaterlevelFacet copy = new FixWaterlevelFacet();
+        copy.set(this);
+        copy.type    = type;
+        copy.hash    = hash;
+        copy.stateId = stateId;
+        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/fixings/QWD.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,38 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import java.util.Date;
+
+public class QWD
+extends      QWI
+{
+    protected double deltaW;
+
+    public QWD() {
+    }
+
+    public QWD(double q, double w) {
+        super(q, w);
+    }
+
+    public QWD(
+        double  q,
+        double  w,
+        String  description,
+        Date    date,
+        boolean interpolated,
+        double  deltaW,
+        int     index
+    ) {
+        super(q, w, description, date, interpolated, index);
+        this.deltaW = deltaW;
+    }
+
+    public double getDeltaW() {
+        return deltaW;
+    }
+
+    public void setDeltaW(double deltaW) {
+        this.deltaW = deltaW;
+    }
+}
+// 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/fixings/QWI.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,69 @@
+package de.intevation.flys.artifacts.model.fixings;
+
+import de.intevation.flys.artifacts.model.QW;
+
+import java.util.Date;
+
+public class QWI
+extends      QW
+{
+    protected String  description;
+    protected Date    date;
+    protected boolean interpolated;
+    protected int     index;
+
+    public QWI() {
+    }
+
+    public QWI(double q, double w) {
+        super(q, w);
+    }
+
+    public QWI(
+        double  q,
+        double  w,
+        String  description,
+        Date    date,
+        boolean interpolated,
+        int     index
+    ) {
+        super(q, w);
+        this.description  = description;
+        this.date         = date;
+        this.interpolated = interpolated;
+        this.index        = index;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public boolean getInterpolated() {
+        return interpolated;
+    }
+
+    public void setInterpolated(boolean interpolated) {
+        this.interpolated = interpolated;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+}
+// 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/map/WMSDBLayerFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,106 @@
+package de.intevation.flys.artifacts.model.map;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+public class WMSDBLayerFacet extends WMSLayerFacet {
+
+    protected String data;
+    protected String filter;
+    protected String labelItem;
+    protected String geometryType;
+    protected String connection;
+    protected String connectionType;
+
+
+    public WMSDBLayerFacet() {
+        super();
+    }
+
+
+    public WMSDBLayerFacet(int index, String name, String description) {
+        this(index, name, description, ComputeType.FEED, null, null);
+    }
+
+
+    public WMSDBLayerFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateId,
+        String      hash
+
+    ) {
+        super(index, name, description, type, stateId, hash);
+    }
+
+
+    public WMSDBLayerFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateId,
+        String      hash,
+        String      url
+    ) {
+        super(index, name, description, type, stateId, hash, url);
+    }
+
+
+    public void setFilter(String filter) {
+        this.filter = filter;
+    }
+
+    public String getFilter() {
+        return filter;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setGeometryType(String geometryType) {
+        this.geometryType = geometryType;
+    }
+
+    public String getGeometryType() {
+        return geometryType;
+    }
+
+    public void setConnection(String connection) {
+        this.connection = connection;
+    }
+
+    public String getConnection() {
+        return connection;
+    }
+
+    public void setConnectionType(String connectionType) {
+        this.connectionType = connectionType;
+    }
+
+    public String getConnectionType() {
+        return connectionType;
+    }
+
+    public void setLabelItem(String labelItem) {
+        this.labelItem = labelItem;
+    }
+
+    public String getLabelItem() {
+        return labelItem;
+    }
+
+
+    @Override
+    public boolean isQueryable() {
+        return true;
+    }
+}
+// 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/map/WMSLayerFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,184 @@
+package de.intevation.flys.artifacts.model.map;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+import de.intevation.artifactdatabase.state.DefaultFacet;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.utils.GeometryUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+public class WMSLayerFacet
+extends      DefaultFacet
+{
+    protected ComputeType  type;
+    protected List<String> layers;
+    protected String       stateId;
+    protected String       hash;
+    protected String       url;
+    protected Envelope     extent;
+    protected Envelope     originalExtent;
+    protected String       srid;
+
+
+    private static final Logger logger = Logger.getLogger(WMSLayerFacet.class);
+
+    public WMSLayerFacet() {
+    }
+
+
+    public WMSLayerFacet(int index, String name, String description) {
+        this(index, name, description, ComputeType.FEED, null, null);
+    }
+
+
+    public WMSLayerFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateId,
+        String      hash
+
+    ) {
+        super(index, name, description);
+        this.layers  = new ArrayList<String>();
+        this.type    = type;
+        this.stateId = stateId;
+        this.hash    = hash;
+    }
+
+
+    public WMSLayerFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateId,
+        String      hash,
+        String      url
+    ) {
+        this(index, name, description, type, stateId, hash);
+        this.url = url;
+    }
+
+
+    public void addLayer(String name) {
+        if (name != null && name.length() > 0) {
+            layers.add(name);
+        }
+    }
+
+
+    public List<String> getLayers() {
+        return layers;
+    }
+
+
+    public void removeLayer(String layer) {
+        if (layers != null) {
+            layers.remove(layer);
+        }
+    }
+
+
+    public void setExtent(Envelope extent) {
+        if (extent != null) {
+            this.extent = extent;
+        }
+        else {
+            logger.debug("setExtent(): extent is null");
+        }
+    }
+
+
+    public Envelope getExtent() {
+        return extent;
+    }
+
+
+    public void setOriginalExtent(Envelope originalExtent) {
+        this.originalExtent = originalExtent;
+    }
+
+
+    public Envelope getOriginalExtent() {
+        return originalExtent;
+    }
+
+
+    public void setSrid(String srid) {
+        if (srid != null) {
+            this.srid = srid;
+        }
+    }
+
+
+    public String getSrid() {
+        return srid;
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        return null;
+    }
+
+
+    @Override
+    public Node toXML(Document doc) {
+        ElementCreator ec = new ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element facet = ec.create("facet");
+        ec.addAttr(facet, "description", description, true);
+        ec.addAttr(facet, "index", String.valueOf(index), true);
+        ec.addAttr(facet, "name", name, true);
+        ec.addAttr(facet, "url", url, true);
+        ec.addAttr(facet, "layers", layers.get(0), true);
+        ec.addAttr(facet, "srid", srid != null ? srid : "", true);
+        ec.addAttr(facet, "extent", originalExtent != null
+            ? GeometryUtils.jtsBoundsToOLBounds(originalExtent)
+            : "", true);
+        ec.addAttr(facet, "queryable", String.valueOf(isQueryable()), true);
+
+        return facet;
+    }
+
+
+    public boolean isQueryable() {
+        return false;
+    }
+
+
+    @Override
+    public Facet deepCopy() {
+        WMSLayerFacet copy = new WMSLayerFacet();
+        copy.set(this);
+
+        copy.type    = type;
+        copy.layers  = new ArrayList<String>(layers);
+        copy.stateId = stateId;
+        copy.hash    = hash;
+        copy.url     = url;
+        copy.extent  = extent;
+        copy.srid    = srid;
+
+        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/map/WSPLGENCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,83 @@
+package de.intevation.flys.artifacts.model.map;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.flys.artifacts.model.Calculation;
+
+
+public class WSPLGENCalculation extends Calculation {
+
+    private static final Logger log = Logger.getLogger(WSPLGENCalculation.class);
+
+    protected Map<Integer, String> errors;
+    protected Map<Integer, String> warnings;
+
+
+    public WSPLGENCalculation() {
+        errors   = new HashMap<Integer, String>();
+        warnings = new HashMap<Integer, String>();
+    }
+
+
+    public void addError(Integer key, String msg) {
+        log.debug("New error: (" + key + ") " + msg);
+        errors.put(key, msg);
+    }
+
+
+    public void addWarning(Integer key, String msg) {
+        log.debug("New warning: (" + key + ") " + msg);
+        warnings.put(key, msg);
+    }
+
+
+    public int numErrors() {
+        return errors.size();
+    }
+
+
+    public int numWarnings() {
+        return warnings.size();
+    }
+
+
+    @Override
+    public void toXML(Document document, CallMeta meta) {
+        Element root = document.createElement("problems");
+
+        if (numErrors() > 0) {
+            Set<Map.Entry<Integer, String>> entrySet = errors.entrySet();
+
+            for (Map.Entry<Integer, String> entry: entrySet) {
+                Element problem = document.createElement("problem");
+                problem.setAttribute("error", String.valueOf(entry.getKey()));
+                problem.setTextContent(entry.getValue());
+
+                root.appendChild(problem);
+            }
+        }
+
+        if (numWarnings() > 0) {
+            Set<Map.Entry<Integer, String>> entrySet = warnings.entrySet();
+
+            for (Map.Entry<Integer, String> entry: entrySet) {
+                Element problem = document.createElement("problem");
+                problem.setAttribute("error", String.valueOf(entry.getKey()));
+                problem.setTextContent(entry.getValue());
+
+                root.appendChild(problem);
+            }
+        }
+
+        document.appendChild(root);
+    }
+}
+// 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/map/WSPLGENJob.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,473 @@
+package de.intevation.flys.artifacts.model.map;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.wsplgen.FacetCreator;
+
+
+public class WSPLGENJob {
+
+    public static final String GEL_SPERRE   = "SPERRE";
+    public static final String GEL_NOSPERRE = "NOSPERRE";
+
+
+    protected FLYSArtifact artifact;
+
+    protected CallContext callContext;
+
+    protected WSPLGENCalculation calculation;
+
+    protected FacetCreator facetCreator;
+
+    protected File workingDir;
+
+    protected String dgm;
+    protected String pro;
+    protected String wsp;
+    protected String wspTag;
+    protected String axis;
+    protected String area;
+    protected String gel;
+    protected String outFile;
+
+    protected List<String> lin;
+
+    protected int out;
+
+    protected double start;
+    protected double end;
+    protected double from;
+    protected double to;
+    protected double diff;
+    protected double dist;
+
+
+
+    public WSPLGENJob(
+        FLYSArtifact       flys,
+        File               workingDir,
+        FacetCreator       facetCreator,
+        CallContext        context,
+        WSPLGENCalculation calculation)
+    {
+        this.artifact     = flys;
+        this.workingDir   = workingDir;
+        this.facetCreator = facetCreator;
+        this.callContext  = context;
+        this.calculation  = calculation;
+
+        out   = -1;
+        start = Double.NaN;
+        end   = Double.NaN;
+        from  = Double.NaN;
+        to    = Double.NaN;
+        diff  = Double.NaN;
+        dist  = Double.NaN;
+        lin   = new ArrayList<String>(3);
+    }
+
+
+    public File getWorkingDir() {
+        return workingDir;
+    }
+
+
+    public FLYSArtifact getArtifact() {
+        return artifact;
+    }
+
+
+    public FacetCreator getFacetCreator() {
+        return facetCreator;
+    }
+
+
+    public WSPLGENCalculation getCalculation() {
+        return calculation;
+    }
+
+
+    public CallContext getCallContext() {
+        return callContext;
+    }
+
+
+    public void setWsp(String wsp) {
+        this.wsp = wsp;
+    }
+
+
+    public String getWsp() {
+        return wsp;
+    }
+
+
+    public void setWspTag(String wspTag) {
+        this.wspTag = wspTag;
+    }
+
+
+    public String getWspTag() {
+        return wspTag;
+    }
+
+
+    public void addLin(String lin) {
+        this.lin.add(lin);
+    }
+
+
+    public List<String> getLin() {
+        return lin;
+    }
+
+
+    public void setAxis(String axis) {
+        this.axis = axis;
+    }
+
+
+    public String getAxis() {
+        return axis;
+    }
+
+
+    public void setArea(String area) {
+        this.area = area;
+    }
+
+
+    public String getArea() {
+        return area;
+    }
+
+
+    public void setOut(int out) {
+        this.out = out;
+    }
+
+
+    public int getOut() {
+        return out;
+    }
+
+
+    public void setOutFile(String outFile) {
+        this.outFile = outFile;
+    }
+
+
+    public String getOutFile() {
+        return outFile;
+    }
+
+
+    public void setStart(double start) {
+        this.start = start;
+    }
+
+
+    public double getStart() {
+        return start;
+    }
+
+
+    public void setEnd(double end) {
+        this.end = end;
+    }
+
+
+    public double getEnd() {
+        return end;
+    }
+
+
+    public void setPro(String pro) {
+        this.pro = pro;
+    }
+
+
+    public String getPro() {
+        return pro;
+    }
+
+
+    public void setDgm(String dgm) {
+        this.dgm = dgm;
+    }
+
+
+    public String getDgm() {
+        return dgm;
+    }
+
+
+    public void setFrom(double from) {
+        this.from = from;
+    }
+
+
+    public double getFrom() {
+        return from;
+    }
+
+
+    public void setTo(double to) {
+        this.to = to;
+    }
+
+
+    public double getTo() {
+        return to;
+    }
+
+
+    public void setDiff(double diff) {
+        this.diff = diff;
+    }
+
+
+    public double getDiff() {
+        return diff;
+    }
+
+
+    public void setDist(double dist) {
+        this.dist = dist;
+    }
+
+
+    public double getDist() {
+        return dist;
+    }
+
+
+    public void setGel(String gel) {
+        if (gel == null || gel.length() == 0) {
+            return;
+        }
+
+        if (gel.equals(GEL_SPERRE) || gel.equals(GEL_NOSPERRE)) {
+            this.gel = gel;
+        }
+    }
+
+
+    public String getGel() {
+        return gel;
+    }
+
+
+    public void toFile(File file)
+    throws IOException, IllegalArgumentException
+    {
+        PrintWriter writer = null;
+
+        try {
+            writer =
+                new PrintWriter(
+                    new OutputStreamWriter(
+                        new FileOutputStream(file)));
+
+            write(writer);
+        }
+        finally {
+            if (writer != null) {
+                writer.flush();
+                writer.close();
+            }
+        }
+    }
+
+
+    protected void write(PrintWriter writer)
+    throws IOException, IllegalArgumentException
+    {
+        writeWsp(writer);    // required
+        writeWspTag(writer); // required
+        writeLin(writer);
+        writeAxis(writer);
+        writeArea(writer);
+        writeOut(writer);
+        writeOutFile(writer);
+        writeRange(writer);
+        writeDelta(writer);
+        writeGel(writer);
+        writeDist(writer);
+        writePro(writer);
+        writeDgm(writer);    // required
+    }
+
+
+    protected void writeWsp(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        String wsp = getWsp();
+
+        if (wsp != null && wsp.length() > 0) {
+            writer.println("-WSP=\"" + wsp + "\"");
+            return;
+        }
+
+        throw new IllegalArgumentException("Required WSP missing!");
+    }
+
+    protected void writeWspTag(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        String wspTag = getWspTag();
+
+        if (wspTag != null && wspTag.length() > 0) {
+            writer.println("-WSPTAG=\"" + wspTag + "\"");
+            return;
+        }
+
+        throw new IllegalArgumentException("Required WSPTAG missing!");
+    }
+
+    protected void writeLin(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        List<String> lins = getLin();
+
+        if (lins != null && !lins.isEmpty()) {
+            for (String lin: lins) {
+                writer.println("-LIN=\"" + lin + "\"");
+            }
+        }
+    }
+
+    protected void writeAxis(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        String axis = getAxis();
+
+        if (axis != null && axis.length() > 0) {
+            writer.println("-ACHSE=\"" + axis + "\"");
+        }
+    }
+
+    protected void writeGel(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        if (area != null && area.length() > 0) {
+            writer.println("-GEL=" + getGel());
+        }
+    }
+
+    protected void writeArea(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        String area = getArea();
+
+        if (area != null && area.length() > 0) {
+            writer.println("-GEBIET=\"" + area + "\"");
+        }
+    }
+
+
+    protected void writeOut(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        int out = getOut();
+
+        if (out >= 0) {
+            writer.println("-OUTPUT=" + String.valueOf(out));
+        }
+    }
+
+    protected void writeOutFile(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        String outFile = getOutFile();
+
+        if (outFile != null && outFile.length() > 0) {
+            writer.println("-AUSGABE=\""+ outFile + "\"");
+        }
+    }
+
+    protected void writeRange(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        StringBuilder sb = new StringBuilder("-STRECKE=");
+
+        double start = getStart();
+        double end   = getEnd();
+
+        if (Double.isNaN(start) && Double.isNaN(end)) {
+            return;
+        }
+
+        if (! Double.isNaN(getStart())) {
+            sb.append(getStart());
+        }
+
+        sb.append(",");
+
+        if (! Double.isNaN(getEnd())) {
+            sb.append(getEnd());
+        }
+
+        writer.println(sb.toString());
+    }
+
+    protected void writeDelta(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        StringBuilder sb = new StringBuilder("-DELTA=");
+        if (! Double.isNaN(from)) {
+            sb.append(from);
+        }
+
+        sb.append(",");
+
+        if (! Double.isNaN(to)) {
+            sb.append(to);
+        }
+
+        sb.append(",");
+
+        if (! Double.isNaN(diff)) {
+            sb.append(diff);
+        }
+
+        writer.println(sb.toString());
+    }
+
+    protected void writeDist(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        if (! Double.isNaN(getDist())) {
+            writer.println("-DIST=" + String.valueOf(getDist()));
+        }
+    }
+
+    protected void writePro(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        if (pro != null && pro.length() > 0) {
+            writer.println("-PRO=\"" + getPro() + "\"");
+        }
+    }
+
+    protected void writeDgm(PrintWriter writer)
+    throws IllegalArgumentException
+    {
+        if (dgm != null && dgm.length() > 0) {
+            writer.println("-DGM=\"" + getDgm() + "\"");
+            return;
+        }
+
+        throw new IllegalArgumentException("Required DGM missing!");
+    }
+}
+// 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/map/WSPLGENLayerFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,46 @@
+package de.intevation.flys.artifacts.model.map;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+public class WSPLGENLayerFacet
+extends      WMSLayerFacet
+{
+    public WSPLGENLayerFacet() {
+    }
+
+
+    public WSPLGENLayerFacet(int index, String name, String description) {
+        this(index, name, description, ComputeType.FEED, null, null);
+    }
+
+
+    public WSPLGENLayerFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateId,
+        String      hash
+    ) {
+        super(index, name, description, type, stateId, hash);
+    }
+
+    public WSPLGENLayerFacet(
+        int         index,
+        String      name,
+        String      description,
+        ComputeType type,
+        String      stateId,
+        String      hash,
+        String      url
+    ) {
+        super(index, name, description, type, stateId, hash, url);
+    }
+
+
+    @Override
+    public boolean isQueryable() {
+        return true;
+    }
+}
+// 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/map/WSPLGENReportFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,58 @@
+package de.intevation.flys.artifacts.model.map;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.ReportFacet;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * This facet is used to provide WSPLGEN reports <b>only</b>.
+ */
+public class WSPLGENReportFacet extends ReportFacet {
+
+    private static Logger logger = Logger.getLogger(WSPLGENReportFacet.class);
+
+
+    protected CalculationResult result;
+
+
+    public WSPLGENReportFacet() {
+    }
+
+
+    public WSPLGENReportFacet(
+        ComputeType       type,
+        String            hash,
+        String            stateId,
+        CalculationResult result
+    ) {
+        super(type, hash, stateId);
+        this.result = result;
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        return result.getReport();
+    }
+
+
+    @Override
+    public Facet deepCopy() {
+        WSPLGENReportFacet copy = new WSPLGENReportFacet();
+        copy.set(this);
+        copy.type    = type;
+        copy.hash    = hash;
+        copy.stateId = stateId;
+        copy.result  = result;
+        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/BedDensityFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,60 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Facet for serving bed density data.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class BedDensityFacet extends DataFacet {
+
+    private static final long serialVersionUID = 1L;
+
+    private static Logger logger = Logger.getLogger(BedDensityFacet.class);
+
+    public BedDensityFacet() {
+    }
+
+    public BedDensityFacet(int idx, String name, String description,
+        ComputeType type, String stateId, String hash) {
+        super(idx, name, description, type, hash, stateId);
+    }
+
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("Get data for bed density at index: " + index);
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(context, hash,
+            stateId, type, false);
+
+        int ndx = index >> 8;
+        Object[] data =
+            ((BedQualityResult[]) res.getData())[ndx].getParameters(); // TODO CAST TO SPECIFIC CLASS
+
+        int ndy = index & 255;
+        return data != null && data.length > ndy ? data[ndy] : null;
+    }
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        BedDensityFacet copy = new BedDensityFacet();
+        copy.set(this);
+        copy.type = type;
+        copy.hash = hash;
+        copy.stateId = stateId;
+        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/BedDiameterFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,59 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Facet for serving bed diameter data.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class BedDiameterFacet extends DataFacet {
+
+    private static final long serialVersionUID = 1L;
+
+    private static Logger logger = Logger.getLogger(BedDiameterFacet.class);
+
+    public BedDiameterFacet() {
+    }
+
+    public BedDiameterFacet(int idx, String name, String description,
+        ComputeType type, String stateId, String hash) {
+        super(idx, name, description, type, hash, stateId);
+    }
+
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("Get data for bed diameter at index: " + index);
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(context, hash,
+            stateId, type, false);
+
+        int ndx = index >> 8;
+        Object[] data = ((BedQualityResult[]) res.getData())[ndx].getBedResults(); // TODO CAST TO SPECIFIC CLASS
+
+        int ndy = index & 255;
+        return data != null && data.length > ndy ? data[ndy] : null;
+    }
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        BedDiameterFacet copy = new BedDiameterFacet();
+        copy.set(this);
+        copy.type = type;
+        copy.hash = hash;
+        copy.stateId = stateId;
+        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/BedDiameterResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import gnu.trove.TDoubleArrayList;
+
+
+public class BedDiameterResult
+extends BedQualityDiameterResult
+{
+    protected TDoubleArrayList diameterCap;
+    protected TDoubleArrayList diameterSub;
+
+    public BedDiameterResult (
+        String type,
+        TDoubleArrayList diameterCap,
+        TDoubleArrayList diameterSub,
+        TDoubleArrayList km
+    ) {
+        super(type, km);
+        this.diameterCap = diameterCap;
+        this.diameterSub = diameterSub;
+    }
+
+    public double getDiameterCap(int ndx) {
+        if (diameterCap != null) {
+            return this.diameterCap.get(ndx);
+        }
+        return Double.NaN;
+    }
+
+    public double getDiameterSub(int ndx) {
+        if (diameterSub != null) {
+            return this.diameterSub.get(ndx);
+        }
+        return Double.NaN;
+    }
+
+    public double getDiameterCap(double km) {
+        if (kms.indexOf(km) >= 0) {
+            return diameterCap.get(kms.indexOf(km));
+        }
+        return Double.NaN;
+    }
+
+    public double getDiameterSub(double km) {
+        if (kms.indexOf(km) >= 0) {
+            return diameterSub.get(kms.indexOf(km));
+        }
+        return Double.NaN;
+    }
+
+    public double[][] getDiameterCapData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            diameterCap.toNativeArray()
+        };
+    }
+
+    public double[][] getDiameterSubData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            diameterSub.toNativeArray()
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,187 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import gnu.trove.TDoubleArrayList;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.BedDifferencesAccess;
+import de.intevation.flys.artifacts.model.Calculation;
+import de.intevation.flys.artifacts.model.CalculationResult;
+
+
+public class BedDiffCalculation
+extends Calculation
+{
+
+    private static final Logger logger = Logger
+        .getLogger(BedDiffCalculation.class);
+
+    protected String river;
+    protected String yearEpoch;
+    protected FLYSArtifact[][] artifacts;
+
+    public BedDiffCalculation() {
+    }
+
+    public CalculationResult calculate(BedDifferencesAccess access) {
+        logger.info("BedDiffCalculation.calculate");
+
+        String river = access.getRiver();
+        String yearEpoch = access.getYearEpoch();
+        FLYSArtifact[][] artifacts = access.getDifferenceArtifacts();
+
+        logger.debug("got artifacts: " + artifacts.length + "; " + artifacts[0].length);
+        if (river == null) {
+            // TODO: i18n
+            addProblem("minfo.missing.river");
+        }
+
+        if (yearEpoch == null) {
+            addProblem("minfo.missing.year_epoch");
+        }
+
+        if (artifacts == null) {
+            addProblem("minfo.missing.differences");
+        }
+
+        if (!hasProblems()) {
+            this.river = river;
+            this.yearEpoch = yearEpoch;
+            this.artifacts = artifacts;
+            return internalCalculate();
+        }
+
+        return new CalculationResult();
+    }
+
+    private CalculationResult internalCalculate() {
+
+        if (yearEpoch.equals("year")) {
+            List<BedDiffYearResult> results =
+                new LinkedList<BedDiffYearResult>();
+
+            for (int i = 0; i < artifacts.length; i++) {
+                BedHeight[] pair =
+                    getHeightPair(artifacts[i][0], artifacts[i][1], "single");
+                BedDiffYearResult res = calculateYearDifference(pair);
+                results.add(res);
+            }
+            return new CalculationResult(
+                results.toArray(new BedDiffYearResult[results.size()]), this);
+        }
+        if (yearEpoch.equals("epoch")) {
+            List<BedDiffEpochResult> results =
+                new LinkedList<BedDiffEpochResult>();
+            for (int i = 0; i < artifacts.length; i++) {
+                BedHeight[] pair =
+                    getHeightPair(artifacts[i][0], artifacts[i][1], "epoch");
+                BedDiffEpochResult res = calculateEpochDifference(pair);
+                results.add(res);
+            }
+            return new CalculationResult(
+                results.toArray(new BedDiffEpochResult[results.size()]), this);
+        }
+
+       return new CalculationResult();
+    }
+
+    private BedHeight[] getHeightPair(
+        FLYSArtifact art1,
+        FLYSArtifact art2,
+        String type
+    ) {
+        int id1 = BedDifferencesAccess.getHeightId(art1);
+        int id2 = BedDifferencesAccess.getHeightId(art2);
+
+        BedHeight[] heights = new BedHeight[2];
+        heights[0] = BedHeightFactory.getHeight(type, id1, 0);
+        heights[1] = BedHeightFactory.getHeight(type, id2, 0);
+        return heights;
+    }
+
+    private BedDiffEpochResult calculateEpochDifference(BedHeight[] pair) {
+
+        TDoubleArrayList stations = pair[0].getStations();
+        TDoubleArrayList diffRes = new TDoubleArrayList();
+        TDoubleArrayList kms = new TDoubleArrayList();
+        TDoubleArrayList heights1 = new TDoubleArrayList();
+        TDoubleArrayList heights2 = new TDoubleArrayList();
+
+        for (int i = 0; i < stations.size(); i++) {
+            if (!Double.isNaN(pair[0].getHeight(stations.get(i))) &&
+                !Double.isNaN(pair[1].getHeight(stations.get(i)))) {
+                double hDiff =
+                    pair[0].getHeight(stations.get(i)) -
+                    pair[1].getHeight(stations.get(i));
+                diffRes.add(hDiff);
+                kms.add(stations.get(i));
+                heights1.add(pair[0].getHeight(stations.get(i)));
+                heights2.add(pair[1].getHeight(stations.get(i)));
+            }
+        }
+        Date start = ((BedHeightEpoch)pair[0]).getStart();
+        Date end = ((BedHeightEpoch)pair[1]).getEnd();
+        return new BedDiffEpochResult(kms, diffRes, heights1, heights2, start, end);
+    }
+
+    private BedDiffYearResult calculateYearDifference(BedHeight[] pair) {
+
+        TDoubleArrayList stations = pair[0].getStations();
+        TDoubleArrayList diffRes = new TDoubleArrayList();
+        TDoubleArrayList kms = new TDoubleArrayList();
+        TDoubleArrayList morphs = new TDoubleArrayList();
+        TDoubleArrayList absolute = new TDoubleArrayList();
+        TDoubleArrayList gap = new TDoubleArrayList();
+        TDoubleArrayList heights1 = new TDoubleArrayList();
+        TDoubleArrayList heights2 = new TDoubleArrayList();
+
+        BedHeightSingle s1 = (BedHeightSingle)pair[0];
+        BedHeightSingle s2 = (BedHeightSingle)pair[1];
+        int range = s1.getYear() - s2.getYear();
+        if (range  < 0) {
+            range = range * -1;
+        }
+        for (int i = 0; i < stations.size(); i++) {
+            if (!Double.isNaN(s1.getHeight(stations.get(i))) &&
+                !Double.isNaN(s2.getHeight(stations.get(i)))) {
+                double hDiff =
+                    s1.getHeight(stations.get(i)) -
+                    s2.getHeight(stations.get(i));
+                diffRes.add(hDiff);
+                double km = stations.get(i);
+                kms.add(km);
+                if (s1.getMorphWidth(km) >
+                    s2.getMorphWidth(km)) {
+                    morphs.add(s1.getMorphWidth(km));
+                }
+                else {
+                    morphs.add(s2.getMorphWidth(km));
+                }
+                if (s1.getDataGap(km) > s2.getDataGap(km)) {
+                    gap.add(s1.getDataGap(km));
+                }
+                else {
+                    gap.add(s2.getDataGap(km));
+                }
+                absolute.add((hDiff / range) * 100);
+                heights1.add(s1.getHeight(km));
+                heights2.add(s2.getHeight(km));
+            }
+        }
+        return new BedDiffYearResult(
+            kms,
+            diffRes,
+            heights1,
+            heights2,
+            morphs,
+            absolute,
+            gap,
+            s1.getYear(),
+            s2.getYear());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffEpochFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,52 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+public class BedDiffEpochFacet
+extends DataFacet
+{
+    private static Logger logger = Logger.getLogger(BedDensityFacet.class);
+
+    public BedDiffEpochFacet() {
+    }
+
+    public BedDiffEpochFacet(int idx, String name, String description,
+        ComputeType type, String stateId, String hash) {
+        super(idx, name, description, type, hash, stateId);
+    }
+
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("Get data for bed density at index: " + index);
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(context, hash,
+            stateId, type, false);
+
+        Object[] data =
+            (BedDiffEpochResult[]) res.getData(); // TODO CAST TO SPECIFIC CLASS
+
+        return data != null && data.length > index ? data[index] : null;
+    }
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        BedDiffEpochFacet copy = new BedDiffEpochFacet();
+        copy.set(this);
+        copy.type = type;
+        copy.hash = hash;
+        copy.stateId = stateId;
+        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/BedDiffEpochResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,39 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import java.util.Date;
+
+import gnu.trove.TDoubleArrayList;
+
+
+public class BedDiffEpochResult
+extends BedDifferencesResult
+{
+
+    protected Date start;
+    protected Date end;
+
+    public BedDiffEpochResult () {
+        super();
+    }
+
+    public BedDiffEpochResult (
+        TDoubleArrayList kms,
+        TDoubleArrayList differences,
+        TDoubleArrayList heights1,
+        TDoubleArrayList heights2,
+        Date start,
+        Date end
+    ) {
+        super(kms, differences, heights1, heights2);
+        this.start = start;
+        this.end = end;
+    }
+
+    public Date getStart() {
+        return this.start;
+    }
+
+    public Date getEnd() {
+        return this.end;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedDiffYearFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,52 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+public class BedDiffYearFacet
+extends DataFacet
+{
+    private static Logger logger = Logger.getLogger(BedDiffYearFacet.class);
+
+    public BedDiffYearFacet() {
+    }
+
+    public BedDiffYearFacet(int idx, String name, String description,
+        ComputeType type, String stateId, String hash) {
+        super(idx, name, description, type, hash, stateId);
+    }
+
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("Get data for bed density at index: " + index);
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(context, hash,
+            stateId, type, false);
+
+        Object[] data =
+            (BedDiffYearResult[]) res.getData(); // TODO CAST TO SPECIFIC CLASS
+
+        return data != null && data.length > index ? data[index] : null;
+    }
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        BedDiffYearFacet copy = new BedDiffYearFacet();
+        copy.set(this);
+        copy.type = type;
+        copy.hash = hash;
+        copy.stateId = stateId;
+        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/BedDiffYearResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,77 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import gnu.trove.TDoubleArrayList;
+
+
+public class BedDiffYearResult
+extends BedDifferencesResult
+{
+
+    protected TDoubleArrayList bedHeights;
+    protected TDoubleArrayList dataGap;
+    protected TDoubleArrayList morphWidth;
+    protected int start;
+    protected int end;
+
+    public BedDiffYearResult () {
+        super();
+        this.bedHeights = new TDoubleArrayList();
+        this.dataGap = new TDoubleArrayList();
+        this.morphWidth = new TDoubleArrayList();
+        this.start = -1;
+        this.end = -1;
+    }
+
+    public BedDiffYearResult(
+        TDoubleArrayList kms,
+        TDoubleArrayList differences,
+        TDoubleArrayList heights1,
+        TDoubleArrayList heights2,
+        TDoubleArrayList morphWidth,
+        TDoubleArrayList bedHeights,
+        TDoubleArrayList dataGap,
+        int start,
+        int end
+    ) {
+        super(kms, differences, heights1, heights2);
+        this.bedHeights = bedHeights;
+        this.dataGap = dataGap;
+        this.morphWidth = morphWidth;
+        this.start = start;
+        this.end = end;
+    }
+
+    public TDoubleArrayList getBedHeights() {
+        return this.bedHeights;
+    }
+
+    public TDoubleArrayList getDataGap() {
+        return this.dataGap;
+    }
+
+    public TDoubleArrayList getMorphWidth() {
+        return this.morphWidth;
+    }
+
+    public int getStart() {
+        return this.start;
+    }
+
+    public int getEnd() {
+        return this.end;
+    }
+
+    public double[][] getMorphWidthData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            morphWidth.toNativeArray()
+        };
+    }
+
+    public double[][] getHeightPerYearData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            bedHeights.toNativeArray()
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedDifferencesResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,71 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import gnu.trove.TDoubleArrayList;
+
+import java.io.Serializable;
+
+
+public class BedDifferencesResult
+implements Serializable
+{
+
+    protected TDoubleArrayList kms;
+    protected TDoubleArrayList differences;
+    protected TDoubleArrayList height1;
+    protected TDoubleArrayList height2;
+
+    public BedDifferencesResult () {
+        kms = new TDoubleArrayList();
+        differences = new TDoubleArrayList();
+
+    }
+
+    public BedDifferencesResult(
+        TDoubleArrayList kms,
+        TDoubleArrayList differences,
+        TDoubleArrayList heights1,
+        TDoubleArrayList heights2
+    ) {
+        this.kms = kms;
+        this.differences = differences;
+        this.height1 = heights1;
+        this.height2 = heights2;
+    }
+
+    public TDoubleArrayList getKms() {
+        return this.kms;
+    }
+
+    public TDoubleArrayList getDifferences() {
+        return this.differences;
+    }
+
+    public double[][] getDifferencesData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            differences.toNativeArray()
+        };
+    }
+
+    public TDoubleArrayList getHeights1() {
+        return this.height1;
+    }
+
+    public TDoubleArrayList getHeights2() {
+        return this.height2;
+    }
+
+    public double[][] getHeights1Data() {
+        return new double[][] {
+            kms.toNativeArray(),
+            height1.toNativeArray()
+        };
+    }
+
+    public double[][] getHeights2Data() {
+        return new double[][] {
+            kms.toNativeArray(),
+            height2.toNativeArray()
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeight.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,109 @@
+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;
+
+    public BedHeight() {
+        heights = new TDoubleArrayList();
+        station = new TDoubleArrayList();
+    }
+
+    public BedHeight(String name) {
+        super(name);
+        heights = new TDoubleArrayList();
+        station = new TDoubleArrayList();
+    }
+
+    public BedHeight(int capacity) {
+        this(capacity, "");
+    }
+
+    public BedHeight(int capacity, String name) {
+        super(name);
+        heights = new TDoubleArrayList(capacity);
+        station = new TDoubleArrayList(capacity);
+    }
+
+    public void add(double value, double station) {
+        this.heights.add(value);
+        this.station.add(station);
+    }
+
+    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);
+        return dst;
+    }
+
+   public double minHeights() {
+        return heights.min();
+    }
+
+    public TDoubleArrayList getStations() {
+        return this.station;
+    }
+
+    public double getHeight(double station) {
+        if (this.station.indexOf(station) >= 0) {
+            return this.heights.get(this.station.indexOf(station));
+        }
+        return Double.NaN;
+    }
+
+
+    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/BedHeightEpoch.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import java.util.Date;
+
+
+public class BedHeightEpoch
+extends BedHeight
+{
+
+    protected Date start;
+    protected Date end;
+
+    public BedHeightEpoch() {
+        this.start = new Date();
+        this.end = new Date();
+    }
+
+    public BedHeightEpoch(String name) {
+        super(name);
+        this.start = new Date();
+        this.end = new Date();
+    }
+
+    public void add(
+        double value,
+        double station,
+        Date start,
+        Date end
+    ) {
+        super.add(value, station);
+        this.start = start;
+        this.end = end;
+    }
+
+    public Date getStart() {
+        return start;
+    }
+
+    public Date getEnd() {
+        return end;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedHeightFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -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	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,179 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+
+import java.util.Date;
+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 bhsv.height, bhsv.station, bhsv.data_gap, bhsv.sounding_width, bhs.year " +
+        "   FROM bed_height_single bhs" +
+        "       JOIN bed_height_single_values bhsv on bhsv.bed_height_single_id = bhs.id" +
+        "   WHERE bhs.id = :height_id";
+
+    /** Query to get name for wst_id and column_pos. */
+    public static final String SQL_SELECT_EPOCH =
+        "SELECT bv.height, bv.station, ti.start_time, ti.stop_time" +
+        "   FROM bed_height_epoch b" +
+        "       JOIN bed_height_epoch_values bv ON b.id = bv.bed_height_epoch_id" +
+        "       JOIN time_intervals ti ON b.time_interval_id = ti.id" +
+        "   WHERE b.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");
+        }
+
+        Session session = SessionHolder.HOLDER.get();
+        SQLQuery sqlQuery = null;
+        if (type.equals("single")) {
+            BedHeightSingle height =
+                new BedHeightSingle(getHeightName(type, height_id));
+            sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLE)
+                .addScalar("height", StandardBasicTypes.DOUBLE)
+                .addScalar("station", StandardBasicTypes.DOUBLE)
+                .addScalar("data_gap", StandardBasicTypes.DOUBLE)
+                .addScalar("sounding_width", StandardBasicTypes.DOUBLE)
+                .addScalar("year", StandardBasicTypes.INTEGER);
+            sqlQuery.setInteger("height_id", height_id);
+            List<Object []> results = sqlQuery.list();
+
+            for (int i = 0; i < results.size(); i++) {
+                Object[] row = results.get(i);
+                log.debug("got station: " + (Double)row[1]);
+                height.add(
+                    (Double) row[0],
+                    (Double) row[1],
+                    (Double) row[2],
+                    (Double) row[3],
+                    (Integer) row[4]);
+            }
+            return height;
+        }
+        else if (type.equals("epoch")) {
+            BedHeightEpoch height =
+                new BedHeightEpoch(getHeightName(type, height_id));
+            sqlQuery = session.createSQLQuery(SQL_SELECT_EPOCH)
+                .addScalar("height", StandardBasicTypes.DOUBLE)
+                .addScalar("station", StandardBasicTypes.DOUBLE)
+                .addScalar("start_time", StandardBasicTypes.DATE)
+                .addScalar("stop_time", StandardBasicTypes.DATE);
+            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],
+                    (Date) row[2],
+                    (Date)row[3]);
+            }
+            return height;
+        }
+        return new BedHeight();
+    }
+}
+// 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/BedHeightSingle.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,66 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import gnu.trove.TDoubleArrayList;
+
+
+public class BedHeightSingle
+extends BedHeight
+{
+
+    protected int year;
+    protected TDoubleArrayList data_gap;
+    protected TDoubleArrayList morphWidth;
+
+    public BedHeightSingle() {
+        super();
+        this.year = -1;
+        data_gap = new TDoubleArrayList();
+        morphWidth = new TDoubleArrayList();
+    }
+
+    public BedHeightSingle(String name) {
+        super(name);
+        this.year = -1;
+        data_gap = new TDoubleArrayList();
+        morphWidth = new TDoubleArrayList();
+    }
+
+    public void add(
+        double value,
+        double station,
+        double gap,
+        double width,
+        int year
+    ) {
+        super.add(value, station);
+        this.year = year;
+        this.data_gap.add(gap);
+        this.morphWidth.add(width);
+    }
+
+    public int getYear() {
+        return this.year;
+    }
+
+    public double getMorphWidth(int idx) {
+        return this.morphWidth.get(idx);
+    }
+
+    public double getDataGap(int idx) {
+        return this.data_gap.get(idx);
+    }
+
+    public double getMorphWidth(double station) {
+        if (this.station.indexOf(station) >= 0) {
+            return this.morphWidth.get(this.station.indexOf(station));
+        }
+        return Double.NaN;
+    }
+
+    public double getDataGap(double station) {
+        if (this.station.indexOf(station) >= 0) {
+            return this.getDataGap(this.station.indexOf(station));
+        }
+        return Double.NaN;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedOverview.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,200 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.type.StandardBasicTypes;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import de.intevation.flys.utils.KMIndex;
+
+public class BedOverview
+implements Serializable
+{
+    /**
+     * Serial version UId.
+     */
+    private static final long serialVersionUID = -7967134407371364911L;
+
+    public interface Filter {
+        boolean accept(KMIndex<List<Date>> entry);
+
+    } // interface Filter
+
+
+    public static final Filter ACCEPT = new Filter() {
+        public boolean accept(KMIndex<List<Date>> entry) {
+            return true;
+        }
+    };
+
+    public static class KmFilter implements Filter {
+
+        protected double km;
+
+        public KmFilter (double km) {
+            this.km = km;
+        }
+        public boolean accept(KMIndex<List<Date>> list) {
+            for (KMIndex.Entry<List<Date>> e: list){
+                if (e.getKm() == km) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    public static class DateFilter implements Filter {
+
+        protected Date date;
+
+        public DateFilter (Date date) {
+            this.date = date;
+        }
+
+        public boolean accept(KMIndex<List<Date>> list) {
+            for (KMIndex.Entry<List<Date>> e: list){
+                if (e.getValue().equals(this.date)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    private static Logger log = Logger.getLogger(BedOverview.class);
+
+    public static final double EPSILON = 1e-4;
+
+    public static final String DATE_FORMAT = "dd.MM.yyyy";
+
+    public static final String SQL_SQ =
+        "SELECT" +
+        "    so.km    AS km," +
+        "    so.datum AS datum " +
+        "FROM sohltest so " +
+        "    JOIN station s" +
+        "       ON so.stationid = s.stationid " +
+        "    JOIN gewaesser g " +
+        "       ON s.gewaesserid = g.gewaesserid " +
+        "WHERE" +
+        "    g.name = :name AND" +
+        "    so.km IS NOT NULL " +
+        "ORDER by" +
+        "    so.km, so.datum";
+
+    protected String       riverName;
+
+    protected KMIndex<List<Date>> entries;
+
+    public BedOverview() {
+        entries = new KMIndex<List<Date>>();
+    }
+
+    public BedOverview(String riverName) {
+        this();
+        this.riverName = riverName;
+    }
+
+    private static final boolean epsilonEquals(double a, double b) {
+        return Math.abs(a - b) < EPSILON;
+    }
+
+    protected void loadData(Session session) {
+        SQLQuery query = session.createSQLQuery(SQL_SQ)
+            .addScalar("km",    StandardBasicTypes.DOUBLE)
+            .addScalar("datum", StandardBasicTypes.DATE);
+
+        query.setString("name", riverName);
+
+        List<Object []> list = query.list();
+
+        if (list.isEmpty()) {
+            log.warn("No river '" + riverName + "' found.");
+        }
+
+        Double prevKm = -Double.MAX_VALUE;
+        List<Date> dates = new ArrayList<Date>();
+
+        for (Object [] row: list) {
+            Double km = (Double)row[0];
+            if (!epsilonEquals(km, prevKm) && !dates.isEmpty()) {
+                entries.add(prevKm, dates);
+                dates = new ArrayList<Date>();
+            }
+            dates.add((Date)row[1]);
+            prevKm = km;
+        }
+
+        if (!dates.isEmpty()) {
+            entries.add(prevKm, dates);
+        }
+    }
+
+    public boolean load(Session session) {
+
+        loadData(session);
+
+        return true;
+    }
+
+
+    public void generateOverview(Document document) {
+        generateOverview(document, ACCEPT);
+    }
+
+    public KMIndex<List<Date>> filter(Filter f) {
+        // TODO: Apply filter
+        return entries;
+    }
+
+    public void generateOverview(
+        Document document,
+        Filter   filter
+    ) {
+        KMIndex<List<Date>> filtered = filter(ACCEPT);
+
+        Element sqElement = document.createElement("bed");
+
+        Element riverElement = document.createElement("river");
+
+        riverElement.setAttribute("name", riverName);
+
+        sqElement.appendChild(riverElement);
+
+        SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
+
+        Element kmE = document.createElement("km");
+
+        for (KMIndex.Entry<List<Date>> e: filtered) {
+
+            List<Date> dates = e.getValue();
+
+            if (!dates.isEmpty()) {
+                Element dEs = document.createElement("dates");
+
+                for (Date d: dates) {
+                    Element dE = document.createElement("date");
+
+                    dE.setAttribute("value", df.format(d));
+
+                    dEs.appendChild(dE);
+                }
+
+                kmE.appendChild(dEs);
+            }
+        }
+
+        sqElement.appendChild(kmE);
+
+        document.appendChild(sqElement);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedOverviewFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,70 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.apache.log4j.Logger;
+import org.hibernate.Session;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+import de.intevation.flys.backend.SedDBSessionHolder;
+
+public class BedOverviewFactory {
+
+    private static Logger log = Logger.getLogger(BedOverviewFactory.class);
+
+    public static final String CACHE_NAME = "sq-overviews";
+
+    private BedOverviewFactory() {
+    }
+
+
+    public static BedOverview getOverview(String river) {
+
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug(
+                "Looking for bed overview for river '" + river + "'");
+        }
+
+        Cache cache = CacheFactory.getCache(CACHE_NAME);
+
+        if (cache == null) {
+            if (debug) {
+                log.debug("Cache not configured.");
+            }
+            return getUncached(river);
+        }
+
+        String key = "bed-over-" + river;
+
+        Element element = cache.get(key);
+
+        if (element != null) {
+            if (debug) {
+                log.debug("Overview found in cache");
+            }
+            return (BedOverview)element.getValue();
+        }
+
+        BedOverview overview = getUncached(river);
+
+        if (overview != null) {
+            if (debug) {
+                log.debug("Store overview in cache.");
+            }
+            cache.put(new Element(key, overview));
+        }
+
+        return overview;
+    }
+
+    public static BedOverview getUncached(String river) {
+        BedOverview overview = new BedOverview(river);
+
+        Session session = SedDBSessionHolder.HOLDER.get();
+
+        return overview.load(session) ? overview : null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedParametersResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,106 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import gnu.trove.TDoubleArrayList;
+
+import java.io.Serializable;
+
+
+public class BedParametersResult
+implements Serializable
+{
+    protected TDoubleArrayList porosityCap;
+    protected TDoubleArrayList porositySub;
+    protected TDoubleArrayList loadDensityCap;
+    protected TDoubleArrayList loadDensitySub;
+    protected TDoubleArrayList kms;
+
+    public BedParametersResult() {
+
+    }
+
+    public BedParametersResult(
+        TDoubleArrayList kms,
+        TDoubleArrayList porosityCap,
+        TDoubleArrayList porositySub,
+        TDoubleArrayList densityCap,
+        TDoubleArrayList densitySub
+    ) {
+        this.kms = kms;
+        this.porosityCap = porosityCap;
+        this.porositySub = porositySub;
+        this.loadDensityCap = densityCap;
+        this.loadDensitySub = densitySub;
+    }
+
+    public double getPorosityCap(int ndx) {
+        return porosityCap.get(ndx);
+    }
+
+    public double getPorositySub(int ndx) {
+        return porositySub.get(ndx);
+    }
+
+    public double getLoadDensityCap(int ndx) {
+        return loadDensityCap.get(ndx);
+    }
+
+    public double getLoadDensitySub(int ndx) {
+        return loadDensitySub.get(ndx);
+    }
+
+    public double getPorosityCap(double km) {
+        if (kms.indexOf(km) >= 0) {
+            return porosityCap.get(kms.indexOf(km));
+        }
+        return Double.NaN;
+    }
+
+    public double getPorositySub(double km) {
+        if (kms.indexOf(km) >= 0) {
+            return porositySub.get(kms.indexOf(km));
+        }
+        return Double.NaN;
+    }
+
+    public double getLoadDensityCap(double km) {
+        if (kms.indexOf(km) >= 0) {
+            return loadDensityCap.get(kms.indexOf(km));
+        }
+        return Double.NaN;
+    }
+
+    public double getLoadDensitySub(double km) {
+        if (kms.indexOf(km) >= 0) {
+            return loadDensitySub.get(kms.indexOf(km));
+        }
+        return Double.NaN;
+    }
+
+    public double[][] getPorosityCapData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            porosityCap.toNativeArray()
+        };
+    }
+
+    public double[][] getPorositySubData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            porositySub.toNativeArray()
+        };
+    }
+
+    public double[][] getDensityCapData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            loadDensityCap.toNativeArray()
+        };
+    }
+
+    public double[][] getDensitySubData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            loadDensitySub.toNativeArray()
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedPorosityFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,59 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Facet for serving bed porosity data.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class BedPorosityFacet extends DataFacet {
+
+    private static final long serialVersionUID = 1L;
+
+    private static Logger logger = Logger.getLogger(BedPorosityFacet.class);
+
+    public BedPorosityFacet() {
+    }
+
+    public BedPorosityFacet(int idx, String name, String description,
+        ComputeType type, String stateId, String hash) {
+        super(idx, name, description, type, hash, stateId);
+    }
+
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("Get data for bed porosity at index: " + index);
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(context, hash,
+            stateId, type, false);
+
+        int ndx = index >> 8;
+        Object[] data = ((BedQualityResult[]) res.getData())[ndx].getParameters(); // TODO CAST TO SPECIFIC CLASS
+
+        int ndy = index & 255;
+        return data != null && data.length > ndy ? data[ndy] : null;
+    }
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        BedPorosityFacet copy = new BedPorosityFacet();
+        copy.set(this);
+        copy.type = type;
+        copy.hash = hash;
+        copy.stateId = stateId;
+        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/BedQualityCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,331 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import gnu.trove.TDoubleArrayList;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.access.BedQualityAccess;
+import de.intevation.flys.artifacts.model.Calculation;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DateRange;
+import de.intevation.flys.backend.SedDBSessionHolder;
+
+
+public class BedQualityCalculation extends Calculation {
+
+    private static final Logger logger = Logger
+        .getLogger(BedQualityCalculation.class);
+
+    protected String river;
+    protected double from;
+    protected double to;
+    protected List<String> bedDiameter;
+    protected List<String> bedloadDiameter;
+    protected List<DateRange> ranges;
+
+    public BedQualityCalculation() {
+    }
+
+    public CalculationResult calculate(BedQualityAccess access) {
+        logger.info("BedQualityCalculation.calculate");
+
+        String river = access.getRiver();
+        Double from = access.getFrom();
+        Double to = access.getTo();
+        List<String> bedDiameter = access.getBedDiameter();
+        List<String> bedloadDiameter = access.getBedloadDiameter();
+        List<DateRange> ranges = access.getDateRanges();
+
+        if (river == null) {
+            // TODO: i18n
+            addProblem("minfo.missing.river");
+        }
+
+        if (from == null) {
+            // TODO: i18n
+            addProblem("minfo.missing.from");
+        }
+
+        if (to == null) {
+            // TODO: i18n
+            addProblem("minfo.missing.to");
+        }
+
+        if (ranges == null) {
+            // TODO: i18n
+            addProblem("minfo.missing.periods");
+        }
+
+        if (!hasProblems()) {
+            this.river = river;
+            this.from = from;
+            this.to = to;
+            this.ranges = ranges;
+            this.bedDiameter = bedDiameter;
+            this.bedloadDiameter = bedloadDiameter;
+
+            SedDBSessionHolder.acquire();
+            try {
+                return internalCalculate();
+            }
+            finally {
+                SedDBSessionHolder.release();
+            }
+        }
+
+        return new CalculationResult();
+    }
+
+    protected CalculationResult internalCalculate() {
+
+        List<BedQualityResult> results = new LinkedList<BedQualityResult>();
+        // Calculate for all time periods.
+        for (DateRange dr : ranges) {
+            QualityMeasurements loadMeasurements =
+                QualityMeasurementFactory.getBedloadMeasurements(
+                    river,
+                    from,
+                    to,
+                    dr.getFrom(),
+                    dr.getTo());
+            QualityMeasurements bedMeasurements =
+                QualityMeasurementFactory.getBedMeasurements(
+                    river,
+                    from,
+                    to,
+                    dr.getFrom(),
+                    dr.getTo());
+            BedQualityResult result = new BedQualityResult();
+            result.setDateRange(dr);
+            if (bedDiameter != null) {
+                result.add(calculateBedParameter(bedMeasurements, dr));
+                for (String bd : bedDiameter) {
+                    BedDiameterResult bedResult =
+                        calculateBed(bedMeasurements, bd, dr);
+
+                    // Avoid adding empty result sets.
+                    if (!bedResult.isEmpty()) {
+                        result.add(bedResult);
+                    }
+                }
+            }
+            if (bedloadDiameter != null) {
+                for (String bld : bedloadDiameter) {
+                    BedloadDiameterResult loadResult =
+                        calculateBedload(loadMeasurements, bld, dr);
+                    result.add(loadResult);
+                }
+            }
+            results.add(result);
+        }
+
+        return new CalculationResult(
+            results.toArray(new BedQualityResult[results.size()]), this);
+    }
+
+    private BedParametersResult calculateBedParameter(
+        QualityMeasurements qm,
+        DateRange dr
+    ) {
+        List<Double> kms = qm.getKms();
+        QualityMeasurements capFiltered = filterCapMeasurements(qm);
+        QualityMeasurements subFiltered = filterSubMeasurements(qm);
+        TDoubleArrayList location = new TDoubleArrayList();
+        TDoubleArrayList porosityCap = new TDoubleArrayList();
+        TDoubleArrayList porositySub = new TDoubleArrayList();
+        TDoubleArrayList densityCap = new TDoubleArrayList();
+        TDoubleArrayList densitySub = new TDoubleArrayList();
+
+        for(double km : kms) {
+            double[] pCap = calculatePorosity(capFiltered, km);
+            double[] pSub = calculatePorosity(subFiltered, km);
+            double[] dCap = calculateDensity(capFiltered, pCap);
+            double[] dSub = calculateDensity(subFiltered, pSub);
+
+            double pCapRes = 0d;
+            double pSubRes = 0d;
+            double dCapRes = 0d;
+            double dSubRes = 0d;
+            for (int i = 0; i < pCap.length; i++) {
+                pCapRes += pCap[i];
+                dCapRes += dCap[i];
+            }
+            for (int i = 0; i < pSub.length; i++) {
+                pSubRes += pSub[i];
+                dSubRes += dSub[i];
+            }
+            location.add(km);
+            porosityCap.add((pCapRes / pCap.length) * 100 );
+            porositySub.add((pSubRes / pSub.length) * 100);
+            densityCap.add((dCapRes / dCap.length) / 1000);
+            densitySub.add((dSubRes / dSub.length) / 1000);
+
+        }
+
+        return new BedParametersResult(
+            location,
+            porosityCap,
+            porositySub,
+            densityCap,
+            densitySub);
+    }
+
+    protected BedDiameterResult calculateBed(
+        QualityMeasurements qm,
+        String diameter,
+        DateRange range
+    ) {
+        List<Double> kms = qm.getKms();
+        TDoubleArrayList location = new TDoubleArrayList();
+        TDoubleArrayList avDiameterCap = new TDoubleArrayList();
+        TDoubleArrayList avDiameterSub = new TDoubleArrayList();
+        for (double km : kms) {
+            //Filter cap and sub measurements.
+            QualityMeasurements capFiltered = filterCapMeasurements(qm);
+            QualityMeasurements subFiltered = filterSubMeasurements(qm);
+
+            List<QualityMeasurement> cm = capFiltered.getMeasurements(km);
+            List<QualityMeasurement> sm = subFiltered.getMeasurements(km);
+
+            double avCap = calculateAverage(cm, diameter);
+            double avSub = calculateAverage(sm, diameter);
+            location.add(km);
+            avDiameterCap.add(avCap);
+            avDiameterSub.add(avSub);
+        }
+        return new BedDiameterResult(
+            diameter,
+            avDiameterCap,
+            avDiameterSub,
+            location);
+    }
+
+    private double[] calculateDensity(
+        QualityMeasurements capFiltered,
+        double[] porosity
+    ) {
+        double[] density = new double[porosity.length];
+        for (int i = 0; i < porosity.length; i++) {
+            density[i] = (1 - porosity[i]) * 2650;
+        }
+        return density;
+    }
+
+    private double[] calculatePorosity(
+        QualityMeasurements capFiltered,
+        double km
+    ) {
+        List<QualityMeasurement> list = capFiltered.getMeasurements(km);
+        double[] results = new double[list.size()];
+        int i = 0;
+        for (QualityMeasurement qm : list) {
+            double deviation = calculateDeviation(qm);
+            double p = calculateP(qm);
+            double porosity = 0.353 - 0.068 * deviation + 0.146 * p;
+            results[i] = porosity;
+            i++;
+        }
+
+        return results;
+    }
+
+    protected BedloadDiameterResult calculateBedload(
+        QualityMeasurements qm,
+        String diameter,
+        DateRange range
+    ) {
+        List<Double> kms = qm.getKms();
+        TDoubleArrayList location = new TDoubleArrayList();
+        TDoubleArrayList avDiameter = new TDoubleArrayList();
+        for (double km : kms) {
+            List<QualityMeasurement> measurements = qm.getMeasurements(km);
+            double mid = calculateAverage(measurements, diameter);
+            location.add(km);
+            avDiameter.add(mid);
+        }
+        return new BedloadDiameterResult(
+            diameter,
+            avDiameter,
+            location,
+            range);
+    }
+
+    protected double calculateAverage(
+        List<QualityMeasurement> list,
+        String diameter
+    ) {
+        double av = 0;
+        for (QualityMeasurement qm : list) {
+            av += qm.getDiameter(diameter);
+        }
+        return av/list.size();
+    }
+
+    protected QualityMeasurements filterCapMeasurements(
+        QualityMeasurements qms
+    ) {
+        List<QualityMeasurement> result = new LinkedList<QualityMeasurement>();
+        for (QualityMeasurement qm : qms.getMeasurements()) {
+            if (qm.getDepth1() == 0d && qm.getDepth2() <= 0.3) {
+                result.add(qm);
+            }
+        }
+        return new QualityMeasurements(result);
+    }
+
+    protected QualityMeasurements filterSubMeasurements(
+        QualityMeasurements qms
+    ) {
+        List<QualityMeasurement> result = new LinkedList<QualityMeasurement>();
+        for (QualityMeasurement qm : qms.getMeasurements()) {
+            if (qm.getDepth1() > 0d && qm.getDepth2() <= 0.5) {
+                result.add(qm);
+            }
+        }
+        return new QualityMeasurements(result);
+    }
+
+    public double calculateDeviation(QualityMeasurement qm) {
+        Map<String, Double> dm = qm.getAllDiameter();
+        double phiM = 0;
+        double[] phis = new double[dm.size()];
+        double[] ps = new double[dm.size()];
+        int i = 0;
+        for (String key : dm.keySet()) {
+            double d = dm.get(key);
+            double phi = -Math.log(d)/Math.log(2);
+            phis[i] = phi;
+            double p = calculateWeight(qm, key);
+            ps[i] = p;
+            phiM += phi * p;
+            i++;
+        }
+
+        double sig = 0d;
+        for (i = 0; i < dm.size(); i++) {
+            sig += ps[i] * Math.exp(phis[i] - phiM);
+        }
+        double deviation = Math.sqrt(sig);
+        return deviation;
+    }
+
+    protected double calculateP(QualityMeasurement qm) {
+        return calculateWeight(qm, "dmin");
+    }
+
+    public double calculateWeight(QualityMeasurement qm, String diameter) {
+        Map<String, Double> dm = qm.getAllDiameter();
+        double value = qm.getDiameter(diameter);
+
+        double sum = 0d;
+        for (Double d : dm.values()) {
+            sum =+ d.doubleValue();
+        }
+        double weight = sum/100*value;
+        return weight;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityDiameterResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,61 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import gnu.trove.TDoubleArrayList;
+
+import java.io.Serializable;
+
+public class BedQualityDiameterResult implements Serializable {
+
+    public static enum DIAMETER_TYPE {
+        D90,
+        D84,
+        D80,
+        D75,
+        D70,
+        D60,
+        D50,
+        D40,
+        D30,
+        D25,
+        D20,
+        D16,
+        D10,
+        DMIN,
+        DMAX
+    }
+
+    protected DIAMETER_TYPE type;
+    protected TDoubleArrayList kms;
+    protected boolean empty;
+
+    public BedQualityDiameterResult () {
+        empty = true;
+    }
+
+    public BedQualityDiameterResult (
+        String type,
+        TDoubleArrayList km
+    ) {
+        if (km.size() > 0) {
+            empty = false;
+        }
+        this.type = DIAMETER_TYPE.valueOf(type.toUpperCase());
+        this.kms = km;
+    }
+
+    public DIAMETER_TYPE getType() {
+        return this.type;
+    }
+
+    public TDoubleArrayList getKms() {
+        return this.kms;
+    }
+
+    public void setType(DIAMETER_TYPE type) {
+        this.type = type;
+    }
+
+    public boolean isEmpty() {
+        return empty;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,69 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import java.io.Serializable;
+import java.util.LinkedList;
+import java.util.List;
+
+import de.intevation.flys.artifacts.model.DateRange;
+
+public class BedQualityResult
+implements Serializable
+{
+
+    protected List<BedDiameterResult> bedResults;
+    protected List<BedloadDiameterResult> bedloadResults;
+    protected List<BedParametersResult> bedParameters;
+    protected DateRange dateRange;
+
+    public BedQualityResult () {
+        bedResults = new LinkedList<BedDiameterResult>();
+        bedloadResults = new LinkedList<BedloadDiameterResult>();
+        bedParameters = new LinkedList<BedParametersResult>();
+    };
+
+    public BedQualityResult (
+        List<BedDiameterResult> bedResults,
+        List<BedloadDiameterResult> bedloadResults,
+        List<BedParametersResult> bedParameters,
+        DateRange range
+    ) {
+        this.dateRange = range;
+        this.bedResults = bedResults;
+        this.bedloadResults = bedloadResults;
+        this.bedParameters = bedParameters;
+    }
+
+    public BedParametersResult[] getParameters() {
+        return bedParameters.toArray(
+            new BedParametersResult[bedParameters.size()]);
+    }
+
+    public BedDiameterResult[] getBedResults() {
+        return bedResults.toArray(new BedDiameterResult[bedResults.size()]);
+    }
+
+    public BedloadDiameterResult[] getBedloadResults() {
+        return bedloadResults.toArray(
+            new BedloadDiameterResult[bedloadResults.size()]);
+    }
+
+    public void add(BedloadDiameterResult result) {
+        bedloadResults.add(result);
+    }
+
+    public void add(BedDiameterResult result) {
+        bedResults.add(result);
+    }
+
+    public void add(BedParametersResult result) {
+        bedParameters.add(result);
+    }
+
+    public DateRange getDateRange() {
+        return dateRange;
+    }
+
+    public void setDateRange(DateRange range) {
+        this.dateRange = range;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadDiameterFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,61 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Facet for serving bedload diameter data.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class BedloadDiameterFacet extends DataFacet {
+
+    private static final long serialVersionUID = 1L;
+
+    private static Logger logger = Logger.getLogger(BedloadDiameterFacet.class);
+
+    public BedloadDiameterFacet() {
+        // required for clone operation deepCopy()
+    }
+
+    public BedloadDiameterFacet(int idx, String name, String description,
+        ComputeType type, String stateId, String hash) {
+        super(idx, name, description, type, hash, stateId);
+    }
+
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("Get data for bedload diameter at index: " + index);
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(context, hash,
+            stateId, type, false);
+
+        int ndx = index >> 8;
+        Object[] data =
+            ((BedQualityResult[]) res.getData())[ndx].getBedloadResults(); // TODO CAST TO SPECIFIC CLASS
+
+        int ndy = index & 255;
+        return data != null && data.length > ndy ? data[ndy] : null;
+    }
+
+    /** Copy deeply. */
+    @Override
+    public Facet deepCopy() {
+        BedloadDiameterFacet copy = new BedloadDiameterFacet();
+        copy.set(this);
+        copy.type = type;
+        copy.hash = hash;
+        copy.stateId = stateId;
+        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/BedloadDiameterResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import de.intevation.flys.artifacts.model.DateRange;
+import gnu.trove.TDoubleArrayList;
+
+
+public class BedloadDiameterResult
+extends BedQualityDiameterResult
+{
+    protected TDoubleArrayList diameter;
+
+    public BedloadDiameterResult(
+        String type,
+        TDoubleArrayList diameter,
+        TDoubleArrayList km,
+        DateRange range
+    ) {
+        super (type, km);
+        this.diameter = diameter;
+    }
+
+    public double getDiameter(int ndx) {
+        if (diameter != null) {
+            return this.diameter.get(ndx);
+        }
+        return Double.NaN;
+    }
+
+    public double getDiameter(double km) {
+        if (kms.indexOf(km) >= 0) {
+            return diameter.get(kms.indexOf(km));
+        }
+        return Double.NaN;
+    }
+
+    public double[][] getDiameterData() {
+        return new double[][] {
+            kms.toNativeArray(),
+            diameter.toNativeArray()
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverview.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,199 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.type.StandardBasicTypes;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import de.intevation.flys.utils.KMIndex;
+
+public class BedloadOverview implements Serializable {
+
+    private static Logger log = Logger.getLogger(BedloadOverview.class);
+
+    /**
+     * Serial version UId.
+     */
+    private static final long serialVersionUID = -7607668985959407096L;
+
+    public interface Filter {
+        boolean accept(KMIndex<List<Date>> entry);
+
+    } // interface Filter
+
+
+    public static final Filter ACCEPT = new Filter() {
+        public boolean accept(KMIndex<List<Date>> entry) {
+            return true;
+        }
+    };
+
+    public static class KmFilter implements Filter {
+
+        protected double km;
+
+        public KmFilter (double km) {
+            this.km = km;
+        }
+        public boolean accept(KMIndex<List<Date>> list) {
+            for (KMIndex.Entry<List<Date>> e: list){
+                if (e.getKm() == km) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    public static class DateFilter implements Filter {
+
+        protected Date date;
+
+        public DateFilter (Date date) {
+            this.date = date;
+        }
+
+        public boolean accept(KMIndex<List<Date>> list) {
+            for (KMIndex.Entry<List<Date>> e: list){
+                if (e.getValue().equals(this.date)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    public static final double EPSILON = 1e-4;
+
+    public static final String DATE_FORMAT = "dd.MM.yyyy";
+
+    public static final String SQL_SQ =
+        "SELECT" +
+        "    m.km    AS km," +
+        "    m.datum AS datum " +
+        "FROM messung m " +
+        "    JOIN station s" +
+        "       ON m.stationid = s.stationid " +
+        "    JOIN gewaesser g " +
+        "       ON s.gewaesserid = g.gewaesserid " +
+        "WHERE" +
+        "    g.name = :name AND " +
+        "    m.km IS NOT NULL " +
+        "ORDER by" +
+        "    m.km, m.datum";
+
+    protected String       riverName;
+
+    protected KMIndex<List<Date>> entries;
+
+    public BedloadOverview() {
+        entries = new KMIndex<List<Date>>();
+    }
+
+    public BedloadOverview(String riverName) {
+        this();
+        this.riverName = riverName;
+    }
+
+    private static final boolean epsilonEquals(double a, double b) {
+        return Math.abs(a - b) < EPSILON;
+    }
+
+    protected void loadData(Session session) {
+        SQLQuery query = session.createSQLQuery(SQL_SQ)
+            .addScalar("km",    StandardBasicTypes.DOUBLE)
+            .addScalar("datum", StandardBasicTypes.DATE);
+
+        query.setString("name", riverName);
+
+        List<Object []> list = query.list();
+
+        if (list.isEmpty()) {
+            log.warn("No river '" + riverName + "' found.");
+        }
+
+        Double prevKm = -Double.MAX_VALUE;
+        List<Date> dates = new ArrayList<Date>();
+
+        for (Object [] row: list) {
+            Double km = (Double)row[0];
+            if (!epsilonEquals(km, prevKm) && !dates.isEmpty()) {
+                entries.add(prevKm, dates);
+                dates = new ArrayList<Date>();
+            }
+            dates.add((Date)row[1]);
+            prevKm = km;
+        }
+
+        if (!dates.isEmpty()) {
+            entries.add(prevKm, dates);
+        }
+    }
+
+    public boolean load(Session session) {
+
+        loadData(session);
+
+        return true;
+    }
+
+
+    public void generateOverview(Document document) {
+        generateOverview(document, ACCEPT);
+    }
+
+    public KMIndex<List<Date>> filter(Filter f) {
+        // TODO: Apply filter
+        return entries;
+    }
+
+    public void generateOverview(
+        Document document,
+        Filter   filter
+    ) {
+        KMIndex<List<Date>> filtered = filter(ACCEPT);
+
+        Element sqElement = document.createElement("bedload");
+
+        Element riverElement = document.createElement("river");
+
+        riverElement.setAttribute("name", riverName);
+
+        sqElement.appendChild(riverElement);
+
+        SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
+
+        Element kmE = document.createElement("km");
+
+        for (KMIndex.Entry<List<Date>> e: filtered) {
+
+            List<Date> dates = e.getValue();
+
+            if (!dates.isEmpty()) {
+                Element dEs = document.createElement("dates");
+
+                for (Date d: dates) {
+                    Element dE = document.createElement("date");
+
+                    dE.setAttribute("value", df.format(d));
+
+                    dEs.appendChild(dE);
+                }
+
+                kmE.appendChild(dEs);
+            }
+        }
+
+        sqElement.appendChild(kmE);
+
+        document.appendChild(sqElement);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedloadOverviewFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,70 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.apache.log4j.Logger;
+import org.hibernate.Session;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+import de.intevation.flys.backend.SedDBSessionHolder;
+
+public class BedloadOverviewFactory {
+
+    private static Logger log = Logger.getLogger(BedloadOverviewFactory.class);
+
+    public static final String CACHE_NAME = "sq-overviews";
+
+    private BedloadOverviewFactory() {
+    }
+
+
+    public static BedloadOverview getOverview(String river) {
+
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug(
+                "Looking for bedload overview for river '" + river + "'");
+        }
+
+        Cache cache = CacheFactory.getCache(CACHE_NAME);
+
+        if (cache == null) {
+            if (debug) {
+                log.debug("Cache not configured.");
+            }
+            return getUncached(river);
+        }
+
+        String key = "bedload-over-" + river;
+
+        Element element = cache.get(key);
+
+        if (element != null) {
+            if (debug) {
+                log.debug("Overview found in cache");
+            }
+            return (BedloadOverview)element.getValue();
+        }
+
+        BedloadOverview overview = getUncached(river);
+
+        if (overview != null) {
+            if (debug) {
+                log.debug("Store overview in cache.");
+            }
+            cache.put(new Element(key, overview));
+        }
+
+        return overview;
+    }
+
+    public static BedloadOverview getUncached(String river) {
+        BedloadOverview overview = new BedloadOverview(river);
+
+        Session session = SedDBSessionHolder.HOLDER.get();
+
+        return overview.load(session) ? overview : null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurement.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,80 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import java.util.Date;
+import java.util.Map;
+
+
+public class QualityMeasurement {
+
+    private double              km;
+    private Date                date;
+    private double              depth1;
+    private double              depth2;
+    private Map<String, Double> charDiameter;
+
+    public QualityMeasurement() {
+
+    }
+
+    public QualityMeasurement(
+        double km,
+        Date date,
+        double depth1,
+        double depth2,
+        Map<String, Double> diameter) {
+        this.setKm(km);
+        this.setDate(date);
+        this.depth1 = depth1;
+        this.depth2 = depth2;
+        this.setDiameter(diameter);
+    }
+
+    public double getKm() {
+        return km;
+    }
+
+    public void setKm(double km) {
+        this.km = km;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public Map<String, Double> getAllDiameter() {
+        return charDiameter;
+    }
+
+    public void setDiameter(Map<String, Double> charDiameter) {
+        this.charDiameter = charDiameter;
+    }
+
+    public double getDiameter(String key) {
+        return charDiameter.get(key);
+    }
+
+    public void setDiameter(String key, double value) {
+        charDiameter.put(key, value);
+    }
+
+    public double getDepth1() {
+        return depth1;
+    }
+
+    public void setDepth1(double depth1) {
+        this.depth1 = depth1;
+    }
+
+    public double getDepth2() {
+        return depth2;
+    }
+
+    public void setDepth2(double depth2) {
+        this.depth2 = depth2;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,203 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.transform.BasicTransformerAdapter;
+import org.hibernate.type.StandardBasicTypes;
+
+import de.intevation.flys.backend.SedDBSessionHolder;
+
+
+public class QualityMeasurementFactory {
+
+    private static Logger logger = Logger.getLogger(QualityMeasurementFactory.class);
+
+    private static final String SQL_BED_MEASUREMENT =
+        "SELECT st.km       as km," +
+        "       st.datum    as datum," +
+        "       sp.tiefevon as depth1," +
+        "       sp.tiefebis as depth2," +
+        "       sa.d10      as d10," +
+        "       sa.d16      as d16," +
+        "       sa.d20      as d20," +
+        "       sa.d25      as d25," +
+        "       sa.d30      as d30," +
+        "       sa.d40      as d40," +
+        "       sa.d50      as d50," +
+        "       sa.d60      as d60," +
+        "       sa.d70      as d70," +
+        "       sa.d75      as d75," +
+        "       sa.d80      as d80," +
+        "       sa.d84      as d84," +
+        "       sa.d90      as d90," +
+        "       sa.dmin     as dmin," +
+        "       sa.dmax     as dmax " +
+        "FROM sohltest st " +
+        "    JOIN station sn ON sn.stationid = st.stationid " +
+        "    JOIN gewaesser gw ON gw.gewaesserid = sn.gewaesserid " +
+        "    JOIN sohlprobe sp ON sp.sohltestid = st.sohltestid " +
+        "    JOIN siebanalyse sa ON sa.sohlprobeid = sp.sohlprobeid " +
+        "WHERE gw.name = :name AND " +
+        "      st.km IS NOT NULL AND " +
+        "      sp.tiefevon IS NOT NULL AND " +
+        "      sp.tiefebis IS NOT NULL AND " + // TODO: Test if char diameter ist null.
+        "      st.km BETWEEN :from - 0.001 AND :to + 0.001 AND " +
+        "      st.datum BETWEEN :start AND :end";
+
+    private static final String SQL_BEDLOAD_MEASUREMENT =
+        "SELECT m.km    as km," +
+        "       m.datum as datum," +
+        "       m.d10   as d10," +
+        "       m.d16   as d16," +
+        "       m.d20   as d20," +
+        "       m.d25   as d25," +
+        "       m.d30   as d30," +
+        "       m.d40   as d40," +
+        "       m.d50   as d50," +
+        "       m.d60   as d60," +
+        "       m.d70   as d70," +
+        "       m.d75   as d75," +
+        "       m.d80   as d80," +
+        "       m.d84   as d84," +
+        "       m.d90   as d90," +
+        "       m.dmin  as dmin," +
+        "       m.dmax  as dmax " +
+        "FROM messung m" +
+        "    JOIN station sn ON sn.stationid = m.stationid" +
+        "    JOIN gewaesser gw ON gw.gewaesserid = sn.gewaesserid " +
+        "WHERE gw.name = :name AND " +
+        "      m.km IS NOT NULL AND " +
+        "      m.d10 IS NOT NULL AND" + //TODO: Add all other char. diameter.
+        "      m.km BETWEEN :from - 0.001 AND :to + 0.001 AND" +
+        "      m.datum BETWEEN :start AND :end";
+
+    public static final class QualityMeasurementResultTransformer
+    extends BasicTransformerAdapter {
+
+        public static QualityMeasurementResultTransformer INSTANCE = new QualityMeasurementResultTransformer();
+
+        public QualityMeasurementResultTransformer() {
+        }
+
+        @Override
+        public Object transformTuple(Object[] tuple, String[] aliases) {
+            Map<String, Double> map = new HashMap<String, Double>();
+            double km = 0;
+            Date d = null;
+            double depth1 = Double.NaN;
+            double depth2 = Double.NaN;
+            for (int i = 0; i < tuple.length; ++i) {
+                if (tuple[i] != null) {
+                    if (aliases[i].equals("km")) {
+                        km = ((Number) tuple[i]).doubleValue();
+                    }
+                    else if (aliases[i].equals("datum")) {
+                        d = (Date) tuple[i];
+                    }
+                    else if (aliases[i].equals("depth1")) {
+                        depth1 = ((Number) tuple[i]).doubleValue();
+                    }
+                    else if (aliases[i].equals("depth2")) {
+                        depth2 = ((Number) tuple[i]).doubleValue();
+                    }
+                    else {
+                        map.put(aliases[i], ((Double) tuple[i])/1000);
+                    }
+                }
+            }
+            return new QualityMeasurement(km, d, depth1, depth2, map);
+        }
+    } // class BasicTransformerAdapter
+
+    private QualityMeasurementFactory() {
+    }
+
+    protected static QualityMeasurements load(
+        Session session,
+        String river,
+        double from,
+        double to,
+        Date start,
+        Date end,
+        String statement
+    ) {
+        SQLQuery query = session.createSQLQuery(statement)
+            .addScalar("km", StandardBasicTypes.DOUBLE)
+            .addScalar("datum", StandardBasicTypes.DATE)
+            .addScalar("d10", StandardBasicTypes.DOUBLE)
+            .addScalar("d16", StandardBasicTypes.DOUBLE)
+            .addScalar("d20", StandardBasicTypes.DOUBLE)
+            .addScalar("d25", StandardBasicTypes.DOUBLE)
+            .addScalar("d30", StandardBasicTypes.DOUBLE)
+            .addScalar("d40", StandardBasicTypes.DOUBLE)
+            .addScalar("d50", StandardBasicTypes.DOUBLE)
+            .addScalar("d60", StandardBasicTypes.DOUBLE)
+            .addScalar("d70", StandardBasicTypes.DOUBLE)
+            .addScalar("d75", StandardBasicTypes.DOUBLE)
+            .addScalar("d80", StandardBasicTypes.DOUBLE)
+            .addScalar("d84", StandardBasicTypes.DOUBLE)
+            .addScalar("d90", StandardBasicTypes.DOUBLE)
+            .addScalar("dmin", StandardBasicTypes.DOUBLE)
+            .addScalar("dmax", StandardBasicTypes.DOUBLE);
+
+        if (statement.equals(SQL_BED_MEASUREMENT)) {
+            query.addScalar("depth1", StandardBasicTypes.DOUBLE);
+            query.addScalar("depth2", StandardBasicTypes.DOUBLE);
+        }
+
+        query.setString("name", river);
+        query.setDouble("from", from);
+        query.setDouble("to", to);
+        query.setDate("start", start);
+        query.setDate("end", end);
+
+        query.setResultTransformer(
+            QualityMeasurementResultTransformer.INSTANCE);
+
+        return new QualityMeasurements(query.list());
+    }
+
+    public static QualityMeasurements getBedMeasurements(
+        String river,
+        double from,
+        double to,
+        Date start,
+        Date end) {
+        Session session = SedDBSessionHolder.HOLDER.get();
+        try {
+            return load(session, river, from, to, start, end,
+            SQL_BED_MEASUREMENT);
+        }
+        finally {
+            //session.close();
+        }
+    }
+
+    public static QualityMeasurements getBedloadMeasurements(
+        String river,
+        double from,
+        double to,
+        Date start,
+        Date end
+    ) {
+        Session session = SedDBSessionHolder.HOLDER.get();
+        try {
+            return load(
+                session,
+                river,
+                from,
+                to,
+                start,
+                end,
+                SQL_BEDLOAD_MEASUREMENT);
+        }
+        finally {
+            //session.close();
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurements.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,50 @@
+package de.intevation.flys.artifacts.model.minfo;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class QualityMeasurements {
+    private static Logger logger = Logger.getLogger(QualityMeasurements.class);
+    private List<QualityMeasurement> measurements;
+
+    public QualityMeasurements() {
+    }
+
+    public QualityMeasurements(List<QualityMeasurement> list) {
+        measurements = list;
+    }
+
+    public List<QualityMeasurement> getMeasurements() {
+        return measurements;
+    }
+
+    public List<QualityMeasurement> getMeasurements(double km) {
+        List<QualityMeasurement> res = new LinkedList<QualityMeasurement>();
+        for (QualityMeasurement qm: measurements) {
+            if (qm.getKm() == km) {
+                res.add(qm);
+            }
+        }
+        return res;
+    }
+
+    public List<Double> getKms() {
+        List<Double> result = new LinkedList<Double>();
+        for (QualityMeasurement qm : measurements) {
+            if (result.indexOf(qm.getKm()) < 0) {
+                result.add(qm.getKm());
+            }
+        }
+        return result;
+    }
+
+    public void setMeasurements(List<QualityMeasurement> list) {
+        this.measurements = list;
+    }
+
+    public void addMeasurement(QualityMeasurement qm) {
+        this.measurements.add(qm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Fitting.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,149 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math.MathException;
+
+import org.apache.commons.math.optimization.fitting.CurveFitter;
+
+import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer;
+
+import org.apache.log4j.Logger;
+
+public class Fitting
+implements   Outlier.Callback
+{
+    private static Logger log = Logger.getLogger(Fitting.class);
+
+    public interface Callback {
+
+        void afterIteration(
+            double [] parameters,
+            SQ []     measurements,
+            SQ []     outliers,
+            double    standardDeviation,
+            double    chiSqr);
+    } // interfacte
+
+    protected Function function;
+
+    protected double [] coeffs;
+
+    protected de.intevation.flys.artifacts.math.Function instance;
+
+    protected double stdDevFactor;
+    protected double chiSqr;
+
+    protected Callback callback;
+
+    public Fitting() {
+    }
+
+    public Fitting(Function function, double stdDevFactor) {
+        this();
+        this.function     = function;
+        this.stdDevFactor = stdDevFactor;
+    }
+
+    public Function getFunction() {
+        return function;
+    }
+
+    public void setFunction(Function function) {
+        this.function = function;
+    }
+
+    public double getStdDevFactor() {
+        return stdDevFactor;
+    }
+
+    public void setStdDevFactor(double stdDevFactor) {
+        this.stdDevFactor = stdDevFactor;
+    }
+
+    @Override
+    public void initialize(List<SQ> sqs) throws MathException {
+
+        LevenbergMarquardtOptimizer lmo =
+            new LevenbergMarquardtOptimizer();
+
+        CurveFitter cf = new CurveFitter(lmo);
+        for (SQ sq: sqs) {
+            cf.addObservedPoint(sq.getQ(), sq.getS());
+        }
+
+        coeffs = cf.fit(
+            function, function.getInitialGuess());
+
+        instance = function.instantiate(coeffs);
+
+        chiSqr = lmo.getChiSquare();
+    }
+
+    @Override
+    public double eval(SQ sq) {
+        double s = instance.value(sq.q);
+        return sq.s - s;
+    }
+
+    @Override
+    public void iterationFinished(
+        double   standardDeviation,
+        SQ       outlier,
+        List<SQ> remainings
+    ) {
+        if (log.isDebugEnabled()) {
+            log.debug("iterationFinished ----");
+            log.debug(" num remainings: " + remainings.size());
+            log.debug(" has outlier: " + outlier != null);
+            log.debug(" standardDeviation: " + standardDeviation);
+            log.debug(" Chi^2: " + chiSqr);
+            log.debug("---- iterationFinished");
+        }
+        callback.afterIteration(
+            coeffs,
+            remainings.toArray(new SQ[remainings.size()]),
+            outlier != null ? new SQ [] { outlier} : new SQ [] {},
+            standardDeviation,
+            chiSqr);
+    }
+
+    protected static final List<SQ> onlyValid(List<SQ> sqs) {
+
+        List<SQ> good = new ArrayList<SQ>(sqs.size());
+
+        for (SQ sq: sqs) {
+            if (sq.isValid()) {
+                good.add(sq);
+            }
+        }
+
+        return good;
+    }
+
+    public boolean fit(List<SQ> sqs, Callback callback) {
+
+        sqs = onlyValid(sqs);
+
+        if (sqs.size() < 2) {
+            log.warn("Too less points for fitting.");
+            return false;
+        }
+
+        this.callback = callback;
+
+        try {
+            Outlier.detectOutliers(this, sqs, stdDevFactor);
+        }
+        catch (MathException me) {
+            log.warn(me);
+            return false;
+        }
+
+        return true;
+    }
+}
+// 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/sq/Measurement.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,128 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import java.util.Map;
+
+public class Measurement
+{
+    protected Map<String, Object> data;
+
+    protected Measurement prev;
+    protected Measurement next;
+
+    public Measurement() {
+    }
+
+    public Measurement(Map<String, Object> data) {
+        this.data = data;
+    }
+
+    protected double get(String name) {
+        Number value = (Number)data.get(name);
+        return value != null ? value.doubleValue() : Double.NaN;
+    }
+
+    public double S_SS() {
+        return get("TSAND");
+    }
+
+    public double S_SF() {
+        return get("TSCHWEB") - get("TSAND");
+    }
+
+    public double Q() {
+        return get("Q_BPEGEL");
+    }
+
+    public double TOTAL_BL() {
+        return get("TGESCHIEBE");
+    }
+
+    public double BL_G() {
+        // TODO: Implement me!
+        return Double.NaN;
+    }
+
+    public double BL_C() {
+        // TODO: Implement me!
+        return Double.NaN;
+    }
+
+    public double BL_S() {
+        // TODO: Implement me!
+        return Double.NaN;
+    }
+
+    public double S_BL_S() {
+        return TOTAL_BL() * BL_S();
+    }
+
+    public double S_BL_FG() {
+        return TOTAL_BL() * BL_G();
+    }
+
+    public double S_BL_CG() {
+        return TOTAL_BL() * BL_C();
+    }
+
+    public double S_BL_1() {
+        return S_BL_S() + S_BL_FG() + S_BL_CG();
+    }
+
+    public double S_BL_2() {
+        return S_SS() + S_BL_S() + S_BL_FG() + S_BL_CG();
+    }
+
+    public double SIEB(int i) {
+        return get(String.format("SIEB%02d", i));
+    }
+
+    public double RSIEB(int i) {
+        return get(String.format("RSIEB%02d", i));
+    }
+
+    public double REST() {
+        return get("REST");
+    }
+
+    @Override
+    public String toString() {
+        return "Measurement: " + data;
+    }
+
+    /**
+     * Gets the prev for this instance.
+     *
+     * @return The prev.
+     */
+    public Measurement getPrev() {
+        return this.prev;
+    }
+
+    /**
+     * Sets the prev for this instance.
+     *
+     * @param prev The prev.
+     */
+    public void setPrev(Measurement prev) {
+        this.prev = prev;
+    }
+
+    /**
+     * Gets the next for this instance.
+     *
+     * @return The next.
+     */
+    public Measurement getNext() {
+        return this.next;
+    }
+
+    /**
+     * Sets the next for this instance.
+     *
+     * @param next The next.
+     */
+    public void setNext(Measurement next) {
+        this.next = next;
+    }
+}
+// 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/sq/MeasurementFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,180 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import java.util.List;
+
+import de.intevation.flys.artifacts.model.DateRange;
+
+import de.intevation.flys.backend.SedDBSessionHolder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+
+import org.hibernate.transform.BasicTransformerAdapter;
+
+import org.hibernate.type.StandardBasicTypes;
+
+public class MeasurementFactory
+{
+    private static final Logger log =
+        Logger.getLogger(MeasurementFactory.class);
+
+    public static final String SQL_MEASSURE =
+        "SELECT m.datum        AS DATUM," +
+               "g.UFERABST     AS UFERABST," +
+               "g.UFERABLINKS  AS UFERABLINKS," +
+               "m.TSCHWEB      AS TSCHWEB," +
+               "m.TSAND        AS TSAND," +
+               "gp.MESSDAUER   AS MESSDAUER," +
+               "gp.MENGE       AS MENGE," +
+               "gp.GTRIEB      AS GTRIEB," +
+               "gp.LFDNR       AS LFDNR," +
+               "m.TGESCHIEBE   AS TGESCHIEBE," +
+               "gs.RSIEB01     AS RSIEB01," +
+               "gs.RSIEB02     AS RSIEB02," +
+               "gs.RSIEB03     AS RSIEB03," +
+               "gs.RSIEB04     AS RSIEB04," +
+               "gs.RSIEB05     AS RSIEB05," +
+               "gs.RSIEB06     AS RSIEB06," +
+               "gs.RSIEB07     AS RSIEB07," +
+               "gs.RSIEB08     AS RSIEB08," +
+               "gs.RSIEB09     AS RSIEB09," +
+               "gs.RSIEB10     AS RSIEB10," +
+               "gs.RSIEB11     AS RSIEB11," +
+               "gs.RSIEB12     AS RSIEB12," +
+               "gs.RSIEB13     AS RSIEB13," +
+               "gs.RSIEB14     AS RSIEB14," +
+               "gs.RSIEB15     AS RSIEB15," +
+               "gs.RSIEB16     AS RSIEB16," +
+               "gs.RSIEB17     AS RSIEB17," +
+               "gs.RSIEB18     AS RSIEB18," +
+               "gs.RSIEB19     AS RSIEB19," +
+               "gs.RSIEB20     AS RSIEB20," +
+               "gs.RSIEB21     AS RSIEB21," +
+               "gs.REST        AS REST," +
+               "g.GLOTRECHTEID AS GLOTRECHTEID " +
+        "FROM MESSUNG m " +
+            "JOIN STATION    s ON m.STATIONID    = s.STATIONID " +
+            "JOIN glotrechte g ON m.MESSUNGID    = g.MESSUNGID " +
+            "JOIN gprobe    gp ON g.GLOTRECHTEID = gp.GLOTRECHTEID " +
+            "JOIN GSIEBUNG  gs ON g.GLOTRECHTEID = gs.GLOTRECHTEID " +
+        "WHERE " +
+            "g.NAME = :river_name " +
+            "AND m.Q_BPEGEL IS NOT NULL " +
+            "AND s.KM BETWEEN :location - 0.001 AND :location + 0.001 " +
+            "AND m.DATUM BETWEEN :from AND :to " +
+            "AND m.TGESCHIEBE IS NOT NULL " +
+        "ORDER BY m.DATUM";
+
+    public static final class MeasurementResultTransformer
+    extends                   BasicTransformerAdapter
+    {
+        public static MeasurementResultTransformer INSTANCE =
+            new MeasurementResultTransformer();
+
+        public MeasurementResultTransformer() {
+        }
+
+        @Override
+        public Object transformTuple(Object [] tuple, String [] aliases) {
+            Map<String, Object> map = new HashMap<String, Object>();
+            for (int i = 0; i < tuple.length; ++i) {
+                if (tuple[i] != null) {
+                    map.put(aliases[i], tuple[i]);
+                }
+            }
+            return new Measurement(map);
+        }
+    } // class BasicTransformerAdapter
+
+    private MeasurementFactory() {
+    }
+
+    protected static Measurements load(
+        Session   session,
+        String    river,
+        double    location,
+        DateRange dateRange
+    ) {
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug(SQL_MEASSURE);
+        }
+
+        SQLQuery query = session.createSQLQuery(SQL_MEASSURE)
+            .addScalar("Q_BPEGEL",     StandardBasicTypes.DOUBLE)
+            .addScalar("DATUM",        StandardBasicTypes.DATE)
+            .addScalar("UFERABST",     StandardBasicTypes.DOUBLE)
+            .addScalar("UFERABLINKS",  StandardBasicTypes.DOUBLE)
+            .addScalar("TSCHWEB",      StandardBasicTypes.DOUBLE)
+            .addScalar("TSAND",        StandardBasicTypes.DOUBLE)
+            .addScalar("MESSDAUER",    StandardBasicTypes.DOUBLE)
+            .addScalar("MENGE",        StandardBasicTypes.DOUBLE)
+            .addScalar("GTRIEB",       StandardBasicTypes.DOUBLE)
+            .addScalar("LFDNR",        StandardBasicTypes.DOUBLE)
+            .addScalar("TGESCHIEBE",   StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB01",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB02",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB03",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB04",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB05",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB06",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB07",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB08",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB09",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB10",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB11",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB12",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB13",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB14",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB15",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB16",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB17",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB18",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB19",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB20",      StandardBasicTypes.DOUBLE)
+            .addScalar("RSIEB21",      StandardBasicTypes.DOUBLE)
+            .addScalar("REST",         StandardBasicTypes.DOUBLE)
+            .addScalar("GLOTRECHTEID", StandardBasicTypes.DOUBLE);
+
+        query.setString("river_name", river);
+        query.setDouble("location", location);
+        query.setDate("from", dateRange.getFrom());
+        query.setDate("to", dateRange.getTo());
+
+        query.setResultTransformer(MeasurementResultTransformer.INSTANCE);
+
+        @SuppressWarnings("unchecked")
+		List<Measurement> measuments = (List<Measurement>)query.list();
+
+        for (int i = 0, N = measuments.size(); i < N; ++i) {
+            Measurement m = measuments.get(i);
+            Measurement p = i >   0 ? measuments.get(i-1) : null;
+            Measurement n = i < N-1 ? measuments.get(i+1) : null;
+            m.setPrev(p);
+            m.setNext(n);
+        }
+
+        return new Measurements(measuments);
+    }
+
+    public static Measurements getMeasurements(
+        String    river,
+        double    location,
+        DateRange dateRange
+    ) {
+        Session session = SedDBSessionHolder.HOLDER.get();
+        try {
+            return load(session, river, location, dateRange);
+        }
+        finally {
+            session.close();
+        }
+    }
+}
+// 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/sq/Measurements.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,125 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class Measurements
+{
+    private static final Logger log = Logger.getLogger(Measurements.class);
+
+    public interface SExtractor {
+        double getS(Measurement measument);
+    } // interface SExtractor
+
+    public static final SExtractor S_SF_EXTRACTOR = new SExtractor() {
+        @Override
+        public double getS(Measurement measument) {
+            return measument.S_SF();
+        }
+    };
+
+    public static final SExtractor S_SS_EXTRACTOR = new SExtractor() {
+        @Override
+        public double getS(Measurement measument) {
+            return measument.S_SS();
+        }
+    };
+
+    public static final SExtractor S_BL_S_EXTRACTOR = new SExtractor() {
+        @Override
+        public double getS(Measurement measument) {
+            return measument.S_BL_S();
+        }
+    };
+
+    public static final SExtractor S_BL_FG_EXTRACTOR = new SExtractor() {
+        @Override
+        public double getS(Measurement measument) {
+            return measument.S_BL_FG();
+        }
+    };
+
+    public static final SExtractor S_BL_CG_EXTRACTOR = new SExtractor() {
+        @Override
+        public double getS(Measurement measument) {
+            return measument.S_BL_CG();
+        }
+    };
+
+    public static final SExtractor S_BL_EXTRACTOR = new SExtractor() {
+        @Override
+        public double getS(Measurement measument) {
+            return measument.BL_S();
+        }
+    };
+
+    protected List<Measurement> measuments;
+
+    public Measurements() {
+    }
+
+    public Measurements(List<Measurement> measuments) {
+        this.measuments = measuments;
+    }
+
+    public List<SQ> extractSQ(SExtractor extractor) {
+        List<SQ> result = new ArrayList(measuments.size());
+        for (Measurement measument: measuments) {
+            SQ sq = new SQ(extractor.getS(measument), measument.Q());
+            if (sq.isValid()) {
+                result.add(sq);
+            }
+        }
+        return result;
+    }
+
+    public List<SQ> S_SF() {
+        return extractSQ(S_SF_EXTRACTOR);
+    }
+
+    public List<SQ> S_SS() {
+        return extractSQ(S_SS_EXTRACTOR);
+    }
+
+    public List<SQ> S_BL_S() {
+        return extractSQ(S_BL_S_EXTRACTOR);
+    }
+
+    public List<SQ> S_BL_FG() {
+        return extractSQ(S_BL_FG_EXTRACTOR);
+    }
+
+    public List<SQ> S_BL_CG() {
+        return extractSQ(S_BL_CG_EXTRACTOR);
+    }
+
+    public List<SQ> S_BL() {
+        return extractSQ(S_BL_EXTRACTOR);
+    }
+
+    public List<SQ> getSQs(int index) {
+        switch (index) {
+            case 0: return S_SF();
+            case 1: return S_SS();
+            case 2: return S_BL_S();
+            case 3: return S_BL_FG();
+            case 4: return S_BL_CG();
+            case 5: return S_BL();
+        }
+        log.error("THIS SHOULD NOT HAPPEN: Tried to access SQ[" + index + "]");
+        return new ArrayList<SQ>(0);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("Measurements [");
+        for (int i = 0, M = measuments.size(); i < M; ++i) {
+            if (i > 0) sb.append(", ");
+            sb.append(measuments.get(i));
+        }
+        return sb.append(']').toString();
+    }
+}
+// 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/sq/Outlier.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,84 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math.MathException;
+
+import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
+
+import org.apache.log4j.Logger;
+
+public class Outlier
+{
+    private static Logger log = Logger.getLogger(Outlier.class);
+
+    public interface Callback {
+
+        void initialize(List<SQ> sqs) throws MathException;
+
+        double eval(SQ sq);
+
+        void iterationFinished(
+            double   stdDev,
+            SQ       outlier,
+            List<SQ> remaining);
+
+    } // interface Callback
+
+    public static void detectOutliers(
+        Callback callback,
+        List<SQ> sqs,
+        double   stdDevFactor
+    )
+    throws MathException
+    {
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("stdDevFactor: " + stdDevFactor);
+        }
+
+        List<SQ> data = new ArrayList<SQ>(sqs);
+
+        while (data.size() > 2) {
+
+            callback.initialize(data);
+
+            StandardDeviation stdDev = new StandardDeviation();
+
+            double maxValue = -Double.MAX_VALUE;
+            int    maxIndex = -1;
+
+            for (int i = data.size()-1; i >= 0; --i) {
+                double value = Math.abs(callback.eval(data.get(i)));
+                stdDev.increment(value);
+                if (value > maxValue) {
+                    maxValue = value;
+                    maxIndex = i;
+                }
+            }
+
+            double sd = stdDev.getResult();
+
+            double accepted = stdDevFactor * sd;
+
+            if (debug) {
+                log.debug("std dev: " + stdDev);
+                log.debug("accepted: " + accepted);
+                log.debug("max value: " + maxValue);
+            }
+
+            SQ outlier = maxValue > accepted
+                ? data.remove(maxIndex)
+                : null;
+
+            callback.iterationFinished(sd, outlier, data);
+
+            if (outlier == null) {
+                break;
+            }
+        }
+    }
+}
+// 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/sq/SQ.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,41 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import java.io.Serializable;
+
+
+public class SQ implements Serializable {
+
+    protected double s;
+    protected double q;
+
+    public SQ() {
+    }
+
+    public SQ(double s, double q) {
+        this.s = s;
+        this.q = q;
+    }
+
+
+    public double getS() {
+        return s;
+    }
+
+    public void setS(double s) {
+        this.s = s;
+    }
+
+
+    public double getQ() {
+        return q;
+    }
+
+    public void setQ(double q) {
+        this.q = q;
+    }
+
+    public boolean isValid() {
+        return !Double.isNaN(s) && !Double.isNaN(q);
+    }
+}
+// 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/sq/SQCurveFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,103 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.math.fitting.Function;
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Facet to show the curve in a sq relation.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class SQCurveFacet extends DataFacet implements FacetTypes {
+
+    private static final Logger log = Logger.getLogger(SQCurveFacet.class);
+
+
+    public static final String FUNCTION = "sq-pow";
+
+
+    private int fractionIdx;
+
+
+    public SQCurveFacet() {
+    }
+
+
+    public SQCurveFacet(
+        int    idx,
+        int    fractionIdx,
+        String name,
+        String description,
+        String hash,
+        String stateId
+    ) {
+        super(idx, name, description, ComputeType.ADVANCE, hash, stateId);
+        this.fractionIdx = fractionIdx;
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        log.debug("SQCurveFacet.getData");
+
+        if (!(artifact instanceof FLYSArtifact)) {
+            return null;
+        }
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(
+            context, ComputeType.ADVANCE, false);
+
+        SQResult[]       results = (SQResult[]) res.getData();
+        SQFractionResult result  = results[index].getFraction(fractionIdx);
+
+        Parameters params = result.getParameters();
+
+        if (params == null) {
+            log.debug("no parameters found");
+            return null;
+        }
+
+        Function func = FunctionFactory.getInstance().getFunction(FUNCTION);
+        String[] paramNames = func.getParameterNames();
+
+        double [] coeffs = params.get(0, paramNames);
+
+        if (log.isDebugEnabled()) {
+            for (int i = 0, N = paramNames.length; i < N; i++) {
+                log.debug("retrieved parameter " + paramNames[i] +
+                          " = " + coeffs[i]);
+            }
+        }
+
+        de.intevation.flys.artifacts.math.Function mf =
+            func.instantiate(coeffs);
+
+        double [] extent = result.getQExtent();
+        return new SQFunction(mf, extent[0], extent[1]);
+    }
+
+
+    @Override
+    public SQCurveFacet deepCopy() {
+        SQCurveFacet copy = new SQCurveFacet();
+        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/sq/SQFractionResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,166 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import de.intevation.flys.artifacts.model.Parameters;
+
+import java.io.Serializable;
+
+import java.util.List;
+
+public class SQFractionResult
+implements   Serializable
+{
+    public static class Iteration
+    implements          Serializable
+    {
+        protected Parameters parameters;
+        protected SQ []      measurements;
+        protected SQ []      outliers;
+
+        public Iteration() {
+        }
+
+        public Iteration(
+            Parameters parameters,
+            SQ []      measurements,
+            SQ []      outliers
+        ) {
+            this.parameters   = parameters;
+            this.measurements = measurements;
+            this.outliers     = outliers;
+        }
+
+        public Parameters getParameters() {
+            return parameters;
+        }
+
+        public void setParameters(Parameters parameters) {
+            this.parameters = parameters;
+        }
+
+        public SQ [] getMeasurements() {
+            return measurements;
+        }
+
+        public void setMeasurements(SQ [] measurements) {
+            this.measurements = measurements;
+        }
+
+        public SQ [] getOutliers() {
+            return outliers;
+        }
+
+        public void setOutliers(SQ [] outliers) {
+            this.outliers = outliers;
+        }
+
+        public boolean isValid() {
+            return parameters   != null
+                && measurements != null
+                && outliers     != null;
+        }
+
+        public int numOutliers() {
+            return outliers != null
+                ? outliers.length
+                : 0;
+        }
+
+        public int numMeasurements() {
+            return measurements != null
+                ? measurements.length
+                : 0;
+        }
+    } // class Iteration
+
+    protected SQ []           measurements;
+    protected List<Iteration> iterations;
+
+    public SQFractionResult() {
+    }
+
+    public SQFractionResult(
+        SQ []           measurements,
+        List<Iteration> iterations
+    ) {
+        this.measurements = measurements;
+        this.iterations   = iterations;
+    }
+
+    public SQ [] getMeasurements() {
+        return measurements;
+    }
+
+    public void setMeasurements(SQ [] measurements) {
+        this.measurements = measurements;
+    }
+
+    public List<Iteration> getIterations() {
+        return iterations;
+    }
+
+    public void setIterations(List<Iteration> iterations) {
+        this.iterations = iterations;
+    }
+
+    public double [] getQExtent() {
+        return getQExtent(new double[2]);
+    }
+
+    public double [] getQExtent(double extent[]) {
+        extent[0] =  Double.MAX_VALUE;
+        extent[1] = -Double.MIN_VALUE;
+
+        for (SQ sq: measurements) {
+            double q = sq.getQ();
+            if (q < extent[0]) extent[0] = q;
+            if (q > extent[1]) extent[1] = q;
+        }
+
+        return extent;
+    }
+
+    public int numIterations() {
+        return iterations != null ? iterations.size() : 0;
+    }
+
+    public Parameters getParameters() {
+        return iterations != null && !iterations.isEmpty()
+            ? iterations.get(iterations.size()-1).getParameters()
+            : null;
+    }
+
+    public SQ [] getOutliers(int index) {
+        return index >= 0 && index < iterations.size()
+            ? iterations.get(index).getOutliers()
+            : null;
+    }
+
+    public Parameters getParameters(int index) {
+        return index >= 0 && index < iterations.size()
+            ? iterations.get(index).getParameters()
+            : null;
+    }
+
+    public SQ [] getMeasurements(int index) {
+        return index >= 0 && index < iterations.size()
+            ? iterations.get(index).getMeasurements()
+            : null;
+    }
+
+    public int totalNumOutliers() {
+        int sum = 0;
+        if (iterations != null) {
+            for (Iteration iteration: iterations) {
+                sum += iteration.numOutliers();
+            }
+        }
+        return sum;
+    }
+
+    public int numMeasurements() {
+        return measurements != null
+            ? measurements.length
+            : 0;
+    }
+}
+// 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/sq/SQFunction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,36 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import de.intevation.flys.artifacts.math.Function;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class SQFunction {
+
+    private Function function;
+
+    private double minQ;
+    private double maxQ;
+
+
+    public SQFunction(Function function, double minQ, double maxQ) {
+        this.function = function;
+        this.minQ     = minQ;
+        this.maxQ     = maxQ;
+    }
+
+
+    public Function getFunction() {
+        return function;
+    }
+
+    public double getMinQ() {
+        return minQ;
+    }
+
+    public double getMaxQ() {
+        return maxQ;
+    }
+}
+// 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/sq/SQMeasurementFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,73 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+
+/**
+ * Facet to show the outliers in a sq relation.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class SQMeasurementFacet extends DataFacet implements FacetTypes {
+
+    private static final Logger log = Logger.getLogger(SQMeasurementFacet.class);
+
+
+    private int fractionIdx;
+
+
+    public SQMeasurementFacet() {
+    }
+
+
+    public SQMeasurementFacet(
+        int    idx,
+        int    fractionIdx,
+        String name,
+        String description,
+        String hash,
+        String stateId
+    ) {
+        super(idx, name, description, ComputeType.ADVANCE, hash, stateId);
+        this.fractionIdx = fractionIdx;
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        log.debug("SQMeasurementFacet.getData");
+
+        if (!(artifact instanceof FLYSArtifact)) {
+            return null;
+        }
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(
+            context, ComputeType.ADVANCE, false);
+
+        SQResult[]       result  = (SQResult[]) res.getData();
+        SQFractionResult fResult = result[index].getFraction(fractionIdx);
+
+        return fResult.getMeasurements();
+    }
+
+
+    @Override
+    public SQMeasurementFacet deepCopy() {
+        SQMeasurementFacet copy = new SQMeasurementFacet();
+        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/sq/SQOutlierCurveFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,102 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import org.apache.log4j.Logger;
+
+public class SQOutlierCurveFacet
+extends      DataFacet
+implements   FacetTypes
+{
+    private static final Logger log =
+        Logger.getLogger(SQOutlierCurveFacet.class);
+
+    public static final String FUNCTION = "sq-pow";
+
+    public static final int BITMASK_ITERATION = (1 << 16) - 1;
+
+    private int fractionIdx;
+
+    public SQOutlierCurveFacet() {
+    }
+
+    public SQOutlierCurveFacet(
+        int    idx,
+        int    fractionIdx,
+        String name,
+        String description,
+        String hash,
+        String stateId
+    ) {
+        super(idx, name, description, ComputeType.ADVANCE, hash, stateId);
+        this.fractionIdx = fractionIdx;
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        log.debug("SQOutlierCurveFacet.getData");
+
+        if (!(artifact instanceof FLYSArtifact)) {
+            return null;
+        }
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(
+            context, ComputeType.ADVANCE, false);
+
+        int idx  = this.index >> 16;
+        int iter = this.index & BITMASK_ITERATION;
+
+        SQResult[]       results = (SQResult[]) res.getData();
+        SQFractionResult result  = results[idx].getFraction(fractionIdx);
+
+        Parameters params = result.getParameters(iter);
+
+        if (params == null) {
+            return null;
+        }
+
+        Function func = FunctionFactory.getInstance().getFunction(FUNCTION);
+        String [] paramNames = func.getParameterNames();
+
+        double [] coeffs = params.get(0, paramNames);
+
+        if (log.isDebugEnabled()) {
+            for (int i = 0; i < paramNames.length; i++) {
+                log.debug("retrieved parameter " + paramNames[i] +
+                          " = " + coeffs[i]);
+            }
+        }
+
+        de.intevation.flys.artifacts.math.Function mf =
+            func.instantiate(coeffs);
+
+        double [] extent = result.getQExtent();
+        return new SQFunction(mf, extent[0], extent[1]);
+    }
+
+    @Override
+    public Facet deepCopy() {
+        SQOutlierCurveFacet copy = new SQOutlierCurveFacet();
+        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/sq/SQOutlierFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,97 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Facet to show the curve in a sq relation.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class SQOutlierFacet extends DataFacet implements FacetTypes {
+
+    private static final Logger log = Logger.getLogger(SQOutlierFacet.class);
+
+    public static final int BITMASK_ITERATION = (1 << 16) - 1;
+
+    private int fractionIdx;
+
+    public SQOutlierFacet() {
+    }
+
+    public SQOutlierFacet(
+        int    idx,
+        int    fractionIdx,
+        String name,
+        String description,
+        String hash,
+        String stateId
+    ) {
+        super(idx, name, description, ComputeType.ADVANCE, hash, stateId);
+        this.fractionIdx = fractionIdx;
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        log.debug("SQOutlierFacet.getData");
+
+        if (!(artifact instanceof FLYSArtifact)) {
+            return null;
+        }
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(
+            context, ComputeType.ADVANCE, false);
+
+        int idx  = this.index >> 16;
+        int iter = this.index & BITMASK_ITERATION;
+
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("Fetch data for index : " + this.index);
+            log.debug("  > index:       " + idx);
+            log.debug("  > fraction:    " + fractionIdx);
+            log.debug("  > iteration:   " + iter);
+        }
+
+        SQResult[]       result  = (SQResult[]) res.getData();
+        SQFractionResult fResult = result[idx].getFraction(fractionIdx);
+
+        if (fResult == null) {
+            log.warn("No SQFractionResult at " + idx + "|" + fractionIdx);
+            return null;
+        }
+
+        SQ [] outliers = fResult.getOutliers(iter);
+
+        if (debug) {
+            int num = outliers != null ? outliers.length : 0;
+            log.debug("Found " + num + " outliers for iteration " + iter);
+        }
+
+        return outliers;
+    }
+
+
+    @Override
+    public SQOutlierFacet deepCopy() {
+        SQOutlierFacet copy = new SQOutlierFacet();
+        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/sq/SQOutlierMeasurementFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,73 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+import org.apache.log4j.Logger;
+
+public class SQOutlierMeasurementFacet
+extends      DataFacet
+implements   FacetTypes
+{
+    private static final Logger log =
+        Logger.getLogger(SQOutlierMeasurementFacet.class);
+
+    private int fractionIdx;
+
+    public static final int BITMASK_ITERATION = (1 << 16) - 1;
+
+    public SQOutlierMeasurementFacet() {
+    }
+
+    public SQOutlierMeasurementFacet(
+        int    idx,
+        int    fractionIdx,
+        String name,
+        String description,
+        String hash,
+        String stateId
+    ) {
+        super(idx, name, description, ComputeType.ADVANCE, hash, stateId);
+        this.fractionIdx = fractionIdx;
+    }
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        log.debug("SQOutlierMeasurementFacet.getData");
+
+        if (!(artifact instanceof FLYSArtifact)) {
+            return null;
+        }
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        CalculationResult res = (CalculationResult) flys.compute(
+            context, ComputeType.ADVANCE, false);
+
+        int idx  = this.index >> 16;
+        int iter = this.index & BITMASK_ITERATION;
+
+        SQResult[]       result  = (SQResult[]) res.getData();
+        SQFractionResult fResult = result[idx].getFraction(fractionIdx);
+
+        return fResult.getMeasurements(iter);
+    }
+
+    @Override
+    public Facet deepCopy() {
+        SQOutlierMeasurementFacet copy = new SQOutlierMeasurementFacet();
+        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/sq/SQOverviewFacet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,61 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+
+public class SQOverviewFacet
+extends      DataFacet
+implements   FacetTypes
+{
+    private static final Logger logger = Logger.getLogger(SQOverviewFacet.class);
+
+    protected int fractionIdx;
+
+    public SQOverviewFacet() {
+    }
+
+    public SQOverviewFacet(
+        int    idx,
+        int    fractionIdx,
+        String name,
+        String description,
+        String hash,
+        String stateId
+    ) {
+        super(idx, name, description, ComputeType.ADVANCE, hash, stateId);
+        this.fractionIdx = fractionIdx;
+    }
+
+
+    @Override
+    public Object getData(Artifact artifact, CallContext context) {
+        logger.debug("SQOverviewFacet.getData");
+
+        switch(fractionIdx) {
+            case 0: return "sq_relation_a";
+            case 1: return "sq_relation_b";
+            case 2: return "sq_relation_c";
+            case 3: return "sq_relation_d";
+            case 4: return "sq_relation_e";
+            case 5: return "sq_relation_f";
+            default: return null;
+        }
+    }
+
+
+    @Override
+    public SQOverviewFacet deepCopy() {
+        SQOverviewFacet copy = new SQOverviewFacet();
+        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/sq/SQRelationCalculation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,189 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import de.intevation.flys.artifacts.access.SQRelationAccess;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+
+import de.intevation.flys.artifacts.model.Calculation;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DateRange;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.backend.SedDBSessionHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class SQRelationCalculation extends Calculation {
+
+    private static final Logger log =
+        Logger.getLogger(SQRelationCalculation.class);
+
+    public static final String SQ_FUNCTION_NAME = "sq-pow";
+
+    protected String    river;
+    protected double    location;
+    protected DateRange period;
+    protected double    outliers;
+
+    public SQRelationCalculation() {
+    }
+
+    public SQRelationCalculation(SQRelationAccess access) {
+
+        String    river    = access.getRiver();
+        Double    location = access.getLocation();
+        DateRange period   = access.getPeriod();
+        Double    outliers = access.getOutliers();
+
+        //river = "Rhein";
+
+        if (river == null) {
+            // TODO: i18n
+            addProblem("sq.missing.river");
+        }
+
+        if (location == null) {
+            // TODO: i18n
+            addProblem("sq.missing.location");
+        }
+
+        if (period == null) {
+            // TODO: i18n
+            addProblem("sq.missing.periods");
+        }
+
+        if (outliers == null) {
+            // TODO: i18n
+            addProblem("sq.missing.outliers");
+        }
+
+        if (!hasProblems()) {
+            this.river    = river;
+            this.location = location;
+            this.period   = period;
+            this.outliers = outliers;
+        }
+    }
+
+
+    public CalculationResult calculate() {
+        log.debug("SQRelationCalculation.calculate");
+
+        if (hasProblems()) {
+            return new CalculationResult(this);
+        }
+
+        SedDBSessionHolder.acquire();
+        try {
+            return internalCalculate();
+        }
+        finally {
+            SedDBSessionHolder.release();
+        }
+    }
+
+    protected CalculationResult internalCalculate() {
+
+        boolean debug = log.isDebugEnabled();
+
+        Function function = FunctionFactory
+            .getInstance()
+            .getFunction(SQ_FUNCTION_NAME);
+
+        if (function == null) {
+            log.error("No '" + SQ_FUNCTION_NAME + "' function found.");
+            // TODO: i18n
+            addProblem("sq.missing.sq.function");
+        }
+
+        String [] parameterNames = function.getParameterNames();
+
+        Measurements measurements =
+            MeasurementFactory.getMeasurements(river, location, period);
+
+        SQFractionResult [] fractionResults =
+            new SQFractionResult[SQResult.NUMBER_FRACTIONS];
+
+        for (int i = 0; i < fractionResults.length; ++i) {
+            List<SQ> sqs = measurements.getSQs(i);
+
+            SQFractionResult fractionResult;
+
+            List<SQFractionResult.Iteration> iterations =
+                doFitting(function, sqs);
+
+            if (iterations == null) {
+                // TODO: i18n
+                addProblem("sq.fitting.failed." + i);
+                fractionResult = new SQFractionResult();
+            }
+            else {
+                fractionResult = new SQFractionResult(
+                    sqs.toArray(new SQ[sqs.size()]),
+                    iterations);
+            }
+
+            fractionResults[i] = fractionResult;
+        }
+
+        return new CalculationResult(
+            new SQResult[] { new SQResult(location, fractionResults) },
+            this);
+    }
+
+    protected List<SQFractionResult.Iteration> doFitting(
+        final Function function,
+        List<SQ> sqs
+    ) {
+        final List<SQFractionResult.Iteration> iterations =
+            new ArrayList<SQFractionResult.Iteration>();
+
+        boolean success = new Fitting(function, outliers).fit(
+            sqs,
+            new Fitting.Callback() {
+                @Override
+                public void afterIteration(
+                    double [] coeffs,
+                    SQ []     measurements,
+                    SQ []     outliers,
+                    double    standardDeviation,
+                    double    chiSqr
+                ) {
+                    Parameters parameters = createParameters(
+                        function.getParameterNames(),
+                        coeffs,
+                        standardDeviation,
+                        chiSqr);
+                    iterations.add(new SQFractionResult.Iteration(
+                        parameters,
+                        measurements,
+                        outliers));
+                }
+            });
+
+        return success ? iterations : null;
+    }
+
+    public static final Parameters createParameters(
+        String [] names,
+        double [] values,
+        double    standardDeviation,
+        double    chiSqr
+    ) {
+        String [] columns = new String[names.length + 2];
+        columns[0] = "chi_sqr";
+        columns[1] = "std_dev";
+        System.arraycopy(names, 0, columns, 2, names.length);
+        Parameters parameters = new Parameters(columns);
+        int row = parameters.newRow();
+        parameters.set(row, names, values);
+        parameters.set(row, "chi_sqr", chiSqr);
+        parameters.set(row, "std_dev", standardDeviation);
+        return parameters;
+    }
+}
+// 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/sq/SQResult.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,60 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import java.io.Serializable;
+
+
+
+public class SQResult implements Serializable {
+
+    public static final int NUMBER_FRACTIONS = 6;
+
+    public static final int FRACTION_A = 0;
+    public static final int FRACTION_B = 1;
+    public static final int FRACTION_C = 2;
+    public static final int FRACTION_D = 3;
+    public static final int FRACTION_E = 4;
+    public static final int FRACTION_F = 5;
+
+    protected double km;
+    protected SQFractionResult[] fractions;
+
+    public SQResult() {
+        this(0d, new SQFractionResult[NUMBER_FRACTIONS]);
+    }
+
+    public SQResult(double km, SQFractionResult [] fractions) {
+        this.km        = km;
+        this.fractions = fractions;
+    }
+
+    public SQFractionResult getFraction(int idx) {
+        return idx >= 0 && idx < fractions.length
+            ? fractions[idx]
+            : null;
+    }
+
+    public void setFraction(int idx, SQFractionResult fraction) {
+        if (idx >= 0 && idx < fractions.length) {
+            this.fractions[idx] = fraction;
+        }
+    }
+
+    public static final String [] FRACTION_NAMES = {
+        "A", "B", "C", "D", "E", "F"
+    };
+
+    public String getFractionName(int idx) {
+        return idx >= 0 && idx < FRACTION_NAMES.length
+            ? FRACTION_NAMES[idx]
+            : "";
+    }
+
+    public double getKm() {
+        return km;
+    }
+
+    public void setKm(double km) {
+        this.km = km;
+    }
+}
+// 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/sq/Sieve.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,52 @@
+package de.intevation.flys.artifacts.model.sq;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class Sieve
+{
+    public double [] fractionSizes;
+
+    protected List<List<SQ>> fractions;
+
+    public Sieve() {
+    }
+
+    public Sieve(double [] fractionSizes) {
+        this.fractionSizes = fractionSizes;
+        fractions = new ArrayList<List<SQ>>(fractionSizes.length+1);
+        for (int i = fractionSizes.length; i >= 0; --i) {
+            fractions.add(new ArrayList<SQ>());
+        }
+    }
+
+    public void sieve(Iterator<SQ> sqs) {
+        OUTER: while (sqs.hasNext()) {
+            SQ sq = sqs.next();
+            double q = sq.getQ();
+            for (int i = 0; i < fractionSizes.length; ++i) {
+                if (q < fractionSizes[i]) {
+                    fractions.get(i).add(sq);
+                    continue OUTER;
+                }
+            }
+            fractions.get(fractions.size()-1).add(sq);
+        }
+    }
+
+    public int numFractions() {
+        return fractions.size();
+    }
+
+    public List<SQ> getFraction(int idx) {
+        return fractions.get(idx);
+    }
+
+    public void reset() {
+        for (List<SQ> fraction: fractions) {
+            fraction.clear();
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/resources/Resources.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/resources/Resources.java	Fri Sep 28 12:15:52 2012 +0200
@@ -37,7 +37,7 @@
      *
      * @return the supported locales.
      */
-    public Locale[] getLocales() {
+    public synchronized Locale [] getLocales() {
         if (locales == null) {
             readLocales();
         }
@@ -58,10 +58,15 @@
     }
 
 
-    public static Locale getLocale(CallMeta meta) {
+    private static synchronized void ensureInstance() {
         if (INSTANCE == null) {
             INSTANCE = new Resources();
         }
+    }
+
+
+    public static Locale getLocale(CallMeta meta) {
+        ensureInstance();
 
         Locale[] locales = INSTANCE.getLocales();
         return meta.getPreferredLocale(locales);
@@ -80,9 +85,7 @@
      * @return the translated message.
      */
     public static String getMsg(CallMeta meta, String key, String def) {
-        if (INSTANCE == null) {
-            INSTANCE = new Resources();
-        }
+        ensureInstance();
 
         Locale[] locales = INSTANCE.getLocales();
         Locale   locale  = meta.getPreferredLocale(locales);
@@ -90,6 +93,13 @@
         return getMsg(locale, key, def);
     }
 
+    public static String getMsg(
+            CallMeta meta,
+            String   key,
+            Object[] args
+            ) {
+        return getMsg(meta, key, key, args);
+    }
 
     /**
      * Returns a translated message based on a template specified by <i>key</i>
@@ -103,20 +113,45 @@
      * @return a translated string.
      */
     public static String getMsg(
-        CallMeta meta,
-        String   key,
-        String   def,
-        Object[] args)
+            CallMeta meta,
+            String   key,
+            String   def,
+            Object[] args)
     {
-        String template = getMsg(meta, key, null);
+        String template = getMsg(meta, key, (String)null);
 
         if (template == null) {
             return def;
         }
 
-        return MessageFormat.format(template, args);
+        return format(meta, template, args);
     }
 
+    public static String format(
+            CallMeta   meta,
+            String     key,
+            String     def,
+            Object ... args
+            ) {
+        String template = getMsg(meta, key, (String)null);
+
+        if (template == null) {
+            template = def;
+        }
+
+        return format(meta, template, args);
+    }
+
+    /**
+     * Formats the given template using the arguments with respect of the
+     * appropriate locale given by the CallMeta instance.
+     */
+    public static String format(CallMeta meta, String templ, Object ... args) {
+        Locale locale = getLocale(meta);
+        MessageFormat mf = new MessageFormat(templ, locale);
+
+        return mf.format(args, new StringBuffer(), null).toString();
+    }
 
     /**
      * This method returns the translated value for <i>key</i> or <i>def</i> if
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/BedKMChartService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,305 @@
+package de.intevation.flys.artifacts.services;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.DateAxis;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifactdatabase.DefaultService;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.Service;
+import de.intevation.flys.artifacts.model.minfo.BedOverview;
+import de.intevation.flys.artifacts.model.minfo.BedOverviewFactory;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.backend.SedDBSessionHolder;
+import de.intevation.flys.utils.KMIndex;
+
+public class BedKMChartService extends DefaultService {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -4946194087923870485L;
+
+    private static final Logger log =
+        Logger.getLogger(BedKMChartService.class);
+
+    public static final int DEFAULT_WIDTH  = 240;
+    public static final int DEFAULT_HEIGHT = 180;
+
+    public static final String I18N_CHART_LABEL =
+        "bed.km.chart.label";
+
+    public static final String DEFAULT_CHART_LABEL =
+        "Measuring Points";
+
+    public static final String I18N_CHART_TITLE =
+        "bed.km.chart.title";
+
+    public static final String DEFAULT_CHART_TITLE =
+        "Measuring points";
+
+    public static final String I18N_KM_AXIS =
+        "bed.km.chart.km.axis";
+
+    public static final String DEFAULT_KM_AXIS =
+        "km";
+
+    public static final String I18N_DATE_AXIS =
+        "bed.km.chart.date.axis";
+
+    public static final String DEFAULT_DATE_AXIS =
+        "Date";
+
+    public static final String DEFAULT_FORMAT = "png";
+
+    // TODO: Load fancy image from resources.
+    public static final byte [] EMPTY = {
+        (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47,
+        (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d,
+        (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
+        (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x3a, (byte)0x7e, (byte)0x9b,
+        (byte)0x55, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x01, (byte)0x73, (byte)0x52, (byte)0x47,
+        (byte)0x42, (byte)0x00, (byte)0xae, (byte)0xce,
+        (byte)0x1c, (byte)0xe9, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x09, (byte)0x70, (byte)0x48,
+        (byte)0x59, (byte)0x73, (byte)0x00, (byte)0x00,
+        (byte)0x0b, (byte)0x13, (byte)0x00, (byte)0x00,
+        (byte)0x0b, (byte)0x13, (byte)0x01, (byte)0x00,
+        (byte)0x9a, (byte)0x9c, (byte)0x18, (byte)0x00,
+        (byte)0x00, (byte)0x00, (byte)0x07, (byte)0x74,
+        (byte)0x49, (byte)0x4d, (byte)0x45, (byte)0x07,
+        (byte)0xdc, (byte)0x04, (byte)0x04, (byte)0x10,
+        (byte)0x30, (byte)0x15, (byte)0x7d, (byte)0x77,
+        (byte)0x36, (byte)0x0b, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x08, (byte)0x74, (byte)0x45,
+        (byte)0x58, (byte)0x74, (byte)0x43, (byte)0x6f,
+        (byte)0x6d, (byte)0x6d, (byte)0x65, (byte)0x6e,
+        (byte)0x74, (byte)0x00, (byte)0xf6, (byte)0xcc,
+        (byte)0x96, (byte)0xbf, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x0a, (byte)0x49, (byte)0x44,
+        (byte)0x41, (byte)0x54, (byte)0x08, (byte)0xd7,
+        (byte)0x63, (byte)0xf8, (byte)0x0f, (byte)0x00,
+        (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x00,
+        (byte)0x1b, (byte)0xb6, (byte)0xee, (byte)0x56,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x49, (byte)0x45, (byte)0x4e, (byte)0x44,
+        (byte)0xae, (byte)0x42, (byte)0x60, (byte)0x82
+    };
+
+    private static final Output empty() {
+        return new Output(EMPTY, "image/png");
+    }
+
+    @Override
+    public Service.Output process(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        log.debug("SQKMChartService.process");
+
+        SedDBSessionHolder.acquire();
+        try {
+            return doProcess(data, globalContext, callMeta);
+        }
+        finally {
+            SedDBSessionHolder.HOLDER.get().close();
+            SedDBSessionHolder.release();
+        }
+    }
+
+    protected Service.Output doProcess(
+        Document      input,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        String    river  = getRiverName(input);
+        Dimension extent = getExtent(input);
+        String    format = getFormat(input);
+
+        if (river == null) {
+            log.warn("River invalid.");
+            return empty();
+        }
+
+        BedOverview overview = BedOverviewFactory.getOverview(river);
+
+        if (overview == null) {
+            log.warn("No overview found for river '" + river + "'");
+            return empty();
+        }
+
+        KMIndex<List<Date>> entries = overview.filter(BedOverview.ACCEPT);
+
+        JFreeChart chart = createChart(entries, river, callMeta);
+
+        return encode(chart, extent, format);
+    }
+
+    protected static Output encode(
+        JFreeChart chart,
+        Dimension  extent,
+        String     format
+    ) {
+        BufferedImage image = chart.createBufferedImage(
+            extent.width, extent.height,
+            Transparency.BITMASK,
+            null);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try {
+            ImageIO.write(image, format, out);
+        }
+        catch (IOException ioe) {
+            log.warn("writing image failed", ioe);
+            return empty();
+        }
+
+        return new Output(out.toByteArray(), "image/" + format);
+    }
+
+    protected static JFreeChart createChart(
+        KMIndex<List<Date>> entries,
+        String      river,
+        CallMeta    callMeta
+    ) {
+
+        XYSeriesCollection dataset = new XYSeriesCollection();
+        String key = Resources.format(
+            callMeta, I18N_CHART_LABEL, DEFAULT_CHART_LABEL, river);
+
+        XYSeries series = new XYSeries(key);
+        for (KMIndex.Entry<List<Date>> e: entries) {
+            double km = e.getKm();
+            List<Date> ds = e.getValue();
+            for (Date d: ds) {
+                series.add(km, d.getTime());
+            }
+        }
+
+        dataset.addSeries(series);
+        String title = Resources.format(
+            callMeta, I18N_CHART_TITLE, DEFAULT_CHART_TITLE, river);
+
+        String kmAxis = Resources.getMsg(
+            callMeta, I18N_KM_AXIS, DEFAULT_KM_AXIS);
+
+        String dateAxis = Resources.getMsg(
+            callMeta, I18N_DATE_AXIS, DEFAULT_DATE_AXIS);
+
+        JFreeChart chart = ChartFactory.createXYLineChart(
+            title,
+            kmAxis,
+            dateAxis,
+            null,
+            PlotOrientation.VERTICAL,
+            true,
+            true,
+            false);
+
+        XYPlot plot = (XYPlot)chart.getPlot();
+
+        DateAxis dA = new DateAxis();
+        plot.setRangeAxis(dA);
+        plot.setDataset(0, dataset);
+
+        chart.setBackgroundPaint(Color.white);
+        plot.setBackgroundPaint(Color.white);
+        plot.setDomainGridlinePaint(Color.gray);
+        plot.setRangeGridlinePaint(Color.gray);
+        plot.setDomainGridlinesVisible(true);
+        plot.setRangeGridlinesVisible(true);
+        XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
+
+        renderer.setSeriesPaint(0, Color.gray);
+        renderer.setSeriesLinesVisible(0, false);
+        renderer.setSeriesShapesVisible(0, true);
+        renderer.setDrawOutlines(true);
+        return chart;
+    }
+
+
+    protected static String getRiverName(Document input) {
+        NodeList rivers = input.getElementsByTagName("river");
+
+        if (rivers.getLength() == 0) {
+            return null;
+        }
+
+        String river = ((Element)rivers.item(0)).getAttribute("name");
+
+        return river.length() > 0 ? river : null;
+    }
+
+    protected static Dimension getExtent(Document input) {
+
+        int width  = DEFAULT_WIDTH;
+        int height = DEFAULT_HEIGHT;
+
+        NodeList extents = input.getElementsByTagName("extent");
+
+        if (extents.getLength() > 0) {
+            Element element = (Element)extents.item(0);
+            String w = element.getAttribute("width");
+            String h = element.getAttribute("height");
+
+            try {
+                width = Math.max(1, Integer.parseInt(w));
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("width '" + w + "' is not a valid.");
+            }
+
+            try {
+                height = Math.max(1, Integer.parseInt(h));
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("height '" + h + "' is not a valid");
+            }
+        }
+
+        return new Dimension(width, height);
+    }
+
+    protected static String getFormat(Document input) {
+        String format = DEFAULT_FORMAT;
+
+        NodeList formats = input.getElementsByTagName("format");
+
+        if (formats.getLength() > 0) {
+            String type = ((Element)formats.item(0)).getAttribute("type");
+            if (type.length() > 0) {
+                format = type;
+            }
+        }
+
+        return format;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/BedloadKMChartService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,305 @@
+package de.intevation.flys.artifacts.services;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.DateAxis;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifactdatabase.DefaultService;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.Service;
+import de.intevation.flys.artifacts.model.minfo.BedloadOverview;
+import de.intevation.flys.artifacts.model.minfo.BedloadOverviewFactory;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.backend.SedDBSessionHolder;
+import de.intevation.flys.utils.KMIndex;
+
+public class BedloadKMChartService extends DefaultService {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 4156704841305086495L;
+
+    private static final Logger log =
+        Logger.getLogger(BedloadKMChartService.class);
+
+    public static final int DEFAULT_WIDTH  = 240;
+    public static final int DEFAULT_HEIGHT = 180;
+
+    public static final String I18N_CHART_LABEL =
+        "bedload.km.chart.label";
+
+    public static final String DEFAULT_CHART_LABEL =
+        "Measuring Points";
+
+    public static final String I18N_CHART_TITLE =
+        "bedload.km.chart.title";
+
+    public static final String DEFAULT_CHART_TITLE =
+        "Measuring points";
+
+    public static final String I18N_KM_AXIS =
+        "bedload.km.chart.km.axis";
+
+    public static final String DEFAULT_KM_AXIS =
+        "km";
+
+    public static final String I18N_DATE_AXIS =
+        "bedload.km.chart.date.axis";
+
+    public static final String DEFAULT_DATE_AXIS =
+        "Date";
+
+    public static final String DEFAULT_FORMAT = "png";
+
+    // TODO: Load fancy image from resources.
+    public static final byte [] EMPTY = {
+        (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47,
+        (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d,
+        (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
+        (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x3a, (byte)0x7e, (byte)0x9b,
+        (byte)0x55, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x01, (byte)0x73, (byte)0x52, (byte)0x47,
+        (byte)0x42, (byte)0x00, (byte)0xae, (byte)0xce,
+        (byte)0x1c, (byte)0xe9, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x09, (byte)0x70, (byte)0x48,
+        (byte)0x59, (byte)0x73, (byte)0x00, (byte)0x00,
+        (byte)0x0b, (byte)0x13, (byte)0x00, (byte)0x00,
+        (byte)0x0b, (byte)0x13, (byte)0x01, (byte)0x00,
+        (byte)0x9a, (byte)0x9c, (byte)0x18, (byte)0x00,
+        (byte)0x00, (byte)0x00, (byte)0x07, (byte)0x74,
+        (byte)0x49, (byte)0x4d, (byte)0x45, (byte)0x07,
+        (byte)0xdc, (byte)0x04, (byte)0x04, (byte)0x10,
+        (byte)0x30, (byte)0x15, (byte)0x7d, (byte)0x77,
+        (byte)0x36, (byte)0x0b, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x08, (byte)0x74, (byte)0x45,
+        (byte)0x58, (byte)0x74, (byte)0x43, (byte)0x6f,
+        (byte)0x6d, (byte)0x6d, (byte)0x65, (byte)0x6e,
+        (byte)0x74, (byte)0x00, (byte)0xf6, (byte)0xcc,
+        (byte)0x96, (byte)0xbf, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x0a, (byte)0x49, (byte)0x44,
+        (byte)0x41, (byte)0x54, (byte)0x08, (byte)0xd7,
+        (byte)0x63, (byte)0xf8, (byte)0x0f, (byte)0x00,
+        (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x00,
+        (byte)0x1b, (byte)0xb6, (byte)0xee, (byte)0x56,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x49, (byte)0x45, (byte)0x4e, (byte)0x44,
+        (byte)0xae, (byte)0x42, (byte)0x60, (byte)0x82
+    };
+
+    private static final Output empty() {
+        return new Output(EMPTY, "image/png");
+    }
+
+    @Override
+    public Service.Output process(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        log.debug("SQKMChartService.process");
+
+        SedDBSessionHolder.acquire();
+        try {
+            return doProcess(data, globalContext, callMeta);
+        }
+        finally {
+            SedDBSessionHolder.HOLDER.get().close();
+            SedDBSessionHolder.release();
+        }
+    }
+
+    protected Service.Output doProcess(
+        Document      input,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        String    river  = getRiverName(input);
+        Dimension extent = getExtent(input);
+        String    format = getFormat(input);
+
+        if (river == null) {
+            log.warn("River invalid.");
+            return empty();
+        }
+
+        BedloadOverview overview = BedloadOverviewFactory.getOverview(river);
+
+        if (overview == null) {
+            log.warn("No overview found for river '" + river + "'");
+            return empty();
+        }
+
+        KMIndex<List<Date>> entries = overview.filter(BedloadOverview.ACCEPT);
+
+        JFreeChart chart = createChart(entries, river, callMeta);
+
+        return encode(chart, extent, format);
+    }
+
+    protected static Output encode(
+        JFreeChart chart,
+        Dimension  extent,
+        String     format
+    ) {
+        BufferedImage image = chart.createBufferedImage(
+            extent.width, extent.height,
+            Transparency.BITMASK,
+            null);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try {
+            ImageIO.write(image, format, out);
+        }
+        catch (IOException ioe) {
+            log.warn("writing image failed", ioe);
+            return empty();
+        }
+
+        return new Output(out.toByteArray(), "image/" + format);
+    }
+
+    protected static JFreeChart createChart(
+        KMIndex<List<Date>> entries,
+        String      river,
+        CallMeta    callMeta
+    ) {
+
+        XYSeriesCollection dataset = new XYSeriesCollection();
+        String key = Resources.format(
+            callMeta, I18N_CHART_LABEL, DEFAULT_CHART_LABEL, river);
+
+        XYSeries series = new XYSeries(key);
+        for (KMIndex.Entry<List<Date>> e: entries) {
+            double km = e.getKm();
+            List<Date> ds = e.getValue();
+            for (Date d: ds) {
+                series.add(km, d.getTime());
+            }
+        }
+
+        dataset.addSeries(series);
+        String title = Resources.format(
+            callMeta, I18N_CHART_TITLE, DEFAULT_CHART_TITLE, river);
+
+        String kmAxis = Resources.getMsg(
+            callMeta, I18N_KM_AXIS, DEFAULT_KM_AXIS);
+
+        String dateAxis = Resources.getMsg(
+            callMeta, I18N_DATE_AXIS, DEFAULT_DATE_AXIS);
+
+        JFreeChart chart = ChartFactory.createXYLineChart(
+            title,
+            kmAxis,
+            dateAxis,
+            null,
+            PlotOrientation.VERTICAL,
+            true,
+            true,
+            false);
+
+        XYPlot plot = (XYPlot)chart.getPlot();
+
+        DateAxis dA = new DateAxis();
+        plot.setRangeAxis(dA);
+        plot.setDataset(0, dataset);
+
+        chart.setBackgroundPaint(Color.white);
+        plot.setBackgroundPaint(Color.white);
+        plot.setDomainGridlinePaint(Color.gray);
+        plot.setRangeGridlinePaint(Color.gray);
+        plot.setDomainGridlinesVisible(true);
+        plot.setRangeGridlinesVisible(true);
+        XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
+
+        renderer.setSeriesPaint(0, Color.gray);
+        renderer.setSeriesLinesVisible(0, false);
+        renderer.setSeriesShapesVisible(0, true);
+        renderer.setDrawOutlines(true);
+        return chart;
+    }
+
+
+    protected static String getRiverName(Document input) {
+        NodeList rivers = input.getElementsByTagName("river");
+
+        if (rivers.getLength() == 0) {
+            return null;
+        }
+
+        String river = ((Element)rivers.item(0)).getAttribute("name");
+
+        return river.length() > 0 ? river : null;
+    }
+
+    protected static Dimension getExtent(Document input) {
+
+        int width  = DEFAULT_WIDTH;
+        int height = DEFAULT_HEIGHT;
+
+        NodeList extents = input.getElementsByTagName("extent");
+
+        if (extents.getLength() > 0) {
+            Element element = (Element)extents.item(0);
+            String w = element.getAttribute("width");
+            String h = element.getAttribute("height");
+
+            try {
+                width = Math.max(1, Integer.parseInt(w));
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("width '" + w + "' is not a valid.");
+            }
+
+            try {
+                height = Math.max(1, Integer.parseInt(h));
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("height '" + h + "' is not a valid");
+            }
+        }
+
+        return new Dimension(width, height);
+    }
+
+    protected static String getFormat(Document input) {
+        String format = DEFAULT_FORMAT;
+
+        NodeList formats = input.getElementsByTagName("format");
+
+        if (formats.getLength() > 0) {
+            String type = ((Element)formats.item(0)).getAttribute("type");
+            if (type.length() > 0) {
+                format = type;
+            }
+        }
+
+        return format;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/CacheInvalidationService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,54 @@
+package de.intevation.flys.artifacts.services;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifactdatabase.XMLService;
+
+import de.intevation.flys.artifacts.cache.CacheFactory;
+
+import net.sf.ehcache.Cache;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class CacheInvalidationService
+extends      XMLService
+{
+    @Override
+    public Document processXML(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        Document result = XMLUtils.newDocument();
+
+        Element all = result.createElement("caches");
+
+        NodeList caches = data.getElementsByTagName("cache");
+
+        for (int i = 0, C = caches.getLength(); i < C; ++i) {
+            Element c = (Element)caches.item(i);
+            String name = c.getAttribute("name");
+            Element e = result.createElement("cache");
+            e.setAttribute("name", name);
+            Cache cache = CacheFactory.getCache(name);
+            if (cache != null) {
+                cache.removeAll();
+                e.setTextContent("All elements removed.");
+            }
+            else {
+                e.setTextContent("Error: Cache not found.");
+            }
+            all.appendChild(e);
+        }
+
+        result.appendChild(all);
+
+        return result;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -76,8 +76,6 @@
         NodeList crossSectionNodes =
             data.getElementsByTagName("art:cross-section");
 
-        Cache cache = CacheFactory.getCache(CACHE_NAME);
-
         Document document = XMLUtils.newDocument();
 
         Element all = document.createElement("cross-sections");
@@ -111,25 +109,7 @@
                 continue;
             }
 
-            NavigableMap<Double, Integer> map;
-
-            if (cache == null) {
-                map = getUncached(crossSectionId);
-            }
-            else {
-                net.sf.ehcache.Element element = cache.get(crossSectionId);
-                if (element == null) {
-                    map = getUncached(crossSectionId);
-                    if (map != null) {
-                        element = new net.sf.ehcache.Element(
-                            crossSectionId, map);
-                        cache.put(element);
-                    }
-                }
-                else {
-                    map = (NavigableMap<Double, Integer>)element.getValue();
-                }
-            }
+            NavigableMap<Double, Integer> map = getKms(crossSectionId);
 
             if (map == null) {
                 logger.debug("cannot find cross section " + crossSectionId);
@@ -159,6 +139,32 @@
         return document;
     }
 
+    public static NavigableMap<Double, Integer> getKms(int crossSectionId) {
+
+        Cache cache = CacheFactory.getCache(CACHE_NAME);
+
+        if (cache == null) {
+            return getUncached(crossSectionId);
+        }
+
+        NavigableMap<Double, Integer> map;
+
+        net.sf.ehcache.Element element = cache.get(crossSectionId);
+        if (element == null) {
+            map = getUncached(crossSectionId);
+            if (map != null) {
+                element = new net.sf.ehcache.Element(
+                    crossSectionId, map);
+                cache.put(element);
+            }
+        }
+        else {
+            map = (NavigableMap<Double, Integer>)element.getValue();
+        }
+
+        return map;
+    }
+
 
     /**
      * @param km  the kilometer from which to start searching for other
@@ -173,9 +179,10 @@
         Deque<Map.Entry<Double, Integer>> result =
             new ArrayDeque<Map.Entry<Double, Integer>>(2*N);
 
-        if(map.get(km) != null) {
-            result.add(new AbstractMap.SimpleEntry<Double, Integer>(km,map.get(km)));
+        Integer v = map.get(km);
 
+        if (v != null) {
+            result.add(new AbstractMap.SimpleEntry<Double, Integer>(km, v));
         }
 
         int i = 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DischargeInfoService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,128 @@
+package de.intevation.flys.artifacts.services;
+
+import java.util.List;
+import java.util.Date;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.DischargeTable;
+import de.intevation.flys.model.TimeInterval;
+
+/**
+ * This service provides information about discharges at a defined gauge.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class DischargeInfoService extends FLYSService {
+
+    /** The logger used in this service. */
+    private static Logger logger = Logger.getLogger(DischargeInfoService.class);
+
+    public static final String GAUGE_XPATH = "/art:gauge/text()";
+
+    public DischargeInfoService() {
+    }
+
+
+    @Override
+    public Document doProcess(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        logger.debug("DischargeInfoService.process");
+
+        String gaugeNumber = XMLUtils.xpathString(
+            data, GAUGE_XPATH, ArtifactNamespaceContext.INSTANCE);
+
+        if(gaugeNumber == null ||
+           (gaugeNumber = gaugeNumber.trim()).length() == 0) {
+            logger.warn("No gauge specified. Cannot return discharge info.");
+            return XMLUtils.newDocument();
+        }
+
+        logger.debug("Getting discharge for gauge: " + gaugeNumber);
+
+        long gn;
+        try {
+            gn = Long.parseLong(gaugeNumber);
+        }
+        catch (NumberFormatException nfe) {
+            logger.warn("Invalid gauge number. Cannot return discharg info.");
+            return XMLUtils.newDocument();
+        }
+
+        Gauge gauge = Gauge.getGaugeByOfficialNumber(gn);
+
+        logger.debug("Found gauge: " + gauge.getName());
+
+        return buildDocument(gauge);
+    }
+
+
+    protected Document buildDocument(Gauge gauge) {
+        Document result = XMLUtils.newDocument();
+
+        List<DischargeTable> tables =gauge.getDischargeTables();
+
+        Element all = result.createElement("discharges");
+        for (DischargeTable dt: tables) {
+            if (dt.getKind() == Gauge.MASTER_DISCHARGE_TABLE) {
+                continue;
+            }
+
+            Element discharge = result.createElement("discharge");
+            discharge.setAttribute("description", dt.getDescription());
+
+            // Get time interval.
+            TimeInterval ti = dt.getTimeInterval();
+
+            if (ti == null) {
+                logger.warn("DischargeTable has no TimeInterval set!");
+                continue;
+            }
+
+            Date startTime = ti.getStartTime();
+            Date stopTime = ti.getStopTime();
+
+            // Get the year for start end end date.
+            int startYear;
+            int stopYear;
+            Calendar c = new GregorianCalendar();
+            if (startTime != null) {
+                c.setTime(startTime);
+                startYear = c.get(Calendar.YEAR);
+            }
+            else {
+                startYear = -1;
+            }
+            if (stopTime != null) {
+                c.setTime(stopTime);
+                stopYear = c.get(Calendar.YEAR);
+            }
+            else {
+                stopYear = -1;
+            }
+
+            discharge.setAttribute("start", String.valueOf(startYear));
+            discharge.setAttribute("end", String.valueOf(stopYear));
+
+            all.appendChild(discharge);
+        }
+        result.appendChild(all);
+        return result;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,6 +1,5 @@
 package de.intevation.flys.artifacts.services;
 
-import java.math.BigDecimal;
 import java.util.Iterator;
 
 import org.apache.log4j.Logger;
@@ -14,17 +13,10 @@
 import de.intevation.artifacts.common.ArtifactNamespaceContext;
 import de.intevation.artifacts.common.utils.XMLUtils;
 
-import de.intevation.flys.model.Annotation;
-import de.intevation.flys.model.Attribute;
-import de.intevation.flys.model.Position;
-import de.intevation.flys.model.Range;
-import de.intevation.flys.model.Edge;
+import de.intevation.flys.model.FastAnnotations;
 
-import de.intevation.flys.artifacts.model.AnnotationsFactory;
+import de.intevation.flys.artifacts.model.LocationProvider;
 
-import de.intevation.flys.artifacts.cache.CacheFactory;
-
-import net.sf.ehcache.Cache;
 
 /**
  * This service provides information about distances of a specified river.
@@ -33,15 +25,9 @@
  */
 public class DistanceInfoService extends FLYSService {
 
-    private static enum DistanceFilter {
-        NONE, LOCATIONS, DISTANCES
-    }
-
     /** The logger used in this service. */
     private static Logger logger = Logger.getLogger(DistanceInfoService.class);
 
-    public static final String CACHE_NAME = "service-distanceinfo";
-
     public static final String RIVER_XPATH = "/art:river/text()";
 
     public static final String FILTER_XPATH = "/art:river/art:filter/text()";
@@ -65,7 +51,7 @@
         String river = XMLUtils.xpathString(
             data, RIVER_XPATH, ArtifactNamespaceContext.INSTANCE);
 
-        String filter  = XMLUtils.xpathString(
+        String filterName  = XMLUtils.xpathString(
             data, FILTER_XPATH, ArtifactNamespaceContext.INSTANCE);
 
         if (river == null || (river = river.trim()).length() == 0) {
@@ -75,60 +61,22 @@
 
         logger.debug("Search distances for river: " + river);
 
-        Cache cache = CacheFactory.getCache(CACHE_NAME);
-
-        if (cache == null) {
-            logger.debug("no cache configured for distance info");
-            return getUncached(river, filter);
-        }
-
-
-        String key = getCacheKey(river, filter);
-
-        net.sf.ehcache.Element element = cache.get(key);
+        FastAnnotations fas = LocationProvider.getAnnotations(river);
 
-        if (element != null) {
-            logger.debug("distance info found in cache");
-            return (Document)element.getValue();
-        }
-
-        Document result = getUncached(river, filter);
+        FastAnnotations.Filter filter = selectFilter(filterName);
 
-        element = new net.sf.ehcache.Element(key, result);
-
-        logger.debug("store distance info found into cache");
-
-        cache.put(element);
-
-        return result;
+        return buildDocument(fas.filter(filter));
     }
 
-
-    protected String getCacheKey(String river, String filtertype) {
-        return filtertype != null && filtertype.length() > 0
-            ? river + "_" + filtertype
-            : river;
-    }
-
-
-    protected Document getUncached(String river, String filtertype) {
-
+    protected Document buildDocument(
+        Iterator<FastAnnotations.Annotation> iter
+    ) {
         Document result = XMLUtils.newDocument();
 
-        Iterator<Annotation> iter =
-            AnnotationsFactory.getAnnotationsIterator(river);
-
         Element all = result.createElement("distances");
 
-        DistanceFilter filter = getDistanceFilter(filtertype);
-
         while (iter.hasNext()) {
-            Annotation a = iter.next();
-            Element distance = buildDistanceNode(result, a, filter);
-
-            if (distance != null) {
-                all.appendChild(distance);
-            }
+            all.appendChild(buildNode(result, iter.next()));
         }
 
         result.appendChild(all);
@@ -136,75 +84,55 @@
         return result;
     }
 
+    protected static FastAnnotations.Filter selectFilter(String name) {
 
-    protected static DistanceFilter getDistanceFilter(String type) {
-        if (type.equals("locations")) {
-            logger.debug("Found 'location' filter.");
-            return DistanceFilter.LOCATIONS;
-        }
-        else if (type.equals("distances")) {
-            logger.debug("Found 'distances' filter.");
-            return DistanceFilter.DISTANCES;
+        if (name != null) {
+            if ("locations".equals(name)) return FastAnnotations.IS_POINT;
+            if ("distances".equals(name)) return FastAnnotations.IS_RANGE;
+            if ("measuringpoint".equals(name))
+                return new FastAnnotations.NameFilter("Messstelle");
         }
 
-        logger.debug("Do not use any filter at all.");
-
-        return DistanceFilter.NONE;
+        return FastAnnotations.ALL;
     }
 
-
     /**
      * Builds an Element for a distance info.
      *
-     * @param anno The Annotation that provides information about the distance.
+     * @param an The Annotation that provides information about the distance.
      *
      * @return an Element that contains information about a distance.
      */
-    protected static Element buildDistanceNode(
-        Document       document,
-        Annotation     anno,
-        DistanceFilter filter
+    protected static Element buildNode(
+        Document                   document,
+        FastAnnotations.Annotation an
     ) {
-        Position   pos   = anno.getPosition();
-        Range      range = anno.getRange();
-        Attribute  attr  = anno.getAttribute();
-        Edge       edge  = anno.getEdge();
-        BigDecimal a     = range.getA();
-        BigDecimal b     = range.getB();
-
-        if (b == null && filter == DistanceFilter.DISTANCES) {
-            return null;
-        }
-
-        if (b != null && filter == DistanceFilter.LOCATIONS) {
-            return null;
-        }
-
         Element distance = document.createElement("distance");
 
-        distance.setAttribute("description", pos.getValue());
+        distance.setAttribute("description", an.getPosition());
 
-        String riverSide = attr.getValue();
+        String riverSide = an.getAttribute();
 
         if (riverSide != null && riverSide.length() > 0) {
             distance.setAttribute("riverside", riverSide);
         }
 
-        if (a != null) {
-            distance.setAttribute("from", a.toString());
-        }
-        if (b != null) {
-            distance.setAttribute("to", b.toString());
+        distance.setAttribute("from", String.valueOf(an.getA()));
+
+        double b      = an.getB();
+        double bottom = an.getBottom();
+        double top    = an.getTop();
+
+        if (!Double.isNaN(b)) {
+            distance.setAttribute("to", String.valueOf(b));
         }
-        if (edge != null) {
-            BigDecimal bottom = edge.getBottom();
-            BigDecimal top    = edge.getTop();
-            if (bottom != null) {
-                distance.setAttribute("bottom", bottom.toString());
-            }
-            if (top != null) {
-                distance.setAttribute("top", top.toString());
-            }
+
+        if (!Double.isNaN(bottom)) {
+            distance.setAttribute("bottom", String.valueOf(bottom));
+        }
+
+        if (!Double.isNaN(top)) {
+            distance.setAttribute("top", String.valueOf(top));
         }
 
         return distance;
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/FLYSService.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/FLYSService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -9,17 +9,18 @@
 import de.intevation.artifacts.CallMeta;
 import de.intevation.artifacts.GlobalContext;
 
-import de.intevation.artifactdatabase.DefaultService;
+import de.intevation.artifactdatabase.XMLService;
 
 import de.intevation.flys.backend.SessionHolder;
 
 
-public abstract class FLYSService extends DefaultService {
+public abstract class FLYSService extends XMLService {
 
     private static final Logger logger = Logger.getLogger(FLYSService.class);
 
 
-    public Document process(
+    @Override
+    public Document processXML(
         Document      data,
         GlobalContext globalContext,
         CallMeta      callMeta
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/FileUploadService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,104 @@
+package de.intevation.flys.artifacts.services;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import org.apache.commons.codec.binary.Base64;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.artifacts.common.utils.FileTools;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FileUploadService extends FLYSService {
+
+    /** The logger used in this service.*/
+    private static Logger logger = Logger.getLogger(FileUploadService.class);
+
+    /** XPath that points to the artifact uuid.*/
+    public static final String XPATH_ARTIFACT_UUID =
+        "/upload/artifact-uuid/text()";
+
+    /** XPath that points to the base64 encoded data.*/
+    public static final String XPATH_DATA = "/upload/data/text()";
+
+    public FileUploadService() {
+    }
+
+
+    @Override
+    protected Document doProcess(
+        Document data,
+        GlobalContext context,
+        CallMeta callMeta
+    ) {
+        logger.debug("FileUploadService.process");
+
+        String uuid = extractUuid(data);
+
+        byte[] fileData = extractData(data);
+        if (fileData != null) {
+            try {
+                String shapePath = FLYSUtils.getXPathString(
+                    FLYSUtils.XPATH_SHAPEFILE_DIR);
+
+                File artifactDir = FileTools.getDirectory(shapePath, uuid);
+                FileOutputStream fos =
+                    new FileOutputStream(
+                    new File(artifactDir, "user-rgd.zip"));
+                try {
+                    fos.write(fileData);
+                }
+                finally {
+                    fos.close();
+                }
+            }
+            catch (IOException ioe) {
+                logger.warn(ioe, ioe);
+            }
+        }
+        else {
+            logger.debug("No data in uploaded xml.");
+        }
+
+        Document doc = XMLUtils.newDocument();
+        ElementCreator ec = new ElementCreator(doc, null, null);
+        Element resp = ec.create("response");
+        doc.appendChild(resp);
+
+        return doc;
+    }
+
+
+    protected String extractUuid(Document data) {
+        return XMLUtils.xpathString(
+            data, XPATH_ARTIFACT_UUID, ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    protected byte[] extractData(Document data) {
+        String b64Data = XMLUtils.xpathString(
+            data, XPATH_DATA, ArtifactNamespaceContext.INSTANCE);
+
+        if (b64Data != null && b64Data.length() > 0) {
+           byte[] fileData = Base64.decodeBase64(b64Data);
+           return fileData;
+        }
+        return null;
+    }
+}
+// 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/services/FixingsKMChartService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,486 @@
+package de.intevation.flys.artifacts.services;
+
+import de.intevation.artifactdatabase.DefaultService;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.Service;
+
+import de.intevation.flys.artifacts.model.FixingsColumn;
+import de.intevation.flys.artifacts.model.FixingsColumnFactory;
+import de.intevation.flys.artifacts.model.FixingsFilterBuilder;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.Fixing;
+
+import de.intevation.flys.artifacts.model.FixingsOverview;
+import de.intevation.flys.artifacts.model.FixingsOverviewFactory;
+import de.intevation.flys.artifacts.model.GaugeFinder;
+import de.intevation.flys.artifacts.model.GaugeFinderFactory;
+import de.intevation.flys.artifacts.model.GaugeRange;
+
+import de.intevation.flys.artifacts.model.fixings.QWI;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import de.intevation.flys.backend.SessionHolder;
+
+import de.intevation.flys.jfree.ShapeRenderer;
+
+import de.intevation.flys.utils.Formatter;
+import de.intevation.flys.utils.Pair;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Transparency;
+
+import java.awt.geom.Rectangle2D;
+
+import java.awt.image.BufferedImage;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.LegendItemCollection;
+
+import org.jfree.chart.axis.NumberAxis;
+
+import org.jfree.chart.plot.Marker;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.ValueMarker;
+import org.jfree.chart.plot.XYPlot;
+
+import org.jfree.data.Range;
+
+import org.jfree.ui.RectangleAnchor;
+import org.jfree.ui.TextAnchor;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+
+/** Serve chart of Fixings at certain km. */
+public class FixingsKMChartService
+extends      DefaultService
+{
+    private static final Logger log =
+        Logger.getLogger(FixingsKMChartService.class);
+
+    public static final int DEFAULT_WIDTH  = 240;
+    public static final int DEFAULT_HEIGHT = 180;
+
+    public static final String [] I18N_Q_SECTOR_BOARDERS = {
+        "fix.km.chart.q.sector.border0",
+        "fix.km.chart.q.sector.border1",
+        "fix.km.chart.q.sector.border2"
+    };
+
+    public static final String [] DEFAULT_Q_SECTOR_BORDERS = {
+        "(MNQ + MQ)/2",
+        "(MQ + MHQ)/2",
+        "HQ5"
+    };
+
+    public static final String I18N_CHART_LABEL_DATE =
+        "fix.km.chart.label.date";
+
+    public static final String DEFAULT_CHART_LABEL_DATE =
+        "yyyy/MM/dd";
+
+    public static final String I18N_CHART_TITLE =
+        "fix.km.chart.title";
+
+    public static final String DEFAULT_CHART_TITLE =
+        "Fixings {0} km {1,number,#.###}";
+
+    public static final String I18N_Q_AXIS =
+        "fix.km.chart.q.axis";
+
+    public static final String DEFAULT_Q_AXIS =
+        "Q [m\u00b3/s]";
+
+    public static final String I18N_W_AXIS =
+        "fix.km.chart.w.axis";
+
+    public static final String DEFAULT_W_AXIS =
+        "W [NN + m]";
+
+    public static final String I18N_MEASURED =
+        "fix.km.chart.measured";
+
+    public static final String DEFAULT_MEASURED =
+        "measured";
+
+    public static final String I18N_INTERPOLATED =
+        "fix.km.chart.interpolated";
+
+    public static final String DEFAULT_INTERPOLATED =
+        "interpolated";
+
+    public static final String DEFAULT_FORMAT = "png";
+
+    // TODO: Load fancy image from resources.
+    public static final byte [] EMPTY = {
+        (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47,
+        (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d,
+        (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
+        (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x3a, (byte)0x7e, (byte)0x9b,
+        (byte)0x55, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x01, (byte)0x73, (byte)0x52, (byte)0x47,
+        (byte)0x42, (byte)0x00, (byte)0xae, (byte)0xce,
+        (byte)0x1c, (byte)0xe9, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x09, (byte)0x70, (byte)0x48,
+        (byte)0x59, (byte)0x73, (byte)0x00, (byte)0x00,
+        (byte)0x0b, (byte)0x13, (byte)0x00, (byte)0x00,
+        (byte)0x0b, (byte)0x13, (byte)0x01, (byte)0x00,
+        (byte)0x9a, (byte)0x9c, (byte)0x18, (byte)0x00,
+        (byte)0x00, (byte)0x00, (byte)0x07, (byte)0x74,
+        (byte)0x49, (byte)0x4d, (byte)0x45, (byte)0x07,
+        (byte)0xdc, (byte)0x04, (byte)0x04, (byte)0x10,
+        (byte)0x30, (byte)0x15, (byte)0x7d, (byte)0x77,
+        (byte)0x36, (byte)0x0b, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x08, (byte)0x74, (byte)0x45,
+        (byte)0x58, (byte)0x74, (byte)0x43, (byte)0x6f,
+        (byte)0x6d, (byte)0x6d, (byte)0x65, (byte)0x6e,
+        (byte)0x74, (byte)0x00, (byte)0xf6, (byte)0xcc,
+        (byte)0x96, (byte)0xbf, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x0a, (byte)0x49, (byte)0x44,
+        (byte)0x41, (byte)0x54, (byte)0x08, (byte)0xd7,
+        (byte)0x63, (byte)0xf8, (byte)0x0f, (byte)0x00,
+        (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x00,
+        (byte)0x1b, (byte)0xb6, (byte)0xee, (byte)0x56,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x49, (byte)0x45, (byte)0x4e, (byte)0x44,
+        (byte)0xae, (byte)0x42, (byte)0x60, (byte)0x82
+    };
+
+    private static final Output empty() {
+        return new Output(EMPTY, "image/png");
+    }
+
+    @Override
+    public Service.Output process(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        log.debug("FixingsKMChartService.process");
+
+        SessionHolder.acquire();
+        try {
+            return doProcess(data, globalContext, callMeta);
+        }
+        finally {
+            SessionHolder.HOLDER.get().close();
+            SessionHolder.release();
+        }
+    }
+
+    protected Service.Output doProcess(
+        Document      input,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        String    river  = getRiverName(input);
+        Double    km     = getKM(input);
+        Dimension extent = getExtent(input);
+        String    format = getFormat(input);
+
+        if (river == null || km == null) {
+            log.warn("River and/or km invalid.");
+            return empty();
+        }
+
+        FixingsOverview overview = FixingsOverviewFactory.getOverview(river);
+
+        if (overview == null) {
+            log.warn("No overview found for river '" + river + "'");
+            return empty();
+        }
+
+        FixingsFilterBuilder ffb = new FixingsFilterBuilder(input);
+
+        List<Fixing.Column> columns = overview.filter(
+            ffb.getRange(),
+            ffb.getFilter());
+
+        List<Pair<Fixing.Column, FixingsColumn>> cols =
+            new ArrayList<Pair<Fixing.Column, FixingsColumn>>();
+
+        for (Fixing.Column col: columns) {
+            FixingsColumn data =
+                FixingsColumnFactory.INSTANCE.getColumnData(col);
+            if (data != null) {
+                cols.add(new Pair<Fixing.Column, FixingsColumn>(col, data));
+            }
+        }
+
+        JFreeChart chart = createChart(cols, river, km, callMeta);
+
+        return encode(chart, extent, format);
+    }
+
+    protected static Output encode(
+        JFreeChart chart,
+        Dimension  extent,
+        String     format
+    ) {
+        BufferedImage image = chart.createBufferedImage(
+            extent.width, extent.height,
+            Transparency.BITMASK,
+            null);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try {
+            ImageIO.write(image, format, out);
+        }
+        catch (IOException ioe) {
+            log.warn("writing image failed", ioe);
+            return empty();
+        }
+
+        return new Output(out.toByteArray(), "image/" + format);
+    }
+
+    protected static JFreeChart createChart(
+        List<Pair<Fixing.Column, FixingsColumn>> cols,
+        String      river,
+        double      km,
+        CallMeta    callMeta
+    ) {
+        String labelFormat = Resources.getMsg(
+            callMeta, I18N_CHART_LABEL_DATE, DEFAULT_CHART_LABEL_DATE);
+
+        QWSeriesCollection.LabelGenerator lg =
+            new QWSeriesCollection.DateFormatLabelGenerator(labelFormat);
+
+        QWSeriesCollection dataset = new QWSeriesCollection(lg);
+
+        double [] w = new double[1];
+        for (Pair<Fixing.Column, FixingsColumn> col: cols) {
+            boolean interpolated = !col.getB().getW(km, w);
+            double q = col.getB().getQ(km);
+            if (!Double.isNaN(w[0]) && !Double.isNaN(q)) {
+                QWI qw = new QWI(
+                    q, w[0],
+                    col.getA().getDescription(),
+                    col.getA().getStartTime(),
+                    interpolated, 0);
+                dataset.add(qw);
+            }
+        }
+
+        String title = Resources.format(
+            callMeta, I18N_CHART_TITLE, DEFAULT_CHART_TITLE, river, km);
+
+        String qAxis = Resources.getMsg(
+            callMeta, I18N_Q_AXIS, DEFAULT_Q_AXIS);
+
+        String wAxis = Resources.getMsg(
+            callMeta, I18N_W_AXIS, DEFAULT_W_AXIS);
+
+        JFreeChart chart = ChartFactory.createXYLineChart(
+            title,
+            qAxis,
+            wAxis,
+            null,
+            PlotOrientation.VERTICAL,
+            true,
+            true,
+            false);
+
+        XYPlot plot = (XYPlot)chart.getPlot();
+
+        NumberAxis qA = (NumberAxis)plot.getDomainAxis();
+        qA.setNumberFormatOverride(Formatter.getWaterlevelQ(callMeta));
+
+        NumberAxis wA = (NumberAxis)plot.getRangeAxis();
+        wA.setNumberFormatOverride(Formatter.getWaterlevelW(callMeta));
+
+        plot.setRenderer(0, dataset.createRenderer());
+        plot.setDataset(0, dataset);
+
+        Rectangle2D area = dataset.getArea();
+
+        if (area != null) {
+            double height = area.getHeight();
+            double wInset = Math.max(height, 0.01) * 0.25d;
+
+            wA.setAutoRangeIncludesZero(false);
+            wA.setRange(new Range(
+                area.getMinY() - wInset,
+                area.getMaxY() + wInset));
+        }
+
+        final String measuredS = Resources.getMsg(
+            callMeta, I18N_MEASURED, DEFAULT_MEASURED);
+
+        final String interpolatedS = Resources.getMsg(
+            callMeta, I18N_INTERPOLATED, DEFAULT_INTERPOLATED);
+
+        LegendItemCollection lic = plot.getLegendItems();
+        dataset.addLegendItems(lic, new ShapeRenderer.LabelGenerator() {
+            @Override
+            public String createLabel(ShapeRenderer.Entry entry) {
+                return entry.getFilled() ? measuredS : interpolatedS;
+            }
+        });
+        plot.setFixedLegendItems(lic);
+
+        applyQSectorMarkers(plot, river, km, callMeta);
+
+        chart.setBackgroundPaint(Color.white);
+        plot.setBackgroundPaint(Color.white);
+        plot.setDomainGridlinePaint(Color.gray);
+        plot.setRangeGridlinePaint(Color.gray);
+        plot.setDomainGridlinesVisible(true);
+        plot.setRangeGridlinesVisible(true);
+
+        return chart;
+    }
+
+    /** Add domain markers to plot that indicate Q-sectors. */
+    protected static void applyQSectorMarkers(
+        XYPlot   plot,
+        String   river,
+        double   km,
+        CallMeta meta
+    ) {
+        GaugeFinderFactory ggf = GaugeFinderFactory.getInstance();
+        GaugeFinder        gf  = ggf.getGaugeFinder(river);
+
+        if (gf == null) {
+            log.warn("No gauge finder found for river '" + river + "'");
+            return;
+        }
+
+        GaugeRange gr = gf.find(km);
+        if (gr == null) {
+            log.debug("No gauge range found for km "
+                + km + " on river " + river + ".");
+            return;
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug(gr);
+        }
+
+        for (int i = 0; i < I18N_Q_SECTOR_BOARDERS.length; ++i) {
+            String key   = I18N_Q_SECTOR_BOARDERS[i];
+            String def   = DEFAULT_Q_SECTOR_BORDERS[i];
+            String label = Resources.getMsg(meta, key, def);
+
+            Marker m = createQSectorMarker(
+                gr.getSectorBorder(i),
+                label);
+
+            if (m != null) {
+                plot.addDomainMarker(m);
+            }
+        }
+    }
+
+    protected static Marker createQSectorMarker(double value, String label) {
+        if (Double.isNaN(value)) {
+            return null;
+        }
+        Marker m = new ValueMarker(value);
+        m.setPaint(Color.black);
+        m.setStroke(new BasicStroke());
+        m.setLabel(label);
+        m.setLabelAnchor(RectangleAnchor.TOP_LEFT);
+        m.setLabelTextAnchor(TextAnchor.TOP_LEFT);
+        return m;
+    }
+
+    protected static String getRiverName(Document input) {
+        NodeList rivers = input.getElementsByTagName("river");
+
+        if (rivers.getLength() == 0) {
+            return null;
+        }
+
+        String river = ((Element)rivers.item(0)).getAttribute("name");
+
+        return river.length() > 0 ? river : null;
+    }
+
+    protected static Double getKM(Document input) {
+        NodeList kms = input.getElementsByTagName("km");
+
+        if (kms.getLength() == 0) {
+            return null;
+        }
+
+        String km = ((Element)kms.item(0)).getAttribute("value");
+
+        try {
+            return Double.valueOf(km);
+        }
+        catch (NumberFormatException nfe) {
+            log.warn("Km '" + km + " is not a valid number.");
+            return null;
+        }
+    }
+
+    protected static Dimension getExtent(Document input) {
+
+        int width  = DEFAULT_WIDTH;
+        int height = DEFAULT_HEIGHT;
+
+        NodeList extents = input.getElementsByTagName("extent");
+
+        if (extents.getLength() > 0) {
+            Element element = (Element)extents.item(0);
+            String w = element.getAttribute("width");
+            String h = element.getAttribute("height");
+
+            try {
+                width = Math.max(1, Integer.parseInt(w));
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("width '" + w + "' is not a valid.");
+            }
+
+            try {
+                height = Math.max(1, Integer.parseInt(h));
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("height '" + h + "' is not a valid");
+            }
+        }
+
+        return new Dimension(width, height);
+    }
+
+    protected static String getFormat(Document input) {
+        String format = DEFAULT_FORMAT;
+
+        NodeList formats = input.getElementsByTagName("format");
+
+        if (formats.getLength() > 0) {
+            String type = ((Element)formats.item(0)).getAttribute("type");
+            if (type.length() > 0) {
+                format = type;
+            }
+        }
+
+        return format;
+    }
+}
+// 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/services/FixingsOverviewService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,63 @@
+package de.intevation.flys.artifacts.services;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.flys.artifacts.model.FixingsFilterBuilder;
+
+import de.intevation.flys.artifacts.model.FixingsOverview.Fixing.Filter;
+
+import de.intevation.flys.artifacts.model.Range;
+
+import de.intevation.flys.artifacts.model.FixingsOverview;
+import de.intevation.flys.artifacts.model.FixingsOverviewFactory;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class FixingsOverviewService
+extends      FLYSService
+{
+    private static Logger log =
+        Logger.getLogger(FixingsOverviewService.class);
+
+    public FixingsOverviewService() {
+    }
+
+    @Override
+    public Document doProcess(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        log.debug("FixingsOverviewService.doProcess");
+
+        Document document = XMLUtils.newDocument();
+
+        NodeList nodes = data.getElementsByTagName("river");
+
+        String river = nodes.getLength() > 0
+            ? ((Element)nodes.item(0)).getAttribute("name")
+            : "";
+
+        FixingsOverview overview = FixingsOverviewFactory.getOverview(river);
+
+        if (overview != null) {
+            FixingsFilterBuilder ffb = new FixingsFilterBuilder(data);
+            Range  range  = ffb.getRange();
+            Filter filter = ffb.getFilter();
+            overview.generateOverview(document, range, filter);
+        }
+        else {
+            log.warn("No overview for river '" + river + "' available.");
+        }
+
+        return document;
+    }
+}
+// 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/services/GaugeInfoService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,160 @@
+package de.intevation.flys.artifacts.services;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.Range;
+import de.intevation.flys.model.River;
+
+import de.intevation.flys.artifacts.model.RiverFactory;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class GaugeInfoService extends FLYSService {
+
+    interface Filter {
+        boolean apply(Gauge gauge);
+    }
+
+
+    private static final class ReferenceNumberFilter implements Filter {
+        private long refNr;
+
+        public ReferenceNumberFilter(long refNr) {
+            this.refNr = refNr;
+        }
+
+        @Override
+        public boolean apply(Gauge  gauge) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("Test gauge '" + gauge.getName() + "'");
+            }
+
+            return gauge != null && gauge.getOfficialNumber() == refNr;
+        }
+    } // end of ReferenceNumberFilter class
+
+
+    /** The logger that is used by this service.*/
+    private static Logger logger = Logger.getLogger(GaugeInfoService.class);
+
+
+    public static final String XPATH_RIVERNAME = "/art:river/@name";
+
+    public static final String XPATH_REFERENCE_NR
+        = "/art:river/art:filter/art:gauge/text()";
+
+
+    public GaugeInfoService() {
+    }
+
+
+    @Override
+    public Document doProcess(
+        Document      data,
+        GlobalContext context,
+        CallMeta      callMeta
+    ) {
+        logger.debug("GaugeInfoService.process");
+
+        if (logger.isDebugEnabled()) {
+            logger.debug(XMLUtils.toString(data));
+        }
+
+        River river = getRiverFromRequest(data);
+
+        List<Filter> filters  = getFilters(data);
+        List<Gauge> allGauges = river.getGauges();
+        List<Gauge> filtered  = new ArrayList<Gauge>();
+
+        for (Gauge g: allGauges) {
+            for (Filter f: filters) {
+                if (f.apply(g)) {
+                    filtered.add(g);
+                    break;
+                }
+            }
+        }
+
+        return buildInfoDocument(filtered);
+    }
+
+
+    protected River getRiverFromRequest(Document data) {
+        String rivername = XMLUtils.xpathString(
+            data,
+            XPATH_RIVERNAME,
+            ArtifactNamespaceContext.INSTANCE);
+
+        logger.debug("Return Gauge info for River '" + rivername + "'");
+
+        return rivername != null ? RiverFactory.getRiver(rivername) : null;
+    }
+
+
+    protected List<Filter> getFilters(Document data) {
+        List<Filter> filters = new ArrayList<Filter>();
+
+        String refNr = XMLUtils.xpathString(
+            data,
+            XPATH_REFERENCE_NR,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (refNr != null && refNr.length() > 0) {
+            try {
+                filters.add(
+                    new ReferenceNumberFilter(Long.parseLong(refNr)));
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn(nfe, nfe);
+            }
+        }
+
+        return filters;
+    }
+
+
+    protected Document buildInfoDocument(List<Gauge> gauges) {
+        Document doc = XMLUtils.newDocument();
+
+        ElementCreator cr = new ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element service = cr.create("service");
+
+        logger.debug("Append " + gauges.size() + " gauges to info doc.");
+
+        for (Gauge g: gauges) {
+            Range r = g.getRange();
+
+            Element el = cr.create("gauge");
+            cr.addAttr(el, "name", g.getName());
+            cr.addAttr(el, "lower", String.valueOf(r.getA().doubleValue()));
+            cr.addAttr(el, "upper", String.valueOf(r.getB().doubleValue()));
+
+            service.appendChild(el);
+        }
+
+        doc.appendChild(service);
+
+        return doc;
+    }
+}
+// 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/services/GaugeOverviewInfoService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,160 @@
+package de.intevation.flys.artifacts.services;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.flys.artifacts.model.RiverFactory;
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.MinMaxWQ;
+import de.intevation.flys.model.Range;
+import de.intevation.flys.model.River;
+
+/**
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public class GaugeOverviewInfoService extends FLYSService {
+
+    private static final Logger logger = Logger.getLogger(
+            GaugeOverviewInfoService.class);
+
+    public static final String RIVER_XPATH = "/art:river/text()";
+
+    @Override
+    public Document doProcess(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        logger.debug("GaugeOverviewInfoService.process");
+
+        String riverstr = XMLUtils.xpathString(
+            data, RIVER_XPATH, ArtifactNamespaceContext.INSTANCE);
+
+        River river = RiverFactory.getRiver(riverstr);
+
+        Document result = XMLUtils.newDocument();
+
+        if (river == null) {
+            logger.warn("No river with name " + riverstr + " found.");
+            return result;
+        }
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element go = ec.create("gauge-info");
+
+        double[] minmax  = river.determineMinMaxDistance();
+        double[] minmaxq = river.determineMinMaxQ();
+
+        Element r = ec.create("river");
+        ec.addAttr(r, "name", river.getName(), true);
+        ec.addAttr(r, "start", Double.toString(minmax[0]), true);
+        ec.addAttr(r, "end", Double.toString(minmax[1]), true);
+        ec.addAttr(r, "wstunit", river.getWstUnit().getName(), true);
+        ec.addAttr(r, "kmup", Boolean.toString(river.getKmUp()), true);
+        ec.addAttr(r, "minq", Double.toString(minmaxq[0]), true);
+        ec.addAttr(r, "maxq", Double.toString(minmaxq[1]), true);
+        ec.addAttr(r, "official", Long.toString(river.getOfficialNumber()),
+                    true);
+
+        Element egs = ec.create("gauges");
+
+        List<Gauge> gauges = river.getGauges();
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Loaded gauges: " + gauges);
+        }
+
+        for (Gauge gauge: river.getGauges()) {
+            Element eg = ec.create("gauge");
+
+            String name = gauge.getName();
+            if (name != null) {
+                ec.addAttr(eg, "name", gauge.getName(), true);
+            }
+
+            String aeo = getGaugeValue(gauge.getAeo());
+            if (aeo != null) {
+                ec.addAttr(eg, "aeo", aeo, true);
+            }
+
+            String datum = getGaugeValue(gauge.getDatum());
+            if (datum != null) {
+                ec.addAttr(eg, "datum", datum, true);
+            }
+
+            Range range = gauge.getRange();
+            if (range != null) {
+                BigDecimal a = range.getA();
+                if (a != null) {
+                    double min = a.doubleValue();
+                    ec.addAttr(eg, "start", Double.toString(min), true);
+                }
+
+                BigDecimal b = range.getB();
+                if (b != null) {
+                    double max = range.getB().doubleValue();
+                    ec.addAttr(eg, "end", Double.toString(max), true);
+                }
+            }
+            MinMaxWQ minmaxwq = gauge.fetchMaxMinWQ();
+            String minw = getGaugeValue(minmaxwq.getMinW());
+            String maxw = getGaugeValue(minmaxwq.getMaxW());
+            String minq = getGaugeValue(minmaxwq.getMinQ());
+            String maxq = getGaugeValue(minmaxwq.getMaxQ());
+
+            if (minw != null) {
+                ec.addAttr(eg, "minw", minw, true);
+            }
+            if (maxw != null) {
+                ec.addAttr(eg, "maxw", maxw, true);
+            }
+            if (minq != null) {
+                ec.addAttr(eg, "minq", minq, true);
+            }
+            if (maxq != null) {
+                ec.addAttr(eg, "maxq", maxq, true);
+            }
+
+            String station = getGaugeValue(gauge.getStation());
+            if (station != null) {
+                ec.addAttr(eg, "station", station, true);
+            }
+
+            Long official = gauge.getOfficialNumber();
+            if (official != null) {
+                ec.addAttr(eg, "official", official.toString(), true);
+            }
+
+            egs.appendChild(eg);
+        }
+
+        go.appendChild(r);
+        go.appendChild(egs);
+        result.appendChild(go);
+
+        return result;
+    }
+
+    /**
+     * Returns a Double from a BigDecimal value or null if value is null
+     */
+    private static String getGaugeValue(BigDecimal value) {
+        return value != null
+            ? Double.toString(value.doubleValue())
+            : "";
+    }
+}
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -21,7 +21,6 @@
 import de.intevation.flys.model.Range;
 import de.intevation.flys.model.River;
 
-import de.intevation.flys.artifacts.model.MainValuesFactory;
 import de.intevation.flys.artifacts.model.RiverFactory;
 
 
@@ -52,6 +51,11 @@
     public MainValuesService() {
     }
 
+    private static final Document error(String msg) {
+        logger.debug(msg);
+        return XMLUtils.newDocument();
+    }
+
 
     @Override
     public Document doProcess(
@@ -61,23 +65,21 @@
     ) {
         logger.debug("MainValuesService.process");
 
-        try {
-            River river     = getRequestedRiver(data);
-            double[] minmax = getRequestedStartEnd(data, river);
-            Gauge gauge     = river.determineGauge(minmax[0], minmax[1]);
-
-            logger.debug("Found gauge: " + gauge.getName());
+        River river = getRequestedRiver(data);
+        if (river == null) {
+            return error("no river found.");
+        }
 
-            List<MainValue> mainValues = getMainValues(river, gauge);
+        double[] minmax = getRequestedStartEnd(data, river);
+        Gauge gauge = river.determineGauge(minmax[0], minmax[1]);
 
-            return buildDocument(river, gauge, mainValues, context);
+        if (gauge == null) {
+            return error("no gauge found.");
         }
-        catch (NullPointerException npe) {
-            logger.error("Could not process the request.");
-            logger.error(npe, npe);
 
-            return XMLUtils.newDocument();
-        }
+        List<MainValue> mainValues = getMainValues(river, gauge);
+
+        return buildDocument(river, gauge, mainValues, context);
     }
 
 
@@ -98,17 +100,9 @@
         String riverStr = XMLUtils.xpathString(
             data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE);
 
-        if (riverStr == null || riverStr.trim().length() == 0) {
-            throw new NullPointerException("No river found in the request.");
-        }
-
-        River river = RiverFactory.getRiver(riverStr);
-
-        if (river == null) {
-            throw new NullPointerException("No such river found: " + riverStr);
-        }
-
-        return river;
+         return riverStr != null && (riverStr = riverStr.trim()).length() > 0
+            ? RiverFactory.getRiver(riverStr)
+            : null;
     }
 
 
@@ -132,18 +126,23 @@
         String endStr = XMLUtils.xpathString(
             data, XPATH_END, ArtifactNamespaceContext.INSTANCE);
 
+        if (startStr == null || endStr == null) {
+            return river.determineMinMaxDistance();
+        }
+
         try {
             double start = Double.parseDouble(startStr);
             double end   = Double.parseDouble(endStr);
 
-            logger.debug("Found start: " + start);
-            logger.debug("Found end: " + end);
+            if (logger.isDebugEnabled()) {
+                logger.debug("Found start: " + start);
+                logger.debug("Found end: " + end);
+            }
 
             return new double[] { start, end };
         }
         catch (NumberFormatException nfe) {
             logger.warn(nfe, nfe);
-
             return river.determineMinMaxDistance();
         }
     }
@@ -159,23 +158,20 @@
      * @return a document that includes the main values of the specified river
      * at the specified gauge.
      */
-    protected List<MainValue> getMainValues(River river, Gauge gauge)
-    throws    NullPointerException
-    {
+    protected List<MainValue> getMainValues(River river, Gauge gauge) {
+
         if (logger.isDebugEnabled()) {
             logger.debug("MainValuesService.buildMainValues");
             logger.debug("River: " + river.getName());
             logger.debug("Gauge: " + gauge.getName());
         }
 
-        List<MainValue> mainValues = MainValuesFactory.getMainValues(gauge);
+        List<MainValue> mainValues = gauge.getMainValues();
 
-        if (mainValues == null || mainValues.isEmpty()) {
-            throw new NullPointerException("No main values found.");
+        if (logger.isDebugEnabled()) {
+            logger.debug(mainValues.size() + " main values found.");
         }
 
-        logger.debug(mainValues.size() + " main values found.");
-
         return mainValues;
     }
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,9 +2,15 @@
 
 import org.apache.log4j.Logger;
 
+import java.util.Map;
+import java.util.HashMap;
+
 import org.w3c.dom.Document;
+import org.w3c.dom.Node;
 import org.w3c.dom.Element;
 
+import javax.xml.xpath.XPathConstants;
+
 import com.vividsolutions.jts.geom.Envelope;
 
 import de.intevation.artifacts.CallMeta;
@@ -15,11 +21,10 @@
 import de.intevation.artifacts.common.utils.XMLUtils;
 import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
 
-import de.intevation.artifactdatabase.DefaultService;
+import de.intevation.artifactdatabase.XMLService;
 
 import de.intevation.flys.model.River;
 
-import de.intevation.flys.model.RiverAxis;
 import de.intevation.flys.utils.GeometryUtils;
 
 /**
@@ -28,19 +33,19 @@
  *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
-public class MapInfoService extends DefaultService {
+public class MapInfoService extends XMLService {
 
     /** XPath that points to the river.*/
     public static final String XPATH_RIVER = "/mapinfo/river/text()";
 
     public static final String XPATH_RIVER_PROJECTION =
-        "/artifact-database/floodmap/river[@name='%RIVER%']/srid/@value";
+        "/artifact-database/floodmap/river[@name=$river]/srid/@value";
 
     public static final String XPATH_RIVER_BACKGROUND =
-        "/artifact-database/floodmap/river[@name='%RIVER%']/background-wms";
+        "/artifact-database/floodmap/river[@name=$river]/background-wms";
 
     public static final String XPATH_RIVER_WMS =
-        "/artifact-database/floodmap/river[@name='%RIVER%']/river-wms/@url";
+        "/artifact-database/floodmap/river[@name=$river]/river-wms/@url";
 
 
     /** The logger used in this service.*/
@@ -53,8 +58,26 @@
     public MapInfoService() {
     }
 
+    protected static String getStringXPath(
+        String              query,
+        Map<String, String> variables
+    ) {
+        return (String)XMLUtils.xpath(
+            Config.getConfig(), query, XPathConstants.STRING,
+            null, variables);
+    }
 
-    public Document process(
+    protected static Node getNodeXPath(
+        String              query,
+        Map<String, String> variables
+    ) {
+        return (Node)XMLUtils.xpath(
+            Config.getConfig(), query, XPathConstants.NODE,
+            null, variables);
+    }
+
+    @Override
+    public Document processXML(
         Document      data,
         GlobalContext globalContext,
         CallMeta      callMeta
@@ -77,27 +100,28 @@
         cr.addAttr(root, "name", river);
         mapinfo.appendChild(root);
 
-        RiverAxis axis = RiverAxis.getRiverAxis(river);
-        if (axis != null) {
-            Envelope env    = axis.getGeom().getEnvelopeInternal();
-            String   bounds = GeometryUtils.jtsBoundsToOLBounds(env);
+        Envelope env = GeometryUtils.getRiverBoundary(river);
+        if (env != null) {
+            String bounds = GeometryUtils.jtsBoundsToOLBounds(env);
+            logger.debug("River '" + river + "' bounds: " + bounds);
 
-            logger.debug("River '" + river + "' bounds: " + bounds);
             Element bbox = cr.create("bbox");
             cr.addAttr(bbox, "value", bounds);
             root.appendChild(bbox);
         }
 
-        String xpathS  = XPATH_RIVER_PROJECTION.replace("%RIVER%", river);
-        String sridStr = Config.getStringXPath(xpathS);
+        Map<String, String> vars = new HashMap<String, String>();
+        vars.put("river", river);
+
+        String sridStr = getStringXPath(XPATH_RIVER_PROJECTION, vars);
+
         if (sridStr != null && sridStr.length() > 0) {
             Element srid = cr.create("srid");
             cr.addAttr(srid, "value", sridStr);
             root.appendChild(srid);
         }
 
-        String xpathB = XPATH_RIVER_BACKGROUND.replace("%RIVER%", river);
-        Element back  = (Element) Config.getNodeXPath(xpathB);
+        Element back = (Element)getNodeXPath(XPATH_RIVER_BACKGROUND, vars);
         if (back != null) {
             Element background = cr.create("background-wms");
             cr.addAttr(background, "url", back.getAttribute("url"));
@@ -105,8 +129,7 @@
             root.appendChild(background);
         }
 
-        String xpathWMS = XPATH_RIVER_WMS.replace("%RIVER%", river);
-        String wmsStr   = Config.getStringXPath(xpathWMS);
+        String wmsStr = getStringXPath(XPATH_RIVER_WMS, vars);
         if (wmsStr != null && wmsStr.length() > 0) {
             Element wms = cr.create("river-wms");
             cr.addAttr(wms, "url", wmsStr);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MetaDataService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -158,7 +158,7 @@
         String [] outs = outsString == null
             ? new String [0]
             : outsString.split("\\s*,\\s*");
-        
+
         Recommendations rec = Recommendations.getInstance();
         rec.recommend(
             flysArtifact, userId, outs, data, result);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/ModuleService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,62 @@
+package de.intevation.flys.artifacts.services;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+import de.intevation.flys.artifacts.model.Module;
+import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.resources.Resources;
+
+public class ModuleService extends FLYSService {
+
+    private static final String MODULE = "module";
+
+    private static Logger logger = Logger.getLogger(ModuleService.class);
+
+    protected Document doProcess(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        logger.debug("ModuleService.process");
+
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element em = ec.create("modules");
+        List<Module> modules = (List<Module>)globalContext.get(FLYSContext.MODULES);
+
+        for (Module module : modules) {
+            Element m = ec.create("module");
+            ec.addAttr(m, "name", module.getName(), true);
+            String localname = Resources.getMsg(callMeta,
+                    MODULE + "." + module.getName(), module.getName());
+            ec.addAttr(m, "localname", localname, true);
+
+            if (module.isSelected()) {
+                ec.addAttr(m, "selected", "true", true);
+            }
+
+            em.appendChild(m);
+        }
+
+        result.appendChild(em);
+
+        return result;
+    }
+}
+
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/QWSeriesCollection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,227 @@
+package de.intevation.flys.artifacts.services;
+
+import de.intevation.flys.artifacts.model.fixings.QWI;
+
+import de.intevation.flys.java2d.ShapeUtils;
+
+import de.intevation.flys.jfree.ShapeRenderer;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Paint;
+import java.awt.Shape;
+
+import java.awt.geom.Rectangle2D;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jfree.chart.LegendItem;
+import org.jfree.chart.LegendItemCollection;
+
+import org.jfree.chart.labels.XYItemLabelGenerator;
+
+import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
+
+import org.jfree.data.xy.XYDataset;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+public class QWSeriesCollection
+extends      XYSeriesCollection
+implements   XYItemLabelGenerator
+{
+    public interface LabelGenerator {
+        String createLabel(QWI qw);
+    } // interface LabelGenerator
+
+    public static class DateFormatLabelGenerator
+    implements          LabelGenerator
+    {
+        protected DateFormat format;
+
+        public DateFormatLabelGenerator() {
+            this("dd.MM.yyyy");
+        }
+
+        public DateFormatLabelGenerator(String format) {
+            this(new SimpleDateFormat(format));
+        }
+
+        public DateFormatLabelGenerator(DateFormat format) {
+            this.format = format;
+        }
+
+        @Override
+        public String createLabel(QWI qw) {
+            Date date = qw.getDate();
+            return date != null ? format.format(date) : "";
+        }
+    } // class DateFormatLabelGenerator
+
+    public static final LabelGenerator SIMPLE_GENERATOR =
+        new DateFormatLabelGenerator();
+
+    protected Date minDate;
+    protected Date maxDate;
+
+    protected List<List<QWI>> labels;
+
+    protected Rectangle2D area;
+
+    protected LabelGenerator labelGenerator;
+
+    protected Map<ShapeRenderer.Entry, Integer> knownShapes =
+        new HashMap<ShapeRenderer.Entry, Integer>();
+
+    public QWSeriesCollection() {
+        labels = new ArrayList<List<QWI>>();
+        labelGenerator = SIMPLE_GENERATOR;
+    }
+
+    public QWSeriesCollection(LabelGenerator labelGenerator) {
+        this();
+        this.labelGenerator = labelGenerator;
+    }
+
+    protected static ShapeRenderer.Entry classify(QWI qw) {
+        boolean interpolated = qw.getInterpolated();
+
+        Shape shape = interpolated
+            ? ShapeUtils.INTERPOLATED_SHAPE
+            : ShapeUtils.MEASURED_SHAPE;
+
+        boolean filled = !interpolated;
+        Color color = Color.blue;
+
+        return new ShapeRenderer.Entry(shape, color, filled);
+    }
+
+    public void add(QWI qw) {
+
+        ShapeRenderer.Entry key = classify(qw);
+
+        Integer seriesNo = knownShapes.get(key);
+
+        XYSeries series;
+
+        if (seriesNo == null) {
+            seriesNo = Integer.valueOf(getSeriesCount());
+            knownShapes.put(key, seriesNo);
+            series = new XYSeries(seriesNo, false);
+            addSeries(series);
+            labels.add(new ArrayList<QWI>());
+        }
+        else {
+            series = getSeries(seriesNo);
+        }
+
+        series.add(qw.getQ(), qw.getW());
+
+        labels.get(seriesNo).add(qw);
+
+        extendDateRange(qw);
+        extendArea(qw);
+    }
+
+    protected void extendDateRange(QWI qw) {
+        Date date = qw.getDate();
+        if (date != null) {
+            if (minDate == null) {
+                minDate = maxDate = date;
+            }
+            else {
+                if (date.compareTo(minDate) < 0) {
+                    minDate = date;
+                }
+                if (date.compareTo(maxDate) > 0) {
+                    maxDate = date;
+                }
+            }
+        }
+    }
+
+    protected void extendArea(QWI qw) {
+        if (area == null) {
+            area = new Rectangle2D.Double(
+                qw.getQ(), qw.getW(), 0d, 0d);
+        }
+        else {
+            area.add(qw.getQ(), qw.getW());
+        }
+    }
+
+    public Rectangle2D getArea() {
+        return area;
+    }
+
+    public Date getMinDate() {
+        return minDate;
+    }
+
+    public Date getMaxDate() {
+        return maxDate;
+    }
+
+    public LabelGenerator getLabelGenerator() {
+        return labelGenerator;
+    }
+
+    @Override
+    public String generateLabel(XYDataset dataset, int series, int item) {
+        return labelGenerator.createLabel(labels.get(series).get(item));
+    }
+
+    public StandardXYItemRenderer createRenderer() {
+        StandardXYItemRenderer renderer = new ShapeRenderer(knownShapes);
+        renderer.setBaseItemLabelGenerator(this);
+        renderer.setBaseSeriesVisibleInLegend(false);
+        renderer.setBaseItemLabelsVisible(true);
+        return renderer;
+    }
+
+    public static final LegendItem legendItem(
+        String  label,
+        Paint   paint,
+        Shape   shape,
+        boolean filled
+    ) {
+        BasicStroke stroke = new BasicStroke();
+        return new LegendItem(
+            label,  // label
+            null,   // description
+            null,   // tooltip
+            null,   // url
+            true,   // shape visible
+            shape,  // shape
+            filled, // shape filled
+            filled ? paint : Color.white, // fill paint
+            true,   // shape outline
+            paint,  // outline paint
+            stroke, // outline stroke
+            false,  // line visible
+            shape,  // line
+            stroke, // line stroke
+            Color.white);
+    }
+
+    public void addLegendItems(
+        LegendItemCollection         lic,
+        ShapeRenderer.LabelGenerator lg
+    ) {
+        for (ShapeRenderer.Entry entry: knownShapes.keySet()) {
+            lic.add(legendItem(
+                lg.createLabel(entry),
+                entry.getPaint(),
+                entry.getShape(),
+                entry.getFilled()));
+        }
+    }
+}
+// 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/services/SQKMChartService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,316 @@
+package de.intevation.flys.artifacts.services;
+
+import de.intevation.artifactdatabase.DefaultService;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+import de.intevation.artifacts.Service;
+
+import de.intevation.flys.artifacts.model.SQOverview;
+import de.intevation.flys.artifacts.model.SQOverviewFactory;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import de.intevation.flys.backend.SedDBSessionHolder;
+
+import de.intevation.flys.utils.KMIndex;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Transparency;
+
+import java.awt.image.BufferedImage;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+
+import org.jfree.chart.axis.DateAxis;
+
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class SQKMChartService
+extends DefaultService {
+
+    private static final Logger log =
+        Logger.getLogger(SQKMChartService.class);
+
+    public static final int DEFAULT_WIDTH  = 240;
+    public static final int DEFAULT_HEIGHT = 180;
+
+    public static final String I18N_CHART_LABEL =
+        "sq.km.chart.label";
+
+    public static final String DEFAULT_CHART_LABEL =
+        "Measuring Points";
+
+    public static final String I18N_CHART_TITLE =
+        "sq.km.chart.title";
+
+    public static final String DEFAULT_CHART_TITLE =
+        "Measuring points";
+
+    public static final String I18N_KM_AXIS =
+        "sq.km.chart.km.axis";
+
+    public static final String DEFAULT_KM_AXIS =
+        "km";
+
+    public static final String I18N_DATE_AXIS =
+        "sq.km.chart.date.axis";
+
+    public static final String DEFAULT_DATE_AXIS =
+        "Date";
+
+    public static final String DEFAULT_FORMAT = "png";
+
+    // TODO: Load fancy image from resources.
+    public static final byte [] EMPTY = {
+        (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47,
+        (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d,
+        (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
+        (byte)0x08, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x3a, (byte)0x7e, (byte)0x9b,
+        (byte)0x55, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x01, (byte)0x73, (byte)0x52, (byte)0x47,
+        (byte)0x42, (byte)0x00, (byte)0xae, (byte)0xce,
+        (byte)0x1c, (byte)0xe9, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x09, (byte)0x70, (byte)0x48,
+        (byte)0x59, (byte)0x73, (byte)0x00, (byte)0x00,
+        (byte)0x0b, (byte)0x13, (byte)0x00, (byte)0x00,
+        (byte)0x0b, (byte)0x13, (byte)0x01, (byte)0x00,
+        (byte)0x9a, (byte)0x9c, (byte)0x18, (byte)0x00,
+        (byte)0x00, (byte)0x00, (byte)0x07, (byte)0x74,
+        (byte)0x49, (byte)0x4d, (byte)0x45, (byte)0x07,
+        (byte)0xdc, (byte)0x04, (byte)0x04, (byte)0x10,
+        (byte)0x30, (byte)0x15, (byte)0x7d, (byte)0x77,
+        (byte)0x36, (byte)0x0b, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x08, (byte)0x74, (byte)0x45,
+        (byte)0x58, (byte)0x74, (byte)0x43, (byte)0x6f,
+        (byte)0x6d, (byte)0x6d, (byte)0x65, (byte)0x6e,
+        (byte)0x74, (byte)0x00, (byte)0xf6, (byte)0xcc,
+        (byte)0x96, (byte)0xbf, (byte)0x00, (byte)0x00,
+        (byte)0x00, (byte)0x0a, (byte)0x49, (byte)0x44,
+        (byte)0x41, (byte)0x54, (byte)0x08, (byte)0xd7,
+        (byte)0x63, (byte)0xf8, (byte)0x0f, (byte)0x00,
+        (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x00,
+        (byte)0x1b, (byte)0xb6, (byte)0xee, (byte)0x56,
+        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+        (byte)0x49, (byte)0x45, (byte)0x4e, (byte)0x44,
+        (byte)0xae, (byte)0x42, (byte)0x60, (byte)0x82
+    };
+
+    private static final Output empty() {
+        return new Output(EMPTY, "image/png");
+    }
+
+    @Override
+    public Service.Output process(
+        Document      data,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        log.debug("SQKMChartService.process");
+
+        SedDBSessionHolder.acquire();
+        try {
+            return doProcess(data, globalContext, callMeta);
+        }
+        finally {
+            SedDBSessionHolder.HOLDER.get().close();
+            SedDBSessionHolder.release();
+        }
+    }
+
+    protected Service.Output doProcess(
+        Document      input,
+        GlobalContext globalContext,
+        CallMeta      callMeta
+    ) {
+        String    river  = getRiverName(input);
+        Dimension extent = getExtent(input);
+        String    format = getFormat(input);
+
+        if (river == null) {
+            log.warn("River invalid.");
+            return empty();
+        }
+
+        SQOverview overview = SQOverviewFactory.getOverview(river);
+
+        if (overview == null) {
+            log.warn("No overview found for river '" + river + "'");
+            return empty();
+        }
+
+        KMIndex<List<Date>> entries = overview.filter(SQOverview.ACCEPT);
+
+        JFreeChart chart = createChart(entries, river, callMeta);
+
+        return encode(chart, extent, format);
+    }
+
+    protected static Output encode(
+        JFreeChart chart,
+        Dimension  extent,
+        String     format
+    ) {
+        BufferedImage image = chart.createBufferedImage(
+            extent.width, extent.height,
+            Transparency.BITMASK,
+            null);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try {
+            ImageIO.write(image, format, out);
+        }
+        catch (IOException ioe) {
+            log.warn("writing image failed", ioe);
+            return empty();
+        }
+
+        return new Output(out.toByteArray(), "image/" + format);
+    }
+
+    protected static JFreeChart createChart(
+        KMIndex<List<Date>> entries,
+        String      river,
+        CallMeta    callMeta
+    ) {
+
+        XYSeriesCollection dataset = new XYSeriesCollection();
+        String key = Resources.format(
+            callMeta, I18N_CHART_LABEL, DEFAULT_CHART_LABEL, river);
+
+        XYSeries series = new XYSeries(key);
+        for (KMIndex.Entry<List<Date>> e: entries) {
+            double km = e.getKm();
+            List<Date> ds = e.getValue();
+            for (Date d: ds) {
+                series.add(km, d.getTime());
+            }
+        }
+
+        dataset.addSeries(series);
+        String title = Resources.format(
+            callMeta, I18N_CHART_TITLE, DEFAULT_CHART_TITLE, river);
+
+        String kmAxis = Resources.getMsg(
+            callMeta, I18N_KM_AXIS, DEFAULT_KM_AXIS);
+
+        String dateAxis = Resources.getMsg(
+            callMeta, I18N_DATE_AXIS, DEFAULT_DATE_AXIS);
+
+        JFreeChart chart = ChartFactory.createXYLineChart(
+            title,
+            kmAxis,
+            dateAxis,
+            null,
+            PlotOrientation.VERTICAL,
+            true,
+            true,
+            false);
+
+        XYPlot plot = (XYPlot)chart.getPlot();
+
+        DateAxis dA = new DateAxis();
+        plot.setRangeAxis(dA);
+        plot.setDataset(0, dataset);
+
+        chart.setBackgroundPaint(Color.white);
+        plot.setBackgroundPaint(Color.white);
+        plot.setDomainGridlinePaint(Color.gray);
+        plot.setRangeGridlinePaint(Color.gray);
+        plot.setDomainGridlinesVisible(true);
+        plot.setRangeGridlinesVisible(true);
+        XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
+
+        renderer.setSeriesPaint(0, Color.gray);
+        renderer.setSeriesLinesVisible(0, false);
+        renderer.setSeriesShapesVisible(0, true);
+        renderer.setDrawOutlines(true);
+        return chart;
+    }
+
+
+    protected static String getRiverName(Document input) {
+        NodeList rivers = input.getElementsByTagName("river");
+
+        if (rivers.getLength() == 0) {
+            return null;
+        }
+
+        String river = ((Element)rivers.item(0)).getAttribute("name");
+
+        return river.length() > 0 ? river : null;
+    }
+
+    protected static Dimension getExtent(Document input) {
+
+        int width  = DEFAULT_WIDTH;
+        int height = DEFAULT_HEIGHT;
+
+        NodeList extents = input.getElementsByTagName("extent");
+
+        if (extents.getLength() > 0) {
+            Element element = (Element)extents.item(0);
+            String w = element.getAttribute("width");
+            String h = element.getAttribute("height");
+
+            try {
+                width = Math.max(1, Integer.parseInt(w));
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("width '" + w + "' is not a valid.");
+            }
+
+            try {
+                height = Math.max(1, Integer.parseInt(h));
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("height '" + h + "' is not a valid");
+            }
+        }
+
+        return new Dimension(width, height);
+    }
+
+    protected static String getFormat(Document input) {
+        String format = DEFAULT_FORMAT;
+
+        NodeList formats = input.getElementsByTagName("format");
+
+        if (formats.getLength() > 0) {
+            String type = ((Element)formats.item(0)).getAttribute("type");
+            if (type.length() > 0) {
+                format = type;
+            }
+        }
+
+        return format;
+    }
+}
+// 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/services/ThemeListingService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,74 @@
+package de.intevation.flys.artifacts.services;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.GlobalContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.flys.themes.Theme;
+import de.intevation.flys.themes.ThemeGroup;
+
+import de.intevation.flys.themes.ThemeFactory;
+import de.intevation.flys.artifacts.context.FLYSContext;
+
+/**
+ * This service provides a list of themes filtered by the theme name.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class ThemeListingService extends FLYSService {
+
+    /** The logger used in this service.*/
+    private static Logger logger = Logger.getLogger(ThemeListingService.class);
+
+    private static final String XPATH_THEME_NAME = "/theme/@name";
+
+    protected Document doProcess(
+        Document      data,
+        GlobalContext context,
+        CallMeta      callMeta
+    ) {
+        logger.debug("ThemeListingService.process");
+        String name = XMLUtils.xpathString(data, XPATH_THEME_NAME, null);
+
+        if (name == null) {
+            logger.warn("No theme name provided.");
+        }
+        Document result = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            result,
+            null,
+            null);
+
+        List<ThemeGroup> tgs =
+            ThemeFactory.getThemeGroups((FLYSContext) context);
+
+        Element te = ec.create("themes");
+
+        for (ThemeGroup tg: tgs) {
+            Element elem = ec.create("themegroup");
+            if (tg.getName().equals("virtual")) {
+                continue;
+            }
+            ec.addAttr(elem, "name", tg.getName());
+            Theme theme = tg.getThemeByName(name);
+            Document d = theme.toXML();
+            Node imported = result.importNode(d.getDocumentElement(), true);
+            elem.appendChild(imported);
+            te.appendChild(elem);
+        }
+
+        result.appendChild(te);
+        return result;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/CalculationSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -54,11 +54,16 @@
     public static final String CALCULATION_REFERENCE_CURVE =
         "calc.reference.curve";
 
+    /** Constant value for the historical discharge curve calculation. */
+    public static final String CALCULATION_HISTORICAL_DISCHARGE_CURVE =
+        "calc.historical.discharge.curve";
+
     /** An array that holds all available calculation modes. */
     public static final String[] CALCULATIONS = {
         CALCULATION_SURFACE_CURVE,
         CALCULATION_FLOOD_MAP,
         CALCULATION_DISCHARGE_CURVE,
+        CALCULATION_HISTORICAL_DISCHARGE_CURVE,
         CALCULATION_DURATION_CURVE,
         CALCULATION_DISCHARGE_LONGITUDINAL_CURVE,
         CALCULATION_W_DIFFERENCES,
@@ -89,10 +94,9 @@
         CallMeta meta   = context.getMeta();
         Element[] calcs = new Element[CALCULATIONS.length];
 
-        int i = 0;
-
-        for (String calc: CALCULATIONS) {
-            calcs[i++] = createItem(
+        for (int i = 0; i < CALCULATIONS.length; ++i) {
+            String calc = CALCULATIONS[i];
+            calcs[i] = createItem(
                 cr, new String[] {
                     Resources.getMsg(meta, calc, calc),
                     calc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/CalculationSelectMinfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,109 @@
+package de.intevation.flys.artifacts.states;
+
+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.artifactdatabase.data.StateData;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.resources.Resources;
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class CalculationSelectMinfo extends DefaultState {
+
+    /** The logger that is used in this class. */
+    private static Logger logger = Logger.getLogger(CalculationSelectMinfo.class);
+
+
+    public static final String FIELD_MODE = "calculation_mode";
+
+    public static final String CALC_BED_MIDDLE    = "calc.bed.middle";
+    public static final String CALC_BED_DIFF      = "calc.bed.diff";
+    public static final String CALC_BED_QUALITY   = "calc.bed.quality";
+    public static final String CALC_SEDIMENT_LOAD = "calc.sediment.load";
+    public static final String CALC_FLOW_VELOCITY = "calc.flow.velocity";
+    public static final String CALC_SQ_RELATION   = "calc.sq.relation";
+
+    /** An array that holds all available calculation modes. */
+    public static final String[] CALCULATIONS = {
+        CALC_BED_MIDDLE,
+        CALC_BED_DIFF,
+        CALC_BED_QUALITY,
+        CALC_SEDIMENT_LOAD,
+        CALC_FLOW_VELOCITY,
+        CALC_SQ_RELATION
+    };
+
+
+    /** Error message that is thrown if no mode has been chosen. */
+    public static final String ERROR_NO_CALCULATION_MODE =
+        "error_feed_no_calculation_mode";
+
+    /** Error message that is thrown if an invalid calculation mode has been
+     * chosen. */
+    public static  final String ERROR_INVALID_CALCULATION_MODE =
+        "error_feed_invalid_calculation_mode";
+
+
+    public CalculationSelectMinfo() {
+    }
+
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator cr,
+        Artifact    artifact,
+        String      name,
+        CallContext context)
+    {
+        CallMeta meta   = context.getMeta();
+        Element[] calcs = new Element[CALCULATIONS.length];
+
+        for (int i = 0; i < CALCULATIONS.length; ++i) {
+            String calc = CALCULATIONS[i];
+            calcs[i] = createItem(
+                cr, new String[] {
+                    Resources.getMsg(meta, calc, calc),
+                    calc
+                });
+        }
+
+        return calcs;
+    }
+
+
+    @Override
+    public boolean validate(Artifact artifact)
+    throws IllegalArgumentException
+    {
+        logger.debug("CalculationSelect.validate");
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        StateData data = getData(flys, FIELD_MODE);
+        String    calc = (data != null) ? (String) data.getValue() : null;
+
+        if (calc == null) {
+            throw new IllegalArgumentException(ERROR_NO_CALCULATION_MODE);
+        }
+
+        calc = calc.trim().toLowerCase();
+
+        for (String mode: CALCULATIONS) {
+            if (mode.equals(calc)) {
+                return true;
+            }
+        }
+
+        throw new IllegalArgumentException(ERROR_INVALID_CALCULATION_MODE);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ComputationRangeState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,8 +1,5 @@
 package de.intevation.flys.artifacts.states;
 
-import java.util.Date;
-import java.util.List;
-
 import org.apache.log4j.Logger;
 
 import org.w3c.dom.Element;
@@ -14,23 +11,15 @@
 
 import de.intevation.artifactdatabase.ProtocolUtils;
 import de.intevation.artifactdatabase.data.StateData;
-import de.intevation.artifactdatabase.state.Facet;
-
-import de.intevation.flys.model.DischargeTable;
-import de.intevation.flys.model.Gauge;
-import de.intevation.flys.model.River;
-import de.intevation.flys.model.TimeInterval;
 
 import de.intevation.flys.artifacts.FLYSArtifact;
-import de.intevation.flys.artifacts.WINFOArtifact;
-import de.intevation.flys.artifacts.model.CalculationResult;
+
 import de.intevation.flys.artifacts.model.FacetTypes;
-import de.intevation.flys.artifacts.model.GaugesFactory;
-import de.intevation.flys.artifacts.model.RiverFactory;
-import de.intevation.flys.artifacts.model.WaterlevelFacet;
-import de.intevation.flys.artifacts.model.WQKms;
 import de.intevation.flys.artifacts.resources.Resources;
 
+import de.intevation.flys.utils.FLYSUtils;
+
+
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
@@ -149,96 +138,9 @@
 
 
     @Override
-    public Object computeFeed(
-        FLYSArtifact artifact,
-        String       hash,
-        CallContext  context,
-        List<Facet>  facets,
-        Object       old
-    ) {
-        logger.debug("computeFeed");
-
-        WINFOArtifact winfo = (WINFOArtifact)artifact;
-
-        CalculationResult res = old instanceof CalculationResult
-            ? (CalculationResult)old
-            : winfo.getDischargeCurveData();
-
-        if (facets == null) {
-            logger.debug("generate no facets");
-            return res;
-        }
-
-        WQKms [] wqkms = (WQKms [])res.getData();
-
-        logger.debug("generate " + wqkms.length + " facets.");
-
-        String stateID = winfo.getCurrentStateId();
-
-        for (int i = 0; i < wqkms.length; ++i) {
-            String name = getSeriesName(context, wqkms[i].getName());
-            facets.add(new WaterlevelFacet(
-                i, DISCHARGE_CURVE, name, ComputeType.FEED, stateID, hash));
-        }
-
-
-        return res;
-    }
-
-    protected String getSeriesName(CallContext cc, String gaugeName) {
-        Gauge gauge = GaugesFactory.getGauge(gaugeName);
-
-        if (gauge == null) {
-            logger.warn("Cannot determine Gauge for name: " + gaugeName);
-            return gaugeName;
-        }
-
-        List<DischargeTable> dts = gauge.getDischargeTables();
-
-        for (DischargeTable dt: dts) {
-            if (dt.getKind() == 0) {
-                TimeInterval ti = dt.getTimeInterval();
-
-                Date start = ti.getStartTime();
-                Date end   = ti.getStopTime();
-
-                String name  = gauge.getName();
-
-                if (end == null) {
-                    Object[] args = new Object[] { name, start };
-                    return Resources.getMsg(
-                        cc.getMeta(),
-                        "chart.discharge.curve.curve.valid.from",
-                        "",
-                        args);
-                }
-                else {
-                    Object[] args = new Object[] { name, start, end };
-                    return Resources.getMsg(
-                        cc.getMeta(),
-                        "chart.discharge.curve.curve.valid.range",
-                        "",
-                        args);
-                }
-            }
-        }
-
-        return gauge.getName();
-    }
-
-
-    @Override
     protected double[] getMinMax(Artifact artifact) {
         FLYSArtifact flysArtifact = (FLYSArtifact) artifact;
-        StateData    data         = getData(flysArtifact, "river");
-
-        String name = data != null ? (String) data.getValue() : "";
-
-        logger.debug("Search for the min/max distances of '" + name + "'");
-
-        River river = RiverFactory.getRiver(name);
-
-        return river != null ? river.determineMinMaxDistance() : null;
+        return FLYSUtils.getRiverMinMax(flysArtifact);
     }
 
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ComputedDischargeCurveState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -10,11 +10,13 @@
 
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.ChartArtifact;
 
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.WaterlevelFacet;
 import de.intevation.flys.artifacts.model.DataFacet;
 import de.intevation.flys.artifacts.model.ReportFacet;
+import de.intevation.flys.artifacts.model.EmptyFacet;
 import de.intevation.flys.artifacts.model.WQKms;
 import de.intevation.flys.artifacts.model.CalculationResult;
 
@@ -40,6 +42,10 @@
     }
 
 
+    /**
+     * Get computed discharge curve data from cache (if available) or
+     * compute anew. Create Waterlevel and DataFacets.
+     */
     @Override
     public Object computeAdvance(
         FLYSArtifact artifact,
@@ -48,40 +54,50 @@
         List<Facet>  facets,
         Object       old
     ) {
-        WINFOArtifact winfo = (WINFOArtifact)artifact;
-
-        CalculationResult res = old instanceof CalculationResult
-            ? (CalculationResult)old
-            : winfo.getComputedDischargeCurveData();
-
-        WQKms [] wqkms = (WQKms [])res.getData();
-
-        if (facets != null && wqkms.length > 0) {
-            for (int i = 0; i < wqkms.length; ++i) {
+        logger.debug("ComputedDischargeCurveState.computeAdvance");
+        if(artifact instanceof WINFOArtifact) {
+            WINFOArtifact winfo = (WINFOArtifact)artifact;
 
-                Object[] args = new Object[] {
-                    FLYSUtils.getRiver(winfo).getName(),
-                    wqkms[i].getName()
-                };
+            CalculationResult res = old instanceof CalculationResult
+                ? (CalculationResult)old
+                : winfo.getComputedDischargeCurveData();
 
-                String name = Resources.getMsg(
-                    context.getMeta(),
-                    "chart.computed.discharge.curve.curve.label",
-                    "",
-                    args);
+            WQKms [] wqkms = (WQKms [])res.getData();
 
-                facets.add(new WaterlevelFacet(i, COMPUTED_DISCHARGE_Q, name));
-                facets.add(new WaterlevelFacet(i, AT, "AT data"));
+            if (facets != null && wqkms.length > 0) {
+                for (int i = 0; i < wqkms.length; ++i) {
+
+                    Object[] args = new Object[] {
+                        FLYSUtils.getRiver(winfo).getName(),
+                        wqkms[i].getName()
+                    };
+
+                    String name = Resources.getMsg(
+                        context.getMeta(),
+                        "chart.computed.discharge.curve.curve.label",
+                        "",
+                        args);
+
+                    facets.add(new WaterlevelFacet(i, COMPUTED_DISCHARGE_Q, name));
+                    facets.add(new WaterlevelFacet(i, AT, "AT data"));
+                }
+
+                facets.add(new DataFacet(CSV, "CSV data"));
+                facets.add(new DataFacet(PDF, "PDF data"));
+
+                if (res.getReport().hasProblems()) {
+                    facets.add(new ReportFacet());
+                }
             }
 
-            facets.add(new DataFacet(CSV, "CSV data"));
-
-            if (res.getReport().hasProblems()) {
-                facets.add(new ReportFacet());
-            }
+            return res;
         }
-
-        return res;
+        else if(artifact instanceof ChartArtifact) {
+            ChartArtifact chart = (ChartArtifact)artifact;
+            facets.add(new EmptyFacet());
+            return null;
+        }
+        return null;
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DefaultState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DefaultState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,7 +1,6 @@
 package de.intevation.flys.artifacts.states;
 
 import java.text.NumberFormat;
-import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
 import java.util.List;
@@ -22,7 +21,6 @@
 
 import de.intevation.artifactdatabase.ProtocolUtils;
 
-import de.intevation.artifactdatabase.data.DefaultStateData;
 import de.intevation.artifactdatabase.data.StateData;
 
 import de.intevation.artifactdatabase.state.AbstractState;
@@ -75,22 +73,22 @@
 
         CallMeta meta = context.getMeta();
 
+        String helpText = Resources.getMsg(meta, getHelpText(), getHelpText());
+
         String label = Resources.getMsg(meta, getID(), getID());
         Element ui   = ProtocolUtils.createArtNode(
             creator, "state",
-            new String[] { "name", "uiprovider", "label" },
-            new String[] { getID(), getUIProvider(), label });
+            new String[] { "name", "uiprovider", "label", "helpText"},
+            new String[] { getID(), getUIProvider(), label, helpText });
 
         Map<String, StateData> theData = getData();
         if (theData == null) {
             return ui;
         }
 
-        Iterator<String> iter = theData.keySet().iterator();
-        FLYSArtifact     flys = (FLYSArtifact) artifact;
+        FLYSArtifact flys = (FLYSArtifact)artifact;
 
-        while (iter.hasNext()) {
-            String name = iter.next();
+        for (String name: theData.keySet()) {
             appendStaticData(flys, context, creator, ui, name);
         }
 
@@ -112,10 +110,15 @@
             return;
         }
 
-        logger.debug("Append element '" + name + "' (" + value + ")");
+        String type = data.getType();
 
-        Element e = createStaticData(
-            flys, cr, context, name, value, data.getType());
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "Append element " + type + "'" +
+                name + "' (" + value + ")");
+        }
+
+        Element e = createStaticData(flys, cr, context, name, value, type);
 
         ui.appendChild(e);
 
@@ -127,7 +130,7 @@
      * document.
      *
      * @param creator The ElementCreator that is used to build new Elements.
-     * @param meta The CallMeta object used for i18n.
+     * @param cc The CallContext object used for nested i18n retrieval.
      * @param name The name of the data item.
      * @param value The value as string.
      *
@@ -141,8 +144,6 @@
         String         value,
         String         type
     ) {
-        CallMeta meta = cc.getMeta();
-
         Element dataElement = creator.create("data");
         creator.addAttr(dataElement, "name", name, true);
         creator.addAttr(dataElement, "type", type, true);
@@ -150,24 +151,75 @@
         Element itemElement = creator.create("item");
         creator.addAttr(itemElement, "value", value, true);
 
-        String attrValue = "";
+        creator.addAttr(
+            itemElement,
+            "label",
+            getLabelFor(cc, name, value, type),
+            true);
+
+        dataElement.appendChild(itemElement);
+
+        return dataElement;
+    }
+
+
+    /**
+     * @param cc
+     * @param name
+     * @param value
+     * @param type
+     *
+     * @return
+     */
+    protected String getLabelFor(
+        CallContext cc,
+        String      name,
+        String      value,
+        String      type
+    ) {
+        CallMeta meta = cc.getMeta();
+
         try {
             // XXX A better way to format the output would be to use the
             // 'type' value of the data objects.
-            double doubleVal = Double.valueOf(value);
+            double doubleVal = Double.parseDouble(value);
             Locale         l = Resources.getLocale(meta);
             NumberFormat  nf = NumberFormat.getInstance(l);
 
-            attrValue = nf.format(doubleVal);
+            return nf.format(doubleVal);
         }
         catch (NumberFormatException nfe) {
-            attrValue = Resources.getMsg(meta, value, value);
+            return Resources.getMsg(meta, value, value);
+        }
+    }
+
+
+    /**
+     * This method returns the default value and description for <i>data</i>.
+     * Note, that this method returns the defaults only if <i>USE_DEFAULTS</i>
+     * is set; otherwise, null is returned.
+     * @param context The CallContext used for i18n.
+     * @param data The data objects that the defaults are for.
+     * @return a String[] with [default value, default label].
+     */
+    protected String[] getDefaultsFor(CallContext context, StateData data) {
+        if (USE_DEFAULTS) {
+            String defValue = (String) data.getValue();
+            String defDesc  = null;
+
+            if (defValue != null && defValue.length() > 0) {
+                defDesc = Resources.getMsg(
+                    context.getMeta(),
+                    defValue,
+                    defValue);
+            }
+
+            if (defValue != null && defDesc != null) {
+                return new String[] { defValue, defDesc };
+            }
         }
 
-        creator.addAttr(itemElement, "label", attrValue, true);
-        dataElement.appendChild(itemElement);
-
-        return dataElement;
+        return null;
     }
 
 
@@ -183,16 +235,22 @@
             ArtifactNamespaceContext.NAMESPACE_URI,
             ArtifactNamespaceContext.NAMESPACE_PREFIX);
 
+        String helpText = Resources.getMsg(
+            context.getMeta(), getHelpText(), getHelpText());
+
         Element ui        = null;
         String uiprovider = getUIProvider();
         if (uiprovider != null) {
             ui = ProtocolUtils.createArtNode(
                 creator, "dynamic",
-                new String[] { "uiprovider" },
-                new String[] { uiprovider });
+                new String[] { "uiprovider", "helpText" },
+                new String[] { uiprovider, helpText });
         }
         else {
-            ui = ProtocolUtils.createArtNode(creator, "dynamic", null, null);
+            ui = ProtocolUtils.createArtNode(
+                creator, "dynamic",
+                new String[] { "helpText" },
+                new String[] { helpText });
         }
 
         Map<String, StateData> theData = getData();
@@ -200,46 +258,25 @@
             return ui;
         }
 
-        Iterator<String> iter = theData.keySet().iterator();
-        FLYSArtifact     flys = (FLYSArtifact) artifact;
+        FLYSArtifact flys = (FLYSArtifact)artifact;
 
-        while (iter.hasNext()) {
-            String    name = iter.next();
+        for (String name: theData.keySet()) {
             StateData data = getData(flys, name);
 
-            data = data != null ? data : getData(name);
+            if (data == null) {
+                data = getData(name);
+            }
 
             Element select = createData(creator, artifact, data, context);
 
-            if (USE_DEFAULTS) {
-                String defValue = (String) data.getValue();
-                String defDesc  = null;
-
-                if (defValue != null && defValue.length() > 0) {
-                    defDesc = Resources.getMsg(
-                        context.getMeta(),
-                        defValue,
-                        defValue);
-                }
-
-                if (defValue != null && defDesc != null) {
-                    creator.addAttr(select, "defaultValue", defValue, true);
-                    creator.addAttr(select, "defaultLabel", defDesc, true);
-                }
+            String[] defaults = getDefaultsFor(context, data);
+            if (defaults != null && defaults.length > 1) {
+                creator.addAttr(select, "defaultValue", defaults[0], true);
+                creator.addAttr(select, "defaultLabel", defaults[1], true);
             }
 
-            Element choices = ProtocolUtils.createArtNode(
-            creator, "choices", null, null);
-
-            select.appendChild(choices);
+            appendItems(artifact, creator, name, context, select);
             ui.appendChild(select);
-
-            Element[] items = createItems(creator, artifact, name, context);
-            if (items != null) {
-                for (Element item: items) {
-                    choices.appendChild(item);
-                }
-            }
         }
 
         return ui;
@@ -247,11 +284,38 @@
 
 
     /**
+     * @param artifact
+     * @param creator
+     * @param name
+     * @param context
+     * @param select
+     */
+    protected void appendItems(
+        Artifact       artifact,
+        ElementCreator creator,
+        String         name,
+        CallContext    context,
+        Element        select
+    ) {
+        Element choices = ProtocolUtils.createArtNode(
+            creator, "choices", null, null);
+
+        select.appendChild(choices);
+
+        Element[] items = createItems(creator, artifact, name, context);
+        if (items != null) {
+            for (Element item: items) {
+                choices.appendChild(item);
+            }
+        }
+    }
+
+
+    /**
      * This method creates the root node that contains the list of selectable
      * items.
      *
      * @param cr The ElementCreator.
-     * @param name The name of the amount of data.
      *
      * @return the root node of the item list.
      */
@@ -338,11 +402,17 @@
     public StateData transform(
         FLYSArtifact flys,
         CallContext  cc,
+        StateData    stateData,
         String       name,
         String       val
     ) {
-        logger.debug("Transform data ('" + name + "','" + val + "')");
-        return new DefaultStateData(name, null, null, val);
+        if (logger.isDebugEnabled()) {
+            logger.debug("Transform data ('" + name + "','" + val + "')");
+        }
+
+        stateData.setValue(val);
+
+        return stateData;
     }
 
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -10,10 +10,14 @@
 
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.ChartArtifact;
 
+import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet;
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.ReportFacet;
 import de.intevation.flys.artifacts.model.WaterlevelFacet;
+import de.intevation.flys.artifacts.model.EmptyFacet;
+
 import de.intevation.flys.artifacts.model.WQKms;
 import de.intevation.flys.artifacts.model.WQCKms;
 import de.intevation.flys.artifacts.model.CalculationResult;
@@ -36,6 +40,12 @@
         List<Facet>  facets,
         Object       old
     ) {
+        if (artifact instanceof ChartArtifact) {
+            ChartArtifact chart = (ChartArtifact)artifact;
+            facets.add(new EmptyFacet());
+            return null;
+        }
+
         WINFOArtifact winfo = (WINFOArtifact)artifact;
 
         CalculationResult res = old instanceof CalculationResult
@@ -67,6 +77,9 @@
             Facet q = new WaterlevelFacet(
                 i, DISCHARGE_LONGITUDINAL_Q, nameQ);
 
+            Facet s = new CrossSectionWaterLineFacet(i, nameW);
+
+            facets.add(s);
             facets.add(w);
             facets.add(q);
 
@@ -80,7 +93,12 @@
                 Facet c = new WaterlevelFacet(
                     i, DISCHARGE_LONGITUDINAL_C, nameC);
 
+                // Here, avoid index clash with Facet "s" above and
+                // signal the WINFO later that we want to access Cs.
+                Facet r = new CrossSectionWaterLineFacet(i + 1, nameC);
+
                 facets.add(c);
+                facets.add(r);
             }
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DischargeState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,161 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.model.KVP;
+
+import de.intevation.flys.model.DischargeZone;
+import de.intevation.flys.model.River;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.utils.FLYSUtils;
+
+
+public class DischargeState extends MultiIntArrayState {
+
+    public static final String MAIN_CHANNEL  = "main_channel";
+    public static final String TOTAL_CHANNEL = "total_channel";
+
+
+    private static final Logger logger = Logger.getLogger(DischargeState.class);
+
+
+    /** Let client display a matrix. */
+    @Override
+    public String getUIProvider() {
+        return "parameter-matrix";
+    }
+
+
+    /**
+     * This method fetches all DischargeZones for a given river (extracted from
+     * <i>artifact</i>) and returns a KVP[] where the key is the ID of the
+     * DischargeZone and the value is a string that consists of lower discharge
+     * and upper discharge.
+     *
+     * @param artifact Needs to be a FLYSArtifact that provides river
+     * information.
+     * @param parameterName The name of a parameter.
+     *
+     * @return a KVP[].
+     */
+    @Override
+    protected KVP<Integer, String>[] getOptions(
+        Artifact artifact,
+        String   parameterName
+    )
+    throws IllegalArgumentException
+    {
+        if (!testParameterName(parameterName)) {
+            throw new IllegalArgumentException(
+                "Invalid parameter for state: '" + parameterName + "'");
+        }
+
+        List<DischargeZone> zones = getDischargeZones(artifact);
+
+        KVP[] kvp = new KVP[zones.size()];
+
+        for (int i = 0, Z = zones.size(); i < Z; i++) {
+            DischargeZone zone = zones.get(i);
+
+            String lower = zone.getLowerDischarge();
+            String upper = zone.getUpperDischarge();
+
+            if (lower.equals(upper)) {
+                kvp[i] = new KVP(zone.getId(), lower);
+            }
+            else {
+                kvp[i] = new KVP(zone.getId(), lower + " - " + upper);
+            }
+        }
+
+        return kvp;
+    }
+
+
+    @Override
+    protected String getLabelFor(
+        CallContext cc,
+        String      parameterName,
+        int         value
+    ) throws IllegalArgumentException
+    {
+        if (!testParameterName(parameterName)) {
+            throw new IllegalArgumentException(
+                "Invalid parameter for state: '" + parameterName + "'");
+        }
+
+        DischargeZone zone = DischargeZone.getDischargeZoneById(value);
+
+        if (zone == null) {
+            throw new IllegalArgumentException(
+                "Invalid id for DischargeZone: '" + value + "'");
+        }
+
+        String lo = zone.getLowerDischarge();
+        String hi = zone.getUpperDischarge();
+
+        return hi != null && !lo.equals(hi)
+            ? lo + " - " + hi
+            : lo;
+    }
+
+
+    /**
+     * This method might be used to test, if a parameter name is handled by this
+     * state.
+     *
+     * @param parameterName The name of a parameter.
+     *
+     * @return true, if parameterName is one of <i>MAIN_CHANNEL</i> or
+     * <i>TOTAL_CHANNEL</i>. Otherwise false.
+     */
+    protected boolean testParameterName(String parameterName) {
+        if (parameterName == null || parameterName.length() == 0) {
+            return false;
+        }
+        else if (parameterName.equals(MAIN_CHANNEL)) {
+            return true;
+        }
+        else if (parameterName.equals(TOTAL_CHANNEL)) {
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Returns all discharge zones for a given river. The river information is
+     * extracted from <i>artifact</i> using FLYSUtils.getRiver().
+     *
+     * @param artifact Needs to be a FLYSArtifact that stores a rivername.
+     *
+     * @return a list of DischargeZones.
+     *
+     * @throws IllegalArgumentException if no river information is provided by
+     * <i>artifact</i>.
+     */
+    protected List<DischargeZone> getDischargeZones(Artifact artifact)
+    throws IllegalArgumentException
+    {
+        River river = FLYSUtils.getRiver((FLYSArtifact) artifact);
+
+        if (river == null) {
+            throw new IllegalArgumentException("No river found");
+        }
+
+        List<DischargeZone> zones = DischargeZone.getDischargeZones(river);
+
+        logger.debug("Found " + zones.size() + " DischargeZones.");
+
+        return zones;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DurationCurveState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -10,6 +10,7 @@
 
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.ChartArtifact;
 
 import de.intevation.flys.artifacts.model.DurationCurveFacet;
 import de.intevation.flys.artifacts.model.FacetTypes;
@@ -17,6 +18,7 @@
 
 import de.intevation.flys.artifacts.model.DataFacet;
 import de.intevation.flys.artifacts.model.ReportFacet;
+import de.intevation.flys.artifacts.model.EmptyFacet;
 import de.intevation.flys.artifacts.model.CalculationResult;
 
 import de.intevation.flys.artifacts.resources.Resources;
@@ -49,50 +51,61 @@
         List<Facet>  facets,
         Object       old
     ) {
-        WINFOArtifact winfo = (WINFOArtifact)artifact;
-
-        CalculationResult res;
-
-        if (old instanceof CalculationResult) {
-            res = (CalculationResult)old;
-        }
-        else {
-            res = winfo.getDurationCurveData();
-        }
-
-        WQDay wqday = (WQDay)res.getData();
-
-        if (wqday != null && facets != null) {
-            Object[] args = new Object[] {
-                FLYSUtils.getRiver(winfo).getName()
-            };
+        if (artifact instanceof WINFOArtifact) {
+            WINFOArtifact winfo = (WINFOArtifact)artifact;
 
-            String nameW = Resources.getMsg(
-                context.getMeta(),
-                "chart.duration.curve.curve.w",
-                "",
-                args);
-
-            String nameQ = Resources.getMsg(
-                context.getMeta(),
-                "chart.duration.curve.curve.q",
-                "",
-                args);
+            CalculationResult res;
 
-            Facet w = new DurationCurveFacet(DURATION_W, nameW);
-            Facet q = new DurationCurveFacet(DURATION_Q, nameQ);
-
-            facets.add(w);
-            facets.add(q);
+            if (old instanceof CalculationResult) {
+                res = (CalculationResult)old;
+            }
+            else {
+                res = winfo.getDurationCurveData();
+            }
 
-            facets.add(new DataFacet(CSV, "CSV data"));
+            WQDay wqday = (WQDay)res.getData();
 
-            if (res.getReport().hasProblems()) {
-                facets.add(new ReportFacet());
+            if (wqday != null && facets != null) {
+                // Create an i18ed name for a (w or q) duration curve facet.
+                Object[] args = new Object[] {
+                    FLYSUtils.getRiver(winfo).getName(),
+                    FLYSUtils.getLocations(winfo)[0]
+                };
+
+                String nameW = Resources.getMsg(
+                    context.getMeta(),
+                    "chart.duration.curve.curve.w",
+                    "",
+                    args);
+
+                String nameQ = Resources.getMsg(
+                    context.getMeta(),
+                    "chart.duration.curve.curve.q",
+                    "",
+                    args);
+
+                Facet w = new DurationCurveFacet(DURATION_W, nameW);
+                Facet q = new DurationCurveFacet(DURATION_Q, nameQ);
+
+                facets.add(w);
+                facets.add(q);
+
+                facets.add(new DataFacet(CSV, "CSV data"));
+                facets.add(new DataFacet(PDF, "PDF data"));
+
+                if (res.getReport().hasProblems()) {
+                    facets.add(new ReportFacet());
+                }
             }
+
+            return res;
         }
-
-        return res;
+        else if (artifact instanceof ChartArtifact) {
+            ChartArtifact chart = (ChartArtifact)artifact;
+            facets.add(new EmptyFacet());
+            return null;
+        }
+        return null;
     }
 }
 // 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/EnterLocationState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,41 @@
+package de.intevation.flys.artifacts.states;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+
+/**
+ * Get me a double (km).
+ */
+public class EnterLocationState extends InputDoubleState {
+
+    /** Provoke this kind of provider in the UI. */
+    @Override
+    protected String getUIProvider() {
+        return "location_panel";
+    }
+
+
+    /** Allow from min km of river. */
+    @Override
+    protected Object getLower(FLYSArtifact flys) {
+        double[] lowerUpper = FLYSUtils.getRiverMinMax(flys);
+
+        return lowerUpper != null
+            ? lowerUpper[0]
+            : 0;
+    }
+
+
+    /** Allow to max km of river. */
+    @Override
+    protected Object getUpper(FLYSArtifact flys) {
+        double[] lowerUpper = FLYSUtils.getRiverMinMax(flys);
+
+        return lowerUpper != null
+            ? lowerUpper[1]
+            : 0;
+    }
+}
+// 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/EnterMultipleLocationsState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,73 @@
+package de.intevation.flys.artifacts.states;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.common.utils.StringUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.flys.artifacts.WINFOArtifact;
+
+
+/**
+ * Get me doubles (km).
+ */
+public class EnterMultipleLocationsState extends EnterLocationState {
+    /** The logger for this class. */
+    private static Logger logger = Logger.getLogger(EnterMultipleLocationsState.class);
+
+    @Override
+    protected String getUIProvider() {
+        logger.debug("multi location panel");
+        return "multi_location_panel";
+    }
+
+
+    /** Deal with multiple double values. */
+    @Override
+    protected String getLabelFor(
+        CallContext cc,
+        String      name,
+        String      value,
+        String      type
+    ) {
+        String label = "";
+        String[] vals = value.split(" ");
+        for (int i = 0; i < vals.length; i++) {
+            vals[i] = super.getLabelFor(cc, name, vals[i], type);
+        }
+
+        return StringUtils.join(" ", vals);
+    }
+
+    /**
+     * This method creates a list of items. These items represent the amount of
+     * input data that is possible for this state.
+     *
+     * @param cr The ElementCreator.
+     * @param name The name of the amount of data.
+     *
+     * @return a list of items.
+     */
+    @Override
+    protected Element[] createItems(
+        ElementCreator cr,
+        Artifact    artifact,
+        String      name,
+        CallContext context
+    ) {
+        if (name.equals("reference_endpoint")) {
+            Element[] elements = new Element[1];
+            WINFOArtifact winfo = (WINFOArtifact) artifact;
+            Double km = winfo.getReferenceStartKm();
+            elements[0] = createItem(
+                cr,
+                new String[] {"start_km", km.toString()});
+            return elements;
+        }
+        return null;
+    }
+
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -7,48 +7,43 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.log4j.Logger;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureCollections;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.Geometry;
 import com.vividsolutions.jts.geom.LineString;
 import com.vividsolutions.jts.geom.Polygon;
 
-import org.apache.log4j.Logger;
-
-import org.opengis.feature.simple.SimpleFeature;
-import org.opengis.feature.simple.SimpleFeatureType;
-
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.FeatureCollections;
-import org.geotools.feature.simple.SimpleFeatureBuilder;
-
+import de.intevation.artifactdatabase.state.Facet;
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
 import de.intevation.artifacts.GlobalContext;
-
 import de.intevation.artifacts.common.utils.FileTools;
-
-import de.intevation.artifactdatabase.state.Facet;
-
-import de.intevation.flys.model.CrossSectionTrack;
-import de.intevation.flys.model.DGM;
-import de.intevation.flys.model.Floodplain;
-import de.intevation.flys.model.RiverAxis;
-
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.context.FLYSContext;
 import de.intevation.flys.artifacts.model.CalculationMessage;
 import de.intevation.flys.artifacts.model.CalculationResult;
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.WQKms;
-import de.intevation.flys.artifacts.model.WSPLGENCalculation;
-import de.intevation.flys.artifacts.model.WSPLGENJob;
-import de.intevation.flys.artifacts.model.WSPLGENReportFacet;
+import de.intevation.flys.artifacts.model.map.WMSLayerFacet;
+import de.intevation.flys.artifacts.model.map.WSPLGENCalculation;
+import de.intevation.flys.artifacts.model.map.WSPLGENJob;
+import de.intevation.flys.artifacts.model.map.WSPLGENReportFacet;
 import de.intevation.flys.artifacts.resources.Resources;
-import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
 import de.intevation.flys.exports.WstWriter;
+import de.intevation.flys.model.CrossSectionTrack;
+import de.intevation.flys.model.DGM;
+import de.intevation.flys.model.Floodplain;
+import de.intevation.flys.model.RiverAxis;
 import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.GeometryUtils;
 import de.intevation.flys.utils.MapfileGenerator;
-import de.intevation.flys.utils.GeometryUtils;
 import de.intevation.flys.wsplgen.FacetCreator;
 import de.intevation.flys.wsplgen.JobObserver;
 import de.intevation.flys.wsplgen.Scheduler;
@@ -66,6 +61,8 @@
         System.getProperty("flys.uesk.keep.artifactsdir", "false");
 
 
+    public static final String OUTPUT_NAME = "floodmap";
+
     public static final String WSP_ARTIFACT = "wsp";
 
     public static final String WINFO_WSP_STATE_ID = "state.winfo.waterlevel";
@@ -78,10 +75,81 @@
     public static final String WSPLGEN_FLOODPLAIN     = "talaue.shp";
     public static final String WSPLGEN_WSP_FILE       = "waterlevel.wst";
     public static final String WSPLGEN_OUTPUT_FILE    = "wsplgen.shp";
+    public static final String WSPLGEN_USER_SHAPE     = "user-rgd.shp";
+    public static final String WSPLGEN_USER_ZIP       = "user-rgd.zip";
+    public static final String WSPLGEN_USER_FILENAME  = "user-rgd";
+
+    public static final String WSPLGEN_QPS_NAME = "qps";
 
     public static final int WSPLGEN_DEFAULT_OUTPUT = 0;
 
 
+    /**
+     * @param orig
+     * @param owner
+     * @param context
+     * @param callMeta
+     */
+    @Override
+    public void initialize(
+        Artifact orig,
+        Artifact owner,
+        Object   context,
+        CallMeta callMeta
+    ) {
+        logger.info("Initialize State with Artifact: " + orig.identifier());
+
+        copyShapeDir(orig, owner);
+        modifyFacets(orig, owner, context, callMeta);
+
+        MapfileGenerator.getInstance().update();
+    }
+
+
+    protected void copyShapeDir(Artifact orig, Artifact owner) {
+        File origDir = getDirectory((FLYSArtifact) orig);
+        File thisDir = getDirectory((FLYSArtifact) owner);
+
+        FileTools.copyDirectory(origDir, thisDir);
+    }
+
+
+    protected void modifyFacets(
+        Artifact orig,
+        Artifact owner,
+        Object   context,
+        CallMeta callMeta
+    ) {
+        FLYSArtifact flys  = (FLYSArtifact) owner;
+        List<Facet> facets = flys.getFacets();
+        if (facets == null || facets.isEmpty()) {
+            logger.warn("No facets for '" + OUTPUT_NAME + "' given!");
+            return;
+        }
+
+        for (Facet facet: facets) {
+            if (facet instanceof WMSLayerFacet) {
+                WMSLayerFacet wms = (WMSLayerFacet) facet;
+
+                List<String> layers = wms.getLayers();
+
+                for (String layer: layers) {
+                    if (layer.startsWith(MapfileGenerator.MS_WSPLGEN_PREFIX)) {
+                        wms.removeLayer(layer);
+
+                        String newLayer = MapfileGenerator.MS_WSPLGEN_PREFIX +
+                            owner.identifier();
+
+                        wms.addLayer(newLayer);
+
+                        logger.debug(
+                            "Replaced layer: " + layer + " with " + newLayer);
+                    }
+                }
+            }
+        }
+    }
+
 
     @Override
     public Object computeAdvance(
@@ -195,7 +263,6 @@
         logger.info("FloodMapState.endOfLife: " + artifact.identifier());
 
         FLYSArtifact flys = (FLYSArtifact) artifact;
-        removeDirectory(flys);
 
         Scheduler scheduler = Scheduler.getInstance();
         scheduler.cancelJob(flys.identifier());
@@ -228,6 +295,7 @@
         setGel(artifact, job);
         setDist(artifact, job);
         setLine(artifact, facetCreator, artifactDir, job);
+        setUserShape(artifact, facetCreator, artifactDir, job);
         setAxis(artifact, artifactDir, job);
         setPro(artifact, artifactDir, job);
         setDgm(artifact, job);
@@ -343,7 +411,7 @@
             "barriers", srs, Geometry.class);
 
         List<SimpleFeature> features = GeometryUtils.parseGeoJSON(geoJSON, ft);
-        if (features == null || features.size() == 0) {
+        if (features == null || features.isEmpty()) {
             logger.debug("No barrier features extracted.");
             return;
         }
@@ -401,6 +469,31 @@
     }
 
 
+    protected void setUserShape(
+        FLYSArtifact artifact,
+        FacetCreator facetCreator,
+        File         dir,
+        WSPLGENJob   job
+    ) {
+        File archive = new File(dir, WSPLGEN_USER_ZIP);
+        boolean exists = archive.exists();
+        logger.debug("Zip file exists: " + exists);
+        if (exists) {
+            try {
+                File tmpDir = new File(dir, "usr_tmp");
+                FileTools.extractArchive(archive, tmpDir);
+                moveFiles(tmpDir, dir);
+            }
+            catch (IOException ioe) {
+                logger.warn("Zip archive " + dir + "/" + WSPLGEN_USER_ZIP + " could not be extracted.");
+                return;
+            }
+
+            job.addLin(dir + "/" + WSPLGEN_USER_SHAPE);
+            facetCreator.createUserShapeFacet();
+        }
+    }
+
     protected SimpleFeatureType getBarriersFeatureType(
         String name,
         String srs,
@@ -510,22 +603,26 @@
         String srid    = FLYSUtils.getRiverSrid(artifact);
         String srs     = "EPSG:" + srid;
 
-        RiverAxis axis = RiverAxis.getRiverAxis(river);
-        if (axis == null) {
+        List<RiverAxis> axes = RiverAxis.getRiverAxis(river);
+        if (axes == null || axes.isEmpty()) {
             logger.warn("Could not find river axis for: '" + river + "'");
             return;
         }
 
-        Geometry geom = axis.getGeom();
-
         SimpleFeatureType ft = GeometryUtils.buildFeatureType(
             "axis", srs, LineString.class);
 
         SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
-        builder.add(geom);
+        FeatureCollection collection = FeatureCollections.newCollection();
 
-        FeatureCollection collection = FeatureCollections.newCollection();
-        collection.add(builder.buildFeature("0"));
+        for (int i = 0, n = axes.size(); i < n; i++) {
+            RiverAxis axis = axes.get(i);
+
+            builder.add(axis.getGeom());
+            collection.add(builder.buildFeature(String.valueOf(i)));
+
+            builder.reset();
+        }
 
         File axisShape = new File(dir, WSPLGEN_AXIS);
 
@@ -546,7 +643,7 @@
         String srs     = "EPSG:" + srid;
 
         List<CrossSectionTrack> cst =
-            CrossSectionTrack.getCrossSectionTrack(river);
+            CrossSectionTrack.getCrossSectionTrack(river, WSPLGEN_QPS_NAME);
 
         logger.debug("Found " + cst.size() + " CrossSectionTracks.");
 
@@ -734,5 +831,42 @@
             }
         }
     }
+
+
+    protected void moveFiles(File source, final File target)
+    throws IOException
+    {
+        if (!source.exists()) {
+            return;
+        }
+        if (!target.exists()) {
+            target.mkdir();
+        }
+        FileTools.walkTree(source, new FileTools.FileVisitor() {
+            public boolean visit(File file) {
+                if (!file.isDirectory()) {
+                    String name = file.getName();
+                    String suffix = "";
+                    int pos = name.lastIndexOf('.');
+                    if (pos > 0 && pos < name.length() - 1) {
+                        suffix = name.substring(pos + 1);
+                    }
+                    else {
+                        return true;
+                    }
+                    try {
+                        FileTools.copyFile(file, new File(target, WSPLGEN_USER_FILENAME + "." + suffix));
+                    }
+                    catch (IOException ioe) {
+                        logger.warn ("Error while copying file " + file.getName());
+                        return true;
+                    }
+                }
+                return true;
+            }
+        });
+
+        FileTools.deleteRecursive(source);
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodplainChoice.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,6 +2,8 @@
 
 import org.w3c.dom.Element;
 
+import org.apache.log4j.Logger;
+
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
 import de.intevation.artifacts.CallMeta;
@@ -18,7 +20,12 @@
  */
 public class FloodplainChoice extends DefaultState {
 
-    public static final String OPTION = "floodplain.option";
+    public static final String OPTION   = "floodplain.option";
+    public static final String ACTIVE   = "floodplain.active";
+    public static final String INACTIVE = "floodplain.inactive";
+
+    private static final Logger logger =
+        Logger.getLogger(FloodplainChoice.class);
 
 
     @Override
@@ -44,6 +51,23 @@
     }
 
 
+    @Override
+    protected String getLabelFor(
+        CallContext cc,
+        String      name,
+        String      value,
+        String      type
+    ) {
+        logger.debug("GET LABEL FOR '" + name + "' / '" + value + "'");
+        if (value != null && value.equals("true")) {
+            return Resources.getMsg(cc.getMeta(), ACTIVE, ACTIVE);
+        }
+        else {
+            return Resources.getMsg(cc.getMeta(), INACTIVE, INACTIVE);
+        }
+    }
+
+
     protected Element createItem(XMLUtils.ElementCreator cr, Object obj) {
         Element item  = ProtocolUtils.createArtNode(cr, "item", null, null);
         Element label = ProtocolUtils.createArtNode(cr, "label", null, null);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FlowVelocityState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,159 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.FlowVelocityAccess;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.FlowVelocityCalculation;
+import de.intevation.flys.artifacts.model.FlowVelocityData;
+import de.intevation.flys.artifacts.model.FlowVelocityFacet;
+import de.intevation.flys.artifacts.resources.Resources;
+
+
+public class FlowVelocityState extends DefaultState implements FacetTypes {
+
+    private static Logger logger = Logger.getLogger(FlowVelocityState.class);
+
+
+    public static final String I18N_MAINCHANNEL_FACET =
+        "facet.flow_velocity.mainchannel";
+
+    public static final String I18N_TOTALCHANNEL_FACET =
+        "facet.flow_velocity.totalchannel";
+
+    public static final String I18N_TAU_FACET =
+        "facet.flow_velocity.tauchannel";
+
+
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        logger.debug("FlowVelocityState.computeAdvance");
+
+        List<Facet> newFacets = new ArrayList<Facet>();
+
+        FlowVelocityAccess access = new FlowVelocityAccess(artifact);
+
+        CalculationResult res = old instanceof CalculationResult
+            ? (CalculationResult) old
+            : new FlowVelocityCalculation().calculate(access);
+
+        if (facets == null || res == null) {
+            return res;
+        }
+
+        FlowVelocityData[] data = (FlowVelocityData[]) res.getData();
+
+        logger.debug("Calculated " + data.length + " FlowVelocityData objects");
+
+        String id  = getID();
+        int    idx = 0;
+
+        for (FlowVelocityData d: data) {
+            logger.error("TODO: Implement Facet creation for chart!");
+
+            newFacets.add(new FlowVelocityFacet(
+                idx,
+                FLOW_VELOCITY_MAINCHANNEL,
+                buildMainChannelName(artifact, context, d),
+                ComputeType.ADVANCE,
+                id,
+                hash
+            ));
+
+            newFacets.add(new FlowVelocityFacet(
+                idx,
+                FLOW_VELOCITY_TOTALCHANNEL,
+                buildTotalChannelName(artifact, context, d),
+                ComputeType.ADVANCE,
+                id,
+                hash
+            ));
+
+            newFacets.add(new FlowVelocityFacet(
+                idx,
+                FLOW_VELOCITY_TAU,
+                buildTauName(artifact, context, d),
+                ComputeType.ADVANCE,
+                id,
+                hash
+            ));
+
+            idx++;
+        }
+
+        Facet csv = new DataFacet(
+            CSV, "CSV data", ComputeType.ADVANCE, hash, id);
+
+        // TODO ADD PDF FACET
+
+        newFacets.add(csv);
+
+        logger.debug("Created " + newFacets.size() + " new Facets.");
+
+        facets.addAll(newFacets);
+
+        return res;
+    }
+
+
+    protected String buildFacetName(
+        FLYSArtifact     flys,
+        CallContext      cc,
+        FlowVelocityData data,
+        String           resourceId
+    ) {
+        Object[] args = new Object[] {
+            data.getZone()
+        };
+
+        return Resources.getMsg(
+            cc.getMeta(),
+            resourceId,
+            resourceId,
+            args);
+    }
+
+
+    protected String buildMainChannelName(
+        FLYSArtifact     flys,
+        CallContext      cc,
+        FlowVelocityData data
+    ) {
+        return buildFacetName(flys, cc, data, I18N_MAINCHANNEL_FACET);
+    }
+
+
+    protected String buildTotalChannelName(
+        FLYSArtifact     flys,
+        CallContext      cc,
+        FlowVelocityData data
+    ) {
+        return buildFacetName(flys, cc, data, I18N_TOTALCHANNEL_FACET);
+    }
+
+
+    protected String buildTauName(
+        FLYSArtifact     flys,
+        CallContext      cc,
+        FlowVelocityData data
+    ) {
+        return buildFacetName(flys, cc, data, I18N_TAU_FACET);
+    }
+}
+// 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/GaugeDischargeState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,161 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.ChartArtifact;
+import de.intevation.flys.artifacts.GaugeDischargeArtifact;
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.GaugeDischargeFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.ReportFacet;
+import de.intevation.flys.artifacts.model.EmptyFacet;
+import de.intevation.flys.artifacts.model.CalculationResult;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import de.intevation.flys.model.Gauge;
+
+
+/**
+ * The only state for an GaugeDischargeState (River and km known).
+ */
+public class GaugeDischargeState
+extends      DefaultState
+implements   FacetTypes
+{
+    /** Developer-centric description of facet. */
+    public static final String I18N_DESCRIPTION = "facet.discharge.curve";
+
+    /** The logger that is used in this state. */
+    private static final Logger logger =
+        Logger.getLogger(GaugeDischargeState.class);
+
+
+    /**
+     * Create i18ned name for gaugedischargeFacet.
+     * @param artifact The artifact which has information about the gauge.
+     * @param meta used for i18n.
+     * @return localized name for gaugedischargefacet.
+     */
+    protected String createFacetName(GaugeDischargeArtifact artifact,
+        CallMeta meta) {
+
+        Gauge gauge = artifact.getGauge();
+        Object[] args = new Object[] {
+            gauge.getName(),
+            gauge.getStation()
+        };
+
+        String name = Resources.getMsg(
+            meta,
+            "chart.computed.discharge.curve.gauge",
+            "",
+            args);
+
+        return name;
+    }
+
+
+    /**
+     * Add an GaugeDischargeFacet to list of Facets.
+     *
+     * @param artifact Ignored.
+     * @param hash Ignored.
+     * @param context Ignored.
+     * @param meta CallMeta to be used for internationalization.
+     * @param facets List to add AnnotationFacet to.
+     *
+     * @return null.
+     */
+    @Override
+    public Object computeInit(
+        FLYSArtifact artifact,
+        String       hash,
+        Object       context,
+        CallMeta     meta,
+        List<Facet>  facets
+    ) {
+        logger.debug("GaugeDischargeState.computeInit()");
+
+        GaugeDischargeFacet facet = new GaugeDischargeFacet(
+            0,
+            DISCHARGE_CURVE,
+            createFacetName((GaugeDischargeArtifact) artifact, meta));
+
+        facets.add(facet);
+
+        return null;
+    }
+
+
+    /**
+     * 'Calculate' Discharge at Gauge.
+     */
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        if (artifact instanceof GaugeDischargeArtifact) {
+            logger.debug("GaugeDischargeState.computeAdvance()");
+            GaugeDischargeArtifact dischargeArtifact = (GaugeDischargeArtifact) artifact;
+
+            CalculationResult res;
+
+
+            if (old instanceof CalculationResult) {
+                res = (CalculationResult) old;
+            }
+            else {
+                res = dischargeArtifact.getDischargeCurveData();
+            }
+
+            WQKms[] wqkms = (WQKms[]) res.getData();
+
+            if (wqkms != null && facets != null) {
+                logger.debug("GaugeDischargeState.computeAdvance(): create facets");
+
+                GaugeDischargeFacet facet = new GaugeDischargeFacet(
+                    0,
+                    DISCHARGE_CURVE,
+                    createFacetName(dischargeArtifact, context.getMeta()));
+
+                facets.add(facet);
+
+                //facets.add(new DataFacet(CSV, "CSV data"));
+                //facets.add(new DataFacet(PDF, "PDF data"));
+
+                if (res.getReport().hasProblems()) {
+                    facets.add(new ReportFacet());
+                }
+            }
+            else {
+                if (wqkms == null)
+                    logger.debug("GaugeDischargeState.computeAdvance(): wqkms 0");
+                else
+                    logger.debug("GaugeDischargeState.computeAdvance(): facets 0");
+            }
+
+            return res;
+        }
+        else if (artifact instanceof ChartArtifact) {
+            ChartArtifact chart = (ChartArtifact)artifact;
+            facets.add(new EmptyFacet());
+            return null;
+        }
+        return null;
+    }
+}
+// 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/GaugeTimerangeState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,87 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.Calendar;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.type.StandardBasicTypes;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.backend.SessionHolder;
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.utils.FLYSUtils;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class GaugeTimerangeState extends IntRangeState {
+
+    private static final Logger logger =
+            Logger.getLogger(GaugeTimerangeState.class);
+
+
+    protected int[] getLowerUpper(FLYSArtifact flys) {
+        Gauge gauge = FLYSUtils.getReferenceGauge(flys);
+
+        if (gauge == null) {
+            logger.warn("No reference gauge specified!");
+            return new int[] { 0, 0 };
+        }
+
+        Session session = SessionHolder.HOLDER.get();
+
+        SQLQuery query = session.createSQLQuery(
+                "SELECT min(start_time) as min, max(stop_time) as max " +
+                        "FROM time_intervals WHERE id in " +
+                        "(SELECT time_interval_id FROM discharge_tables " +
+                "WHERE gauge_id =:gid)");
+
+        query.addScalar("min", StandardBasicTypes.CALENDAR);
+        query.addScalar("max", StandardBasicTypes.CALENDAR);
+
+        query.setInteger("gid", gauge.getId());
+
+        List<?> results = query.list();
+
+        if (results != null) {
+            Object[] res = (Object[]) results.get(0);
+
+            Calendar lo = (Calendar) res[0];
+            Calendar up = (Calendar) res[1];
+
+            if (lo != null && up != null) {
+                return new int[] { lo.get(Calendar.YEAR), up.get(Calendar.YEAR) };
+            }
+        }
+
+        logger.warn("Could not determine time range for gauge: " + gauge);
+
+        return null;
+    }
+
+
+    @Override
+    protected Object getLower(FLYSArtifact flys) {
+        int[] lowerUpper = getLowerUpper(flys);
+
+        return lowerUpper != null ? lowerUpper[0] : 0;
+    }
+
+
+    @Override
+    protected Object getUpper(FLYSArtifact flys) {
+        int[] lowerUpper = getLowerUpper(flys);
+
+        return lowerUpper != null ? lowerUpper[1] : 0;
+    }
+
+
+    @Override
+    protected String getUIProvider() {
+        return "gaugetimerange";
+    }
+}
+// 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/HistoricalDischargeComputeState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,121 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.HistoricalDischargeFacet;
+import de.intevation.flys.artifacts.model.HistoricalDischargeDifferenceFacet;
+import de.intevation.flys.artifacts.model.HistoricalWQTimerange;
+import de.intevation.flys.artifacts.model.ReportFacet;
+import de.intevation.flys.artifacts.model.WQTimerange;
+
+
+/**
+ * State to calculate historical discharge curves.
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalDischargeComputeState
+extends      DefaultState
+implements   FacetTypes
+{
+
+    private static final Logger logger =
+        Logger.getLogger(HistoricalDischargeComputeState.class);
+
+
+    @Override
+    protected void appendItems(
+        Artifact       artifact,
+        ElementCreator creator,
+        String         name,
+        CallContext    context,
+        Element        select
+    ) {
+        // TODO IMPLEMENT ME
+    }
+
+
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        logger.debug("HistoricalDischargeComputeState.computeAdvance");
+
+        WINFOArtifact winfo = (WINFOArtifact) artifact;
+
+        CalculationResult res = old instanceof CalculationResult
+            ? (CalculationResult) old
+            : winfo.getHistoricalDischargeData();
+
+        if (facets == null) {
+            return res;
+        }
+
+        if (res.getReport().hasProblems()) {
+            facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id));
+        }
+
+        WQTimerange[] data = (WQTimerange[]) res.getData();
+        if (data == null || data.length == 0) {
+            logger.warn("Historical Discharge calculation has no results!");
+            return res;
+        }
+
+        facets.add(
+            new DataFacet(CSV, "CSV data", ComputeType.ADVANCE, hash, id));
+
+        facets.add(
+            new DataFacet(PDF, "PDF data", ComputeType.ADVANCE, hash, id));
+
+        prepareFacets(facets, data);
+
+        return res;
+    }
+
+
+    protected void prepareFacets(List<Facet> facets, WQTimerange[] wqts) {
+        int i = 0;
+
+        for (WQTimerange wqt: wqts) {
+            logger.debug("Prepare facet for: " + wqt.getName());
+
+            // TODO CREATE BETTER TITLE FOR FACETS
+
+            facets.add(new HistoricalDischargeFacet(
+                i,
+                HISTORICAL_DISCHARGE_Q,
+                wqt.getName()));
+
+            if (wqt instanceof HistoricalWQTimerange) {
+                logger.debug("Create another facet for historical differences.");
+
+                facets.add(new HistoricalDischargeDifferenceFacet(
+                    i,
+                    HISTORICAL_DISCHARGE_Q_DIFF,
+                    "DIFF: " + wqt.getName()));
+            }
+
+            i++;
+        }
+    }
+}
+// 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/HistoricalDischargeState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,152 @@
+package de.intevation.flys.artifacts.states;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalDischargeState extends DefaultState {
+
+    private static final Logger logger =
+        Logger.getLogger(HistoricalDischargeState.class);
+
+
+    public static final String I18N_MODE_W = "historical.mode.w";
+    public static final String I18N_MODE_Q = "historical.mode.q";
+
+    public static final String DATA_MODE   = "historical_mode";
+    public static final String DATA_VALUES = "historical_values";
+    public static final int    DATA_MODE_W = 0;
+    public static final int    DATA_MODE_Q = 1;
+
+
+    @Override
+    protected String getUIProvider() {
+        return "wq_simple_array";
+    }
+
+    protected void appendItems(
+        Artifact       artifact,
+        ElementCreator creator,
+        String         name,
+        CallContext    context,
+        Element        select
+    ) {
+        if (name != null && name.equals(DATA_VALUES)) {
+            select.setAttributeNS(
+                ArtifactNamespaceContext.NAMESPACE_URI,
+                "art:type",
+                "doublearray");
+        }
+        else if (name != null && name.equals(DATA_MODE)) {
+            select.setAttributeNS(
+                ArtifactNamespaceContext.NAMESPACE_URI,
+                "art:type",
+                "intoptions");
+        }
+
+        super.appendItems(artifact, creator, name, context, select);
+    }
+
+
+    @Override
+    protected Element[] createItems(
+        ElementCreator creator,
+        Artifact       artifact,
+        String         name,
+        CallContext    context
+    ) {
+        logger.debug("createItems()");
+
+        if (name != null && name.equals(DATA_MODE)) {
+            return createModeItem(creator, artifact, name, context);
+        }
+        else if (name != null && name.equals(DATA_VALUES)) {
+            return createValuesItem(creator, artifact, name, context);
+        }
+
+        logger.warn("Tried to create item for invalid data: " + name);
+
+        return new Element[0];
+    }
+
+
+    @Override
+    protected String getLabelFor(
+        CallContext cc,
+        String      name,
+        String      value,
+        String      type
+    ) {
+        CallMeta meta = cc.getMeta();
+
+        if (name.equals(DATA_MODE)) {
+            if (value.equals(String.valueOf(DATA_MODE_W))) {
+                return Resources.getMsg(meta, I18N_MODE_W, I18N_MODE_W);
+            }
+            else {
+                return Resources.getMsg(meta, I18N_MODE_Q, I18N_MODE_Q);
+            }
+        }
+        else {
+            return value;
+        }
+    }
+
+
+    protected Element[] createModeItem(
+        ElementCreator creator,
+        Artifact       artifact,
+        String         name,
+        CallContext    context
+    ) {
+        logger.debug("createModeItem()");
+
+        CallMeta meta = context.getMeta();
+
+        Element modeW = createItem(
+            creator,
+            new String[] {
+                Resources.getMsg(meta, I18N_MODE_W, I18N_MODE_W),
+                String.valueOf(DATA_MODE_W) } );
+
+        Element modeQ = createItem(
+            creator,
+            new String[] {
+                Resources.getMsg(meta, I18N_MODE_Q, I18N_MODE_Q),
+                String.valueOf(DATA_MODE_Q) } );
+
+        return new Element[] { modeW, modeQ };
+    }
+
+
+    protected Element[] createValuesItem(
+        ElementCreator creator,
+        Artifact       artifact,
+        String         name,
+        CallContext    context
+    ) {
+        logger.debug("createValuesItem()");
+
+        Element valuesW = createItem(
+            creator, new String[] { "ws", "" } );
+
+        Element valuesQ = createItem(
+            creator, new String[] { "qs", "" } );
+
+        return new Element[] { valuesW, valuesQ };
+    }
+}
+// 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/InputDoubleState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,39 @@
+package de.intevation.flys.artifacts.states;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+
+/**
+ * State to keep a double value and validate it against a range
+ */
+public class InputDoubleState extends MinMaxState {
+
+    private static final Logger logger = Logger.getLogger(InputDoubleState.class);
+
+
+    @Override
+    protected String getUIProvider() {
+        return "location_panel";
+    }
+
+
+    @Override
+    protected Object getLower(FLYSArtifact flys) {
+        return 0;
+    }
+
+
+    @Override
+    protected Object getUpper(FLYSArtifact flys) {
+        return 0;
+    }
+
+
+    @Override
+    protected String getType() {
+        return "double";
+    }
+}
+// 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/IntRangeState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,39 @@
+package de.intevation.flys.artifacts.states;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class IntRangeState extends MinMaxState {
+
+    private static final Logger logger = Logger.getLogger(IntRangeState.class);
+
+
+    @Override
+    protected String getUIProvider() {
+        return "timerange";
+    }
+
+
+    @Override
+    protected Object getLower(FLYSArtifact flys) {
+        return 0;
+    }
+
+
+    @Override
+    protected Object getUpper(FLYSArtifact flys) {
+        return 0;
+    }
+
+
+    @Override
+    protected String getType() {
+        return "intrange";
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationDistanceSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,6 +8,7 @@
 
 import de.intevation.artifactdatabase.data.StateData;
 
+import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.WINFOArtifact;
 
 
@@ -24,7 +25,7 @@
     /** The name of the 'mode' field. */
     public static final String MODE = "ld_mode";
 
-    /** The name of the 'locations' field.*/
+    /** The name of the 'locations' field. */
     public static final String LOCATIONS = "ld_locations";
 
 
@@ -41,24 +42,29 @@
     }
 
 
+    /** Validates the range (or location). */
     @Override
     public boolean validate(Artifact artifact)
     throws IllegalArgumentException
     {
         logger.debug("LocationDistanceSelect.validate");
 
-        WINFOArtifact flys = (WINFOArtifact) artifact;
-
-        if (flys.isRange()) {
-            return super.validate(flys);
+        FLYSArtifact flys = (FLYSArtifact)artifact;
+        StateData mode = getData(flys, MODE);
+        String mValue = mode != null ? (String)mode.getValue() : null;
+        if (mValue != null) {
+            if (mValue.equals("distance")) {
+                return super.validate(flys);
+            }
+            else {
+                return validateLocations(flys);
+            }
         }
-        else {
-            return validateLocations(flys);
-        }
+        return false;
     }
 
 
-    protected boolean validateLocations(WINFOArtifact flys)
+    protected boolean validateLocations(FLYSArtifact flys)
     throws    IllegalArgumentException
     {
         StateData dValues = getData(flys, LOCATIONS);
@@ -119,7 +125,7 @@
 
 
     public static double[] getLocations(WINFOArtifact flys) {
-        StateData data  = flys.getData("ld_locations");
+        StateData data  = flys.getData(LOCATIONS);
         String    value = data != null ? (String) data.getValue() : null;
 
         if (value == null || value.length() == 0) {
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/LocationSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -17,8 +17,9 @@
 
 
 /**
- * This state is used to realize the input of multiple locations as string. The
- * string should be a whitespace separated list of double values where each
+ * This state is used to realize the input of multiple locations as string.
+ *
+ * The string should be a whitespace separated list of double values where each
  * double value represents a location.
  *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
@@ -28,14 +29,12 @@
     /** The logger used in this class.*/
     private static Logger logger = Logger.getLogger(LocationSelect.class);
 
-    /** The name of the StateData object that stores the location string.*/
-    public static final String FIELD_LOCATIONS = "ld_locations";
-
 
     public LocationSelect() {
     }
 
 
+    /** UI Provider (which input method should the client provide to user. */
     @Override
     protected String getUIProvider() {
         return "location_panel";
@@ -62,7 +61,7 @@
             logger.warn("Could not read min/max distance values!");
         }
 
-        if (name.equals(FIELD_LOCATIONS)) {
+        if (name.equals(LOCATIONS)) {
             Element min = createItem(
                 cr,
                 new String[] {"min", new Double(minVal).toString()});
@@ -78,6 +77,7 @@
     }
 
 
+    /** Validates data from artifact. */
     @Override
     public boolean validate(Artifact artifact)
     throws IllegalArgumentException
@@ -85,9 +85,11 @@
         logger.debug("LocationSelect.validate");
 
         FLYSArtifact flys = (FLYSArtifact) artifact;
-        StateData    data = getData(flys, FIELD_LOCATIONS);
+        StateData    data = getData(flys, LOCATIONS);
 
-        String locationStr = data != null ? (String) data.getValue() : null;
+        String locationStr = data != null
+            ? (String) data.getValue()
+            : null;
 
         if (locationStr == null || locationStr.length() == 0) {
             logger.error("No locations given.");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ManualPointsSingleState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,141 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.ManualPointsArtifact;
+import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.ManualPointsFacet;
+import de.intevation.flys.artifacts.resources.Resources;
+
+/**
+ * The only state for an ManualPointArtifact.
+ */
+public class ManualPointsSingleState
+extends      DefaultState
+implements   FacetTypes
+{
+    /** Developer-centric description of facet. */
+    public static final String I18N_DESCRIPTION
+        = "facet.longitudinal_section.manualpoint";
+
+    /** Part of data key. */
+    protected static final String DOT_DATA
+        = ".data";
+
+    /** Part of data key. */
+    protected static final String DOT_LINES
+        = ".lines";
+
+    /** The logger that is used in this state. */
+    private static final Logger logger =
+        Logger.getLogger(ManualPointsSingleState.class);
+
+
+    /**
+     * Add ManualPointsFacets to list of Facets.
+     *
+     * @param artifact Ignored.
+     * @param hash Ignored.
+     * @param meta CallMeta to be used for internationalization.
+     * @param facets List to add ManualPointsFacet to.
+     *
+     * @return null.
+     */
+    public Object compute(
+        FLYSArtifact artifact,
+        String       hash,
+        CallMeta     meta,
+        List<Facet>  facets
+    ) {
+        logger.debug("ManualPointsSingleState.compute()");
+        ManualPointsArtifact points = (ManualPointsArtifact) artifact;
+
+        // Add Facet per Diagram type if data given.
+        for (ChartType ct: ChartType.values()) {
+            // Handle points.
+            String pointData = points.getDataAsString(ct + "." + MANUALPOINTS +
+                DOT_DATA);
+            if (pointData != null && pointData.length() != 0
+                && !pointData.equals("[]")) {
+                String fName = ct + "." + MANUALPOINTS;
+                ManualPointsFacet facet = new ManualPointsFacet(
+                    0,
+                    fName,
+                    Resources.getMsg(meta, "manualpoints", "Manual Points"));
+                facets.add(facet);
+                logger.debug("compute(): ManualPointsFacet for " + ct + " created");
+            }
+            else {
+                logger.debug("compute(): No points for " + ct);
+            }
+
+            // Handle lines.
+            String linesData = points.getDataAsString(ct + "." + MANUALPOINTS +
+                DOT_LINES);
+            if (linesData != null && linesData.length() != 0
+                && !linesData.equals("[]")) {
+                try {
+                    JSONArray lines = new JSONArray(linesData);
+                    for (int i = 0, P = lines.length(); i < P; i++) {
+                        JSONArray array = lines.getJSONArray(i);
+                        double y    = array.getDouble(0);
+                        String name = array.getString(1);
+                        String fName = ct + "." + MANUALLINE;
+                        logger.debug("have facet: " + y + " / " + name + " -> " + fName);
+                        CrossSectionWaterLineFacet facet = new CrossSectionWaterLineFacet(
+                            i,
+                            fName,
+                            name);
+
+                        facets.add(facet);
+                    }
+                }
+                catch(JSONException e){
+                    logger.error("Could not decode json.");
+                }
+
+            }
+            else {
+                //logger.debug("No points for " + ct);
+            }
+        }
+
+        return null;
+    }
+
+
+    /** Call compute. */
+    @Override
+    public Object computeInit(
+        FLYSArtifact artifact,
+        String       hash,
+        Object       context,
+        CallMeta     meta,
+        List<Facet>  facets
+     ) {
+        return compute(artifact, hash, meta, facets);
+    }
+
+
+    /** Call compute. */
+    @Override
+    public Object computeFeed(
+        FLYSArtifact artifact,
+        String hash,
+        CallContext context,
+        List<Facet> facets,
+        Object old
+    ) {
+        return compute(artifact, hash, context.getMeta(), facets);
+    }
+}
+// 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/MiddleBedHeight.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,95 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.BedHeightAccess;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.MiddleBedHeightData;
+import de.intevation.flys.artifacts.model.MiddleBedHeightFacet;
+import de.intevation.flys.artifacts.model.MiddleBedHeightCalculation;
+
+
+public class MiddleBedHeight extends DefaultState implements FacetTypes {
+
+    private static final Logger logger = Logger.getLogger(MiddleBedHeight.class);
+
+
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        logger.debug("MiddleBedHeight.computeAdvance");
+
+        List<Facet> newFacets = new ArrayList<Facet>();
+
+        BedHeightAccess access = new BedHeightAccess(artifact);
+
+        CalculationResult res = old instanceof CalculationResult
+            ? (CalculationResult) old
+            : new MiddleBedHeightCalculation().calculate(access);
+
+        if (facets == null || res == null) {
+            return res;
+        }
+
+        MiddleBedHeightData[] data = (MiddleBedHeightData[]) res.getData();
+
+        logger.debug("Calculated " + data.length + " MiddleBedHeightData objects");
+
+        String id  = getID();
+        int    idx = 0;
+
+        for (MiddleBedHeightData d: data) {
+            if (d.getStartYear() == d.getEndYear()) {
+                newFacets.add(new MiddleBedHeightFacet(
+                    idx,
+                    MIDDLE_BED_HEIGHT_SINGLE,
+                    d.getSoundingName(context),
+                    ComputeType.ADVANCE,
+                    id,
+                    hash
+                ));
+            }
+            else {
+                newFacets.add(new MiddleBedHeightFacet(
+                    idx,
+                    MIDDLE_BED_HEIGHT_EPOCH,
+                    d.getSoundingName(context),
+                    ComputeType.ADVANCE,
+                    id,
+                    hash
+                ));
+            }
+
+            idx++;
+        }
+
+        Facet csv = new DataFacet(
+            CSV, "CSV data", ComputeType.ADVANCE, hash, id);
+
+        // TODO ADD PDF FACET
+
+        newFacets.add(csv);
+
+        logger.debug("Created " + newFacets.size() + " new Facets.");
+
+        facets.addAll(newFacets);
+
+        return res;
+    }
+}
+// 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/MinMaxState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,173 @@
+package de.intevation.flys.artifacts.states;
+
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+
+import de.intevation.artifactdatabase.ProtocolUtils;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+
+/**
+ * State that holds minimun and maximum (for validation).
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public abstract class MinMaxState extends DefaultState {
+
+    private static final Logger logger = Logger.getLogger(MinMaxState.class);
+
+    @Override
+    protected void appendItems(
+        Artifact       artifact,
+        ElementCreator creator,
+        String         name,
+        CallContext    context,
+        Element        select
+    ) {
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        select.setAttributeNS(
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            "art:type",
+            getType());
+
+        String[] defMinMax = getDefaults(artifact, name);
+
+        Element min = ProtocolUtils.createArtNode(
+            creator,
+            "min",
+            new String[] { "value", "default" },
+            new String[] { String.valueOf(getLower(flys)), defMinMax[0] });
+
+        Element max = ProtocolUtils.createArtNode(
+            creator,
+            "max",
+            new String[] { "value", "default" },
+            new String[] { String.valueOf(getUpper(flys)), defMinMax[1] });
+
+        select.appendChild(min);
+        select.appendChild(max);
+    }
+
+
+    /**
+     * @param cc
+     * @param name
+     * @param value
+     * @param type
+     *
+     * @return
+     */
+    @Override
+    protected String getLabelFor(
+        CallContext cc,
+        String      name,
+        String      value,
+        String      type
+    ) {
+        if (type.indexOf("range") > 0) {
+            String[] minmax = extractRangeAsString(value);
+
+            if (minmax != null) {
+                return minmax[0] + " - " + minmax[1];
+            }
+        }
+
+        return super.getLabelFor(cc, name, value, type);
+    }
+
+
+    /**
+     * Returns a string array with [min,max] from <i>rawValue</i>.
+     * <i>rawValue</i> should be a string like "1999;2001".
+     *
+     * @param rawValue A string with min and max separated by a ';'.
+     *
+     * @return the min and max as string array ([min,max]).
+     */
+    protected String[] extractRangeAsString(String rawValue) {
+        return rawValue.split(";");
+    }
+
+
+    /**
+     * This method returns the default values for min and max. If the static
+     * field DefaultState.USE_DEFAULTS is set, the minimum and maximum inserted
+     * by the user is returned as string. Otherwise, the absolute minimum and
+     * maximum are returned.
+     *
+     * @param artifact The FLYSArtifact.
+     * @param name The name of the parameter.
+     *
+     * @return a string array [min,max] that contains the minimum and maximum
+     * values for the parameter <i>name</i>.
+     */
+    protected String[] getDefaults(Artifact artifact, String name) {
+        if (DefaultState.USE_DEFAULTS) {
+            String[] tmp = getMinMaxByParameter(artifact, name);
+
+            return tmp != null ? tmp : getMinMaxDefaults(artifact, name);
+        }
+        else {
+            return getMinMaxDefaults(artifact, name);
+        }
+    }
+
+
+    /**
+     * Returns a string array with minimum and maximum inserted by the user as
+     * [min,max].
+     *
+     * @param artifact The FLYSArtifact that stores the parameter.
+     * @param name The name of the parameter for raw min/max value string.
+     *
+     * @return a string array [min,max].
+     */
+    protected String[] getMinMaxByParameter(Artifact artifact, String name) {
+        FLYSArtifact flys     = (FLYSArtifact) artifact;
+        String       rawValue = flys.getDataAsString(name);
+
+        if (rawValue == null) {
+            logger.debug("No value for '" + rawValue + "' existing.");
+            return null;
+        }
+
+        logger.debug("Raw value for '" + name + "' = " + rawValue);
+
+        return extractRangeAsString(rawValue);
+    }
+
+
+    /**
+     * Returns a string array with absolute minimum and maximum as [min,max].
+     *
+     * @param artifact The FLYSArtifact (not used in this implementation).
+     * @param name The parameter name (not used in this implementation).
+     *
+     * @return a string array [min,max].
+     */
+    protected String[] getMinMaxDefaults(Artifact artifact, String name) {
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+
+        Object lower = getLower(flys);
+        Object upper = getUpper(flys);
+
+        return new String[] { String.valueOf(lower), String.valueOf(upper) };
+    }
+
+
+    protected abstract Object getLower(FLYSArtifact flys);
+
+    protected abstract Object getUpper(FLYSArtifact flys);
+
+    protected abstract String getType();
+}
+// 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/MultiIntArrayState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,101 @@
+package de.intevation.flys.artifacts.states;
+
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.artifacts.common.model.KVP;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.utils.FLYSUtils;
+
+
+/**
+ * State that holds minimun and maximum (for validation).
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public abstract class MultiIntArrayState extends DefaultState {
+
+    private static final Logger logger =
+        Logger.getLogger(MultiIntArrayState.class);
+
+
+    @Override
+    protected void appendItems(
+        Artifact       artifact,
+        ElementCreator creator,
+        String         name,
+        CallContext    context,
+        Element        select
+    ) {
+        try {
+            creator.addAttr(select, "type", "intoptions", true);
+
+            for (KVP kvp: getOptions(artifact, name)) {
+                Element item = creator.create("item");
+                creator.addAttr(item, "label", kvp.getValue().toString(), true);
+                creator.addAttr(item, "value", kvp.getKey().toString(), true);
+
+                select.appendChild(item);
+            }
+        }
+        catch (IllegalArgumentException iae) {
+            logger.warn("Illegal argument", iae);
+        }
+    }
+
+
+    @Override
+    protected Element createStaticData(
+        FLYSArtifact   flys,
+        ElementCreator creator,
+        CallContext    cc,
+        String         name,
+        String         value,
+        String         type
+    ) {
+        Element data = creator.create("data");
+        creator.addAttr(data, "name",  name, true);
+        creator.addAttr(data, "type",  type, true);
+        creator.addAttr(data, "label",
+            Resources.getMsg(cc.getMeta(), name, name), true);
+
+        int[] values = FLYSUtils.intArrayFromString(value);
+
+        for (int val: values) {
+            try {
+                Element item = creator.create("item");
+                creator.addAttr(item, "value", String.valueOf(val), true);
+                creator.addAttr(item, "label", getLabelFor(cc, name, val), true);
+
+                data.appendChild(item);
+            }
+            catch (IllegalArgumentException iae) {
+                logger.warn("Cannot append item: " + val, iae);
+            }
+        }
+
+        return data;
+    }
+
+
+    protected abstract KVP<Integer, String>[] getOptions(
+        Artifact artifact,
+        String   parameterName
+    )
+    throws IllegalArgumentException;
+
+
+    protected abstract String getLabelFor(
+        CallContext cc,
+        String      parameterName,
+        int         value)
+    throws IllegalArgumentException;
+}
+// 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/MultiStringArrayState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,96 @@
+package de.intevation.flys.artifacts.states;
+
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.artifacts.common.model.KVP;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.resources.Resources;
+
+
+/**
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public abstract class MultiStringArrayState extends DefaultState {
+
+    private static final Logger logger =
+        Logger.getLogger(MultiStringArrayState.class);
+
+
+    @Override
+    protected void appendItems(
+        Artifact       artifact,
+        ElementCreator creator,
+        String         name,
+        CallContext    context,
+        Element        select
+    ) {
+        try {
+            creator.addAttr(select, "type", "options", true);
+
+            for (KVP kvp: getOptions(artifact, name, context)) {
+                Element item = creator.create("item");
+                creator.addAttr(item, "label", kvp.getValue().toString(), true);
+                creator.addAttr(item, "value", kvp.getKey().toString(), true);
+
+                select.appendChild(item);
+            }
+        }
+        catch (IllegalArgumentException iae) {
+            logger.warn("Illegal argument", iae);
+        }
+    }
+
+
+    @Override
+    protected Element createStaticData(
+        FLYSArtifact   flys,
+        ElementCreator creator,
+        CallContext    cc,
+        String         name,
+        String         value,
+        String         type
+    ) {
+        Element data = creator.create("data");
+        creator.addAttr(data, "name",  name, true);
+        creator.addAttr(data, "type",  type, true);
+        creator.addAttr(data, "label",
+            Resources.getMsg(cc.getMeta(), name, name), true);
+
+        String[] values = value.split(";");
+
+        for (String val: values) {
+            Element item = creator.create("item");
+            creator.addAttr(item, "value", val, true);
+            creator.addAttr(item, "label", getLabelFor(cc, name, val), true);
+
+            data.appendChild(item);
+        }
+
+        return data;
+    }
+
+
+    protected abstract KVP<String, String>[] getOptions(
+        Artifact artifact,
+        String   parameterName,
+        CallContext context
+    )
+    throws IllegalArgumentException;
+
+
+    protected abstract String getLabelFor(
+        CallContext cc,
+        String      parameterName,
+        String      value
+    )
+    throws IllegalArgumentException;
+}
+// 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/OutliersInput.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,41 @@
+package de.intevation.flys.artifacts.states;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.data.StateData;
+import de.intevation.artifacts.CallContext;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class OutliersInput extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(OutliersInput.class);
+
+    public static final String PARAMETER_NAME = "outliers";
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public OutliersInput() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return "outliers_input";
+    }
+
+
+    @Override
+    protected String[] getDefaultsFor(CallContext context, StateData data) {
+        if (data != null && data.getName().equals(PARAMETER_NAME)) {
+            return new String[] {"3", "3"};
+        }
+
+        return null;
+    }
+
+}
+// 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/PeriodSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,21 @@
+package de.intevation.flys.artifacts.states;
+
+public class PeriodSelect extends DefaultState {
+
+    public static final String UI_PROVIDER = "period_select";
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public PeriodSelect() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return UI_PROVIDER;
+    }
+
+}
+// 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/PeriodsSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,26 @@
+package de.intevation.flys.artifacts.states;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class PeriodsSelect extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(PeriodsSelect.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public PeriodsSelect() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return "periods_select";
+    }
+
+}
+// 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/QSectorSingleState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,91 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.QSectorArtifact;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.QSectorFacet;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+/**
+ * The only state for an QSectorArtifact.
+ */
+public class QSectorSingleState
+extends      DefaultState
+implements   FacetTypes
+{
+    /** Developer-centric description of facet. */
+    public static final String I18N_DESCRIPTION
+        = "facet.qsector";
+
+    /** The logger that is used in this state. */
+    private static final Logger logger =
+        Logger.getLogger(QSectorSingleState.class);
+
+
+    /**
+     * Add QSectorFacets to list of Facets.
+     *
+     * @param artifact Ignored.
+     * @param hash Ignored.
+     * @param meta CallMeta to be used for internationalization.
+     * @param facets List to add QSectorFacet to.
+     *
+     * @return null.
+     */
+    public Object compute(
+        FLYSArtifact artifact,
+        String       hash,
+        CallMeta     meta,
+        List<Facet>  facets
+    ) {
+        logger.debug("QSectorSingleState.compute()");
+        QSectorArtifact points = (QSectorArtifact) artifact;
+
+        QSectorFacet qfacet = new QSectorFacet(
+            0,
+            QSECTOR,
+            Resources.getMsg(meta, "qsectors", "Q Sectors"));
+
+        facets.add(qfacet);
+
+        return null;
+    }
+
+
+    /** Call compute. */
+    @Override
+    public Object computeInit(
+        FLYSArtifact artifact,
+        String       hash,
+        Object       context,
+        CallMeta     meta,
+        List<Facet>  facets
+     ) {
+        return compute(artifact, hash, meta, facets);
+    }
+
+
+    /** Call compute. */
+    @Override
+    public Object computeFeed(
+        FLYSArtifact artifact,
+        String hash,
+        CallContext context,
+        List<Facet> facets,
+        Object old
+    ) {
+        return compute(artifact, hash, context.getMeta(), facets);
+    }
+}
+// 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/ReferenceCurveState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,87 @@
+package de.intevation.flys.artifacts.states;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.WINFOArtifact;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.ReferenceCurveFacet;
+import de.intevation.flys.artifacts.model.ReportFacet;
+import de.intevation.flys.artifacts.model.WWQQ;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+
+/** State of WINFO in which reference curves can be produced. */
+public class ReferenceCurveState
+extends      DefaultState
+implements   FacetTypes
+{
+    private static Logger logger = Logger.getLogger(ReferenceCurveState.class);
+
+
+    public ReferenceCurveState() {
+    }
+
+
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        if (!(artifact instanceof WINFOArtifact)) {
+            return null;
+        }
+
+        String id = getID();
+
+        WINFOArtifact winfo = (WINFOArtifact)artifact;
+
+        CalculationResult res = old instanceof CalculationResult
+            ? (CalculationResult)old
+            : winfo.getReferenceCurveData(context);
+
+        if (facets == null) {
+            return res;
+        }
+
+        WWQQ [] wws = (WWQQ [])res.getData();
+
+        for (int i = 0; i < wws.length; ++i) {
+            String wwsName = wws[i].getName();
+            facets.add(new ReferenceCurveFacet(i,
+                REFERENCE_CURVE,
+                wwsName
+                ));
+            facets.add(new ReferenceCurveFacet(i,
+                REFERENCE_CURVE_NORMALIZED,
+                wwsName
+                ));
+        }
+
+        if (wws.length > 0) {
+            logger.debug("Adding CSV and PDF data facet.");
+            Facet csv = new DataFacet (CSV, "CSV data", ComputeType.ADVANCE, hash, id);
+            Facet pdf = new DataFacet (PDF, "PDF data", ComputeType.ADVANCE, hash, id);
+            facets.add(csv);
+            facets.add(pdf);
+        }
+
+        if (res.getReport().hasProblems()) {
+            facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id));
+        }
+
+        return res;
+    }
+}
+// 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/ReferenceGaugeState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,88 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.List;
+
+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.model.Gauge;
+import de.intevation.flys.model.River;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.utils.FLYSUtils;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class ReferenceGaugeState extends DefaultState {
+
+    private static final Logger logger =
+        Logger.getLogger(ReferenceGaugeState.class);
+
+
+    public static final String DATA_NAME = "reference_gauge";
+
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator cr,
+        Artifact    artifact,
+        String      name,
+        CallContext context)
+    {
+        CallMeta  meta = context.getMeta();
+
+        River       river   = FLYSUtils.getRiver((FLYSArtifact) artifact);
+        List<Gauge> gauges  = river.getGauges();
+
+        int num = gauges != null ? gauges.size() : 0;
+
+        Element[] opts = new Element[num];
+
+        for (int i = 0; i < num; i++ ) {
+            Gauge g = gauges.get(i);
+
+            String gaugeName      = g.getName();
+            long   officialNumber = g.getOfficialNumber();
+
+            opts[i] = createItem(
+                cr, new String[] { gaugeName, String.valueOf(officialNumber) });
+        }
+
+        return opts;
+    }
+
+
+    @Override
+    protected String getLabelFor(
+        CallContext cc,
+        String      name,
+        String      value,
+        String      type
+    ) {
+        if (name.equals(DATA_NAME)) {
+            try {
+                long  number = Long.valueOf(value);
+                Gauge gauge  = Gauge.getGaugeByOfficialNumber(number);
+
+                if (gauge != null) {
+                    return gauge.getName();
+                }
+            }
+            catch (NumberFormatException nfe) {
+                // do nothing
+            }
+        }
+
+        return super.getLabelFor(cc, name, value, type);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/RiverSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -30,7 +30,6 @@
     /** The logger used in this class. */
     private static Logger logger = Logger.getLogger(RiverSelect.class);
 
-
     /** Error message that is thrown if no river was found based on a given
      * name.*/
     public static final String ERROR_NO_SUCH_RIVER =
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/SQRelation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,295 @@
+package de.intevation.flys.artifacts.states;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifacts.common.utils.StringUtils;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.access.SQRelationAccess;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+import de.intevation.flys.artifacts.model.sq.SQCurveFacet;
+import de.intevation.flys.artifacts.model.sq.SQFractionResult;
+import de.intevation.flys.artifacts.model.sq.SQMeasurementFacet;
+import de.intevation.flys.artifacts.model.sq.SQOutlierCurveFacet;
+import de.intevation.flys.artifacts.model.sq.SQOutlierFacet;
+import de.intevation.flys.artifacts.model.sq.SQOutlierMeasurementFacet;
+import de.intevation.flys.artifacts.model.sq.SQOverviewFacet;
+import de.intevation.flys.artifacts.model.sq.SQRelationCalculation;
+import de.intevation.flys.artifacts.model.sq.SQResult;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class SQRelation extends DefaultState implements FacetTypes {
+
+    private static Logger log = Logger.getLogger(SQRelation.class);
+
+
+    public static final String I18N_FACET_CURVE =
+        "facet.sq_relation.curve";
+
+    public static final String I18N_FACET_MEASUREMENTS =
+        "facet.sq_relation.measurements";
+
+    public static final String I18N_FACET_OUTLIERS =
+        "facet.sq_relation.outliers";
+
+    public static final String I18N_FACET_OUTLIER_CURVE =
+        "facet.sq_relation.outlier.curve";
+
+    public static final String I18N_FACET_OUTLIER_MEASUREMENT =
+        "facet.sq_relation.outlier.measurement";
+
+    public static final int CURVE_INDEX               = 0;
+    public static final int MEASURREMENT_INDEX        = 1;
+    public static final int OUTLIER_INDEX             = 2;
+    public static final int OUTLIER_CURVE_INDEX       = 3;
+    public static final int OUTLIER_MEASUREMENT_INDEX = 4;
+
+    public static final String [][] FACET_NAMES = {
+        { SQ_A_CURVE, SQ_B_CURVE, SQ_C_CURVE,
+          SQ_D_CURVE, SQ_E_CURVE, SQ_F_CURVE
+        },
+        { SQ_A_MEASUREMENT, SQ_B_MEASUREMENT, SQ_C_MEASUREMENT,
+          SQ_D_MEASUREMENT, SQ_E_MEASUREMENT, SQ_F_MEASUREMENT
+        },
+        { SQ_A_OUTLIER, SQ_B_OUTLIER, SQ_C_OUTLIER,
+          SQ_D_OUTLIER, SQ_E_OUTLIER, SQ_F_OUTLIER
+        },
+        { SQ_A_OUTLIER_CURVE, SQ_B_OUTLIER_CURVE, SQ_C_OUTLIER_CURVE,
+          SQ_D_OUTLIER_CURVE, SQ_E_OUTLIER_CURVE, SQ_F_OUTLIER_CURVE
+        },
+        { SQ_A_OUTLIER_MEASUREMENT, SQ_B_OUTLIER_MEASUREMENT,
+          SQ_C_OUTLIER_MEASUREMENT, SQ_D_OUTLIER_MEASUREMENT,
+          SQ_E_OUTLIER_MEASUREMENT, SQ_F_OUTLIER_MEASUREMENT
+        }
+    };
+
+
+    static {
+        // Active/deactivate facets.
+        FacetActivity.Registry.getInstance().register(
+            "minfo",
+            new FacetActivity() {
+                @Override
+                public Boolean isInitialActive(
+                    Artifact artifact,
+                    Facet    facet,
+                    String   output
+                ) {
+                    String name = facet.getName();
+
+                    if (StringUtils.contains(
+                        name, FACET_NAMES[CURVE_INDEX])
+                    ||  StringUtils.contains(
+                        name, FACET_NAMES[OUTLIER_INDEX])
+                    ||  StringUtils.contains(
+                        name, FACET_NAMES[MEASURREMENT_INDEX])
+                    ) {
+                        // TODO: Only the last should be active.
+                        return Boolean.TRUE;
+                    }
+
+                    if (StringUtils.contains(
+                        name, FACET_NAMES[OUTLIER_CURVE_INDEX])
+                     || StringUtils.contains(
+                        name, FACET_NAMES[OUTLIER_MEASUREMENT_INDEX])
+                    ) {
+                        return Boolean.FALSE;
+                    }
+
+                    return null;
+                }
+            });
+    }
+
+
+    public SQRelation() {
+    }
+
+
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        log.debug("SQRelation.computeAdvance");
+
+        CalculationResult res = old instanceof CalculationResult
+            ? (CalculationResult)old
+            : new SQRelationCalculation(
+                new SQRelationAccess(artifact)).calculate();
+
+        if (facets == null) {
+            return res;
+        }
+
+        SQResult [] sqr = (SQResult [])res.getData();
+        if (sqr == null) {
+            return res;
+        }
+
+        createFacets(context, facets, sqr, hash);
+
+        Facet csv = new DataFacet(
+            CSV, "CSV data", ComputeType.ADVANCE, hash, id);
+
+        Facet pdf = new DataFacet(
+            PDF, "PDF data", ComputeType.ADVANCE, hash, id);
+
+        facets.add(csv);
+        facets.add(pdf);
+
+        return res;
+    }
+
+
+    protected void createFacets(
+        CallContext context,
+        List<Facet> container,
+        SQResult[]  sqr,
+        String      hash
+    ) {
+        boolean debug = log.isDebugEnabled();
+
+        CallMeta meta    = context.getMeta();
+        String   stateId = getID();
+        for (int i = 0; i < 6; i++) {
+            container.add(new SQOverviewFacet(
+                i,
+                i,
+                "sq_chart_overview",
+                Resources.getMsg(
+                    meta,
+                    I18N_FACET_CURVE,
+                    I18N_FACET_CURVE
+                ),
+                hash,
+                getID()
+            ));
+        }
+        for (int res = 0, n = sqr.length; res < n; res++) {
+
+            for (int i = 0; i < SQResult.NUMBER_FRACTIONS; i++) {
+                SQFractionResult result = sqr[res].getFraction(i);
+
+                if (result == null) {
+                    log.warn("Fraction at index " + i + " is empty!");
+                    continue;
+                }
+
+                container.add(new SQCurveFacet(
+                    res,
+                    i,
+                    getFractionFacetname(CURVE_INDEX, i),
+                    Resources.getMsg(
+                        meta,
+                        I18N_FACET_CURVE,
+                        I18N_FACET_CURVE
+                    ),
+                    hash,
+                    stateId
+                ));
+
+                for (int j = 0, C = result.numIterations()-1; j < C; j++) {
+
+                    Object [] round = new Object [] { j + 1 };
+
+                    int index = res;
+                    index     = index << 16;
+                    index     = index + j;
+
+                    if (debug) {
+                        log.debug("new outliers facet (index=" +index+ ")");
+                        log.debug("   result index = " + res);
+                        log.debug("   fraction idx = " + i);
+                        log.debug("   iteration    = " + j);
+                    }
+
+                    container.add(new SQOutlierFacet(
+                        index,
+                        i,
+                        getFractionFacetname(OUTLIER_INDEX, i),
+                        Resources.getMsg(
+                            meta,
+                            I18N_FACET_OUTLIERS,
+                            I18N_FACET_OUTLIERS,
+                            round
+                        ),
+                        hash,
+                        stateId
+                    ));
+
+                    container.add(new SQOutlierCurveFacet(
+                        index,
+                        i,
+                        getFractionFacetname(OUTLIER_CURVE_INDEX, i),
+                        Resources.getMsg(
+                            meta,
+                            I18N_FACET_OUTLIER_CURVE,
+                            I18N_FACET_OUTLIER_CURVE,
+                            round
+                        ),
+                        hash,
+                        stateId
+                    ));
+
+                    container.add(new SQOutlierMeasurementFacet(
+                        index,
+                        i,
+                        getFractionFacetname(OUTLIER_MEASUREMENT_INDEX, i),
+                        Resources.getMsg(
+                            meta,
+                            I18N_FACET_OUTLIER_MEASUREMENT,
+                            I18N_FACET_OUTLIER_MEASUREMENT,
+                            round
+                        ),
+                        hash,
+                        stateId
+                    ));
+                } // for all outliers
+
+                container.add(new SQMeasurementFacet(
+                    res,
+                    i,
+                    getFractionFacetname(MEASURREMENT_INDEX, i),
+                    Resources.getMsg(
+                        meta,
+                        I18N_FACET_MEASUREMENTS,
+                        I18N_FACET_MEASUREMENTS
+                    ),
+                    hash,
+                    stateId
+                ));
+            } // for all fractions
+        } // for all results
+    }
+
+    protected static String getFractionFacetname(int type, int idx) {
+        if (log.isDebugEnabled()) {
+            log.debug("getFractionFacetname(): " + type + " | " + idx);
+        }
+        type %= FACET_NAMES.length;
+        return FACET_NAMES[type][idx % FACET_NAMES[type].length];
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/ScenarioSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,7 @@
 package de.intevation.flys.artifacts.states;
 
+import java.io.File;
+
 import org.apache.log4j.Logger;
 
 import org.w3c.dom.Element;
@@ -10,11 +12,13 @@
 
 import de.intevation.artifacts.common.utils.XMLUtils;
 import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.artifacts.common.utils.FileTools;
 
 import de.intevation.artifactdatabase.ProtocolUtils;
 
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.utils.FLYSUtils;
 
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
@@ -116,5 +120,38 @@
 
         return item;
     }
+
+
+
+    @Override
+    public void endOfLife(Artifact artifact, Object callContext) {
+        super.endOfLife(artifact, callContext);
+        logger.info("ScenarioSelect.endOfLife: " + artifact.identifier());
+
+        FLYSArtifact flys = (FLYSArtifact) artifact;
+        removeDirectory(flys);
+    }
+
+
+    /**
+     * Removes the directory and all its content where the required data and the
+     * results of WSPLGEN are stored. Should be called in endOfLife().
+     */
+    protected void removeDirectory(FLYSArtifact artifact) {
+        String shapePath = FLYSUtils.getXPathString(
+            FLYSUtils.XPATH_SHAPEFILE_DIR);
+
+        File artifactDir = new File(shapePath, artifact.identifier());
+
+        if (artifactDir.exists()) {
+            logger.info("Delete directory: " + artifactDir.getAbsolutePath());
+            boolean success = FileTools.deleteRecursive(artifactDir);
+        }
+        else {
+            logger.debug("There is no directory to remove.");
+        }
+    }
+
+
 }
 // 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/SoundingsSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,208 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.artifacts.common.model.KVP;
+
+import de.intevation.flys.model.BedHeightEpoch;
+import de.intevation.flys.model.BedHeightSingle;
+import de.intevation.flys.model.River;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.utils.FLYSUtils;
+
+
+public class SoundingsSelect extends MultiStringArrayState {
+
+    public static final String SOUNDINGS = "soundings";
+
+    public static final String PREFIX_SINGLE = "single-";
+
+    public static final String PREFIX_EPOCH = "epoch-";
+
+    /** Private logger. */
+    private static final Logger logger = Logger.getLogger(SoundingsSelect.class);
+
+
+    @Override
+    public String getUIProvider() {
+        return "parameter-matrix";
+    }
+
+
+    @Override
+    protected KVP<String, String>[] getOptions(
+        Artifact artifact,
+        String   parameterName,
+        CallContext context
+    )
+    throws IllegalArgumentException
+    {
+        logger.debug("Get options for parameter: '" + parameterName + "'");
+
+        if (!testParameterName(parameterName)) {
+            throw new IllegalArgumentException(
+                "Invalid parameter for state: '" + parameterName + "'");
+        }
+
+        River river = FLYSUtils.getRiver((FLYSArtifact) artifact);
+        double lo = ((FLYSArtifact) artifact).getDataAsDouble("ld_from");
+        double hi = ((FLYSArtifact) artifact).getDataAsDouble("ld_to");
+
+        double kmLo = Math.min(lo, hi);
+        double kmHi = Math.max(lo, hi);
+
+        List<KVP<String, String>> kvp = new ArrayList<KVP<String, String>>();
+
+        appendSingles(river, kmLo, kmHi, kvp);
+        appendEpochs(river, kmLo, kmHi, kvp);
+
+        return kvp.toArray(new KVP[kvp.size()]);
+    }
+
+
+    protected void appendSingles(
+        River river,
+        double kmLo,
+        double kmHi,
+        List<KVP<String, String>> kvp
+    ) {
+        List<BedHeightSingle> singles =
+            BedHeightSingle.getBedHeightSingles(river, kmLo, kmHi);
+
+        if (singles != null) {
+            int size = singles.size();
+
+            logger.debug("Found " + size + " singles.");
+
+            for (int i = 0; i < size; i++) {
+                BedHeightSingle s = singles.get(i);
+
+                String id    = PREFIX_SINGLE + s.getId();
+                String value = s.getDescription();
+
+                kvp.add(new KVP(id, value));
+            }
+        }
+    }
+
+
+    protected void appendEpochs(
+        River river,
+        double kmLo,
+        double kmHi,
+        List<KVP<String, String>> kvp
+    ) {
+        List<BedHeightEpoch> epochs =
+            BedHeightEpoch.getBedHeightEpochs(river, kmLo, kmHi);
+
+        if (epochs != null) {
+            int size = epochs.size();
+
+            logger.debug("Found " + size + " epochs.");
+
+            for (int i = 0; i < size; i++) {
+                BedHeightEpoch e = epochs.get(i);
+
+                String id    = PREFIX_EPOCH + e.getId();
+                String value = e.getDescription();
+
+                kvp.add(new KVP(id, value));
+            }
+        }
+    }
+
+
+    @Override
+    protected String getLabelFor(
+        CallContext cc,
+        String      parameterName,
+        String      value
+    ) throws IllegalArgumentException
+    {
+        if (!testParameterName(parameterName)) {
+            throw new IllegalArgumentException(
+                "Invalid parameter for state: '" + parameterName + "'");
+        }
+
+        if (value.indexOf(PREFIX_SINGLE) >= 0) {
+            return getLabelForSingle(cc, value);
+        }
+        else if (value.indexOf(PREFIX_EPOCH) >= 0) {
+            return getLabelForEpoch(cc, value);
+        }
+
+        return value;
+    }
+
+
+    protected String getLabelForSingle(CallContext cc, String value) {
+        String id = value.replace(PREFIX_SINGLE, "");
+        try {
+            BedHeightSingle s = BedHeightSingle.getBedHeightSingleById(
+                Integer.parseInt(id));
+
+            if (s != null) {
+                return s.getDescription();
+            }
+            else {
+                return "no value for '" + id + "'";
+            }
+        }
+        catch (NumberFormatException nfe) {
+            logger.warn("Could not parse id from string '" + id + "'", nfe);
+        }
+
+        return "n.A.";
+    }
+
+
+    protected String getLabelForEpoch(CallContext cc, String value) {
+        String id = value.replace(PREFIX_EPOCH, "");
+        try {
+            BedHeightEpoch e = BedHeightEpoch.getBedHeightEpochById(
+                Integer.parseInt(id));
+
+            if (e != null) {
+                return e.getDescription();
+            }
+            else {
+                return "no value for '" + id + "'";
+            }
+        }
+        catch (NumberFormatException nfe) {
+            logger.warn("Could not parse id from string '" + id + "'", nfe);
+        }
+
+        return "n.A.";
+    }
+
+
+    /**
+     * This method might be used to test, if a parameter name is handled by this
+     * state.
+     *
+     * @param parameterName The name of a parameter.
+     *
+     * @return true, if parameterName is one of <i>MAIN_CHANNEL</i> or
+     * <i>TOTAL_CHANNEL</i>. Otherwise false.
+     */
+    protected boolean testParameterName(String parameterName) {
+        if (parameterName == null || parameterName.length() == 0) {
+            return false;
+        }
+        else if (parameterName.equals(SOUNDINGS)) {
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/StateFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/StateFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -103,18 +103,19 @@
             String desc = (String) XMLUtils.xpath(
                 data, XPATH_DATA_DESCRIPTION, XPathConstants.STRING);
 
-            if (name == null || name.equals("")) {
+            if (name == null || name.length() == 0) {
                 logger.warn("No name for data item at pos " + i + " found.");
                 continue;
             }
 
-            if (type == null || type.equals("")) {
+            if (type == null || type.length() == 0) {
                 logger.warn("No type for data item at pos " + i + " found.");
                 logger.warn("Default type 'string' used.");
                 type = "string";
             }
 
-            state.addData(name, new DefaultStateData(name, type, desc));
+            logger.debug("add StateData '" + name + "' (type '" + type + "')");
+            state.addData(name, new DefaultStateData(name, desc, type));
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/StaticHYKState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,110 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.HYKArtifact;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.HYKFacet;
+import de.intevation.flys.artifacts.model.HYKFactory;
+
+/**
+ * Only state of a HYKArtifact.
+ */
+public class StaticHYKState
+extends      DefaultState
+implements   FacetTypes
+{
+    /** The logger that is used in this state. */
+    transient private static final Logger logger = Logger.getLogger(StaticHYKState.class);
+
+
+    /**
+     * From this state can not be continued.
+     */
+    @Override
+    protected String getUIProvider() {
+        return "noinput";
+    }
+
+
+    /**
+     * Compute, create Facets, do the same stuff as all the other states do.
+     */
+    protected Object compute(
+        HYKArtifact   hyk,
+        CallMeta      metaLocale,
+        String        hash,
+        List<Facet>   facets,
+        Object        old
+    ) {
+        logger.debug("StaticHYKState.compute");
+        String id = getID();
+
+        // Prepare comparison against cached result.
+        List<HYKFactory.Zone> resZones = old instanceof List
+            ? (List<HYKFactory.Zone>)old
+            : null;
+
+        // TODO Compare against cached object.
+
+        // Get Zones from HYKFactory
+        List<HYKFactory.Zone> zones = (List<HYKFactory.Zone>)
+            HYKFactory.getHYKs(hyk.getHykId(), hyk.getKm());
+
+        if (facets == null) {
+            logger.debug("StaticHYKState.compute no facets");
+            return zones;
+        }
+
+        // Spawn Facets.
+        Facet facet = new HYKFacet(0, HYKFactory.getHykName(hyk.getHykId()));
+        facets.add(facet);
+
+        return zones;
+    }
+
+
+    /**
+     * Get data, create the facets.
+     *
+     * @param context Ignored.
+     */
+    @Override
+    public Object computeFeed(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        return compute((HYKArtifact) artifact, context.getMeta(),
+            hash, facets, old);
+    }
+
+
+    /**
+     * Create the facets.
+     * @param context Ignored.
+     */
+    @Override
+    public Object computeInit(
+        FLYSArtifact artifact,
+        String       hash,
+        Object       context,
+        CallMeta     meta,
+        List<Facet>  facets
+    ) {
+        return compute((HYKArtifact) artifact, meta, hash, facets,
+            null);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/StaticState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/StaticState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,6 +8,7 @@
 
 import de.intevation.artifactdatabase.state.Facet;
 import de.intevation.artifactdatabase.state.DefaultOutput;
+import de.intevation.artifactdatabase.state.Output;
 
 import de.intevation.flys.artifacts.FLYSArtifact;
 
@@ -107,5 +108,9 @@
     ) {
         return staticCompute(facets, artifact);
     }
+
+    public void addOutput(Output out) {
+        super.addOutput(out);
+    }
 }
 // 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/StaticWQKmsState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,136 @@
+package de.intevation.flys.artifacts.states;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.StaticWQKmsArtifact;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.WQKmsFacet;
+
+/**
+ * Only state of WQKmsArtifact.
+ */
+public class StaticWQKmsState
+extends      DefaultState
+implements   FacetTypes
+{
+    /** The logger that is used in this state. */
+    private static Logger logger = Logger.getLogger(StaticWQKmsState.class);
+
+
+    /**
+     * From this state can not be continued.
+     */
+    @Override
+    protected String getUIProvider() {
+        return "noinput";
+    }
+
+
+    /**
+     * Compute, create Facets, do the same stuff as all the other states do.
+     */
+    protected Object compute(
+        StaticWQKmsArtifact winfo,
+        CallMeta      metaLocale,
+        String        hash,
+        List<Facet>   facets,
+        Object        old
+    ) {
+        String id = getID();
+
+        WQKms res = old instanceof WQKms
+            ? (WQKms)old
+            : winfo.getWQKms();
+
+        WQKms wqkms = res;
+
+        if (facets == null) {
+            return res;
+        }
+
+        /*
+         * TODO: re-enable HEIGHTMARKS_POINTS-thing
+
+           String name;
+           if (parts[0].equals(HEIGHTMARKS_POINTS)) {
+               name = HEIGHTMARKS_POINTS;
+           }
+           else {
+               name = STATIC_WQKMS;
+           }
+        */
+
+        String wkmsName = wqkms.getName();
+        Facet qfacet = new WQKmsFacet(
+            STATIC_WQKMS_Q,
+            wkmsName
+            // TODO re-enable translations.
+            /*
+            Resources.getMsg(
+                metaLocale,
+                wkmsName,
+                wkmsName)*/);
+        facets.add(qfacet);
+
+        wkmsName = "W (" + wkmsName + ")";
+
+        Facet wfacet = new WQKmsFacet(
+            STATIC_WQKMS_W,
+            wkmsName
+            /*
+            // TODO re-enable translations.
+            Resources.getMsg(
+                metaLocale,
+                wkmsName,
+                wkmsName)*/);
+        facets.add(wfacet);
+
+        return res;
+    }
+
+
+    /**
+     * Get data, create the facets.
+     *
+     * @param context Ignored.
+     */
+    @Override
+    public Object computeFeed(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        return compute((StaticWQKmsArtifact) artifact, context.getMeta(),
+            hash, facets, old);
+    }
+
+
+    /**
+     * Create the facets.
+     * @param context Ignored.
+     */
+    @Override
+    public Object computeInit(
+        FLYSArtifact artifact,
+        String       hash,
+        Object       context,
+        CallMeta     meta,
+        List<Facet>  facets
+    ) {
+        return compute((StaticWQKmsArtifact) artifact, meta, hash, facets,
+            null);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WDifferencesState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -13,12 +13,15 @@
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.StaticWKmsArtifact;
 import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.ChartArtifact;
 
 import de.intevation.flys.artifacts.math.WKmsOperation;
 
 import de.intevation.flys.artifacts.model.CalculationResult;
 import de.intevation.flys.artifacts.model.DataFacet;
 import de.intevation.flys.artifacts.model.DifferenceCurveFacet;
+import de.intevation.flys.artifacts.model.EmptyFacet;
+
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.WKms;
 import de.intevation.flys.artifacts.model.WQKms;
@@ -64,6 +67,9 @@
     }
 
 
+    /**
+     * Access the data (wkms).
+     */
     protected WKms getWKms(String mingle, CallContext context) {
         String[] def  = mingle.split(";");
         String   uuid = def[0];
@@ -81,7 +87,7 @@
                 logger.error("No WKms from artifact.");
             return wkms;
         }
-    
+
         WINFOArtifact flys = (WINFOArtifact) FLYSUtils.getArtifact(
             uuid,
             context);
@@ -114,6 +120,11 @@
         List<Facet>  facets,
         Object       old
     ) {
+        if (artifact instanceof ChartArtifact) {
+            ChartArtifact chart = (ChartArtifact)artifact;
+            facets.add(new EmptyFacet());
+            return null;
+        }
         WINFOArtifact winfo = (WINFOArtifact) artifact;
         String id = getID();
 
@@ -148,7 +159,7 @@
             String facetName = "diff ()";
 
             if (minuendWKms != null && subtrahendWKms != null) {
-                facetName = StringUtil.wWrap(minuendWKms.getName()) 
+                facetName = StringUtil.wWrap(minuendWKms.getName())
                     + " - " + StringUtil.wWrap(subtrahendWKms.getName());
                 WKms wkms = WKmsOperation.SUBTRACTION.operate(minuendWKms,
                      subtrahendWKms);
@@ -156,16 +167,19 @@
                 wkmss.add(wkms);
                 logger.debug("WKMSSubtraction happened");
             }
-    
             if (facets != null) {
                 facets.add(new DifferenceCurveFacet(i/2, W_DIFFERENCES, facetName,
                     ComputeType.ADVANCE, id, hash));
-                facets.add(new DataFacet(CSV, "CSV data"));
-                logger.debug("Adding facets in WDifferencesState.");
             }
-            else {
-                logger.debug("Not adding facets in WDifferencesState.");
-            }
+        }
+
+        if (facets != null) {
+            facets.add(new DataFacet(CSV, "CSV data"));
+            facets.add(new DataFacet(PDF, "PDF data"));
+            logger.debug("Adding facets in WDifferencesState.");
+        }
+        else {
+            logger.debug("Not adding facets in WDifferencesState.");
         }
 
         // TODO Evaluate whether null is okay as reports.
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WMSBackgroundState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -7,21 +7,16 @@
 import javax.xml.xpath.XPathConstants;
 
 import org.apache.log4j.Logger;
-
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 
+import de.intevation.artifactdatabase.state.Facet;
 import de.intevation.artifacts.CallMeta;
-
 import de.intevation.artifacts.common.utils.Config;
 import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifactdatabase.state.Facet;
-
 import de.intevation.flys.artifacts.FLYSArtifact;
-import de.intevation.flys.artifacts.model.WMSLayerFacet;
+import de.intevation.flys.artifacts.model.map.WMSLayerFacet;
 import de.intevation.flys.artifacts.resources.Resources;
-import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
 
 
 public class WMSBackgroundState extends OutputState {
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java	Fri Sep 28 12:15:52 2012 +0200
@@ -22,7 +22,7 @@
 import de.intevation.flys.model.River;
 import de.intevation.flys.model.Wst;
 
-import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.FLYSArtifact;
 
 import de.intevation.flys.artifacts.model.RangeWithValues;
 import de.intevation.flys.artifacts.model.WstFactory;
@@ -30,6 +30,7 @@
 
 
 /**
+ * State to input W/Q data.
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class WQAdapted extends DefaultState {
@@ -37,8 +38,7 @@
     /** The logger used in this state.*/
     private static Logger logger = Logger.getLogger(WQAdapted.class);
 
-
-    public static final String FIELD_WQ_MODE = "wq_mode";
+    public static final String FIELD_WQ_MODE = "wq_isq";
 
     public static final String FIELD_WQ_VALUES = "wq_values";
 
@@ -57,9 +57,11 @@
     public static final GaugeOrder GAUGE_UP   = new GaugeOrder(true);
     public static final GaugeOrder GAUGE_DOWN = new GaugeOrder(false);
 
+    /** Trivial, empty constructor. */
     public WQAdapted() {
     }
 
+
     /**
      * This method creates one element for each gauge of the selected river that
      * is intersected by the given kilometer range. Each element is a tuple of
@@ -97,6 +99,7 @@
     }
 
 
+    /** Creates "Q" and "W" items. */
     protected Element[] createModeItems(
         XMLUtils.ElementCreator cr,
         Artifact    artifact,
@@ -120,12 +123,12 @@
     {
         logger.debug("WQAdapted.createValueItems");
 
-        WINFOArtifact flysArtifact = (WINFOArtifact) artifact;
+        FLYSArtifact flysArtifact = (FLYSArtifact) artifact;
 
         double[]    dist   = FLYSUtils.getKmRange(flysArtifact);
         River       river  = FLYSUtils.getRiver(flysArtifact);
         Wst         wst    = WstFactory.getWst(river);
-        List<Gauge> gauges = flysArtifact.getGauges();
+        List<Gauge> gauges = FLYSUtils.getGauges(flysArtifact);
 
         int num = gauges != null ? gauges.size() : 0;
 
@@ -134,13 +137,11 @@
             return null;
         }
 
-        Element[] elements = new Element[num];
+        List<Element> elements = new ArrayList<Element>();
 
         double rangeFrom = dist[0];
         double rangeTo   = dist[1];
 
-        int idx = 0;
-
         if (rangeFrom < rangeTo) {
             Collections.sort(gauges, GAUGE_UP);
             for (Gauge gauge: gauges) {
@@ -148,14 +149,19 @@
                 double lower = range.getA().doubleValue();
                 double upper = range.getB().doubleValue();
 
+                // If gauge out of range, skip it.
+                if (upper <= rangeFrom || lower >= rangeTo) {
+                    continue;
+                }
+
                 double from = lower < rangeFrom ? rangeFrom : lower;
                 double to   = upper > rangeTo   ? rangeTo   : upper;
 
                 double[] mmQ = determineMinMaxQ(gauge, wst);
                 double[] mmW = gauge.determineMinMaxW();
 
-                elements[idx++] = createItem(
-                    cr, new String[] { from + ";" + to, ""}, mmQ, mmW);
+                elements.add(createItem(
+                    cr, new String[] { from + ";" + to, ""}, mmQ, mmW));
             }
         }
         else {
@@ -170,15 +176,18 @@
                 double from = lower < rangeFrom ? rangeFrom : lower;
                 double to   = upper > rangeTo   ? rangeTo   : upper;
 
+                // TODO probably need to continue out if oof range (see above).
+
                 double[] mmQ = determineMinMaxQ(gauge, wst);
                 double[] mmW = gauge.determineMinMaxW();
 
-                elements[idx++] = createItem(
-                    cr, new String[] { to + ";" + from, ""}, mmQ, mmW);
+                elements.add(createItem(
+                    cr, new String[] { to + ";" + from, ""}, mmQ, mmW));
             }
         }
 
-        return elements;
+        Element[] els = new Element[elements.size()];
+        return elements.toArray(els);
     }
 
 
@@ -278,15 +287,18 @@
     {
         logger.debug("WQAdapted.validate");
 
-        WINFOArtifact flys = (WINFOArtifact) artifact;
+        FLYSArtifact flys = (FLYSArtifact) artifact;
         StateData    data = getData(flys, FIELD_WQ_MODE);
 
         String mode = data != null ? (String) data.getValue() : null;
+        boolean isQ = mode != null
+            ? Boolean.valueOf(mode)
+            : false;
 
-        if (mode != null && mode.equals("W")) {
+        if (!isQ) {
             return validateW(artifact);
         }
-        else if (mode != null && mode.equals("Q")) {
+        else if (isQ) {
             return validateQ(artifact);
         }
         else {
@@ -299,7 +311,7 @@
     throws IllegalArgumentException
     {
         logger.debug("WQAdapted.validateW");
-        WINFOArtifact flys = (WINFOArtifact) artifact;
+        FLYSArtifact flys = (FLYSArtifact) artifact;
 
         RangeWithValues[] rwvs = extractInput(getData(flys, "wq_values"));
 
@@ -307,7 +319,7 @@
             throw new IllegalArgumentException("error_missing_wq_data");
         }
 
-        List<Gauge>     gauges = ((WINFOArtifact) artifact).getGauges();
+        List<Gauge> gauges = FLYSUtils.getGauges((FLYSArtifact) artifact);
 
         for (Gauge gauge: gauges) {
             Range range  = gauge.getRange();
@@ -315,7 +327,7 @@
             double upper = range.getB().doubleValue();
 
             for (RangeWithValues rwv: rwvs) {
-                if (lower <= rwv.getLower() && upper >= rwv.getUpper()) {
+                if (lower <= rwv.getStart() && upper >= rwv.getEnd()) {
                     compareWsWithGauge(gauge, rwv.getValues());
                 }
             }
@@ -329,7 +341,7 @@
     throws IllegalArgumentException
     {
         logger.debug("WQAdapted.validateQ");
-        WINFOArtifact flys = (WINFOArtifact) artifact;
+        FLYSArtifact flys = (FLYSArtifact) artifact;
 
         RangeWithValues[] rwvs = extractInput(getData(flys, "wq_values"));
 
@@ -337,7 +349,7 @@
             throw new IllegalArgumentException("error_missing_wq_data");
         }
 
-        List<Gauge> gauges = flys.getGauges();
+        List<Gauge> gauges = FLYSUtils.getGauges(flys);
         River        river = FLYSUtils.getRiver(flys);
         Wst            wst = WstFactory.getWst(river);
 
@@ -347,7 +359,7 @@
             double upper = range.getB().doubleValue();
 
             for (RangeWithValues rwv: rwvs) {
-                if (lower <= rwv.getLower() && upper >= rwv.getUpper()) {
+                if (lower <= rwv.getStart() && upper >= rwv.getEnd()) {
                     compareQsWithGauge(wst, gauge, rwv.getValues());
                 }
             }
@@ -450,7 +462,7 @@
             rwv.add(new RangeWithValues(lower, upper, res));
         }
 
-        return (RangeWithValues[]) rwv.toArray(new RangeWithValues[rwv.size()]);
+        return rwv.toArray(new RangeWithValues[rwv.size()]);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQSelect.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -25,6 +25,7 @@
 import de.intevation.flys.artifacts.WINFOArtifact;
 
 import de.intevation.flys.artifacts.model.WstFactory;
+import de.intevation.flys.artifacts.model.WstValueTable;
 import de.intevation.flys.artifacts.resources.Resources;
 
 import de.intevation.flys.utils.FLYSUtils;
@@ -38,7 +39,6 @@
     /** The logger used in this class. */
     private static Logger logger = Logger.getLogger(WQSelect.class);
 
-
     /** The default step width for Qs. */
     public static final String DEFAULT_STEP_Q = "50";
 
@@ -49,13 +49,13 @@
     public static final int MAX_STEPS = 30;
 
     /** The name of the 'mode' field. */
-    public static final String WQ_MODE = "wq_mode";
+    public static final String WQ_MODE = "wq_isq";
 
     /** Them name fo the 'free' field. */
-    public static final String WQ_FREE = "wq_free";
+    public static final String WQ_FREE = "wq_isfree";
 
     /** The name of the 'selection' field. */
-    public static final String WQ_SELECTION = "wq_selection";
+    public static final String WQ_SELECTION = "wq_isrange";
 
     /** The name of the 'from' field. */
     public static final String WQ_FROM = "wq_from";
@@ -90,8 +90,8 @@
             return super.createStaticData(flys, creator, cc, name, value, type);
         }
 
-        String mode = flys.getDataAsString(WQ_MODE);
-        String free = flys.getDataAsString(WQ_FREE);
+        Boolean isQ = flys.getDataAsBoolean(WQ_MODE);
+        Boolean isFree = flys.getDataAsBoolean(WQ_FREE);
 
         WINFOArtifact winfo = (WINFOArtifact) flys;
 
@@ -102,9 +102,9 @@
         Element itemElement = creator.create("item");
         creator.addAttr(itemElement, "value", value, true);
 
-        String label = "";
+        String label;
 
-        if (mode == null || mode.equals("W") || Boolean.valueOf(free)) {
+        if (!isQ || isFree) {
             label = getLabel(winfo, cc, value);
         }
         else {
@@ -125,25 +125,33 @@
         String        raw
     ) {
         String[] values = raw.split(" ");
-        String   label  = null;
+
+        if (values.length < 1) {
+            return null;
+        }
+
+        StringBuilder label = new StringBuilder();
 
         NumberFormat nf = NumberFormat.getInstance(
             Resources.getLocale(cc.getMeta()));
 
         for (String value: values) {
             try {
-                double v = Double.valueOf(value.trim());
+                double v = Double.parseDouble(value.trim());
 
                 String formatted = nf.format(v);
 
-                label = label != null ? label + ";" + formatted : formatted;
+                if (label.length() > 0) {
+                    label.append(';');
+                }
+                label.append(formatted);
             }
             catch (NumberFormatException nfe) {
                 // do nothing here
             }
         }
 
-        return label;
+        return label.toString();
     }
 
 
@@ -153,34 +161,44 @@
         String        raw
     ) {
         String[] values = raw.split(" ");
-        String   label  = null;
+
+        if (values.length < 1) {
+            return null;
+        }
 
         NumberFormat nf = NumberFormat.getInstance(
             Resources.getLocale(cc.getMeta()));
 
+        Gauge gauge = winfo.getGauge();
+
+        boolean debug = logger.isDebugEnabled();
+
+        StringBuilder label = new StringBuilder();
+
         for (String value: values) {
             try {
-                double v = Double.valueOf(value.trim());
+                double v = Double.parseDouble(value.trim());
 
                 String tmp = nf.format(v);
-                String mv  = FLYSUtils.getNamedMainValue(winfo.getGauge(),v);
+                String mv  = FLYSUtils.getNamedMainValue(gauge, v);
 
                 if (mv != null && mv.length() > 0) {
-                    String add = mv + ": " + tmp;
-                    logger.debug("Add main value: '" + mv + "'");
-                    label = label != null ? label + ";" + add : add;
+                    tmp = mv + ": " + tmp;
+                    if (debug) {
+                        logger.debug("Add main value: '" + mv + "'");
+                    }
                 }
-                else {
-                    logger.debug("Add non main value: '" + tmp + "'");
-                    label = label != null ? label + ";" + tmp : tmp;
+                if (label.length() > 0) {
+                    label.append(';');
                 }
+                label.append(tmp);
             }
             catch (NumberFormatException nfe) {
                 // do nothing here
             }
         }
 
-        return label;
+        return label.toString();
     }
 
 
@@ -221,6 +239,7 @@
         CallContext context)
     {
         double[] minmaxW     = determineMinMaxW(artifact);
+        double[] minmaxWFree = determineMinMaxWFree(artifact);
         double[] minmaxQ     = determineMinMaxQAtGauge(artifact);
         double[] minmaxQFree = determineMinMaxQ(artifact);
 
@@ -237,7 +256,11 @@
                 "minQFree",
                 String.valueOf(minmaxQFree[0])});
 
-            return new Element[] { minW, minQ, minQFree };
+            Element minWFree = createItem(cr, new String[] {
+                "minWFree",
+                String.valueOf(minmaxWFree[0])});
+
+            return new Element[] { minW, minQ, minQFree, minWFree };
         }
         else if (name.equals("wq_to")) {
             Element maxW = createItem(cr, new String[] {
@@ -252,7 +275,11 @@
                 "maxQFree",
                 String.valueOf(minmaxQFree[1])});
 
-            return new Element[] { maxW, maxQ, maxQFree };
+            Element maxWFree = createItem(cr, new String[] {
+                "maxWFree",
+                String.valueOf(minmaxWFree[1])});
+
+            return new Element[] { maxW, maxQ, maxQFree, maxWFree };
         }
         else {
             Element stepW = createItem(
@@ -267,8 +294,12 @@
                 cr, new String[] {
                     "stepQFree",
                     String.valueOf(getStepsQ(minmaxQFree[0], minmaxQFree[1]))});
+            Element stepWFree = createItem(
+                cr, new String[] {
+                    "stepWFree",
+                    String.valueOf(getStepsW(minmaxWFree[0], minmaxWFree[1]))});
 
-            return new Element[] { stepW, stepQ, stepQFree };
+            return new Element[] { stepW, stepQ, stepQFree, stepWFree };
         }
     }
 
@@ -312,14 +343,14 @@
 
 
     protected static double getSteps(double steps, double factor) {
-        int    fac  = (int) steps / 10;
-        double diff = steps - fac * 10;
+        int    fac  = (int) (steps / factor);
+        double diff = steps - fac * factor;
 
         if (diff == 0) {
             return steps;
         }
 
-        return 10d * (fac + 1);
+        return factor * (fac + 1);
     }
 
 
@@ -369,6 +400,40 @@
 
 
     /**
+     * Determines the min and max W value. If no min and
+     * max values could be determined, this method will return
+     * [Double.MIN_VALUE, Double.MAX_VALUE].
+     *
+     * @param artifact The FLYSArtifact.
+     *
+     * @return the min and max W values.
+     */
+    protected double[] determineMinMaxWFree(Artifact artifact) {
+        logger.debug("WQSelect.determineMinMaxWFree");
+
+        WINFOArtifact winfo = (WINFOArtifact) artifact;
+        WstValueTable valueTable = winfo.getWstValueTable();
+
+        double[] minmaxW = null;
+        if(valueTable != null) {
+            double[] km = null;
+            if(winfo.isRange()) {
+                km = winfo.getFromToStep();
+                // Use the start km to determine the min max values.
+                minmaxW = valueTable.getMinMaxW(km[0]);
+            }
+            else {
+                km = winfo.getKms();
+                minmaxW = valueTable.getMinMaxW(km[0]);
+            }
+        }
+        return minmaxW != null
+            ? minmaxW
+            : new double[] { Double.MIN_VALUE, Double.MAX_VALUE };
+    }
+
+
+    /**
      * Determines the min and max Q value for the current gauge. If no min and
      * max values could be determined, this method will return
      * [Double.MIN_VALUE, Double.MAX_VALUE].
@@ -408,20 +473,30 @@
     protected double[] determineMinMaxQ(Artifact artifact) {
         logger.debug("WQSelect.determineMinMaxQ");
 
-        FLYSArtifact flys = (FLYSArtifact) artifact;
-        double[]     kms  = FLYSUtils.getKmRange(flys);
-
-        if (kms == null || kms.length == 0) {
-            return new double[] { Double.MIN_VALUE, Double.MAX_VALUE };
-        }
+        WINFOArtifact winfo = (WINFOArtifact) artifact;
+        WstValueTable valueTable = winfo.getWstValueTable();
 
-        River river = FLYSUtils.getRiver(flys);
-        Wst    wst  = WstFactory.getWst(river);
-
-        logger.debug("User defined KMs: " + kms[0] + " - " + kms[kms.length-1]);
-
-        double[] minmaxQ = wst.determineMinMaxQFree(kms[0]);
-
+        double[] minmaxQ = null;
+        if(valueTable != null) {
+            double[] km = null;
+            if(winfo.isRange()) {
+                km = winfo.getFromToStep();
+                minmaxQ = valueTable.getMinMaxQ(km[0], km[1], km[2]);
+            }
+            else {
+                km = winfo.getKms();
+                minmaxQ = valueTable.getMinMaxQ(km[0]);
+                for (int i = 1; i < km.length; i++) {
+                    double[] tmp = valueTable.getMinMaxQ(km[i]);
+                    if(tmp[0] < minmaxQ[0]) {
+                        minmaxQ[0] = tmp[0];
+                    }
+                    if(tmp[1] > minmaxQ[1]) {
+                        minmaxQ[1] = tmp[1];
+                    }
+                }
+            }
+        }
         return minmaxQ != null
             ? minmaxQ
             : new double[] { Double.MIN_VALUE, Double.MAX_VALUE };
@@ -437,9 +512,13 @@
         WINFOArtifact flys = (WINFOArtifact) artifact;
 
         StateData data       = getData(flys, WQ_SELECTION);
-        String selectionMode = data != null ? (String) data.getValue() : null;
+        boolean isRange = data != null
+            ? Boolean.valueOf((String) data.getValue())
+            : false;
 
-        if (selectionMode == null || selectionMode.equals("single")) {
+
+
+        if (!isRange) {
             return validateSingle(artifact);
         }
         else {
@@ -510,8 +589,11 @@
         else if (mode == FLYSUtils.WQ_MODE.QGAUGE) {
             minmax = determineMinMaxQAtGauge(artifact);
         }
+        else if (mode == FLYSUtils.WQ_MODE.QFREE) {
+            minmax = determineMinMaxQ(artifact);
+        }
         else {
-            minmax = determineMinMaxQ(artifact);
+            minmax = determineMinMaxWFree(artifact);
         }
 
         double min = all.get(0);
@@ -562,6 +644,9 @@
             else if (mode == FLYSUtils.WQ_MODE.QFREE) {
                 return validateFreeQ(artifact, from, to, step);
             }
+            else if (mode == FLYSUtils.WQ_MODE.WFREE) {
+                return validateFreeW(artifact, from, to, step);
+            }
             else {
                 throw new IllegalArgumentException(
                     "error_feed_invalid_wq_mode");
@@ -648,5 +733,32 @@
 
         return validateBounds(minmaxQ[0], minmaxQ[1], from, to, step);
     }
+
+
+    /**
+     * Validates the inserted W values based on the W range for the current
+     * kilometer range.
+     *
+     * @param artifact The owner artifact.
+     * @param from The lower value of the W range.
+     * @param to The upper value of the W range.
+     * @param step The step width.
+     *
+     * @return true, if everything was fine, otherwise an exception is thrown.
+     */
+    protected boolean validateFreeW(
+        Artifact artifact,
+        double   from,
+        double   to,
+        double   step)
+    throws IllegalArgumentException
+    {
+        logger.debug("WQSelect.validateFreeW");
+
+        double[] minmaxW = determineMinMaxWFree(artifact);
+
+        return validateBounds(minmaxW[0], minmaxW[1], from, to, step);
+    }
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelInfoState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -17,7 +17,6 @@
 import de.intevation.flys.artifacts.model.WQKms;
 
 import de.intevation.flys.artifacts.model.DataFacet;
-import de.intevation.flys.artifacts.model.CrossSectionFacet;
 import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet;
 import de.intevation.flys.artifacts.model.CalculationResult;
 
@@ -36,6 +35,7 @@
     }
 
 
+    @Override
     public Object computeInit(
         FLYSArtifact artifact,
         String       hash,
@@ -105,12 +105,6 @@
             facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id));
         }
 
-        // Also register the CrossSectionFacets (added to respective out).
-        int idx = 0;
-        for (String name: winfo.getCrossSectionNames()) {
-            facets.add(new CrossSectionFacet(idx++, name));
-        }
-
         // TODO Adjust to WaterlevelState - implementation.
         facets.add(new CrossSectionWaterLineFacet(0, "Q=" + winfo.getDataAsString("wq_single")));
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelPairSelectState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -124,7 +124,7 @@
 
     /**
      * Get name to display for selected watelerlevels (for example "Q=123")
-     * from the CalculationResult. 
+     * from the CalculationResult.
      */
     public static String[] getLabels(CallContext cc, String value) {
         String[] recommendations = value.split("#");
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelSelectState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -49,6 +49,7 @@
     public StateData transform(
         FLYSArtifact flys,
         CallContext  cc,
+        StateData    stateData,
         String       name,
         String       val
     ) {
@@ -108,7 +109,7 @@
 
     /**
      * Get name to display for selected watelerlevel (for example "Q=123")
-     * from the CalculationResult. 
+     * from the CalculationResult.
      */
     public static String[] getLabels(CallContext cc, String value) {
         String[] parts = value.split(SPLIT_CHAR);
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WaterlevelState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,22 +4,21 @@
 
 import org.apache.log4j.Logger;
 
+import de.intevation.artifactdatabase.state.Facet;
 import de.intevation.artifacts.CallContext;
-
-import de.intevation.artifactdatabase.state.Facet;
-
+import de.intevation.flys.artifacts.ChartArtifact;
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet;
 import de.intevation.flys.artifacts.model.DataFacet;
-import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet;
-import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.EmptyFacet;
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.ReportFacet;
-import de.intevation.flys.artifacts.model.WaterlevelFacet;
 import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.WaterlevelFacet;
 import de.intevation.flys.utils.FLYSUtils;
 
-
 public class WaterlevelState
 extends      DefaultState
 implements   FacetTypes
@@ -37,6 +36,10 @@
     }
 
 
+    /**
+     * Compute result or returned object from cache, create facets.
+     * @param old Object that was cached.
+     */
     protected Object compute(
         WINFOArtifact winfo,
         CallContext   cc,
@@ -47,30 +50,41 @@
         String id = getID();
 
         CalculationResult res = old instanceof CalculationResult
-            ? (CalculationResult)old
+            ? (CalculationResult) old
             : winfo.getWaterlevelData();
 
         if (facets == null) {
             return res;
         }
 
-        WQKms [] wqkms = (WQKms [])res.getData();
+        boolean debug = logger.isDebugEnabled();
+
+        WQKms [] wqkms = (WQKms []) res.getData();
 
         for (int i = 0; i < wqkms.length; i++) {
-            String  name = wqkms[i].getName();
+            String name = wqkms[i].getName();
 
             String nameW = FLYSUtils.createWspWTitle(winfo, cc, name);
             String nameQ = FLYSUtils.createWspQTitle(winfo, cc, name);
 
-            logger.debug("Create facet: " + nameW);
-            logger.debug("Create facet: " + nameQ);
+            // Hotfix for theme names. Themes with the same name cause problems
+            // aggregating chart legend items.
+            if (i > 0 && name.equals(wqkms[i - 1].getName())) {
+                nameW += "; Q=" + wqkms[i].get(0, new double[3])[1];
+                nameQ += " = " + wqkms[i].get(0, new double[3])[1];
+            }
+
+            if (debug) {
+                logger.debug("Create facet: " + nameW);
+                logger.debug("Create facet: " + nameQ);
+            }
 
             Facet w = new WaterlevelFacet(
                 i, LONGITUDINAL_W, nameW, ComputeType.ADVANCE, id, hash);
             Facet q = new WaterlevelFacet(
                 i, LONGITUDINAL_Q, nameQ, ComputeType.ADVANCE, id, hash);
 
-            facets.add(new CrossSectionWaterLineFacet(i, nameQ));
+            facets.add(new CrossSectionWaterLineFacet(i, nameW));
 
             facets.add(w);
             facets.add(q);
@@ -81,9 +95,12 @@
                 WST, "WST data", ComputeType.ADVANCE, hash, id);
             Facet csv = new DataFacet(
                 CSV, "CSV data", ComputeType.ADVANCE, hash, id);
+            Facet pdf = new DataFacet(
+                PDF, "PDF data", ComputeType.ADVANCE, hash, id);
 
             facets.add(wst);
             facets.add(csv);
+            facets.add(pdf);
         }
 
         if (res.getReport().hasProblems()) {
@@ -105,6 +122,10 @@
         List<Facet>  facets,
         Object       old
     ) {
+        if (artifact instanceof ChartArtifact) {
+            facets.add(new EmptyFacet());
+            return null;
+        }
         return compute((WINFOArtifact) artifact, context, hash, facets, old);
     }
 
@@ -120,6 +141,10 @@
         List<Facet>  facets,
         Object       old
     ) {
+        if (artifact instanceof ChartArtifact) {
+            facets.add(new EmptyFacet());
+            return null;
+        }
         return compute((WINFOArtifact) artifact, context, hash, facets, old);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/extreme/ExtremeCompute.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,65 @@
+package de.intevation.flys.artifacts.states.extreme;
+
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.access.ExtremeAccess;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.ReportFacet;
+
+import de.intevation.flys.artifacts.model.extreme.ExtremeCalculation;
+
+import de.intevation.flys.artifacts.states.DefaultState;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+public class ExtremeCompute
+extends      DefaultState
+{
+    private static Logger log = Logger.getLogger(ExtremeCompute.class);
+
+    public ExtremeCompute() {
+    }
+
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        log.debug("ExtremeCompute.computeAdvance");
+
+        CalculationResult res;
+
+        ExtremeAccess access = new ExtremeAccess(artifact);
+
+        if (old instanceof CalculationResult) {
+            res = (CalculationResult)old;
+        }
+        else {
+            ExtremeCalculation calc = new ExtremeCalculation(access);
+            res = calc.calculate();
+        }
+
+        if (facets == null) {
+            return res;
+        }
+
+        if (res.getReport().hasProblems()) {
+            facets.add(new ReportFacet());
+        }
+
+        // TODO: Add more facets.
+
+        return res;
+    }
+}
+// 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/fixation/AnalysisPeriods.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,28 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+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 AnalysisPeriods extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(AnalysisPeriods.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public AnalysisPeriods() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return "fix.period_ana_panel";
+    }
+
+}
+// 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/fixation/EventSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,97 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.states.DefaultState;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.utils.FLYSUtils;
+
+import de.intevation.flys.artifacts.model.FixingsOverview;
+import de.intevation.flys.artifacts.model.FixingsOverviewFactory;
+import de.intevation.flys.artifacts.model.FixingsOverview.IdFilter;
+import de.intevation.flys.artifacts.model.FixingsOverview.Fixing;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class EventSelect extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(EventSelect.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public EventSelect() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return "fix.event_panel";
+    }
+
+    @Override
+    protected Element createStaticData(
+        FLYSArtifact   flys,
+        ElementCreator creator,
+        CallContext    cc,
+        String         name,
+        String         value,
+        String         type
+    ) {
+        int[] array = FLYSUtils.intArrayFromString(value);
+
+        Element dataElement = creator.create("data");
+        creator.addAttr(dataElement, "name", name, true);
+        creator.addAttr(dataElement, "type", type, true);
+
+        String river = FLYSUtils.getRiver(flys).getName();
+
+        FixingsOverview overview = FixingsOverviewFactory.getOverview(river);
+
+        for (int i = 0; i < array.length; i++) {
+            Element itemElement = creator.create("item");
+            creator.addAttr(
+                itemElement,
+                "value",
+                String.valueOf(array[i]),
+                true);
+
+            creator.addAttr(
+                itemElement,
+                "label",
+                getLabel(cc, array[i], overview),
+                true);
+            dataElement.appendChild(itemElement);
+        }
+        return dataElement;
+    }
+
+
+    public static String getLabel(
+        CallContext cc,
+        int value,
+        FixingsOverview overview
+    ) {
+        logger.debug("Create label for value: " + value);
+
+        IdFilter filter = new IdFilter(value);
+        List<Fixing.Column> columns = overview.filter(null, filter);
+        if (!columns.isEmpty()) {
+        return columns.get(0).getDescription();
+        }
+
+        return "";
+    }
+}
+// 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/fixation/FixAnalysisCompute.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,319 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.DateRange;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.ReportFacet;
+import de.intevation.flys.artifacts.model.fixings.FixAnalysisCalculation;
+import de.intevation.flys.artifacts.model.fixings.FixAnalysisEventsFacet;
+import de.intevation.flys.artifacts.model.fixings.FixAnalysisPeriodsFacet;
+import de.intevation.flys.artifacts.model.fixings.FixAnalysisResult;
+import de.intevation.flys.artifacts.model.fixings.FixAvSectorFacet;
+import de.intevation.flys.artifacts.model.fixings.FixDerivateFacet;
+import de.intevation.flys.artifacts.model.fixings.FixDeviationFacet;
+import de.intevation.flys.artifacts.model.fixings.FixLongitudinalAnalysisFacet;
+import de.intevation.flys.artifacts.model.fixings.FixLongitudinalAvSectorFacet;
+import de.intevation.flys.artifacts.model.fixings.FixLongitudinalDeviationFacet;
+import de.intevation.flys.artifacts.model.fixings.FixLongitudinalReferenceFacet;
+import de.intevation.flys.artifacts.model.fixings.FixOutlierFacet;
+import de.intevation.flys.artifacts.model.fixings.FixReferenceEventsFacet;
+import de.intevation.flys.artifacts.model.fixings.FixWQCurveFacet;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.artifacts.states.DefaultState;
+import de.intevation.flys.utils.IdGenerator;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixAnalysisCompute
+extends      DefaultState
+implements   FacetTypes
+{
+    /** The log used in this class. */
+    private static Logger log = Logger.getLogger(FixAnalysisCompute.class);
+
+    private static final String I18N_REFERENCEPERIOD_SHORT = "fix.reference.period.event.short";
+
+    private static final String I18N_ANALYSISPERIODS = "fix.analysis.periods";
+
+    private static final String I18N_DERIVATIVE = "fix.derivative";
+
+    private static final String I18N_OUTLIER = "fix.outlier";
+
+    private static final String I18N_ANALYSIS = "fix.analysis.short";
+
+    private static final String I18N_DEVIATION = "fix.deviation";
+
+    private static final String I18N_REFERENCEDEVIATION = "fix.reference.deviation";
+
+    private static final String I18N_REFERENCEPERIOD = "state.fix.analysis.referenceperiod";
+
+    public static final String [] SECTOR_LABELS = {
+        "[0 - (MNQ+MQ)/2)",
+        "[(MNQ+MQ)/2 - (MQ+MHQ)/2)",
+        "[(MQ+MHQ)/2 - HQ5)",
+        "[HQ5 - \u221e)"
+    };
+
+    static {
+        // Active/deactivate facets.
+        FacetActivity.Registry.getInstance().register(
+            "fixanalysis",
+            new FacetActivity() {
+                @Override
+                public Boolean isInitialActive(
+                    Artifact artifact,
+                    Facet    facet,
+                    String   output
+                ) {
+                    if (output.contains(FacetTypes.ChartType.FLSC.toString())) { // Longitudinal section chart
+                        String name = facet.getName();
+
+                        if (name.contains(FacetTypes.FIX_ANALYSIS_EVENTS_DWT)
+                         || name.contains(FacetTypes.FIX_ANALYSIS_EVENTS_LS)
+                         || name.contains(FacetTypes.FIX_ANALYSIS_EVENTS_WQ)
+                         || name.contains(FacetTypes.FIX_REFERENCE_EVENTS_DWT)
+                         || name.contains(FacetTypes.FIX_REFERENCE_EVENTS_LS)
+                         || name.contains(FacetTypes.FIX_REFERENCE_EVENTS_WQ)
+                        ) {
+                            return Boolean.FALSE;
+                        }
+                    }
+
+                    return Boolean.TRUE;
+                }
+            });
+    }
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public FixAnalysisCompute() {
+    }
+
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        log.debug("FixAnalysisCompute.computeAdvance");
+
+        CalculationResult res;
+
+        FixAnalysisAccess access =
+            new FixAnalysisAccess(artifact);
+
+        if (old instanceof CalculationResult) {
+            res = (CalculationResult)old;
+        }
+        else {
+            FixAnalysisCalculation calc = new FixAnalysisCalculation(access);
+            res = calc.calculate();
+        }
+
+        if (facets == null) {
+            return res;
+        }
+
+        if (res.getReport().hasProblems()) {
+            facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id));
+        }
+
+        FixAnalysisResult fr = (FixAnalysisResult)res.getData();
+        if (fr == null) {
+            return res;
+        }
+
+        facets.add(
+            new DataFacet(CSV, "CSV data", ComputeType.ADVANCE, hash, id));
+        facets.add(
+            new DataFacet(
+                FIX_PARAMETERS, "parameters", ComputeType.ADVANCE, hash, id));
+        facets.add(
+            new DataFacet(AT, "AT data", ComputeType.ADVANCE, hash, id));
+
+        int maxId = -100;
+
+        int sectorMask = fr.getUsedSectorsInAnalysisPeriods();
+
+        int qsS = access.getQSectorStart();
+        int qsE = access.getQSectorEnd();
+
+        // TODO: i18n
+        DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
+
+        DateRange [] periods = access.getAnalysisPeriods();
+
+        for (int i = 0; i < periods.length; i++) {
+            DateRange period = periods[i];
+            String startDate = df.format(period.getFrom());
+            String endDate = df.format(period.getTo());
+
+            for (int j = qsS; j <= qsE; j++) {
+
+                // Only emit facets for sectors that really have data.
+                if ((sectorMask & (1 << j)) == 0) {
+                    continue;
+                }
+
+                String sector = SECTOR_LABELS[j];
+                String description = sector + ": " +
+                                     startDate + " - " +
+                                     endDate;
+
+                int sectorNdx = j - qsS;
+                int facetNdx = i << 2;
+                facetNdx = facetNdx | j;
+
+                if (facetNdx > maxId) {
+                    maxId = facetNdx;
+                }
+
+                facets.add(
+                    new FixAvSectorFacet(
+                        facetNdx,
+                        FIX_SECTOR_AVERAGE_DWT + "_" + sectorNdx,
+                        description));
+                facets.add(
+                    new FixLongitudinalAvSectorFacet(
+                        facetNdx,
+                        FIX_SECTOR_AVERAGE_LS + "_" + sectorNdx,
+                        description));
+                // TODO: i18n
+                String dev = "Abweichung: " + description;
+                facets.add(
+                    new FixLongitudinalAvSectorFacet(
+                        facetNdx,
+                        FIX_SECTOR_AVERAGE_LS_DEVIATION + "_" + sectorNdx,
+                        dev));
+                facets.add(
+                    new FixAvSectorFacet(
+                        facetNdx,
+                        FIX_SECTOR_AVERAGE_WQ + "_" + sectorNdx,
+                        description));
+
+            }
+
+            String eventDesc =
+                Resources.getMsg(context.getMeta(),
+                                 I18N_ANALYSIS,
+                                 I18N_ANALYSIS);
+
+            int k = 0;
+            for (Date d: fr.getAnalysisEventsDates(i)) {
+                int anaNdx = i << 8;
+                anaNdx = anaNdx | k;
+                facets.add(new FixAnalysisEventsFacet(anaNdx,
+                    FIX_ANALYSIS_EVENTS_DWT,
+                    eventDesc + (i+1) + " - " + df.format(d)));
+                facets.add(new FixLongitudinalAnalysisFacet(anaNdx,
+                    FIX_ANALYSIS_EVENTS_LS,
+                    eventDesc + (i+1) + " - " + df.format(d)));
+                facets.add(new FixAnalysisEventsFacet(anaNdx,
+                    FIX_ANALYSIS_EVENTS_WQ,
+                    eventDesc + (i+1) +" - " + df.format(d)));
+                k++;
+            }
+        }
+
+        IdGenerator idg = new IdGenerator(maxId + 1);
+
+        String i18n_ref = Resources.getMsg(context.getMeta(),
+                I18N_REFERENCEPERIOD_SHORT,
+                I18N_REFERENCEPERIOD_SHORT);
+        String i18n_dev = Resources.getMsg(context.getMeta(),
+                I18N_REFERENCEDEVIATION,
+                I18N_REFERENCEDEVIATION);
+
+        int i = 0;
+        for (Date d: fr.getReferenceEventsDates()) {
+            int refNdx = idg.next() << 8;
+            refNdx |=  i;
+            facets.add(new FixReferenceEventsFacet(refNdx,
+                FIX_REFERENCE_EVENTS_DWT,
+                i18n_ref + " - " + df.format(d)));
+            refNdx = idg.next() << 8;
+            refNdx = refNdx | i;
+            facets.add(new FixLongitudinalReferenceFacet(refNdx,
+                FIX_REFERENCE_EVENTS_LS,
+                i18n_ref + " - " + df.format(d)));
+            refNdx = idg.next() << 8;
+            refNdx |= i;
+            facets.add(new FixReferenceEventsFacet(refNdx,
+                FIX_REFERENCE_EVENTS_WQ,
+                i18n_ref + " - " + df.format(d)));
+            i++;
+        }
+
+
+        facets.add(new FixLongitudinalDeviationFacet(idg.next(),
+            FIX_DEVIATION_LS,
+            i18n_dev));
+
+        String i18n_ana = Resources.getMsg(context.getMeta(),
+                I18N_ANALYSISPERIODS,
+                I18N_ANALYSISPERIODS);
+        facets.add(new FixAnalysisPeriodsFacet(idg.next(),
+            FIX_ANALYSIS_PERIODS_DWT,
+            i18n_ana));
+        facets.add(new FixAnalysisPeriodsFacet(idg.next(),
+            FIX_ANALYSIS_PERIODS_LS,
+            i18n_ana));
+        facets.add(new FixAnalysisPeriodsFacet(idg.next(),
+            FIX_ANALYSIS_PERIODS_WQ,
+            i18n_ana));
+
+        String i18n_refp = Resources.getMsg(context.getMeta(),
+                I18N_REFERENCEPERIOD,
+                I18N_REFERENCEPERIOD);
+        facets.add(new DataFacet(idg.next(),
+            FIX_REFERENCE_PERIOD_DWT,
+            i18n_refp,
+            ComputeType.ADVANCE, null, null));
+
+        facets.add(new FixWQCurveFacet(idg.next(), "W/Q"));
+
+        Boolean preprocessing = access.getPreprocessing();
+
+        if (preprocessing != null && preprocessing) {
+            facets.add(new FixOutlierFacet(
+                idg.next(),
+                FIX_OUTLIER,
+                Resources.getMsg(
+                    context.getMeta(), I18N_OUTLIER, I18N_OUTLIER)));
+        }
+
+        facets.add(new FixDerivateFacet(
+            idg.next(),
+            FIX_DERIVATE_CURVE,
+            Resources.getMsg(
+                context.getMeta(),
+                I18N_DERIVATIVE,
+                I18N_DERIVATIVE)));
+
+        facets.add(new FixDeviationFacet(
+            idg.next(),
+            FIX_DEVIATION_DWT,
+            Resources.getMsg(context.getMeta(),
+                I18N_DEVIATION,
+                I18N_DEVIATION)));
+        return res;
+    }
+}
+// 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/fixation/FixRealizingCompute.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,147 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.FixRealizingAccess;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.ReportFacet;
+import de.intevation.flys.artifacts.model.WQCKms;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.fixings.FixOutlierFacet;
+import de.intevation.flys.artifacts.model.fixings.FixRealizingCalculation;
+import de.intevation.flys.artifacts.model.fixings.FixRealizingResult;
+import de.intevation.flys.artifacts.model.fixings.FixReferenceEventsFacet;
+import de.intevation.flys.artifacts.model.fixings.FixWQCurveFacet;
+import de.intevation.flys.artifacts.model.fixings.FixWaterlevelFacet;
+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 FixRealizingCompute extends DefaultState implements FacetTypes {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(FixRealizingCompute.class);
+
+
+    public static final String I18N_WQ_CURVE = "fix.vollmer.wq.curve";
+
+    public static final String I18N_WQ_OUTLIER = "fix.vollmer.wq.outliers";
+
+    public static final String I18N_WQ_EVENTS = "fix.vollmer.wq.events";
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public FixRealizingCompute() {
+    }
+
+    @Override
+    public Object computeAdvance(
+        FLYSArtifact artifact,
+        String       hash,
+        CallContext  context,
+        List<Facet>  facets,
+        Object       old
+    ) {
+        logger.debug("FixRealizingCompute.computeAdvance");
+
+        CalculationResult res;
+
+        FixRealizingAccess access =
+            new FixRealizingAccess(artifact);
+
+        if (old instanceof CalculationResult) {
+            res = (CalculationResult)old;
+        }
+        else {
+            FixRealizingCalculation calc = new FixRealizingCalculation(access);
+            res = calc.calculate();
+        }
+
+        if (facets == null) {
+            return res;
+        }
+
+        if (res.getReport().hasProblems()) {
+            facets.add(new ReportFacet());
+        }
+
+        String   id   = getID();
+        CallMeta meta = context.getMeta();
+
+        FixRealizingResult fixRes = (FixRealizingResult) res.getData();
+        WQKms [] wqkms = fixRes != null ? fixRes.getWQKms() : new WQKms[0];
+
+        for (int i = 0; i < wqkms.length; i++) {
+            String nameW = null;
+            String nameQ = null;
+
+            if (access.isQ()) {
+                nameQ = wqkms[i].getName();
+                nameW = "W(" + nameQ + ")";
+            }
+            else {
+                nameW = wqkms[i].getName();
+                nameQ = "Q(" + nameW + ")";
+            }
+
+            Facet w = new FixWaterlevelFacet(
+                i, LONGITUDINAL_W, nameW);
+
+            Facet q = new FixWaterlevelFacet(
+                i, LONGITUDINAL_Q, nameQ);
+
+            facets.add(w);
+            facets.add(q);
+
+            if (wqkms[i] instanceof WQCKms) {
+                String nameC = nameW.replace(
+                    "benutzerdefiniert",
+                    "benutzerdefiniert [korrigiert]");
+
+                Facet c = new FixWaterlevelFacet(
+                    i, DISCHARGE_LONGITUDINAL_C, nameC);
+
+                facets.add(c);
+            }
+        }
+
+        if (wqkms.length > 0) {
+            facets.add(
+                new DataFacet(CSV, "CSV data", ComputeType.ADVANCE, hash, id));
+
+            facets.add(
+                new DataFacet(WST, "WST data", ComputeType.ADVANCE, hash, id));
+
+            facets.add(
+                new DataFacet(PDF, "PDF data", ComputeType.ADVANCE, hash, id));
+        }
+
+        facets.add(new FixWQCurveFacet(
+            0, Resources.getMsg(meta, I18N_WQ_CURVE, I18N_WQ_CURVE)));
+
+        facets.add(new FixReferenceEventsFacet(
+            0,
+            FIX_REFERENCE_EVENTS_WQ,
+            Resources.getMsg(meta, I18N_WQ_EVENTS, I18N_WQ_EVENTS)));
+
+        facets.add(new FixOutlierFacet(
+            0,
+            FIX_OUTLIER,
+            Resources.getMsg(meta, I18N_WQ_OUTLIER, I18N_WQ_OUTLIER)));
+
+        return res;
+    }
+}
+// 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/fixation/FixationPeriod.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,28 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+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 FixationPeriod extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(FixationPeriod.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public FixationPeriod() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return "fix.period_panel";
+    }
+
+}
+// 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/fixation/FixationSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,74 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+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 FixationSelect extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(FixationSelect.class);
+
+
+    /** Constant value for the default fixation calculation. */
+    public static final String CALCULATION_DEFAULT = "calculation.analysis";
+
+    /** Constant value for the vollmer fixation analysis. */
+    public static final String CALCULATION_VOLLMER = "calculation.vollmer";
+
+    /** An Array that holds all available calculation modes.*/
+    public static final String[] CALCULATIONS = {
+        CALCULATION_DEFAULT,
+        CALCULATION_VOLLMER
+    };
+
+    /** Error message that is thrown if no mode has been chosen. */
+    public static final String ERROR_NO_CALCULATION_MODE =
+        "error_feed_no_calculation_mode";
+
+    /** Error message that is thrown if an invalid calculation mode has been
+     * chosen. */
+    public static  final String ERROR_INVALID_CALCULATION_MODE =
+        "error_feed_invalid_calculation_mode";
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public FixationSelect() {
+    }
+
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator ec,
+        Artifact                artifact,
+        String                  name,
+        CallContext             context)
+    {
+        CallMeta meta = context.getMeta();
+        Element[] calculations = new Element[CALCULATIONS.length];
+
+        for (int i = 0; i < CALCULATIONS.length; i++) {
+            String calc = CALCULATIONS[i];
+            calculations[i] = createItem(
+                ec,
+                new String[] {Resources.getMsg(meta, calc, calc), calc});
+        }
+        return calculations;
+    }
+}
+// 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/fixation/FunctionSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,61 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Element;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.flys.artifacts.math.fitting.Function;
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+import de.intevation.flys.artifacts.states.DefaultState;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FunctionSelect extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(FunctionSelect.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public FunctionSelect() {
+    }
+
+    @Override
+    public String getUIProvider() {
+        return "fix.functionselect";
+    }
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator ec,
+        Artifact                artifact,
+        String                  name,
+        CallContext             context)
+    {
+        FunctionFactory ff = FunctionFactory.getInstance();
+        Collection<Function> fc = ff.getFunctions();
+        Element[] functions = new Element[fc.size()];
+        Iterator<Function> i = fc.iterator();
+
+        int j = 0;
+        while(i.hasNext()) {
+            Function f = i.next();
+            String n = f.getName();
+            String d = f.getDescription();
+            functions[j] = createItem(ec, new String[] {d, n});
+            j++;
+        }
+
+        return functions;
+    }
+
+}
+// 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/fixation/GaugeRange.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,28 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+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 GaugeRange extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(GaugeRange.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public GaugeRange() {
+    }
+
+
+    @Override
+    protected String getUIProvider() {
+        return "fix.gaugeselect_panel";
+    }
+}
+// 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/fixation/LocationSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,72 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.states.RangeState;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class LocationSelect extends RangeState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(LocationSelect.class);
+
+    private static final String LOWER = "from";
+
+    private static final String UPPER = "to";
+
+    private static final String STEP = "step";
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public LocationSelect() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return "fix.location_panel";
+    }
+
+    @Override
+    protected double[] getMinMax(Artifact artifact) {
+        FLYSArtifact flysArtifact = (FLYSArtifact) artifact;
+        return FLYSUtils.getRiverMinMax(flysArtifact);
+    }
+
+    @Override
+    protected String getLowerField() {
+        return LOWER;
+    }
+
+    @Override
+    protected String getUpperField() {
+        return UPPER;
+    }
+
+    @Override
+    protected String getStepField() {
+        return STEP;
+    }
+
+
+    /** Misuse to set location mode. */
+    @Override
+    public boolean validate(Artifact artifact)
+    throws IllegalArgumentException
+    {
+        ((FLYSArtifact) artifact).addStringData("ld_mode", "distance");
+        return super.validate(artifact);
+    }
+
+
+}
+// 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/fixation/PreprocessingSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,58 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+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 PreprocessingSelect extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(PreprocessingSelect.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public PreprocessingSelect() {
+    }
+
+    @Override
+    protected Element[] createItems(
+        XMLUtils.ElementCreator ec,
+        Artifact                artifact,
+        String                  name,
+        CallContext             context)
+    {
+        CallMeta meta = context.getMeta();
+        Element[] elements = new Element[1];
+        elements[0] = createItem(
+                ec,
+                new String[] {
+                    Resources.getMsg(meta,
+                        "state.fix.preprocess",
+                        "state.fix.preprocess"),
+                    "preprocess"});
+
+        return elements;
+    }
+
+
+    @Override
+    protected String getUIProvider() {
+        return "fix.preprocessing_panel";
+    }
+}
+// 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/fixation/QSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,29 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+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 QSelect extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(QSelect.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public QSelect() {
+    }
+
+
+    /** Show Q Select Panel in clients. */
+    @Override
+    protected String getUIProvider() {
+        return "fix.qselect_panel";
+    }
+}
+// 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/fixation/ReferencePeriod.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,28 @@
+package de.intevation.flys.artifacts.states.fixation;
+
+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 ReferencePeriod extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(ReferencePeriod.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public ReferencePeriod() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return "fix.period_ref_panel";
+    }
+
+}
+// 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/BedQualityPeriodsSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,24 @@
+package de.intevation.flys.artifacts.states.minfo;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.artifacts.states.DefaultState;
+
+public class BedQualityPeriodsSelect extends DefaultState {
+
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(BedQualityPeriodsSelect.class);
+
+
+    /**
+     * The default constructor that initializes an empty State object.
+     */
+    public BedQualityPeriodsSelect() {
+    }
+
+    @Override
+    protected String getUIProvider() {
+        return "bedquality_periods_select";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/BedQualityState.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,227 @@
+package de.intevation.flys.artifacts.states.minfo;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.BedQualityAccess;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.DataFacet;
+import de.intevation.flys.artifacts.model.DateRange;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.minfo.BedDensityFacet;
+import de.intevation.flys.artifacts.model.minfo.BedDiameterFacet;
+import de.intevation.flys.artifacts.model.minfo.BedDiameterResult;
+import de.intevation.flys.artifacts.model.minfo.BedParametersResult;
+import de.intevation.flys.artifacts.model.minfo.BedPorosityFacet;
+import de.intevation.flys.artifacts.model.minfo.BedQualityCalculation;
+import de.intevation.flys.artifacts.model.minfo.BedQualityDiameterResult;
+import de.intevation.flys.artifacts.model.minfo.BedQualityResult;
+import de.intevation.flys.artifacts.model.minfo.BedloadDiameterFacet;
+import de.intevation.flys.artifacts.model.minfo.BedloadDiameterResult;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.artifacts.states.DefaultState;
+
+
+public class BedQualityState extends DefaultState implements FacetTypes {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final Logger logger = Logger
+        .getLogger(BedQualityState.class);
+
+    public static final String I18N_TOPLAYER = "bedquality.toplayer";
+    public static final String I18N_SUBLAYER = "bedquality.sublayer";
+
+    public static final String I18N_FACET_BED_POROSITY_TOPLAYER = "facet.bedquality.bed.porosity.toplayer";
+    public static final String I18N_FACET_BED_POROSITY_SUBLAYER = "facet.bedquality.bed.porosity.sublayer";
+    public static final String I18N_FACET_BED_DENSITY_TOPLAYER = "facet.bedquality.bed.density.toplayer";
+    public static final String I18N_FACET_BED_DENSITY_SUBLAYER = "facet.bedquality.bed.density.sublayer";
+    public static final String I18N_FACET_BED_DIAMETER_TOPLAYER = "facet.bedquality.bed.diameter.toplayer";
+    public static final String I18N_FACET_BED_DIAMETER_SUBLAYER = "facet.bedquality.bed.diameter.sublayer";
+    public static final String I18N_FACET_BEDLOAD_DIAMETER = "facet.bedquality.bedload.diameter";
+
+    @Override
+    public Object computeAdvance(FLYSArtifact artifact, String hash,
+        CallContext context, List<Facet> facets, Object old) {
+        logger.debug("BedQualityState.computeAdvance");
+
+        List<Facet> newFacets = new ArrayList<Facet>();
+
+        BedQualityAccess access = new BedQualityAccess(artifact);
+
+        CalculationResult res = old instanceof CalculationResult ? (CalculationResult) old
+            : new BedQualityCalculation().calculate(access);
+
+        if (facets == null || res == null) {
+            return res;
+        }
+
+        BedQualityResult[] results = (BedQualityResult[]) res.getData();
+
+        if (results == null || results.length == 0) {
+            logger.warn("Calculation computed no results!");
+            return res;
+        }
+
+        generateFacets(context, newFacets, results, getID(), hash);
+        logger.debug("Created " + newFacets.size() + " new Facets.");
+
+        facets.addAll(newFacets);
+
+        return res;
+    }
+
+    protected void generateFacets(CallContext context, List<Facet> newFacets,
+        BedQualityResult[] results, String stateId, String hash) {
+        logger.debug("BedQualityState.generateFacets");
+
+        CallMeta meta = context.getMeta();
+
+        newFacets.add(new DataFacet(CSV, "CSV data", ComputeType.ADVANCE, hash, id));
+        for (int idx = 0; idx < results.length; idx++) {
+            BedQualityResult result = results[idx];
+            DateRange range = result.getDateRange();
+            BedDiameterResult[] bedDiameter = result.getBedResults();
+            for (int j = 0; j < bedDiameter.length; j++) {
+                newFacets.add(new BedDiameterFacet((idx << 8) + j,
+                    BED_QUALITY_BED_DIAMETER_TOPLAYER,
+                    createDiameterTopLayerDescription(
+                        meta,
+                        bedDiameter[j],
+                        range),
+                    ComputeType.ADVANCE, stateId, hash));
+
+                newFacets.add(new BedDiameterFacet((idx << 8) +j,
+                    BED_QUALITY_BED_DIAMETER_SUBLAYER,
+                    createDiameterSubLayerDescription(
+                        meta,
+                        bedDiameter[j],
+                        range),
+                    ComputeType.ADVANCE, stateId, hash));
+            }
+            BedloadDiameterResult[] bedloadDiameter = result.getBedloadResults();
+            for (int j = 0;  j < bedloadDiameter.length; j++) {
+                newFacets.add(new BedloadDiameterFacet(
+                    (idx << 8) + j,
+                    BED_QUALITY_BEDLOAD_DIAMETER,
+                    createDiameterDescription(
+                        meta, bedloadDiameter[j]),
+                    ComputeType.ADVANCE,
+                    stateId,
+                    hash));
+
+            }
+            BedParametersResult[] bedParameters = result.getParameters();
+            for (int j = 0; j < bedParameters.length; j++) {
+                newFacets.add(new BedPorosityFacet((idx << 8) + j,
+                    BED_QUALITY_POROSITY_TOPLAYER,
+                    createPorosityTopLayerDescription(
+                        meta,
+                        bedParameters[j],
+                        range),
+                    ComputeType.ADVANCE, stateId, hash));
+
+                newFacets.add(new BedPorosityFacet((idx << 8) + j,
+                    BED_QUALITY_POROSITY_SUBLAYER,
+                    createPorositySubLayerDescription(
+                        meta,
+                        bedParameters[j],
+                        range),
+                    ComputeType.ADVANCE, stateId, hash));
+
+                newFacets.add(new BedDensityFacet((idx << 8) + j,
+                    BED_QUALITY_SEDIMENT_DENSITY_TOPLAYER,
+                    createDensityTopLayerDescription(
+                        meta,
+                        bedParameters[j],
+                        range),
+                    ComputeType.ADVANCE, stateId, hash));
+
+                newFacets.add(new BedDensityFacet((idx << 8) + j,
+                    BED_QUALITY_SEDIMENT_DENSITY_SUBLAYER,
+                    createDensitySubLayerDescription(
+                        meta,
+                        bedParameters[j],
+                        range),
+                    ComputeType.ADVANCE, stateId, hash));
+            }
+        }
+    }
+
+    protected String createPorosityTopLayerDescription(CallMeta meta,
+        BedParametersResult result, DateRange range) {
+        Date from = range != null ? range.getFrom() : new Date();
+        Date to = range != null ? range.getTo() : new Date();
+
+        String toplayer = Resources.getMsg(meta, I18N_TOPLAYER, I18N_TOPLAYER);
+        return Resources.getMsg(meta, I18N_FACET_BED_POROSITY_TOPLAYER,
+            I18N_FACET_BED_POROSITY_TOPLAYER, new Object[] { from, to, toplayer });
+    }
+
+    protected String createPorositySubLayerDescription(CallMeta meta,
+        BedParametersResult result, DateRange range) {
+        Date from = range != null ? range.getFrom() : new Date();
+        Date to = range != null ? range.getTo() : new Date();
+
+        String sublayer = Resources.getMsg(meta, I18N_SUBLAYER, I18N_SUBLAYER);
+        return Resources.getMsg(meta, I18N_FACET_BED_POROSITY_SUBLAYER,
+            I18N_FACET_BED_POROSITY_SUBLAYER, new Object[] { from, to, sublayer });
+    }
+
+    protected String createDensityTopLayerDescription(CallMeta meta,
+        BedParametersResult result, DateRange range) {
+        Date from = range != null ? range.getFrom() : new Date();
+        Date to = range != null ? range.getTo() : new Date();
+
+        String toplayer = Resources.getMsg(meta, I18N_TOPLAYER, I18N_TOPLAYER);
+        return Resources.getMsg(meta, I18N_FACET_BED_DENSITY_TOPLAYER,
+            I18N_FACET_BED_DENSITY_TOPLAYER, new Object[] { from, to, toplayer });
+    }
+
+    protected String createDensitySubLayerDescription(CallMeta meta,
+        BedParametersResult result, DateRange range) {
+        Date from = range != null ? range.getFrom() : new Date();
+        Date to = range != null ? range.getTo() : new Date();
+
+        String sublayer = Resources.getMsg(meta, I18N_SUBLAYER, I18N_SUBLAYER);
+        return Resources.getMsg(meta, I18N_FACET_BED_DENSITY_SUBLAYER,
+            I18N_FACET_BED_DENSITY_SUBLAYER, new Object[] { from, to, sublayer });
+    }
+
+    protected String createDiameterTopLayerDescription(CallMeta meta,
+        BedDiameterResult result, DateRange range) {
+        Date from = range != null ? range.getFrom() : new Date();
+        Date to = range != null ? range.getTo() : new Date();
+
+        String toplayer = Resources.getMsg(meta, I18N_TOPLAYER, I18N_TOPLAYER);
+
+        return Resources.getMsg(meta, I18N_FACET_BED_DIAMETER_TOPLAYER,
+            I18N_FACET_BED_DIAMETER_TOPLAYER, new Object[] { result.getType(),
+                from, to, toplayer });
+    }
+
+    protected String createDiameterSubLayerDescription(CallMeta meta,
+        BedDiameterResult result, DateRange range) {
+        Date from = range != null ? range.getFrom() : new Date();
+        Date to = range != null ? range.getTo() : new Date();
+
+        String sublayer = Resources.getMsg(meta, I18N_SUBLAYER, I18N_SUBLAYER);
+        return Resources.getMsg(meta, I18N_FACET_BED_DIAMETER_SUBLAYER,
+            I18N_FACET_BED_DIAMETER_SUBLAYER, new Object[] { result.getType(),
+                from, to, sublayer });
+    }
+
+    protected String createDiameterDescription(CallMeta meta,
+        BedQualityDiameterResult result) {
+        return Resources.getMsg(meta, I18N_FACET_BEDLOAD_DIAMETER,
+            I18N_FACET_BEDLOAD_DIAMETER, new Object[] { result.getType() });
+    }
+}
+// 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/CharDiameter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,88 @@
+package de.intevation.flys.artifacts.states.minfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.common.model.KVP;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.artifacts.states.MultiStringArrayState;
+
+public class CharDiameter extends MultiStringArrayState {
+
+    private static final Logger logger = Logger.getLogger(CharDiameter.class);
+
+    public static final String UI_PROVIDER = "parameter-matrix";
+
+    private static final String CHAR_DIAMETER_MIN  = "calc.bed.dmin";
+    private static final String CHAR_DIAMETER_MAX  = "calc.bed.dmax";
+    private static final String CHAR_DIAMETER_90  = "calc.bed.d90";
+    private static final String CHAR_DIAMETER_84  = "calc.bed.d84";
+    private static final String CHAR_DIAMETER_80  = "calc.bed.d80";
+    private static final String CHAR_DIAMETER_75  = "calc.bed.d75";
+    private static final String CHAR_DIAMETER_70  = "calc.bed.d70";
+    private static final String CHAR_DIAMETER_60  = "calc.bed.d60";
+    private static final String CHAR_DIAMETER_50  = "calc.bed.d50";
+    private static final String CHAR_DIAMETER_40  = "calc.bed.d40";
+    private static final String CHAR_DIAMETER_30  = "calc.bed.d30";
+    private static final String CHAR_DIAMETER_25  = "calc.bed.d25";
+    private static final String CHAR_DIAMETER_20  = "calc.bed.d20";
+    private static final String CHAR_DIAMETER_16  = "calc.bed.d16";
+    private static final String CHAR_DIAMETER_10  = "calc.bed.d10";
+
+    public static final String[] CHAR_DIAMETER = {
+        CHAR_DIAMETER_10,
+        CHAR_DIAMETER_16,
+        CHAR_DIAMETER_20,
+        CHAR_DIAMETER_25,
+        CHAR_DIAMETER_30,
+        CHAR_DIAMETER_40,
+        CHAR_DIAMETER_50,
+        CHAR_DIAMETER_60,
+        CHAR_DIAMETER_70,
+        CHAR_DIAMETER_75,
+        CHAR_DIAMETER_80,
+        CHAR_DIAMETER_84,
+        CHAR_DIAMETER_90,
+        CHAR_DIAMETER_MAX,
+        CHAR_DIAMETER_MIN
+    };
+
+    @Override
+    public String getUIProvider() {
+        return UI_PROVIDER;
+    }
+
+    @Override
+    protected KVP<String, String>[] getOptions(
+        Artifact artifact,
+        String parameterName,
+        CallContext context
+    )
+    throws IllegalArgumentException
+    {
+        CallMeta meta   = context.getMeta();
+
+        List<KVP<String, String>> rows = new ArrayList<KVP<String, String>>();
+        String key = parameterName;
+        for (int i = 0; i < CHAR_DIAMETER.length; ++i) {
+            String calc = CHAR_DIAMETER[i];
+            rows.add(new KVP (calc,
+                              Resources.getMsg(meta, calc, calc)));
+        }
+
+        return rows.toArray(new KVP[rows.size()]);
+    }
+
+    @Override
+    protected String getLabelFor(CallContext cc, String parameterName,
+            String value) throws IllegalArgumentException {
+
+        return Resources.getMsg(cc.getMeta(), value, value);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/DifferenceSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -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	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,248 @@
+package de.intevation.flys.artifacts.states.minfo;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.BedDifferencesAccess;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.minfo.BedDiffCalculation;
+import de.intevation.flys.artifacts.model.minfo.BedDiffEpochFacet;
+import de.intevation.flys.artifacts.model.minfo.BedDiffEpochResult;
+import de.intevation.flys.artifacts.model.minfo.BedDiffYearFacet;
+import de.intevation.flys.artifacts.model.minfo.BedDiffYearResult;
+import de.intevation.flys.artifacts.model.minfo.BedDifferencesResult;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.artifacts.states.DefaultState;
+import de.intevation.flys.utils.Formatter;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class DifferencesState
+extends DefaultState
+implements FacetTypes
+{
+    /** The logger used in this class. */
+    private static Logger logger = Logger.getLogger(DifferencesState.class);
+    public static final String I18N_DIFF_YEAR = "beddifference.year";
+    public static final String I18N_DIFF_EPOCH = "beddifference.epoch";
+
+    public static final String I18N_FACET_BED_DIFF_YEAR = "facet.bedheight.diff.year";
+    public static final String I18N_FACET_BED_DIFF_ABSOLUTE = "facet.bedheight.diff.absolute";
+    public static final String I18N_FACET_BED_DIFF_MORPH = "facet.bedheight.diff.morph";
+    public static final String I18N_FACET_BED_DIFF_EPOCH = "facet.bedheight.diff.epoch";
+    public static final String I18N_FACET_BED_DIFF_HEIGHT1 = "facet.bedheight.diff.height1";
+    public static final String I18N_FACET_BED_DIFF_HEIGHT2 = "facet.bedheight.diff.height2";
+
+    public DifferencesState() {
+    }
+
+    @Override
+    public Object computeAdvance(FLYSArtifact artifact, String hash,
+        CallContext context, List<Facet> facets, Object old) {
+        logger.debug("BedQualityState.computeAdvance");
+
+        List<Facet> newFacets = new ArrayList<Facet>();
+
+        BedDifferencesAccess access =
+            new BedDifferencesAccess(artifact, context);
+
+        CalculationResult res = old instanceof CalculationResult ? (CalculationResult) old
+            : new BedDiffCalculation().calculate(access);
+
+        if (facets == null || res == null) {
+            return res;
+        }
+
+        BedDifferencesResult[] results = (BedDifferencesResult[]) res.getData();
+
+        if (results == null || results.length == 0) {
+            logger.warn("Calculation computed no results!");
+            return res;
+        }
+
+        generateFacets(context, newFacets, results, getID(), hash);
+        logger.debug("Created " + newFacets.size() + " new Facets.");
+
+        facets.addAll(newFacets);
+
+        return res;
+    }
+
+    protected void generateFacets(CallContext context, List<Facet> newFacets,
+        BedDifferencesResult[] results, String stateId, String hash) {
+        logger.debug("BedQualityState.generateFacets");
+
+        CallMeta meta = context.getMeta();
+
+        for (int idx = 0; idx < results.length; idx++) {
+            if (results[idx] instanceof BedDiffYearResult) {
+                newFacets.add(new BedDiffYearFacet(
+                    idx,
+                    BED_DIFFERENCE_YEAR,
+                    createBedDiffYearDescription(
+                        meta,
+                        (BedDiffYearResult)results[idx]),
+                    ComputeType.ADVANCE,
+                    stateId,
+                    hash));
+                newFacets.add(new BedDiffYearFacet(
+                    idx,
+                    BED_DIFFERENCE_MORPH_WIDTH,
+                    createBedDiffMorphDescription(
+                        meta,
+                        (BedDiffYearResult)results[idx]),
+                    ComputeType.ADVANCE,
+                    stateId,
+                    hash));
+                newFacets.add(new BedDiffYearFacet(
+                    idx,
+                    BED_DIFFERENCE_YEAR_HEIGHT1,
+                    createBedDiffHeightDescription(
+                        meta,
+                        (BedDiffYearResult)results[idx],
+                        0),
+                    ComputeType.ADVANCE,
+                    stateId,
+                    hash));
+                 newFacets.add(new BedDiffYearFacet(
+                    idx,
+                    BED_DIFFERENCE_YEAR_HEIGHT2,
+                    createBedDiffHeightDescription(
+                        meta,
+                        (BedDiffYearResult)results[idx],
+                        1),
+                    ComputeType.ADVANCE,
+                    stateId,
+                    hash));
+                newFacets.add(new BedDiffYearFacet(
+                    idx,
+                    BED_DIFFERENCE_HEIGHT_YEAR,
+                    createBedDiffAbsoluteDescription(
+                        meta,
+                        (BedDiffYearResult)results[idx]),
+                    ComputeType.ADVANCE,
+                    stateId,
+                    hash));
+            }
+            if (results[idx] instanceof BedDiffEpochResult) {
+                newFacets.add(new BedDiffEpochFacet(
+                    idx,
+                    BED_DIFFERENCE_EPOCH,
+                    createBedDiffEpochDescription(
+                        meta,
+                        (BedDiffEpochResult)results[idx]),
+                    ComputeType.ADVANCE,
+                    stateId,
+                    hash));
+                newFacets.add(new BedDiffEpochFacet(
+                    idx,
+                    BED_DIFFERENCE_EPOCH_HEIGHT1,
+                    createBedDiffHeightEpochDescription(
+                        meta,
+                        (BedDiffEpochResult)results[idx],
+                        0),
+                    ComputeType.ADVANCE,
+                    stateId,
+                    hash));
+                newFacets.add(new BedDiffEpochFacet(
+                    idx,
+                    BED_DIFFERENCE_EPOCH_HEIGHT2,
+                    createBedDiffHeightEpochDescription(
+                        meta,
+                        (BedDiffEpochResult)results[idx],
+                        1),
+                    ComputeType.ADVANCE,
+                    stateId,
+                    hash));
+
+            }
+        }
+    }
+
+    private String createBedDiffHeightDescription(
+        CallMeta meta,
+        BedDiffYearResult result,
+        int ndx
+    ) {
+        String range = result.getStart() + " - " + result.getEnd();
+
+        if (ndx == 0) {
+            return Resources.getMsg(meta, I18N_FACET_BED_DIFF_HEIGHT1,
+                I18N_FACET_BED_DIFF_HEIGHT1, new Object[] { range });
+        }
+        else {
+            return Resources.getMsg(meta, I18N_FACET_BED_DIFF_HEIGHT2,
+                I18N_FACET_BED_DIFF_HEIGHT2, new Object[] {range});
+        }
+    }
+
+    private String createBedDiffHeightEpochDescription(
+        CallMeta meta,
+        BedDiffEpochResult result,
+        int ndx
+    ) {
+        DateFormat df = Formatter.getDateFormatter(meta, "yyyy");
+        String range =
+            df.format(result.getStart())
+            + " - " +
+            df.format(result.getEnd());
+
+        if (ndx == 0) {
+            return Resources.getMsg(meta, I18N_FACET_BED_DIFF_HEIGHT1,
+                I18N_FACET_BED_DIFF_HEIGHT1, new Object[] { range });
+        }
+        else {
+            return Resources.getMsg(meta, I18N_FACET_BED_DIFF_HEIGHT2,
+                I18N_FACET_BED_DIFF_HEIGHT2, new Object[] {range});
+        }
+    }
+
+    protected String createBedDiffYearDescription(
+        CallMeta meta,
+        BedDiffYearResult result) {
+        String range = result.getStart() + " - " + result.getEnd();
+
+        return Resources.getMsg(meta, I18N_FACET_BED_DIFF_YEAR,
+            I18N_FACET_BED_DIFF_YEAR, new Object[] { range });
+    }
+
+    protected String createBedDiffMorphDescription(
+        CallMeta meta,
+        BedDiffYearResult result) {
+        String range = result.getStart() + " - " + result.getEnd();
+
+        return Resources.getMsg(meta, I18N_FACET_BED_DIFF_MORPH,
+            I18N_FACET_BED_DIFF_MORPH, new Object[] { range });
+    }
+
+    protected String createBedDiffAbsoluteDescription(
+        CallMeta meta,
+        BedDiffYearResult result) {
+        String range = result.getStart() + " - " + result.getEnd();
+
+        return Resources.getMsg(meta, I18N_FACET_BED_DIFF_ABSOLUTE,
+            I18N_FACET_BED_DIFF_ABSOLUTE, new Object[] { range });
+    }
+
+    protected String createBedDiffEpochDescription(
+        CallMeta meta,
+        BedDiffEpochResult result) {
+        DateFormat df = Formatter.getDateFormatter(meta, "yyyy");
+        String range =
+            df.format(result.getStart())
+            + " - " +
+            df.format(result.getEnd());
+
+        return Resources.getMsg(meta, I18N_FACET_BED_DIFF_EPOCH,
+            I18N_FACET_BED_DIFF_EPOCH, new Object[] { range });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/minfo/YearEpochSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/sq/SQPeriodSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.artifacts.states.sq;
+
+import de.intevation.flys.artifacts.states.PeriodsSelect;
+
+public class SQPeriodSelect extends PeriodsSelect {
+
+    public static final String UI_PROVIDER = "sq.period.select";
+
+    private static final long serialVersionUID = 1L;
+
+
+    @Override
+    public String getUIProvider() {
+        return UI_PROVIDER;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/transitions/DefaultTransition.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/transitions/DefaultTransition.java	Fri Sep 28 12:15:52 2012 +0200
@@ -69,7 +69,7 @@
     /**
      * Set the current state ID.
      *
-     * @param to the current state ID.
+     * @param from current state ID.
      */
     public void setFrom(String from) {
         this.from = from;
--- a/flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -100,10 +100,9 @@
 
 
     protected void parseOutput(Node out) {
-        String name = XMLUtils.xpathString(
-            out, "@name", ArtifactNamespaceContext.INSTANCE);
+        String name = ((Element)out).getAttribute("name");
 
-        if (name == null || name.length() == 0) {
+        if (name.length() == 0) {
             logger.warn("No Output name specified. Cancel parsing!");
             return;
         }
@@ -121,12 +120,21 @@
         parseItems(out, name);
     }
 
+    private static final Node getChild(Element element, String name) {
+        NodeList children = element.getChildNodes();
+        for (int i = 0, N = children.getLength(); i < N; ++i) {
+            Node child = children.item(i);
+            if (child.getNodeType() == Node.ELEMENT_NODE
+            && child.getLocalName().equals(name)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
 
     protected void parseSettings(Node out, String outname) {
-        Node settingsNode = (Node) XMLUtils.xpath(
-            out, "settings",
-            XPathConstants.NODE,
-            null);
+        Node settingsNode = getChild((Element)out, "settings");
 
         if (settingsNode == null) {
             logger.debug("No Settings found for Output '" + outname + "'");
@@ -139,21 +147,20 @@
 
 
     protected void parseItems(Node out, String outname) {
-        NodeList themes = (NodeList) XMLUtils.xpath(
-            out, "art:facet",
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
+        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+        Element element = (Element)out;
 
-        int num = themes != null ? themes.getLength() : 0;
+        NodeList themes = element.getElementsByTagNameNS(uri, "facet");
+
+        int num = themes.getLength();
 
         logger.debug("Output has " + num + " themes.");
 
-        String uri = ArtifactNamespaceContext.NAMESPACE_URI;
-
         for (int i = 0; i < num; i++) {
             Element theme = (Element) themes.item(i);
-
-            attribute.addFacet(outname, new ManagedDomFacet(theme));
+            if (theme.getParentNode() == out) {
+                attribute.addFacet(outname, new ManagedDomFacet(theme));
+            }
         }
     }
 }
--- a/flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeWriter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/AttributeWriter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -11,6 +11,7 @@
 import de.intevation.artifacts.ArtifactDatabaseException;
 
 import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.FacetActivity;
 import de.intevation.artifactdatabase.state.Output;
 
 import de.intevation.flys.artifacts.FLYSArtifact;
@@ -90,6 +91,9 @@
      * @return document with merged outputs as described.
      */
     protected CollectionAttribute write() {
+
+        boolean debug = logger.isDebugEnabled();
+
         for (Map.Entry<String, Output> entry: newAttr.entrySet()) {
             String outName = entry.getKey();
             Output a       = entry.getValue();
@@ -100,9 +104,19 @@
             }
 
             attribute.clearFacets(outName);
+
+            if (debug) {
+                logger.debug("Merge Output: " + outName);
+                logger.debug("   old Facets: " + oldFacets.size());
+                logger.debug("   new Facets: " + newFacets.size());
+            }
+
             writeOutput(a.getName(), newFacets, oldFacets);
         }
 
+        // THIS CALL IS ABSOLUTELY NECESSARY!
+        attribute.cleanEmptyOutputs();
+
         return attribute;
     }
 
@@ -118,6 +132,14 @@
         List<Facet> oldOutFacets
     ) {
         List<String> compatFacets = this.compatibilities.get(outputName);
+
+        if (logger.isDebugEnabled() && compatFacets != null) {
+            logger.debug("Compabitle Facets:");
+            for (String compatible: compatFacets) {
+                logger.debug(   "- " + compatible);
+            }
+        }
+
         try {
             writeFacets(outputName, newOutFacets, oldOutFacets, compatFacets);
         }
@@ -134,10 +156,10 @@
      * @return true if any facets are written to the out.
      */
     protected boolean writeFacets(
-        String         outputName,
-        List<Facet>    newFacets,
-        List<Facet>    oldFacets,
-        List<String>   compatibleFacets)
+        String        outputName,
+        List<Facet>   newFacets,
+        List<Facet>   oldFacets,
+        List<String>  compatibleFacets)
     throws ArtifactDatabaseException
     {
         if (compatibleFacets == null) {
@@ -152,8 +174,15 @@
         List<ManagedFacet> currentFacets      = new ArrayList<ManagedFacet>();
         List<ManagedFacet> genuinelyNewFacets = new ArrayList<ManagedFacet>();
 
+        boolean debug = logger.isDebugEnabled();
+
         for (int i = 0; i < num; i++) {
             ManagedFacet facet = (ManagedFacet) newFacets.get(i);
+
+            if (debug) {
+                logger.debug("Try to add Facet: " + facet.getName());
+            }
+
             if (!compatibleFacets.contains(facet.getName())) {
                 //logger.debug("Have incompatible facet, skip: " + facet.getName());
                 continue;
@@ -170,14 +199,18 @@
             }
         }
 
-        // With each genuinely new Facet, ask Artifact whether it comes to live
+        FacetActivity.Registry registry = FacetActivity.Registry.getInstance();
+
+        // With each genuinely new Facet, figure out whether it comes to live
         // in/activate.
         for (ManagedFacet newMF: genuinelyNewFacets) {
-            FLYSArtifact flys = (FLYSArtifact) db.getRawArtifact(newMF.getArtifact());
-            newMF.setActive(flys.getInitialFacetActivity(
-                outputName,
-                newMF.getName(),
-                newMF.getIndex()));
+            FLYSArtifact flys =
+                (FLYSArtifact)db.getRawArtifact(newMF.getArtifact());
+
+            boolean isActive = registry.isInitialActive(
+                flys.getName(), flys, newMF, outputName);
+
+            newMF.setActive(isActive ? 1 : 0);
         }
 
         // For each genuinely new Facet check positional conflicts.
@@ -189,8 +222,12 @@
                 for (ManagedFacet oldMF: currentFacets) {
                     if (newMF.getPosition() == oldMF.getPosition()) {
                         conflicts = true;
-                        logger.debug("Positional conflict while merging " +
-                            "facets, pushing newest facet 1 up (" + newMF.getPosition() + ")");
+                        if (debug) {
+                            logger.debug(
+                                "Positional conflict while merging " +
+                                "facets, pushing newest facet 1 up (" +
+                                newMF.getPosition() + ")");
+                        }
                         newMF.setPosition(newMF.getPosition() + 1);
                         break;
                     }
@@ -202,7 +239,8 @@
         // Fill/correct "gaps" (e.g. position 1,2,5 are taken, after gap filling
         // expect positions 1,2,3 [5->3])
         // Preparations to be able to detect gaps.
-        Map<Integer, ManagedFacet> mfmap = new HashMap<Integer, ManagedFacet>();
+        Map<Integer, ManagedFacet> mfmap =
+            new HashMap<Integer, ManagedFacet>();
         int max = 0;
         for (ManagedFacet mf: currentFacets) {
             int pos = mf.getPosition();
@@ -228,7 +266,7 @@
             attribute.addFacet(outputName, oldMF);
         }
 
-        return currentFacets.size() > 0;
+        return !currentFacets.isEmpty();
     }
 
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/collections/CollectionAttribute.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/CollectionAttribute.java	Fri Sep 28 12:15:52 2012 +0200
@@ -23,12 +23,12 @@
 import de.intevation.artifactdatabase.state.Settings;
 
 
+/** Create attribute part of collection document. */
 public class CollectionAttribute {
 
     private static final Logger logger =
         Logger.getLogger(CollectionAttribute.class);
 
-
     protected ElementCreator ec;
 
     protected Map<String, Output> outputMap;
@@ -58,6 +58,29 @@
     }
 
 
+    public void cleanEmptyOutputs() {
+        if (outputMap == null) {
+            return;
+        }
+
+        List<String> removeUs = new ArrayList<String>();
+
+        Set<Map.Entry<String, Output>> entries = outputMap.entrySet();
+        for (Map.Entry<String, Output> entry: entries) {
+            Output o = entry.getValue();
+
+            List<Facet> facets = o.getFacets();
+            if (facets == null || facets.isEmpty()) {
+                removeUs.add(entry.getKey());
+            }
+        }
+
+        for (String key: removeUs) {
+            outputMap.remove(key);
+        }
+    }
+
+
     public void setSettings(String outputKey, Settings settings) {
         if (settings == null) {
             logger.warn("Tried to set empty Settings for '" + outputKey + "'");
@@ -160,7 +183,7 @@
             return null;
         }
 
-        if (outputMap == null || outputMap.size() == 0) {
+        if (outputMap == null || outputMap.isEmpty()) {
             logger.warn("Tried to retrieve Output, but no Outputs existing.");
             return null;
         }
@@ -194,7 +217,7 @@
     public List<Facet> getFacets() {
         List<Facet> allFacets = new ArrayList<Facet>();
 
-        if (outputMap == null || outputMap.size() == 0) {
+        if (outputMap == null || outputMap.isEmpty()) {
             logger.warn("No Outputs existing.");
             return allFacets;
         }
@@ -210,7 +233,7 @@
 
 
     protected void appendOutputs(Element root) {
-        if (outputMap == null || outputMap.size() == 0) {
+        if (outputMap == null || outputMap.isEmpty()) {
             logger.warn("No outputs to append.");
             return;
         }
@@ -258,7 +281,7 @@
 
 
     protected void appendFacets(Element root, List<Facet> facets) {
-        if (facets == null || facets.size() == 0) {
+        if (facets == null || facets.isEmpty()) {
             logger.warn("Tried to append 0 Facets.");
             return;
         }
--- a/flys-artifacts/src/main/java/de/intevation/flys/collections/CollectionDescriptionHelper.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/CollectionDescriptionHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -6,18 +6,16 @@
 
 import javax.xml.xpath.XPathConstants;
 
+import org.apache.log4j.Logger;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-import org.apache.log4j.Logger;
-
 import de.intevation.artifacts.ArtifactDatabase;
 import de.intevation.artifacts.ArtifactDatabaseException;
 import de.intevation.artifacts.ArtifactNamespaceContext;
 import de.intevation.artifacts.CallContext;
-
 import de.intevation.artifacts.common.utils.XMLUtils;
 import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
 
@@ -63,20 +61,17 @@
         long        ttl,
         CallContext callContext
     ) {
-        this.name     = name;
-        this.uuid     = uuid;
-        this.creation = creation;
-        this.ttl      = ttl;
-        this.context  = callContext;
-        this.database = callContext.getDatabase();
+        this.name      = name;
+        this.uuid      = uuid;
+        this.creation  = creation;
+        this.ttl       = ttl;
+        this.context   = callContext;
+        this.database  = callContext.getDatabase();
+        this.artifacts = new ArrayList<String>();
     }
 
 
     public void addArtifact(String uuid) {
-        if (artifacts == null) {
-            artifacts = new ArrayList<String>();
-        }
-
         if (uuid != null && uuid.length() > 0) {
             artifacts.add(uuid);
         }
@@ -187,7 +182,7 @@
 
         if (dataNodes != null) {
             Document doc = ci.getOwnerDocument();
-            for (int i = 0; i < dataNodes.getLength(); i++) {
+            for (int i = 0, D = dataNodes.getLength(); i < D; i++) {
                 dataNode.appendChild(doc.importNode(dataNodes.item(i), true));
             }
         }
@@ -197,9 +192,12 @@
 
 
     protected void appendAttribute(Element root) {
-        Document owner = root.getOwnerDocument();
-        Document attr  = attribute.toXML();
+        if (attribute != null) {
+            Document owner = root.getOwnerDocument();
+            Document attr  = attribute.toXML();
 
-        root.appendChild(owner.importNode(attr.getFirstChild(), true));
+            root.appendChild(owner.importNode(attr.getFirstChild(), true));
+        }
     }
 }
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/FLYSArtifactCollection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -11,38 +11,28 @@
 import javax.xml.xpath.XPathConstants;
 
 import org.apache.log4j.Logger;
-
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import de.intevation.artifactdatabase.Backend;
+import de.intevation.artifactdatabase.Backend.PersistentArtifact;
+import de.intevation.artifactdatabase.DefaultArtifactCollection;
+import de.intevation.artifactdatabase.state.Output;
+import de.intevation.artifactdatabase.state.Settings;
+import de.intevation.artifactdatabase.state.StateEngine;
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.ArtifactDatabase;
 import de.intevation.artifacts.ArtifactDatabaseException;
 import de.intevation.artifacts.ArtifactNamespaceContext;
 import de.intevation.artifacts.CallContext;
 import de.intevation.artifacts.CallMeta;
-
-import de.intevation.artifacts.common.utils.ClientProtocolUtils;
 import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifactdatabase.Backend;
-import de.intevation.artifactdatabase.Backend.PersistentArtifact;
-import de.intevation.artifactdatabase.DefaultArtifactCollection;
-import de.intevation.artifactdatabase.state.ArtifactAndFacet;
-import de.intevation.artifactdatabase.state.Output;
-import de.intevation.artifactdatabase.state.Settings;
-import de.intevation.artifactdatabase.state.StateEngine;
-
+import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.context.FLYSContext;
-import de.intevation.flys.artifacts.FLYSArtifact;
-import de.intevation.flys.artifacts.model.ManagedFacet;
-import de.intevation.flys.artifacts.model.ManagedDomFacet;
 import de.intevation.flys.exports.OutGenerator;
-import de.intevation.flys.themes.Theme;
-import de.intevation.flys.themes.ThemeFactory;
-
+import de.intevation.flys.exports.OutputHelper;
 import de.intevation.flys.utils.FLYSUtils;
 
 /**
@@ -91,7 +81,11 @@
         AttributeParser parser   = new AttributeParser(oldAttrs);
 
         try {
-            String[]            aUUIDs  = getArtifactUUIDs(context);
+            String[] aUUIDs  = getArtifactUUIDs(context);
+
+            oldAttrs = removeAttributes(oldAttrs, context);
+            parser   = new AttributeParser(oldAttrs);
+
             CollectionAttribute newAttr = mergeAttributes(
                 db, context, parser, aUUIDs);
 
@@ -101,13 +95,10 @@
 
             helper.setAttribute(newAttr);
 
-            // Make it an empty array if null.
-            if (aUUIDs == null) {
-                aUUIDs = new String[] {};
-            }
-
-            for (String uuid: aUUIDs) {
-                helper.addArtifact(uuid);
+            if (aUUIDs != null) {
+                for (String uuid: aUUIDs) {
+                    helper.addArtifact(uuid);
+                }
             }
         }
         catch (ArtifactDatabaseException ade) {
@@ -135,6 +126,11 @@
         CollectionAttribute cAttribute =
             buildOutAttributes(db, context, oldParser, uuids);
 
+        if (cAttribute == null) {
+            log.warn("mergeAttributes: cAttribute == null");
+            return null;
+        }
+
         cAttribute.setLoadedRecommendations(
             getLoadedRecommendations(oldParser.getAttributeDocument()));
 
@@ -144,6 +140,49 @@
     }
 
 
+    protected Document removeAttributes(Document attrs, CallContext context) {
+        Node outs = (Node) XMLUtils.xpath(
+            attrs,
+            "/art:attribute/art:outputs",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        NodeList nodes = (NodeList) XMLUtils.xpath(
+            attrs,
+            "/art:attribute/art:outputs/art:output",
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (nodes != null) {
+            for (int i = 0; i < nodes.getLength(); i++) {
+                Element e = (Element)nodes.item(i);
+                if(!outputExists(e.getAttribute("name"), context)) {
+                    outs.removeChild(e);
+                }
+            }
+        }
+        return attrs;
+    }
+
+
+    /**
+     * True if current MasterArtifact has given output.
+     * @param name Name of the output of interest.
+     * @param context current context
+     * @return true if current master artifact has given output.
+     */
+    protected boolean outputExists(String name, CallContext context) {
+        FLYSArtifact master = getMasterArtifact(context);
+        List<Output> outList = master.getOutputs(context);
+
+        for (Output o : outList) {
+            if (name.equals(o.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * @param db The ArtifactDatabase which is required to save the attribute
      * into.
@@ -181,7 +220,7 @@
      * Merge the recommendations which have already been loaded from the old
      * attribute document into the new attribute document. This is necessary,
      * because mergeAttributes() only merges the art:outputs nodes - all
-     * other nodes are skiped.
+     * other nodes are skipped.
      */
     protected Node getLoadedRecommendations(Document oldAttrs) {
         Element loadedRecoms = (Element) XMLUtils.xpath(
@@ -213,7 +252,7 @@
             ? attribute.getOutputs()
             : null;
 
-        if (outputMap == null || outputMap.size() == 0) {
+        if (outputMap == null || outputMap.isEmpty()) {
             log.debug("No Output Settings check necessary.");
             return modified;
         }
@@ -224,6 +263,9 @@
             String outName = entry.getKey();
             Output output  = entry.getValue();
 
+            if (outName.equals("sq_overview")) {
+                continue;
+            }
             Settings settings = output.getSettings();
 
             if (settings == null) {
@@ -254,7 +296,7 @@
         CollectionAttribute attr,
         String              out
     ) {
-        OutGenerator outGen = getOutGenerator(cc, out, null);
+        OutGenerator outGen = FLYSContext.getOutGenerator(cc, out, null);
 
         if (outGen == null) {
             return null;
@@ -267,7 +309,8 @@
 
         try {
             Document outAttr = getAttribute(cc, attr, out);
-            doOut(outGen, out, out, outAttr, cc);
+            OutputHelper helper = new OutputHelper(identifier());
+            helper.doOut(outGen, out, out, outAttr, cc);
         }
         catch (ArtifactDatabaseException adbe) {
             log.error(adbe, adbe);
@@ -288,9 +331,13 @@
         CallContext  context)
     throws IOException
     {
+        boolean debug = log.isDebugEnabled();
+
         long reqBegin = System.currentTimeMillis();
 
-        log.info("FLYSArtifactCollection.out");
+        if (debug) {
+            log.debug("FLYSArtifactCollection.out");
+        }
 
         String name = XMLUtils.xpathString(
             format, XPATH_OUT_NAME, ArtifactNamespaceContext.INSTANCE);
@@ -298,19 +345,21 @@
         String subtype = XMLUtils.xpathString(
             format, XPATH_OUT_TYPE, ArtifactNamespaceContext.INSTANCE);
 
-        log.info("-> Output name = " + name);
-        log.info("-> Output type = " + type);
-        log.info("-> Output subtype = " + subtype);
+        if (debug) {
+            log.debug("-> Output name = " + name);
+            log.debug("-> Output type = " + type);
+            log.debug("-> Output subtype = " + subtype);
+        }
 
         OutGenerator generator = null;
         if (type != null
              && type.length() > 0
              && type.indexOf("chartinfo") > 0)
         {
-            generator = getOutGenerator(context, type, subtype);
+            generator = FLYSContext.getOutGenerator(context, type, subtype);
         }
         else {
-            generator = getOutGenerator(context, name, subtype);
+            generator = FLYSContext.getOutGenerator(context, name, subtype);
         }
 
         if (generator == null) {
@@ -329,19 +378,26 @@
 
         generator.init(format, out, context);
         generator.setSettings(settings);
+        generator.setCollection(this);
         prepareMasterArtifact(generator, context);
 
         try {
             Document attr = getAttribute(context, cAttr, name);
-            doOut(generator, name, subtype, attr, context);
+            OutputHelper helper = new OutputHelper(identifier());
+            if (name.equals("sq_overview")) {
+                helper.doOut(generator, name, subtype, format, context);
+            }
+            helper.doOut(generator, name, subtype, attr, context);
             generator.generate();
         }
         catch (ArtifactDatabaseException adbe) {
             log.error(adbe, adbe);
         }
 
-        long duration = System.currentTimeMillis() -reqBegin;
-        log.info("Processing out(" + name + ") took " + duration + " ms.");
+        if (debug) {
+            long duration = System.currentTimeMillis() -reqBegin;
+            log.info("Processing out(" + name + ") took " + duration + " ms.");
+        }
     }
 
 
@@ -366,117 +422,6 @@
 
 
     /**
-     * Creates the concrete output.
-     *
-     * @param generator The OutGenerator that creates the output.
-     * @param outputName The name of the requested output.
-     * @param attributes The collection's attributes for this concrete output
-     * type.
-     * @param context The context object.
-     */
-    protected void doOut(
-        OutGenerator generator,
-        String       outName,
-        String       facet,
-        Document     attributes,
-        CallContext  context)
-    throws IOException
-    {
-        log.info("FLYSArtifactCollection.doOut: " + outName);
-
-        ThemeList themeList = new ThemeList(attributes);
-
-        int size = themeList.size();
-        log.debug("Output will contain " + size + " elements.");
-
-        List<ArtifactAndFacet> dataProviders =
-            doBlackboardPass(themeList, context);
-
-        try {
-            for (int i = 0; i < size; i++) {
-                ManagedFacet theme = themeList.get(i);
-
-                if (theme == null) {
-                    log.debug("Theme is empty - no output is generated.");
-                    continue;
-                }
-
-                String art = theme.getArtifact();
-                String facetName = theme.getName();
-
-                if (log.isDebugEnabled()) {
-                    log.debug("Do output for...");
-                    log.debug("... artifact: " + art);
-                    log.debug("... facet: " + facetName);
-                }
-
-                if (outName.equals("export") && !facetName.equals(facet)) {
-                    continue;
-                }
-
-                // Skip invisible themes.
-                if (theme.getVisible() == 0) {
-                    continue;
-                }
-
-                generator.doOut(
-                    dataProviders.get(i),
-                    getFacetThemeFromAttribute(
-                        art,
-                        outName,
-                        facetName,
-                        theme.getDescription(),
-                        theme.getIndex(),
-                        context),
-                    theme.getActive() == 1);
-            }
-        }
-        catch (ArtifactDatabaseException ade) {
-            log.error(ade, ade);
-        }
-    }
-
-
-    /**
-     * Show blackboard (context) to each facet and create a list of
-     * ArtifactAndFacets on the fly (with the same ordering as the passed
-     * ThemeList).
-     * @param themeList ThemeList to create a ArtifactAndFacetList along.
-     * @param contect   The "Blackboard".
-     */
-    protected List<ArtifactAndFacet> doBlackboardPass(
-        ThemeList themeList, CallContext context
-    ) {
-        ArrayList<ArtifactAndFacet> dataProviders =
-            new ArrayList<ArtifactAndFacet>();
-        int size = themeList.size();
-
-        try {
-            // Collect all ArtifactAndFacets for blackboard pass.
-            for (int i = 0; i < size; i++) {
-                ManagedFacet theme = themeList.get(i);
-                String uuid        = theme.getArtifact();
-                Artifact artifact  = getArtifact(uuid, context);
-                FLYSArtifact flys  = (FLYSArtifact) artifact;
-                ArtifactAndFacet artifactAndFacet = new ArtifactAndFacet(artifact,
-                    flys.getNativeFacet(theme));
-
-                // Show blackboard to facet.
-                artifactAndFacet.register(context);
-
-                // Add to themes.
-                dataProviders.add(i, artifactAndFacet);
-            }
-        }
-        catch (ArtifactDatabaseException ade) {
-            log.error("ArtifactDatabaseException!", ade);
-        }
-
-        return dataProviders;
-    }
-
-
-    /**
      * @return masterartifact or null if exception/not found.
      */
     protected FLYSArtifact getMasterArtifact(CallContext context)
@@ -510,18 +455,21 @@
         AttributeParser  aParser,
         String[]         uuids)
     {
-        Document doc = XMLUtils.newDocument();
-
         FLYSContext flysContext = FLYSUtils.getFlysContext(context);
         StateEngine engine = (StateEngine) flysContext.get(
-        FLYSContext.STATE_ENGINE_KEY);
+            FLYSContext.STATE_ENGINE_KEY);
+
+        if (engine == null) {
+            log.error("buildOutAttributes: engine == null");
+            return null;
+        }
 
         FLYSArtifact masterArtifact = getMasterArtifact(context);
 
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            doc,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+        if (masterArtifact == null) {
+            log.debug("buildOutAttributes: masterArtifact == null");
+            return null;
+        }
 
         OutputParser oParser = new OutputParser(db, context);
 
@@ -538,7 +486,7 @@
 
         aParser.parse();
 
-        return new AttributeWriter(
+        AttributeWriter aWriter = new AttributeWriter(
             db,
             aParser.getCollectionAttribute(),
             aParser.getOuts(),
@@ -546,7 +494,8 @@
             oParser.getOuts(),
             oParser.getFacets(),
             engine.getCompatibleFacets(masterArtifact.getStateHistoryIds())
-            ).write();
+            );
+        return aWriter.write();
     }
 
 
@@ -568,11 +517,15 @@
     {
         Document attr = cAttr.toXML();
 
+        Map<String, String> vars = new HashMap<String, String>();
+        vars.put("output", output);
+
         Node out = (Node) XMLUtils.xpath(
             attr,
-            "art:attribute/art:outputs/art:output[@name='" + output + "']",
+            "art:attribute/art:outputs/art:output[@name=$output]",
             XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
+            ArtifactNamespaceContext.INSTANCE,
+            vars);
 
 
         if (out != null) {
@@ -631,7 +584,7 @@
             }
         }
 
-        return (String[]) uuids.toArray(new String[uuids.size()]);
+        return uuids.toArray(new String[uuids.size()]);
     }
 
 
@@ -655,348 +608,5 @@
     }
 
 
-    /**
-     * Returns the attribute that belongs to an artifact and facet stored in
-     * this collection.
-     *
-     * @param uuid The Artifact's uuid.
-     * @param outname The name of the requested output.
-     * @param facet The name of the requested facet.
-     * @param context The CallContext.
-     *
-     * @return an attribute in form of a document.
-     */
-    protected Document getFacetThemeFromAttribute(
-        String      uuid,
-        String      outName,
-        String      facet,
-        String      pattern,
-        int         index,
-        CallContext context)
-    throws    ArtifactDatabaseException
-    {
-        log.debug("FLYSArtifactCollection.getFacetThemeFromAttribute");
-
-        ArtifactDatabase db = context.getDatabase();
-        CallMeta       meta = context.getMeta();
-
-        FLYSContext flysContext = context instanceof FLYSContext
-            ? (FLYSContext) context
-            : (FLYSContext) context.globalContext();
-
-        Document attr = db.getCollectionItemAttribute(identifier(), uuid, meta);
-
-        if (attr == null) {
-            attr = initItemAttribute(uuid, facet, pattern, index, outName, context);
-
-            if (attr == null) {
-                return null;
-            }
-        }
-
-        log.debug("Search attribute of collection item: " + uuid);
-
-        Node tmp = (Node) XMLUtils.xpath(
-            attr,
-            "/art:attribute",
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (tmp == null) {
-            log.warn("No attribute found. Operation failed.");
-            return null;
-        }
-
-        log.debug("Search theme for facet '" + facet + "' in attribute.");
-
-        Node theme = (Node) XMLUtils.xpath(
-            tmp,
-            "art:themes/theme[@facet='" + facet +
-            "' and @index='" + String.valueOf(index) + "']",
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (theme == null) {
-            log.warn("Could not find the theme in attribute of: " + uuid);
-
-            Theme t = getThemeForFacet(
-                uuid, facet, pattern, index, outName, context);
-
-            if (t == null) {
-                log.warn("No theme found for facet: " + facet);
-                return null;
-            }
-
-            addThemeToAttribute(uuid, attr, t, context);
-            theme = t.toXML().getFirstChild();
-        }
-
-        Document doc = XMLUtils.newDocument();
-        doc.appendChild(doc.importNode(theme, true));
-
-        return doc;
-    }
-
-
-    /**
-     * Adds the theme of a facet to a CollectionItem's attribute.
-     *
-     * @param uuid The uuid of the artifact.
-     * @param attr The current attribute of an artifact.
-     * @param t The theme to add.
-     * @param context The CallContext.
-     */
-    protected void addThemeToAttribute(
-        String      uuid,
-        Document    attr,
-        Theme       t,
-        CallContext context)
-    {
-        log.debug("FLYSArtifactCollection.addThemeToAttribute: " + uuid);
-
-        if (t == null) {
-            log.warn("Theme is empty - cancel adding it to attribute!");
-            return;
-        }
-
-        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
-            attr,
-            ArtifactNamespaceContext.NAMESPACE_URI,
-            ArtifactNamespaceContext.NAMESPACE_PREFIX);
-
-        Node tmp = (Node) XMLUtils.xpath(
-            attr,
-            "/art:attribute",
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (tmp == null) {
-            tmp = ec.create("attribute");
-            attr.appendChild(tmp);
-        }
-
-        Node themes = (Node) XMLUtils.xpath(
-            tmp,
-            "art:themes",
-            XPathConstants.NODE,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (themes == null) {
-            themes = ec.create("themes");
-            tmp.appendChild(themes);
-        }
-
-        themes.appendChild(attr.importNode(t.toXML().getFirstChild(), true));
-
-        try {
-            setCollectionItemAttribute(uuid, attr, context);
-
-            log.debug("Successfully added theme to item attribute.");
-        }
-        catch (ArtifactDatabaseException e) {
-            // do nothing
-            log.warn("Cannot set attribute of item: " + uuid);
-        }
-    }
-
-
-    /**
-     * Initializes the attribute of an collection item with the theme of a
-     * specific facet.
-     *
-     * @param uuid The uuid of an artifact.
-     * @param facet The name of a facet.
-     * @param context The CallContext.
-     *
-     * @param the new attribute.
-     */
-    protected Document initItemAttribute(
-        String      uuid,
-        String      facet,
-        String      pattern,
-        int         index,
-        String      outName,
-        CallContext context)
-    {
-        log.info("FLYSArtifactCollection.initItemAttribute");
-
-        Theme t = getThemeForFacet(uuid, facet, pattern, index, outName, context);
-
-        if (t == null) {
-            log.info("Could not find theme for facet. Cancel initialization.");
-            return null;
-        }
-
-        Document attr = XMLUtils.newDocument();
-
-        addThemeToAttribute(uuid, attr, t, context);
-
-        return attr;
-    }
-
-
-    /**
-     * Sets the attribute of a CollectionItem specified by <i>uuid</i> to a new
-     * value <i>attr</i>.
-     *
-     * @param uuid The uuid of the CollectionItem.
-     * @param attr The new attribute for the CollectionItem.
-     * @param context The CallContext.
-     */
-    public void setCollectionItemAttribute(
-        String      uuid,
-        Document    attr,
-        CallContext context)
-    throws ArtifactDatabaseException
-    {
-        Document doc = ClientProtocolUtils.newSetItemAttributeDocument(
-            uuid,
-            attr);
-
-        if (doc == null) {
-            log.warn("Cannot set item attribute: No attribute found.");
-            return;
-        }
-
-        ArtifactDatabase db = context.getDatabase();
-        CallMeta       meta = context.getMeta();
-
-        db.setCollectionItemAttribute(identifier(), uuid, doc, meta);
-    }
-
-
-    /**
-     * Returns the theme of a specific facet.
-     *
-     * @param uuid The uuid of an artifact.
-     * @param facet The name of the facet.
-     * @param context The CallContext object.
-     *
-     * @return the desired theme.
-     */
-    protected Theme getThemeForFacet(
-        String uuid,
-        String facet,
-        String pattern,
-        int    index,
-        String outName,
-        CallContext context)
-    {
-        log.info("FLYSArtifactCollection.getThemeForFacet: " + facet);
-
-        FLYSContext flysContext = context instanceof FLYSContext
-            ? (FLYSContext) context
-            : (FLYSContext) context.globalContext();
-
-        // Push artifact in flysContext.
-        ArtifactDatabase db = context.getDatabase();
-        try {
-            FLYSArtifact artifact = (FLYSArtifact) db.getRawArtifact(uuid);
-            log.debug("Got raw artifact");
-            flysContext.put(flysContext.ARTIFACT_KEY, artifact);
-        }
-        catch (ArtifactDatabaseException dbe) {
-            log.error("Exception caught when trying to get art.", dbe);
-        }
-
-        Theme t = ThemeFactory.getTheme(flysContext, facet, pattern, outName);
-
-        if (t != null) {
-            t.setFacet(facet);
-            t.setIndex(index);
-        }
-
-        return t;
-    }
-
-
-    /**
-     * Returns the OutGenerator for a specified <i>type</i>.
-     *
-     * @param name The name of the output type.
-     * @param type Defines the type of the desired OutGenerator.
-     *
-     * @return Instance of an OutGenerator for specified <i>type</i>.
-     */
-    protected OutGenerator getOutGenerator(
-        CallContext context,
-        String      name,
-        String      type)
-    {
-        log.debug("Search OutGenerator for Output '" + name + "'");
-
-        FLYSContext flysContext = context instanceof FLYSContext
-            ? (FLYSContext) context
-            : (FLYSContext) context.globalContext();
-
-        Map<String, Class> generators = (Map<String, Class>)
-            flysContext.get(FLYSContext.OUTGENERATORS_KEY);
-
-        if (generators == null) {
-            log.error("No output generators found in the running application!");
-            return null;
-        }
-
-        Class clazz = generators.get(name);
-
-        try {
-            return clazz != null ? (OutGenerator) clazz.newInstance() : null;
-        }
-        catch (InstantiationException ie) {
-            log.error(ie, ie);
-        }
-        catch (IllegalAccessException iae) {
-            log.error(iae, iae);
-        }
-
-        return null;
-    }
-
-
-    /**
-     * Inner class to structure/order the themes of a chart.
-     */
-    private static class ThemeList {
-        private Logger logger = Logger.getLogger(ThemeList.class);
-        protected Map<Integer, ManagedFacet> themes;
-
-        public ThemeList(Document output) {
-            themes = new HashMap<Integer, ManagedFacet>();
-            parse(output);
-        }
-
-        protected void parse(Document output) {
-            NodeList themeList = (NodeList) XMLUtils.xpath(
-                output,
-                "art:output/art:facet",
-                XPathConstants.NODESET,
-                ArtifactNamespaceContext.INSTANCE);
-
-            int num = themeList != null ? themeList.getLength() : 0;
-
-            logger.debug("Output has " +  num + " elements.");
-
-            if (num == 0) {
-                return;
-            }
-
-            String uri = ArtifactNamespaceContext.NAMESPACE_URI;
-
-            for (int i = 0; i < num; i++) {
-                Element theme = (Element) themeList.item(i);
-
-                ManagedDomFacet facet = new ManagedDomFacet(theme);
-                themes.put(Integer.valueOf(facet.getPosition()-1), facet);
-            }
-        }
-
-        public ManagedFacet get(int idx) {
-            return themes.get(Integer.valueOf(idx));
-        }
-
-        public int size() {
-            return themes.size();
-        }
-    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/collections/OutputParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/collections/OutputParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,6 +20,10 @@
 import de.intevation.flys.artifacts.model.ManagedFacetAdapter;
 
 
+/**
+ * The OutputParsers task is to pull Artifacts from database and put
+ * its outputs and facets into some structures.
+ */
 public class OutputParser {
 
     /** Constant XPath that points to the outputmodes of an artifact. */
@@ -65,8 +69,11 @@
 
         List<Output> outList = flys.getOutputs(context);
 
+        logger.debug("   has " + outList.size() + " Outputs.");
+
         for (Output out: outList) {
             String name = out.getName();
+            logger.debug("Process Output '" + name + "'");
 
             Output o = outs.get(name);
             int  pos = 1;
@@ -120,6 +127,8 @@
     {
         List<Facet> newFacets = new ArrayList<Facet>(old.size());
 
+        logger.debug("There are " + old.size() + " Facets for this Output.");
+
         for (Facet f: old) {
             newFacets.add(new ManagedFacetAdapter(f, uuid, pos++, 1, 1));
         }
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ATExporter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ATExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -17,6 +17,7 @@
 import de.intevation.flys.artifacts.FLYSArtifact;
 
 import de.intevation.flys.artifacts.model.WQ;
+import de.intevation.flys.collections.FLYSArtifactCollection;
 
 import de.intevation.flys.utils.FLYSUtils;
 
@@ -33,6 +34,9 @@
     protected OutputStream out;
     protected FLYSArtifact master;
 
+    protected FLYSArtifactCollection collection;
+
+
     public ATExporter() {
     }
 
@@ -42,12 +46,18 @@
         this.out     = out;
     }
 
+
     @Override
     public void setMasterArtifact(Artifact master) {
         this.master = (FLYSArtifact) master;
     }
 
     @Override
+    public void setCollection(FLYSArtifactCollection collection) {
+        this.collection = collection;
+    }
+
+    @Override
     public void doOut(
         ArtifactAndFacet artifactf,
         Document attr,
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ATWriter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ATWriter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -92,7 +92,7 @@
         }
     }
 
-    protected static void printQ(PrintWriter out, double q) {
+    public static void printQ(PrintWriter out, double q) {
         String format;
              if (q <   1d) format = " % 8.3f";
         else if (q <  10d) format = " % 8.2f";
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/AbstractExporter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/AbstractExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,6 +4,8 @@
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 
+import java.text.NumberFormat;
+
 import org.w3c.dom.Document;
 
 import org.apache.log4j.Logger;
@@ -20,6 +22,9 @@
 import de.intevation.artifacts.common.utils.XMLUtils;
 
 import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.collections.FLYSArtifactCollection;
+
+import de.intevation.flys.utils.Formatter;
 
 
 /**
@@ -33,10 +38,15 @@
     /** The logger used in this exporter.*/
     private static Logger logger = Logger.getLogger(AbstractExporter.class);
 
+    /* XXX: Why does AbstractExporter do not implement FacetTypes? */
+    public static String FIX_PARAMETERS = "fix_parameters";
 
     /** The name of the CSV facet which triggers the CSV creation. */
     public static final String FACET_CSV = "csv";
 
+    /** The name of the PDF facet which triggers the PDF creation. */
+    public static final String FACET_PDF = "pdf";
+
     /** The default charset for the CSV export. */
     public static final String DEFAULT_CSV_CHARSET = "UTF-8";
 
@@ -46,7 +56,6 @@
     /** XPath that points to the desired export facet. */
     public static final String XPATH_FACET = "/art:action/@art:type";
 
-
     /** The document of the incoming out() request. */
     protected Document request;
 
@@ -59,6 +68,9 @@
     /** The selected facet. */
     protected String facet;
 
+    /** The collection.*/
+    protected FLYSArtifactCollection collection;
+
     /** The master artifact. */
     protected Artifact master;
 
@@ -69,18 +81,26 @@
      *
      * @param writer The CSVWriter.
      */
-    protected abstract void writeCSVData(CSVWriter writer);
+    protected abstract void writeCSVData(CSVWriter writer) throws IOException;
+
+
+    /**
+     * Concrete subclasses need to use this method to write their special data
+     * objects into the PDF document.
+     */
+    protected abstract void writePDF(OutputStream out);
 
 
     /**
      * This method enables concrete subclasses to collected its own special
      * data.
      *
-     * @param artifacts The artifact that stores the data that has to be
+     * @param data The artifact that stores the data that has to be
      * exported.
      */
     protected abstract void addData(Object data);
 
+
     @Override
     public void init(Document request, OutputStream out, CallContext context) {
         logger.debug("AbstractExporter.init");
@@ -97,14 +117,20 @@
     }
 
 
+    @Override
+    public void setCollection(FLYSArtifactCollection collection) {
+        this.collection = collection;
+    }
+
+
     /**
      * This doOut() just collects the data of multiple artifacts. Therefore, it
      * makes use of the addData() method which enables concrete subclasses to
      * store its data on its own. The real output creation takes place in the
      * concrete generate() methods.
      *
-     * @param artifact The artifact.
-     * @param facet The facet to add - NOTE: the facet needs to fit to the first
+     * @param artifactFacet The artifact and facet.
+     * The facet to add - NOTE: the facet needs to fit to the first
      * facet inserted into this exporter. Otherwise this artifact/facet is
      * skipped.
      * @param attr The attr document.
@@ -137,11 +163,19 @@
     {
         logger.debug("AbstractExporter.generate");
 
-        if (facet != null && facet.equals(FACET_CSV)) {
+        if (facet == null) {
+            throw new IOException("invalid (null) facet for exporter");
+        }
+
+        if (facet.equals(FACET_CSV)) {
             generateCSV();
         }
+        else if (facet.equals(FACET_PDF)) {
+            generatePDF();
+        }
         else {
-            throw new IOException("invalid facet for exporter.");
+            throw new IOException(
+                "invalid facet for exporter: '" + facet + "'");
         }
     }
 
@@ -155,7 +189,7 @@
      * @return true, if <i>facet</i> is valid, otherwise false.
      */
     protected boolean isFacetValid(String facet) {
-        logger.debug("AbstractExporter.isFacetValid");
+        logger.debug("AbstractExporter.isFacetValid : " + facet + " (" + getFacet() + ")" );
 
         String thisFacet = getFacet();
 
@@ -223,6 +257,17 @@
 
 
     /**
+     * This method starts PDF creation.
+     */
+    protected void generatePDF()
+    throws    IOException
+    {
+        logger.info("AbstractExporter.generatePDF");
+        writePDF(this.out);
+    }
+
+
+    /**
      * Returns an instance of <i>EmptySettings</i> currently!
      *
      * @return an instance of <i>EmptySettings</i>.
@@ -239,5 +284,35 @@
     public void setSettings(Settings settings) {
         // do nothing
     }
+
+
+    /**
+     * Returns the number formatter for kilometer values.
+     *
+     * @return the number formatter for kilometer values.
+     */
+    protected NumberFormat getKmFormatter() {
+        return Formatter.getWaterlevelKM(context);
+    }
+
+
+    /**
+     * Returns the number formatter for W values.
+     *
+     * @return the number formatter for W values.
+     */
+    protected NumberFormat getWFormatter() {
+        return Formatter.getWaterlevelW(context);
+    }
+
+
+    /**
+     * Returns the number formatter for Q values.
+     *
+     * @return the number formatter for Q values.
+     */
+    protected NumberFormat getQFormatter() {
+        return Formatter.getWaterlevelQ(context);
+    }
 }
 // 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/exports/ChartArea.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,57 @@
+package de.intevation.flys.exports;
+
+import org.jfree.chart.axis.ValueAxis;
+
+import org.jfree.data.Range;
+
+/** Two Ranges that span a rectangular area. */
+public class ChartArea {
+    protected Range xRange;
+    protected Range yRange;
+
+    public ChartArea(Range rangeX, Range rangeY) {
+        this.xRange = rangeX;
+        this.yRange = rangeY;
+    }
+
+    public ChartArea(ValueAxis axisX, ValueAxis axisY) {
+        this.xRange = axisX.getRange();
+        this.yRange = axisY.getRange();
+    }
+
+    public double ofLeft(double percent) {
+        return xRange.getLowerBound()
+            + xRange.getLength() * percent;
+    }
+
+    public double ofRight(double percent) {
+        return xRange.getUpperBound()
+            - xRange.getLength() * percent;
+    }
+
+    public double ofGround(double percent) {
+        return yRange.getLowerBound()
+            + yRange.getLength() * percent;
+    }
+
+    public double atTop() {
+        return yRange.getUpperBound();
+    }
+
+    public double atGround() {
+        return yRange.getLowerBound();
+    }
+
+    public double atRight() {
+        return xRange.getUpperBound();
+    }
+
+    public double atLeft() {
+        return xRange.getLowerBound();
+    }
+
+    public double above(double percent, double base) {
+        return base + yRange.getLength() * percent;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartExportHelper.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartExportHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -31,12 +31,16 @@
 
 import javax.imageio.ImageIO;
 
+import au.com.bytecode.opencsv.CSVWriter;
+
 import org.apache.batik.svggen.SVGGraphics2D;
 import org.apache.batik.svggen.SVGGraphics2DIOException;
 
 import org.apache.log4j.Logger;
 
 import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.data.xy.XYDataset;
 
 import de.intevation.artifacts.CallContext;
 
@@ -57,6 +61,7 @@
 
     public static final String FORMAT_SVG = "svg";
 
+    public static final String FORMAT_CSV = "csv";
 
     /**
      * Constant field to define A4 as default page size.
@@ -68,6 +73,10 @@
      */
     public static final String  DEFAULT_ENCODING  = "UTF-8";
 
+    /** The default separator for the CSV export. */
+    public static final char DEFAULT_CSV_SEPARATOR = ',';
+
+
     /**
      * Logger used for logging with log4j.
      */
@@ -80,9 +89,7 @@
      *
      * @param out OutputStream
      * @param chart JFreeChart object to be exported.
-     * @param format Format (e.g. png, gif, jpg)
-     * @param width Width, the image used to be
-     * @param height Height, the image used to be
+     * @param cc context, in which e.g. size is stored.
      *
      * @throws IOException if writing image to OutputStream failed.
      */
@@ -137,7 +144,9 @@
 
         int[] size = getSize(context);
 
-        chart.draw(graphics, new Rectangle2D.Double(0.0D, 0.0D,size[0],size[1]));
+        ChartRenderingInfo info = new ChartRenderingInfo();
+
+        chart.draw(graphics, new Rectangle2D.Double(0.0D, 0.0D,size[0],size[1]), info);
 
         try {
             graphics.stream(new OutputStreamWriter(out, encoding));
@@ -157,14 +166,6 @@
      *
      * @param out OutputStream
      * @param chart JFreeChart
-     * @param pageFormat String to specify a page format, {@link
-     * #DEFAULT_PAGE_SIZE} is used if no pageFormat is given
-     * @param landscape If this is true, the pdf is delivered in landscape
-     * format
-     * @param marginLeft Space to left border
-     * @param marginRight Space to right border
-     * @param marginTop Space to upper border
-     * @param marginBottom Space to lower border
      */
     public static void exportPDF(
         OutputStream out,
@@ -178,12 +179,12 @@
         if (pageFormat == null)
             pageFormat = DEFAULT_PAGE_SIZE;
 
-        // max size of the chart
+        // Max size of the chart.
         Rectangle page = PageSize.getRectangle(pageFormat);
         float pageWidth  = page.getWidth();
         float pageHeight = page.getHeight();
 
-        // the chart width
+        // The chart width.
         int[] size = getSize(cc);
 
         boolean landscape = size[0] > size[1];
@@ -257,7 +258,9 @@
             Rectangle2D area = new Rectangle2D.Double(
                 origin[0], origin[1], size[0], size[1]);
 
-            chart.draw(graphics, area);
+            ChartRenderingInfo info = new ChartRenderingInfo();
+
+            chart.draw(graphics, area, info);
             graphics.dispose();
             content.addTemplate(template, 0f, 0f);
         }
@@ -270,6 +273,75 @@
     }
 
 
+    /**
+     * A method to export a CSV file to an
+     * <code>OutputStream</code>.
+     *
+     * @param out OutputStream
+     * @param chart JFreeChart containing the data.
+     * @param context The CallContext object that contains extra parameters.
+     */
+    public static void exportCSV(
+        OutputStream out,
+        JFreeChart chart,
+        CallContext context)
+    {
+        log.debug("export chart as CSV");
+        CSVWriter writer = null;
+        try {
+            writer = new CSVWriter(
+                new OutputStreamWriter(
+                    out,
+                    DEFAULT_ENCODING),
+                DEFAULT_CSV_SEPARATOR);
+        }
+        catch(UnsupportedEncodingException uee) {
+            log.warn("Wrong encoding for CSV export.");
+            return;
+        }
+        XYPlot plot = chart.getXYPlot();
+        int count = plot.getDatasetCount();
+        for (int i = 0; i < count; i++) {
+            XYDataset data = plot.getDataset(i);
+            int scount = data.getSeriesCount();
+            for (int j = 0; j < scount; j++) {
+                Comparable seriesKey = data.getSeriesKey(j);
+                log.debug("series key: " + seriesKey.toString());
+                writeCSVHeader(writer, seriesKey.toString());
+                writeCSVData(writer, data);
+            }
+        }
+        try {
+            writer.close();
+        }
+        catch(IOException ioe) {
+            log.error("Writing CSV export failed!");
+        }
+    }
+
+
+    protected static void writeCSVHeader(CSVWriter writer, String key) {
+        writer.writeNext(new String[] {"#"});
+        writer.writeNext(new String[] {"# " + key});
+        writer.writeNext(new String[] {"#"});
+        writer.writeNext(new String[] {"X", "Y"});
+    }
+
+
+    protected static void writeCSVData(CSVWriter writer, XYDataset data) {
+        int series = data.getSeriesCount();
+        for (int i = 0; i < series; i++) {
+            int items = data.getItemCount(i);
+            for (int j = 0; j < items; j++) {
+                log.debug("write data: " + data.getX(i, j) + ", " + data.getY(i, j));
+                writer.writeNext(new String[] {
+                    data.getX(i, j).toString(),
+                    data.getY(i, j).toString()});
+            }
+        }
+    }
+
+
     public static int[] getSize(CallContext cc) {
         int[] size = new int[2];
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,36 +1,71 @@
 package de.intevation.flys.exports;
 
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Settings;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactNamespaceContext;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.PreferredLocale;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.collections.FLYSArtifactCollection;
+import de.intevation.flys.jfree.Bounds;
+import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation;
+import de.intevation.flys.jfree.DoubleBounds;
+import de.intevation.flys.jfree.EnhancedLineAndShapeRenderer;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StableXYDifferenceRenderer;
+import de.intevation.flys.jfree.StickyAxisAnnotation;
+import de.intevation.flys.jfree.Style;
+import de.intevation.flys.jfree.StyledAreaSeriesCollection;
+import de.intevation.flys.jfree.StyledSeries;
+import de.intevation.flys.model.River;
+import de.intevation.flys.themes.LineStyle;
+import de.intevation.flys.themes.TextStyle;
+import de.intevation.flys.themes.ThemeAccess;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.ThemeUtil;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Paint;
+import java.awt.Stroke;
+import java.awt.TexturePaint;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 import javax.xml.xpath.XPathConstants;
 
 import org.apache.log4j.Logger;
-
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.LegendItem;
+import org.jfree.chart.LegendItemCollection;
+import org.jfree.chart.annotations.XYLineAnnotation;
+import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.chart.title.TextTitle;
+import org.jfree.data.Range;
+import org.jfree.data.general.Series;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.ui.RectangleInsets;
+import org.jfree.ui.TextAnchor;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-import org.jfree.data.Range;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.CallContext;
-import de.intevation.artifacts.CallMeta;
-import de.intevation.artifacts.PreferredLocale;
-
-import de.intevation.artifacts.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifactdatabase.state.ArtifactAndFacet;
-import de.intevation.artifactdatabase.state.Settings;
-
-import de.intevation.flys.model.River;
-
-import de.intevation.flys.artifacts.WINFOArtifact;
-
-import de.intevation.flys.artifacts.resources.Resources;
-import de.intevation.flys.utils.FLYSUtils;
-
+import de.intevation.flys.utils.Formatter;
 
 /**
  * The base class for chart creation. It should provide some basic things that
@@ -42,17 +77,16 @@
 
     private static Logger logger = Logger.getLogger(ChartGenerator.class);
 
-    /** The default chart width, if no other width is set. */
-    public static final int DEFAULT_CHART_WIDTH  = 600;
+    public static final int    DEFAULT_CHART_WIDTH     = 600;
+    public static final int    DEFAULT_CHART_HEIGHT    = 400;
+    public static final String DEFAULT_CHART_FORMAT    = "png";
+    public static final Color  DEFAULT_GRID_COLOR      = Color.GRAY;
+    public static final float  DEFAULT_GRID_LINE_WIDTH = 0.3f;
+    public static final int    DEFAULT_FONT_SIZE       = 12;
+    public static final String DEFAULT_FONT_NAME       = "Tahoma";
 
-    /** The default chart height, if no other height is set.*/
-    public static final int DEFAULT_CHART_HEIGHT = 400;
+    protected static float ANNOTATIONS_AXIS_OFFSET = 0.02f;
 
-    /** The default chart format, if no other height is set.*/
-    public static final String DEFAULT_CHART_FORMAT = "png";
-
-    /** The XPath that points to the chart size of the incoming request
-     * document.*/
     public static final String XPATH_CHART_SIZE =
         "/art:action/art:attributes/art:size";
 
@@ -75,13 +109,582 @@
     /** The CallContext object.*/
     protected CallContext context;
 
+    protected FLYSArtifactCollection collection;
+
     /** The artifact that is used to decorate the chart with meta information.*/
     protected Artifact master;
 
     /** The settings that should be used during output creation.*/
     protected Settings settings;
 
+    /** Map of datasets ("index"). */
+    protected SortedMap<Integer, AxisDataset> datasets;
 
+    /** List of annotations to insert in plot. */
+    protected List<FLYSAnnotation> annotations = new ArrayList<FLYSAnnotation>();
+
+    /**
+     * A mini interface that allows to walk over the YAXIS enums defined in
+     * subclasses.
+     */
+    public interface YAxisWalker {
+
+        int length();
+
+        String getId(int idx);
+    } // end of YAxisWalker interface
+
+
+
+    public interface AxisDataset {
+
+        void addDataset(XYDataset dataset);
+
+        XYDataset[] getDatasets();
+
+        boolean isEmpty();
+
+        void setRange(Range range);
+
+        Range getRange();
+
+        boolean isArea(XYDataset dataset);
+
+        void setPlotAxisIndex(int idx);
+
+        int getPlotAxisIndex();
+
+    } // end of AxisDataset interface
+
+
+
+    /**
+     * Default constructor that initializes internal data structures.
+     */
+    public ChartGenerator() {
+        datasets = new TreeMap<Integer, AxisDataset>();
+    }
+
+
+    /**
+     * Adds annotations to list. The given annotation will be visible.
+     */
+    public void addAnnotations(FLYSAnnotation annotation) {
+        annotations.add(annotation);
+    }
+
+    /**
+     * Add a text and a line annotation.
+     * @param area convenience to determine positions in plot.
+     * @param theme (optional) theme document
+     */
+    protected void addStickyAnnotation(
+        StickyAxisAnnotation annotation,
+        XYPlot plot,
+        ChartArea area,
+        LineStyle lineStyle,
+        TextStyle textStyle,
+        Document theme
+    ) {
+        // OPTIMIZE pre-calculate area-related values
+        final float TEXT_OFF = 0.03f;
+
+        XYLineAnnotation lineAnnotation = null;
+        XYTextAnnotation textAnnotation = null;
+
+        int rendererIndex = 0;
+
+        if (annotation.atX()) {
+            textAnnotation = new CollisionFreeXYTextAnnotation(
+                annotation.getText(), annotation.getPos(), area.ofGround(TEXT_OFF));
+            // OPTIMIZE externalize the calculation involving PI.
+            //textAnnotation.setRotationAngle(270f*Math.PI/180f);
+            lineAnnotation = createGroundStickAnnotation(
+                area, annotation.getPos(), lineStyle);
+            textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT);
+            textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT);
+        }
+        else {
+            // Do the more complicated case where we stick to the Y-Axis.
+            // There is one nasty case (duration curves, where annotations
+            // might stick to the second y-axis).
+            // FIXME: Remove dependency to XYChartGenerator here
+            AxisDataset dataset = getAxisDataset(
+                new Integer(annotation.getAxisSymbol()));
+            if (dataset == null) {
+                logger.warn("Annotation should stick to unfindable y-axis: "
+                    + annotation.getAxisSymbol());
+                rendererIndex = 0;
+            }
+            else {
+                rendererIndex = dataset.getPlotAxisIndex();
+            }
+
+            // Stick to the "right" (opposed to left) Y-Axis.
+            if (rendererIndex != 0) {
+                // OPTIMIZE: Pass a different area to this function,
+                //           do the adding to renderer outside (let this
+                //           function return the annotations).
+                //           Note that this path is travelled rarely.
+                ChartArea area2 = new ChartArea(plot.getDomainAxis(), plot.getRangeAxis(rendererIndex));
+                textAnnotation = new CollisionFreeXYTextAnnotation(
+                    annotation.getText(), area2.ofRight(TEXT_OFF), annotation.getPos());
+                textAnnotation.setRotationAnchor(TextAnchor.CENTER_RIGHT);
+                textAnnotation.setTextAnchor(TextAnchor.CENTER_RIGHT);
+                lineAnnotation = createRightStickAnnotation(
+                    area2, annotation.getPos(), lineStyle);
+                if (!Float.isNaN(annotation.getHitPoint()) && theme != null) {
+                    // New line annotation to hit curve.
+                    if (ThemeUtil.parseShowVerticalLine(theme)) {
+                        XYLineAnnotation hitLineAnnotation =
+                            createStickyLineAnnotation(
+                                StickyAxisAnnotation.SimpleAxis.X_AXIS,
+                                annotation.getHitPoint(), annotation.getPos(),// annotation.getHitPoint(),
+                                area2, lineStyle);
+                        plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation,
+                            org.jfree.ui.Layer.BACKGROUND);
+                    }
+                    if (ThemeUtil.parseShowHorizontalLine(theme)) {
+                        XYLineAnnotation lineBackAnnotation =
+                            createStickyLineAnnotation(
+                                StickyAxisAnnotation.SimpleAxis.Y_AXIS2,
+                                annotation.getPos(), annotation.getHitPoint(),
+                                area2, lineStyle);
+                        plot.getRenderer(rendererIndex).addAnnotation(lineBackAnnotation,
+                            org.jfree.ui.Layer.BACKGROUND);
+                    }
+                }
+            }
+            else { // Stick to the left y-axis.
+                textAnnotation = new CollisionFreeXYTextAnnotation(
+                    annotation.getText(), area.ofLeft(TEXT_OFF), annotation.getPos());
+                textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT);
+                textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT);
+                lineAnnotation = createLeftStickAnnotation(area, annotation.getPos(), lineStyle);
+                if (!Float.isNaN(annotation.getHitPoint()) && theme != null) {
+                    // New line annotation to hit curve.
+                    if (ThemeUtil.parseShowHorizontalLine(theme)) {
+                        XYLineAnnotation hitLineAnnotation =
+                            createStickyLineAnnotation(
+                                StickyAxisAnnotation.SimpleAxis.Y_AXIS,
+                                annotation.getPos(), annotation.getHitPoint(),
+                                area, lineStyle);
+                        plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation,
+                            org.jfree.ui.Layer.BACKGROUND);
+                    }
+                    if (ThemeUtil.parseShowVerticalLine(theme)) {
+                        XYLineAnnotation lineBackAnnotation =
+                            createStickyLineAnnotation(
+                                StickyAxisAnnotation.SimpleAxis.X_AXIS,
+                                annotation.getHitPoint(), annotation.getPos(),
+                                area, lineStyle);
+                        plot.getRenderer(rendererIndex).addAnnotation(lineBackAnnotation,
+                            org.jfree.ui.Layer.BACKGROUND);
+                    }
+                }
+            }
+        }
+
+        // Style the text.
+        if (textStyle != null) {
+            textStyle.apply(textAnnotation);
+        }
+
+        // Add the Annotations to renderer.
+        plot.getRenderer(rendererIndex).addAnnotation(textAnnotation,
+            org.jfree.ui.Layer.FOREGROUND);
+        plot.getRenderer(rendererIndex).addAnnotation(lineAnnotation,
+            org.jfree.ui.Layer.FOREGROUND);
+    }
+
+   /**
+     * Create annotation that sticks to "ground" (X) axis.
+     * @param area helper to calculate coordinates
+     * @param pos one-dimensional position (distance from axis)
+     * @param lineStyle the line style to use for the line.
+     */
+    protected static XYLineAnnotation createGroundStickAnnotation(
+        ChartArea area, float pos, LineStyle lineStyle
+    ) {
+        // Style the line.
+        if (lineStyle != null) {
+            return new XYLineAnnotation(
+                pos, area.atGround(),
+                pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET),
+                new BasicStroke(lineStyle.getWidth()),lineStyle.getColor());
+        }
+        else {
+            return new XYLineAnnotation(
+                pos, area.atGround(),
+                pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET));
+        }
+    }
+
+
+    /**
+     * Create annotation that sticks to the second Y axis ("right").
+     * @param area helper to calculate coordinates
+     * @param pos one-dimensional position (distance from axis)
+     * @param lineStyle the line style to use for the line.
+     */
+    protected static XYLineAnnotation createRightStickAnnotation(
+        ChartArea area, float pos, LineStyle lineStyle
+    ) {
+        // Style the line.
+        if (lineStyle != null) {
+            return new XYLineAnnotation(
+                area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos,
+                area.atRight(), pos,
+                new BasicStroke(lineStyle.getWidth()), lineStyle.getColor());
+        }
+        else {
+            return new XYLineAnnotation(
+                area.atRight(), pos,
+                area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos);
+        }
+    }
+
+
+    /**
+     * Create annotation that sticks to the first Y axis ("left").
+     * @param area helper to calculate coordinates
+     * @param pos one-dimensional position (distance from axis)
+     * @param lineStyle the line style to use for the line.
+     */
+    protected static XYLineAnnotation createLeftStickAnnotation(
+        ChartArea area, float pos, LineStyle lineStyle
+    ) {
+        // Style the line.
+        if (lineStyle != null) {
+            return new XYLineAnnotation(
+                area.atLeft(), pos,
+                area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos,
+                new BasicStroke(lineStyle.getWidth()), lineStyle.getColor());
+        }
+        else {
+            return new XYLineAnnotation(
+                area.atLeft(), pos,
+                area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos);
+        }
+    }
+
+
+    /**
+     * Create a line from a axis to a given point.
+     * @param axis   The "simple" axis.
+     * @param fromD1 from-location in first dimension.
+     * @param toD2   to-location in second dimension.
+     * @param area   helper to calculate offsets.
+     * @param lineStyle optional line style.
+     */
+    protected static XYLineAnnotation createStickyLineAnnotation(
+        StickyAxisAnnotation.SimpleAxis axis, float fromD1, float toD2,
+        ChartArea area, LineStyle lineStyle
+    ) {
+        double anchorX1 = 0d, anchorX2 = 0d, anchorY1 = 0d, anchorY2 = 0d;
+        switch(axis) {
+            case X_AXIS:
+                anchorX1 = fromD1;
+                anchorX2 = fromD1;
+                anchorY1 = area.atGround();
+                anchorY2 = toD2;
+                break;
+            case Y_AXIS:
+                anchorX1 = area.atLeft();
+                anchorX2 = toD2;
+                anchorY1 = fromD1;
+                anchorY2 = fromD1;
+                break;
+            case Y_AXIS2:
+                anchorX1 = area.atRight();
+                anchorX2 = toD2;
+                anchorY1 = fromD1;
+                anchorY2 = fromD1;
+                break;
+        }
+        // Style the line.
+        if (lineStyle != null) {
+            return new XYLineAnnotation(
+                anchorX1, anchorY1,
+                anchorX2, anchorY2,
+                new BasicStroke(lineStyle.getWidth()), lineStyle.getColor());
+        }
+        else {
+            return new XYLineAnnotation(
+                anchorX1, anchorY1,
+                anchorX2, anchorY2);
+        }
+    }
+
+    /**
+     * Add the annotations (Sticky, Text and hyk zones) stored
+     * in the annotations field.
+     * @param plot Plot to add annotations to.
+     */
+    protected void addAnnotationsToRenderer(XYPlot plot) {
+        logger.debug("addAnnotationsToRenderer");
+
+        if (annotations == null || annotations.isEmpty()) {
+            logger.debug("addAnnotationsToRenderer: no annotations.");
+            return;
+        }
+
+        // OPTMIMIZE: Pre-calculate positions
+        ChartArea area = new ChartArea(
+            plot.getDomainAxis(0).getRange(),
+            plot.getRangeAxis().getRange());
+
+        // Walk over all Annotation sets.
+        for (FLYSAnnotation fa: annotations) {
+
+            // Access text styling, if any.
+            Document theme = fa.getTheme();
+            TextStyle textStyle = null;
+            LineStyle lineStyle = null;
+
+            // Get Themeing information and add legend item.
+            if (theme != null) {
+                ThemeAccess themeAccess = new ThemeAccess(theme);
+                textStyle = themeAccess.parseTextStyle();
+                lineStyle = themeAccess.parseLineStyle();
+                if (fa.getLabel() != null) {
+                    LegendItemCollection lic = new LegendItemCollection();
+                    LegendItemCollection old = plot.getFixedLegendItems();
+                    lic.add(createLegendItem(theme, fa.getLabel()));
+                    // (Re-)Add prior legend entries.
+                    if (old != null) {
+                        old.addAll(lic);
+                    }
+                    else {
+                        old = lic;
+                    }
+                    plot.setFixedLegendItems(old);
+                }
+            }
+
+            // The 'Sticky' Annotations (at axis, with line and text).
+            for (StickyAxisAnnotation sta: fa.getAxisTextAnnotations()) {
+                addStickyAnnotation(
+                    sta, plot, area, lineStyle, textStyle, theme);
+            }
+
+            // Other Text Annotations (e.g. labels of (manual) points).
+            for (XYTextAnnotation ta: fa.getTextAnnotations()) {
+                // Style the text.
+                if (textStyle != null) {
+                    textStyle.apply(ta);
+                }
+                ta.setY(area.above(0.05d, ta.getY()));
+                plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND);
+            }
+        }
+    }
+
+
+    /**
+     * This method needs to be implemented by concrete subclasses to create new
+     * instances of JFreeChart.
+     *
+     * @return a new instance of a JFreeChart.
+     */
+    public abstract JFreeChart generateChart();
+
+
+    @Override
+    public abstract void doOut(
+        ArtifactAndFacet bundle,
+        Document         attr,
+        boolean          visible);
+
+
+    protected abstract YAxisWalker getYAxisWalker();
+
+
+    protected abstract Series getSeriesOf(XYDataset dataset, int idx);
+
+    /**
+     * Returns the default title of a chart.
+     *
+     * @return the default title of a chart.
+     */
+    protected abstract String getDefaultChartTitle();
+
+
+    /**
+     * Returns the default X-Axis label of a chart.
+     *
+     * @return the default X-Axis label of a chart.
+     */
+    protected abstract String getDefaultXAxisLabel();
+
+
+    /**
+     * This method is called to retrieve the default label for an Y axis at
+     * position <i>pos</i>.
+     *
+     * @param pos The position of an Y axis.
+     *
+     * @return the default Y axis label at position <i>pos</i>.
+     */
+    protected abstract String getDefaultYAxisLabel(int pos);
+
+
+    /**
+     * This method is used to create new AxisDataset instances which may differ
+     * in concrete subclasses.
+     *
+     * @param idx The index of an axis.
+     */
+    protected abstract AxisDataset createAxisDataset(int idx);
+
+
+    /**
+     * Combines the ranges of the X axis at index <i>idx</i>.
+     *
+     * @param bounds A new Bounds.
+     * @param idx The index of the X axis that should be comined with
+     * <i>range</i>.
+     */
+    protected abstract void combineXBounds(Bounds bounds, int idx);
+
+
+    /**
+     * Combines the ranges of the Y axis at index <i>idx</i>.
+     *
+     * @param bounds A new Bounds.
+     * @param index The index of the Y axis that should be comined with.
+     * <i>range</i>.
+     */
+    protected abstract void combineYBounds(Bounds bounds, int index);
+
+
+    /**
+     * This method is used to determine the ranges for axes at a given index.
+     *
+     * @param index The index of the axes at the plot.
+     *
+     * @return a Range[] with [xrange, yrange];
+     */
+    public abstract Range[] getRangesForAxis(int index);
+
+    public abstract Bounds getXBounds(int axis);
+
+    protected abstract void setXBounds(int axis, Bounds bounds);
+
+    public abstract Bounds getYBounds(int axis);
+
+    protected abstract void setYBounds(int axis, Bounds bounds);
+
+
+    /**
+     * This method retrieves the chart subtitle by calling getChartSubtitle()
+     * and adds it as TextTitle to the chart.
+     * The default implementation of getChartSubtitle() returns the same
+     * as getDefaultChartSubtitle() which must be implemented by derived
+     * classes. If you want to add multiple subtitles to the chart override
+     * this method and add your subtitles manually.
+     *
+     * @param chart The JFreeChart chart object.
+     */
+    protected void addSubtitles(JFreeChart chart) {
+        String subtitle = getChartSubtitle();
+
+        if (subtitle != null && subtitle.length() > 0) {
+            chart.addSubtitle(new TextTitle(subtitle));
+        }
+    }
+
+
+    /**
+     * Register annotations like MainValues for later plotting
+     *
+     * @param annotations list of annotations (data of facet).
+     * @param aandf   Artifact and the facet.
+     * @param theme   Theme document for given annotations.
+     * @param visible The visibility of the annotations.
+     */
+    protected void doAnnotations(
+        FLYSAnnotation annotations,
+        ArtifactAndFacet aandf,
+        Document theme,
+        boolean visible
+    ){
+        logger.debug("doAnnotations");
+
+        // Add all annotations to our annotation pool.
+        annotations.setTheme(theme);
+        if (aandf != null) {
+            annotations.setLabel(aandf.getFacetDescription());
+        }
+        else {
+            logger.debug(
+                "Art/Facet for Annotations is null. " +
+                "This should never happen!");
+        }
+
+        if (visible) {
+            addAnnotations(annotations);
+        }
+    }
+
+
+    /**
+     * Generate chart.
+     */
+    @Override
+    public void generate()
+    throws IOException
+    {
+        logger.debug("ChartGenerator.generate");
+
+        JFreeChart chart = generateChart();
+
+        String format = getFormat();
+        int[]  size   = getSize();
+
+        if (size == null) {
+            size = getExportDimension();
+        }
+
+        context.putContextValue("chart.width",  size[0]);
+        context.putContextValue("chart.height", size[1]);
+
+        if (format.equals(ChartExportHelper.FORMAT_PNG)) {
+            context.putContextValue("chart.image.format", "png");
+
+            ChartExportHelper.exportImage(
+                out,
+                chart,
+                context);
+        }
+        else if (format.equals(ChartExportHelper.FORMAT_PDF)) {
+            preparePDFContext(context);
+
+            ChartExportHelper.exportPDF(
+                out,
+                chart,
+                context);
+        }
+        else if (format.equals(ChartExportHelper.FORMAT_SVG)) {
+            prepareSVGContext(context);
+
+            ChartExportHelper.exportSVG(
+                out,
+                chart,
+                context);
+        }
+        else if (format.equals(ChartExportHelper.FORMAT_CSV)) {
+            context.putContextValue("chart.image.format", "csv");
+
+            ChartExportHelper.exportCSV(
+                out,
+                chart,
+                context);
+        }
+    }
+
+
+    @Override
     public void init(Document request, OutputStream out, CallContext context) {
         logger.debug("ChartGenerator.init");
 
@@ -91,18 +694,191 @@
     }
 
 
+    @Override
     public void setMasterArtifact(Artifact master) {
         this.master = master;
     }
 
 
     @Override
+    public void setCollection(FLYSArtifactCollection collection) {
+        this.collection = collection;
+    }
+
+
+    @Override
     public void setSettings(Settings settings) {
         this.settings = settings;
     }
 
 
     /**
+     * Returns an instance of <i>ChartSettings</i> with a chart specific section
+     * but with no axes settings.
+     *
+     * @return an instance of <i>ChartSettings</i>.
+     */
+    @Override
+    public Settings getSettings() {
+        if (this.settings != null) {
+            return this.settings;
+        }
+
+        ChartSettings settings = new ChartSettings();
+
+        ChartSection  chartSection  = buildChartSection();
+        LegendSection legendSection = buildLegendSection();
+        ExportSection exportSection = buildExportSection();
+
+        settings.setChartSection(chartSection);
+        settings.setLegendSection(legendSection);
+        settings.setExportSection(exportSection);
+
+        List<AxisSection> axisSections = buildAxisSections();
+        for (AxisSection axisSection: axisSections) {
+            settings.addAxisSection(axisSection);
+        }
+
+        return settings;
+    }
+
+
+    /**
+     * Creates a new <i>ChartSection</i>.
+     *
+     * @return a new <i>ChartSection</i>.
+     */
+    protected ChartSection buildChartSection() {
+        ChartSection chartSection = new ChartSection();
+        chartSection.setTitle(getChartTitle());
+        chartSection.setSubtitle(getChartSubtitle());
+        chartSection.setDisplayGrid(isGridVisible());
+        chartSection.setDisplayLogo(showLogo());
+        chartSection.setLogoVPlacement(logoVPlace());
+        chartSection.setLogoHPlacement(logoHPlace());
+        return chartSection;
+    }
+
+
+    /**
+     * Creates a new <i>LegendSection</i>.
+     *
+     * @return a new <i>LegendSection</i>.
+     */
+    protected LegendSection buildLegendSection() {
+        LegendSection legendSection = new LegendSection();
+        legendSection.setVisibility(isLegendVisible());
+        legendSection.setFontSize(getLegendFontSize());
+        legendSection.setAggregationThreshold(10);
+        return legendSection;
+    }
+
+
+    /**
+     * Creates a new <i>ExportSection</i> with default values <b>WIDTH=600</b>
+     * and <b>HEIGHT=400</b>.
+     *
+     * @return a new <i>ExportSection</i>.
+     */
+    protected ExportSection buildExportSection() {
+        ExportSection exportSection = new ExportSection();
+        exportSection.setWidth(600);
+        exportSection.setHeight(400);
+        return exportSection;
+    }
+
+
+    /**
+     * Creates a list of Sections that contains all axes of the chart (including
+     * X and Y axes).
+     *
+     * @return a list of Sections for each axis in this chart.
+     */
+    protected List<AxisSection> buildAxisSections() {
+        List<AxisSection> axisSections = new ArrayList<AxisSection>();
+
+        axisSections.addAll(buildXAxisSections());
+        axisSections.addAll(buildYAxisSections());
+
+        return axisSections;
+    }
+
+
+    /**
+     * Creates a new Section for chart's X axis.
+     *
+     * @return a List that contains a Section for the X axis.
+     */
+    protected List<AxisSection> buildXAxisSections() {
+        List<AxisSection> axisSections = new ArrayList<AxisSection>();
+
+        String identifier = "X";
+
+        AxisSection axisSection = new AxisSection();
+        axisSection.setIdentifier(identifier);
+        axisSection.setLabel(getXAxisLabel());
+        axisSection.setFontSize(14);
+        axisSection.setFixed(false);
+
+        // XXX We are able to find better default ranges that [0,0], but the Y
+        // axes currently have no better ranges set.
+        axisSection.setUpperRange(0d);
+        axisSection.setLowerRange(0d);
+
+        axisSections.add(axisSection);
+
+        return axisSections;
+    }
+
+
+    /**
+     * Creates a list of Section for the chart's Y axes. This method makes use
+     * of <i>getYAxisWalker</i> to be able to access all Y axes defined in
+     * subclasses.
+     *
+     * @return a list of Y axis sections.
+     */
+    protected List<AxisSection> buildYAxisSections() {
+        List<AxisSection> axisSections = new ArrayList<AxisSection>();
+
+        YAxisWalker walker = getYAxisWalker();
+        for (int i = 0, n = walker.length(); i < n; i++) {
+            AxisSection ySection = new AxisSection();
+            ySection.setIdentifier(walker.getId(i));
+            ySection.setLabel(getYAxisLabel(i));
+            ySection.setFontSize(14);
+            ySection.setFixed(false);
+
+            // XXX We are able to find better default ranges that [0,0], the
+            // only problem is, that we do NOT have a better range than [0,0]
+            // for each axis, because the initial chart will not have a dataset
+            // for each axis set!
+            ySection.setUpperRange(0d);
+            ySection.setLowerRange(0d);
+
+            axisSections.add(ySection);
+        }
+
+        return axisSections;
+    }
+
+
+    /**
+     * Returns the <i>settings</i> as <i>ChartSettings</i>.
+     *
+     * @return the <i>settings</i> as <i>ChartSettings</i> or null, if
+     * <i>settings</i> is not an instance of <i>ChartSettings</i>.
+     */
+    public ChartSettings getChartSettings() {
+        if (settings instanceof ChartSettings) {
+            return (ChartSettings) settings;
+        }
+
+        return null;
+    }
+
+
+    /**
      * Returns the chart title provided by <i>settings</i>.
      *
      * @param settings A ChartSettings object.
@@ -188,6 +964,397 @@
     }
 
 
+    /**
+     * Returns the title of a chart. The return value depends on the existence
+     * of ChartSettings: if there are ChartSettings set, this method returns the
+     * chart title provided by those settings. Otherwise, this method returns
+     * getDefaultChartTitle().
+     *
+     * @return the title of a chart.
+     */
+    protected String getChartTitle() {
+        ChartSettings chartSettings = getChartSettings();
+
+        if (chartSettings != null) {
+            return getChartTitle(chartSettings);
+        }
+
+        return getDefaultChartTitle();
+    }
+
+
+    /**
+     * Returns the subtitle of a chart. The return value depends on the
+     * existence of ChartSettings: if there are ChartSettings set, this method
+     * returns the chart title provided by those settings. Otherwise, this
+     * method returns getDefaultChartSubtitle().
+     *
+     * @return the subtitle of a chart.
+     */
+    protected String getChartSubtitle() {
+        ChartSettings chartSettings = getChartSettings();
+
+        if (chartSettings != null) {
+            return getChartSubtitle(chartSettings);
+        }
+
+        return getDefaultChartSubtitle();
+    }
+
+
+    /**
+     * This method always returns null. Override it in subclasses that require
+     * subtitles.
+     *
+     * @return null.
+     */
+    protected String getDefaultChartSubtitle() {
+        // Override this method in subclasses
+        return null;
+    }
+
+
+    /**
+     * This method is used to determine, if the chart's legend is visible or
+     * not. If a <i>settings</i> instance is set, this instance determines the
+     * visibility otherwise, this method returns true as default if no
+     * <i>settings</i> is set.
+     *
+     * @return true, if the legend should be visible, otherwise false.
+     */
+    protected boolean isLegendVisible() {
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings != null) {
+            return isLegendVisible(chartSettings);
+        }
+
+        return true;
+    }
+
+
+    /** Where to place the logo. */
+    protected String logoHPlace() {
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings != null) {
+            ChartSection cs    = chartSettings.getChartSection();
+            String       place = cs.getLogoHPlacement();
+
+            return place;
+        }
+        return "center";
+    }
+
+
+    /** Where to place the logo. */
+    protected String logoVPlace() {
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings != null) {
+            ChartSection cs    = chartSettings.getChartSection();
+            String       place = cs.getLogoVPlacement();
+
+            return place;
+        }
+        return "top";
+    }
+
+
+    /** Return the logo id from settings. */
+    protected String showLogo(ChartSettings chartSettings) {
+        if (chartSettings != null) {
+            ChartSection cs   = chartSettings.getChartSection();
+            String       logo = cs.getDisplayLogo();
+
+            return logo;
+        }
+        return "none";
+    }
+
+
+    /**
+     * This method is used to determine if a logo should be added to the plot.
+     *
+     * @return logo name (null if none).
+     */
+    protected String showLogo() {
+        ChartSettings chartSettings = getChartSettings();
+        return showLogo(chartSettings);
+    }
+
+
+    /**
+     * This method is used to determine the font size of the chart's legend. If
+     * a <i>settings</i> instance is set, this instance determines the font
+     * size, otherwise this method returns 12 as default if no <i>settings</i>
+     * is set or if it doesn't provide a legend font size.
+     *
+     * @return a legend font size.
+     */
+    protected int getLegendFontSize() {
+        Integer fontSize = null;
+
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings != null) {
+            fontSize = getLegendFontSize(chartSettings);
+        }
+
+        return fontSize != null ? fontSize : DEFAULT_FONT_SIZE;
+    }
+
+
+    /**
+     * This method is used to determine if the resulting chart should display
+     * grid lines or not. <b>Note: this method always returns true!</b>
+     *
+     * @return true, if the chart should display grid lines, otherwise false.
+     */
+    protected boolean isGridVisible() {
+        return true;
+    }
+
+
+    /**
+     * Returns the X-Axis label of a chart.
+     *
+     * @return the X-Axis label of a chart.
+     */
+    protected String getXAxisLabel() {
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings == null) {
+            return getDefaultXAxisLabel();
+        }
+
+        AxisSection as = chartSettings.getAxisSection("X");
+        if (as != null) {
+            String label = as.getLabel();
+
+            if (label != null) {
+                return label;
+            }
+        }
+
+        return getDefaultXAxisLabel();
+    }
+
+
+    /**
+     * This method returns the font size for the X axis. If the font size is
+     * specified in ChartSettings (if <i>chartSettings</i> is set), this size is
+     * returned. Otherwise the default font size 12 is returned.
+     *
+     * @return the font size for the x axis.
+     */
+    protected int getXAxisLabelFontSize() {
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings == null) {
+            return DEFAULT_FONT_SIZE;
+        }
+
+        AxisSection   as = chartSettings.getAxisSection("X");
+        Integer fontSize = as.getFontSize();
+
+        return fontSize != null ? fontSize : DEFAULT_FONT_SIZE;
+    }
+
+
+    /**
+     * This method returns the font size for an Y axis. If the font size is
+     * specified in ChartSettings (if <i>chartSettings</i> is set), this size is
+     * returned. Otherwise the default font size 12 is returned.
+     *
+     * @return the font size for the x axis.
+     */
+    protected int getYAxisFontSize(int pos) {
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings == null) {
+            return DEFAULT_FONT_SIZE;
+        }
+
+        YAxisWalker walker = getYAxisWalker();
+
+        AxisSection   as = chartSettings.getAxisSection(walker.getId(pos));
+        Integer fontSize = as.getFontSize();
+
+        return fontSize != null ? fontSize : DEFAULT_FONT_SIZE;
+    }
+
+
+    /**
+     * This method returns the export dimension specified in ChartSettings as
+     * int array [width,height].
+     *
+     * @return an int array with [width,height].
+     */
+    protected int[] getExportDimension() {
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings == null) {
+            return new int[] { 600, 400 };
+        }
+
+        ExportSection export = chartSettings.getExportSection();
+        Integer width  = export.getWidth();
+        Integer height = export.getHeight();
+
+        if (width != null && height != null) {
+            return new int[] { width, height };
+        }
+
+        return new int[] { 600, 400 };
+    }
+
+
+    /**
+     * Returns the Y-Axis label of a chart at position <i>pos</i>.
+     *
+     * @return the Y-Axis label of a chart at position <i>0</i>.
+     */
+    protected String getYAxisLabel(int pos) {
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings == null) {
+            return getDefaultYAxisLabel(pos);
+        }
+
+        YAxisWalker walker = getYAxisWalker();
+        AxisSection     as = chartSettings.getAxisSection(walker.getId(pos));
+        if (as != null) {
+            String label = as.getLabel();
+
+            if (label != null) {
+                return label;
+            }
+        }
+
+        return getDefaultYAxisLabel(pos);
+    }
+
+
+    /**
+     * This method searches for a specific axis in the <i>settings</i> if
+     * <i>settings</i> is set. If the axis was found, this method returns the
+     * specified axis range if the axis range is fixed. Otherwise, this method
+     * returns null.
+     *
+     * @param axisId The identifier of an axis.
+     *
+     * @return the specified axis range from <i>settings</i> if the axis is
+     * fixed, otherwise null.
+     */
+    public Range getRangeForAxisFromSettings(String axisId) {
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings == null) {
+            return null;
+        }
+
+        AxisSection as = chartSettings.getAxisSection(axisId);
+        Boolean  fixed = as.isFixed();
+
+        if (fixed != null && fixed) {
+            Double upper = as.getUpperRange();
+            Double lower = as.getLowerRange();
+
+            if (upper != null && lower != null) {
+                return lower < upper
+                    ? new Range(lower, upper)
+                    : new Range(upper, lower);
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Adds a new AxisDataset which contains <i>dataset</i> at index <i>idx</i>.
+     *
+     * @param dataset An XYDataset.
+     * @param idx The axis index.
+     * @param visible Determines, if the dataset should be visible or not.
+     */
+    public void addAxisDataset(XYDataset dataset, int idx, boolean visible) {
+        if (dataset == null || idx < 0) {
+            return;
+        }
+
+        AxisDataset axisDataset = getAxisDataset(idx);
+
+        Bounds[] xyBounds = ChartHelper.getBounds(dataset);
+
+        if (xyBounds == null) {
+            logger.warn("Skip XYDataset for Axis (invalid ranges): " + idx);
+            return;
+        }
+
+        if (visible) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("Add new AxisDataset at index: " + idx);
+                logger.debug("X extent: " + xyBounds[0]);
+                logger.debug("Y extent: " + xyBounds[1]);
+            }
+
+            axisDataset.addDataset(dataset);
+        }
+
+        combineXBounds(xyBounds[0], 0);
+        combineYBounds(xyBounds[1], idx);
+    }
+
+
+    /**
+     * This method grants access to the AxisDatasets stored in <i>datasets</i>.
+     * If no AxisDataset exists for index <i>idx</i>, a new AxisDataset is
+     * created using <i>createAxisDataset()</i>.
+     *
+     * @param idx The index of the desired AxisDataset.
+     *
+     * @return an existing or new AxisDataset.
+     */
+    public AxisDataset getAxisDataset(int idx) {
+        AxisDataset axisDataset = datasets.get(idx);
+
+        if (axisDataset == null) {
+            axisDataset = createAxisDataset(idx);
+            datasets.put(idx, axisDataset);
+        }
+
+        return axisDataset;
+    }
+
+
+    /**
+     * Adjust some Stroke/Grid parameters for <i>plot</i>. The chart
+     * <i>Settings</i> are applied in this method.
+     *
+     * @param plot The XYPlot which is adapted.
+     */
+    protected void adjustPlot(XYPlot plot) {
+        Stroke gridStroke = new BasicStroke(
+            DEFAULT_GRID_LINE_WIDTH,
+            BasicStroke.CAP_BUTT,
+            BasicStroke.JOIN_MITER,
+            3.0f,
+            new float[] { 3.0f },
+            0.0f);
+
+        ChartSettings      cs = getChartSettings();
+        boolean isGridVisible = cs != null ? isGridVisible(cs) : true;
+
+        plot.setDomainGridlineStroke(gridStroke);
+        plot.setDomainGridlinePaint(DEFAULT_GRID_COLOR);
+        plot.setDomainGridlinesVisible(isGridVisible);
+
+        plot.setRangeGridlineStroke(gridStroke);
+        plot.setRangeGridlinePaint(DEFAULT_GRID_COLOR);
+        plot.setRangeGridlinesVisible(isGridVisible);
+
+        plot.setAxisOffset(new RectangleInsets(0d, 0d, 0d, 0d));
+    }
+
+
+    /**
+     * This helper mehtod is used to extract the current locale from instance
+     * vairable <i>context</i>.
+     *
+     * @return the current locale.
+     */
     protected Locale getLocale() {
         CallMeta           meta = context.getMeta();
         PreferredLocale[] prefs = meta.getLanguages();
@@ -208,6 +1375,9 @@
         return Resources.getMsg(context.getMeta(), key, def);
     }
 
+    protected String msg(String key) {
+        return Resources.getMsg(context.getMeta(), key, key);
+    }
 
     protected String msg(String key, String def, Object[] args) {
         return Resources.getMsg(context.getMeta(), key, def, args);
@@ -215,7 +1385,7 @@
 
 
     protected String getRiverName() {
-        WINFOArtifact flys = (WINFOArtifact) master;
+        FLYSArtifact flys = (FLYSArtifact) master;
 
         River river = FLYSUtils.getRiver(flys);
         return (river != null) ? river.getName() : "";
@@ -223,7 +1393,7 @@
 
 
     protected double[] getRange() {
-        WINFOArtifact flys = (WINFOArtifact) master;
+        FLYSArtifact flys = (FLYSArtifact) master;
 
         return FLYSUtils.getKmRange(flys);
     }
@@ -266,6 +1436,13 @@
     }
 
 
+    /**
+     * This method returns the format specified in the <i>request</i> document
+     * or <i>DEFAULT_CHART_FORMAT</i> if no format is specified in
+     * <i>request</i>.
+     *
+     * @return the format used to export this chart.
+     */
     protected String getFormat() {
         String format = (String) XMLUtils.xpath(
             request,
@@ -280,9 +1457,11 @@
 
 
     /**
-     * Get Range of Domain ("X"-) Axis from request.
+     * Returns the X-Axis range as String array from request document.
+     *
+     * @return a String array with [lower, upper].
      */
-    protected Range getDomainAxisRange() {
+    protected String[] getDomainAxisRangeFromRequest() {
         Element xrange = (Element)XMLUtils.xpath(
             request,
             XPATH_CHART_X_RANGE,
@@ -298,34 +1477,11 @@
         String lower = xrange.getAttributeNS(uri, "from");
         String upper = xrange.getAttributeNS(uri, "to");
 
-        if (lower.length() > 0 && upper.length() > 0) {
-            try {
-                double from = Double.parseDouble(lower);
-                double to   = Double.parseDouble(upper);
-
-                if (from == 0 && to == 0) {
-                    logger.debug("No range specified. Lower and upper X == 0");
-                    return null;
-                }
-
-                if (from > to) {
-                    double tmp = to;
-                    to         = from;
-                    from       = tmp;
-                }
-
-                return new Range(from, to);
-            }
-            catch (NumberFormatException nfe) {
-                logger.warn("Wrong values for domain axis range.");
-            }
-        }
-
-        return null;
+        return new String[] { lower, upper };
     }
 
 
-    protected Range getValueAxisRange() {
+    protected String[] getValueAxisRangeFromRequest() {
         Element yrange = (Element)XMLUtils.xpath(
             request,
             XPATH_CHART_Y_RANGE,
@@ -339,30 +1495,10 @@
 
         String uri = ArtifactNamespaceContext.NAMESPACE_URI;
 
-
         String lower = yrange.getAttributeNS(uri, "from");
         String upper = yrange.getAttributeNS(uri, "to");
 
-        if (lower.length() > 0 && upper.length() > 0) {
-            try {
-                double from = Double.parseDouble(lower);
-                double to   = Double.parseDouble(upper);
-
-                if (from == 0 && to == 0) {
-                    logger.debug("No range specified. Lower and upper Y == 0");
-                    return null;
-                }
-
-                return from > to
-                       ? new Range(to, from)
-                       : new Range(from, to);
-            }
-            catch (NumberFormatException nfe) {
-                logger.warn("Wrong values for value axis range.");
-            }
-        }
-
-        return null;
+        return new String[] { lower, upper };
     }
 
 
@@ -376,36 +1512,360 @@
     }
 
 
-    public abstract void doOut(
-        ArtifactAndFacet bundle,
-        Document attr,
-        boolean  visible);
-
-    public abstract void generate() throws IOException;
+    /**
+     * Add datasets stored in instance variable <i>datasets</i> to plot.
+     * <i>datasets</i> actually stores instances of AxisDataset, so each of this
+     * datasets is mapped to a specific axis as well.
+     *
+     * @param plot plot to add datasets to.
+     */
+    protected void addDatasets(XYPlot plot) {
+        logger.debug("addDatasets()");
 
+        // AxisDatasets are sorted, but some might be empty.
+        // Thus, generate numbering on the fly.
+        int axisIndex    = 0;
+        int datasetIndex = 0;
 
-    /**
-     * Returns an instance of <i>EmptySettings</i> currently!
-     *
-     * @return an instance of <i>EmptySettings</i>.
-     */
-    public Settings getSettings() {
-        return settings != null ? settings : new EmptySettings();
+        for (Map.Entry<Integer, AxisDataset> entry: datasets.entrySet()) {
+            if (!entry.getValue().isEmpty()) {
+                // Add axis and range information.
+                AxisDataset axisDataset = entry.getValue();
+                NumberAxis  axis        = createYAxis(entry.getKey());
+
+                plot.setRangeAxis(axisIndex, axis);
+
+                if (axis.getAutoRangeIncludesZero()) {
+                    axisDataset.setRange(
+                        Range.expandToInclude(axisDataset.getRange(), 0d));
+                }
+
+                setYBounds(axisIndex, expandPointRange(axisDataset.getRange()));
+
+                // Add contained datasets, mapping to axis.
+                for (XYDataset dataset: axisDataset.getDatasets()) {
+                    plot.setDataset(datasetIndex, dataset);
+                    plot.mapDatasetToRangeAxis(datasetIndex, axisIndex);
+
+                    applyThemes(plot, dataset,
+                        datasetIndex,
+                        axisDataset.isArea(dataset));
+
+                    datasetIndex++;
+                }
+
+                axisDataset.setPlotAxisIndex(axisIndex);
+                axisIndex++;
+            }
+        }
     }
 
 
     /**
-     * Returns the <i>settings</i> as <i>ChartSettings</i>.
+     * @param idx "index" of dataset/series (first dataset to be drawn has
+     *            index 0), correlates with renderer index.
+     * @param isArea true if the series describes an area and shall be rendered
+     *                as such.
+     */
+    protected void applyThemes(
+        XYPlot    plot,
+        XYDataset series,
+        int       idx,
+        boolean   isArea
+    ) {
+        if (isArea) {
+            applyAreaTheme(plot, (StyledAreaSeriesCollection) series, idx);
+        }
+        else {
+            applyLineTheme(plot, series, idx);
+        }
+    }
+
+
+    /**
+     * This method applies the themes defined in the series itself. Therefore,
+     * <i>StyledXYSeries.applyTheme()</i> is called, which modifies the renderer
+     * for the series.
      *
-     * @return the <i>settings</i> as <i>ChartSettings</i> or null, if
-     * <i>settings</i> is not an instance of <i>ChartSettings</i>.
+     * @param plot The plot.
+     * @param dataset The XYDataset which needs to support Series objects.
+     * @param idx The index of the renderer / dataset.
      */
-    public ChartSettings getChartSettings() {
-        if (settings instanceof ChartSettings) {
-            return (ChartSettings) settings;
+    protected void applyLineTheme(XYPlot plot, XYDataset dataset, int idx) {
+        logger.debug("Apply LineTheme for dataset at index: " + idx);
+
+        LegendItemCollection lic  = new LegendItemCollection();
+        LegendItemCollection anno = plot.getFixedLegendItems();
+
+        Font legendFont = createLegendLabelFont();
+
+        XYLineAndShapeRenderer renderer = createRenderer(plot, idx);
+
+        for (int s = 0, num = dataset.getSeriesCount(); s < num; s++) {
+            Series series = getSeriesOf(dataset, s);
+
+            if (series instanceof StyledSeries) {
+                Style style = ((StyledSeries) series).getStyle();
+                style.applyTheme(renderer, s);
+            }
+
+            // special case: if there is just one single item, we need to enable
+            // points for this series, otherwise we would not see anything in
+            // the chart area.
+            if (series.getItemCount() == 1) {
+                renderer.setSeriesShapesVisible(s, true);
+            }
+
+            LegendItem legendItem = renderer.getLegendItem(idx, s);
+            if (legendItem.getLabel().endsWith(" ") ||
+                legendItem.getLabel().endsWith("interpol")) {
+                legendItem = null;
+            }
+
+            if (legendItem != null) {
+                legendItem.setLabelFont(legendFont);
+                lic.add(legendItem);
+            }
+            else {
+                logger.warn("Could not get LegentItem for renderer: "
+                    + idx + ", series-idx " + s);
+            }
         }
 
-        return null;
+        if (anno != null) {
+            lic.addAll(anno);
+        }
+
+        plot.setFixedLegendItems(lic);
+
+        plot.setRenderer(idx, renderer);
+    }
+
+
+    /**
+     * @param plot The plot.
+     * @param area A StyledAreaSeriesCollection object.
+     * @param idx The index of the dataset.
+     */
+    protected void applyAreaTheme(
+        XYPlot                     plot,
+        StyledAreaSeriesCollection area,
+        int                        idx
+    ) {
+        LegendItemCollection lic  = new LegendItemCollection();
+        LegendItemCollection anno = plot.getFixedLegendItems();
+
+        Font legendFont = createLegendLabelFont();
+
+        logger.debug("Registering an 'area'renderer at idx: " + idx);
+
+        StableXYDifferenceRenderer dRenderer =
+            new StableXYDifferenceRenderer();
+
+        if (area.getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) {
+            dRenderer.setPositivePaint(createTransparentPaint());
+        }
+
+        plot.setRenderer(idx, dRenderer);
+
+        area.applyTheme(dRenderer);
+
+        // i18n
+        dRenderer.setAreaLabelNumberFormat(Formatter.getFormatter(context.getMeta(), 2, 4));
+
+        dRenderer.setAreaLabelTemplate(Resources.getMsg(
+            context.getMeta(), "area.label.template", "Area=%sm2"));
+
+        LegendItem legendItem = dRenderer.getLegendItem(idx, 0);
+        if (legendItem != null) {
+            legendItem.setLabelFont(legendFont);
+            lic.add(legendItem);
+        }
+        else {
+            logger.warn("Could not get LegentItem for renderer: "
+                + idx + ", series-idx " + 0);
+        }
+
+        if (anno != null) {
+            lic.addAll(anno);
+        }
+
+        plot.setFixedLegendItems(lic);
+    }
+
+
+    /**
+     * Expands a given range if it collapses into one point.
+     *
+     * @param range Range to be expanded if upper == lower bound.
+     *
+     * @return Bounds of point plus 5 percent in each direction.
+     */
+    private Bounds expandPointRange(Range range) {
+        if (range == null) {
+            return null;
+        }
+        else if (range.getLowerBound() == range.getUpperBound()) {
+            Range expandedRange = ChartHelper.expandRange(range, 5d);
+            return new DoubleBounds(expandedRange.getLowerBound(), expandedRange.getUpperBound());
+        }
+
+        return new DoubleBounds(range.getLowerBound(), range.getUpperBound());
+    }
+
+
+    /**
+     * Creates a new instance of EnhancedLineAndShapeRenderer.
+     *
+     * @param plot The plot which is set for the new renderer.
+     * @param idx This value is not used in the current implementation.
+     *
+     * @return a new instance of EnhancedLineAndShapeRenderer.
+     */
+    protected XYLineAndShapeRenderer createRenderer(XYPlot plot, int idx) {
+        logger.debug("Create EnhancedLineAndShapeRenderer for idx: " + idx);
+
+        EnhancedLineAndShapeRenderer r =
+            new EnhancedLineAndShapeRenderer(true, false);
+
+        r.setPlot(plot);
+
+        return r;
+    }
+
+
+    /**
+     * Creates a new instance of <i>IdentifiableNumberAxis</i>.
+     *
+     * @param idx The index of the new axis.
+     * @param label The label of the new axis.
+     *
+     * @return an instance of IdentifiableNumberAxis.
+     */
+    protected NumberAxis createNumberAxis(int idx, String label) {
+        YAxisWalker walker = getYAxisWalker();
+
+        return new IdentifiableNumberAxis(walker.getId(idx), label);
+    }
+
+
+    /**
+     * Create Y (range) axis for given index.
+     * Shall be overriden by subclasses.
+     */
+    protected NumberAxis createYAxis(int index) {
+        YAxisWalker walker = getYAxisWalker();
+
+        Font labelFont = new Font(
+            DEFAULT_FONT_NAME,
+            Font.BOLD,
+            getYAxisFontSize(index));
+
+        IdentifiableNumberAxis axis = new IdentifiableNumberAxis(
+            walker.getId(index),
+            getYAxisLabel(index));
+
+        axis.setAutoRangeIncludesZero(false);
+        axis.setLabelFont(labelFont);
+        axis.setTickLabelFont(labelFont);
+
+        return axis;
+    }
+
+
+    /**
+     * Creates a new LegendItem with <i>name</i> and font provided by
+     * <i>createLegendLabelFont()</i>.
+     *
+     * @param theme The theme of the chart line.
+     * @param name The displayed name of the item.
+     *
+     * @return a new LegendItem instance.
+     */
+    public LegendItem createLegendItem(Document theme, String name) {
+        // OPTIMIZE Pass font, parsed Theme items.
+        ThemeAccess themeAccess = new ThemeAccess(theme);
+
+        Color      color       = themeAccess.parseLineColorField();
+        LegendItem legendItem  = new LegendItem(name, color);
+
+        legendItem.setLabelFont(createLegendLabelFont());
+        return legendItem;
+    }
+
+
+    /**
+     * Creates Font (Family and size) to use when creating Legend Items. The
+     * font size depends in the return value of <i>getLegendFontSize()</i>.
+     *
+     * @return a new Font instance with <i>DEFAULT_FONT_NAME</i>.
+     */
+    protected Font createLegendLabelFont() {
+        return new Font(
+            DEFAULT_FONT_NAME,
+            Font.PLAIN,
+            getLegendFontSize()
+        );
+    }
+
+
+    /**
+     * Create new legend entries, dependent on settings.
+     * @param plot The plot for which to modify the legend.
+     */
+    public void aggregateLegendEntries(XYPlot plot) {
+        int AGGR_THRESHOLD = 0;
+
+        if (getChartSettings() == null) {
+            return;
+        }
+        Integer threshold = getChartSettings().getLegendSection()
+            .getAggregationThreshold();
+
+        AGGR_THRESHOLD = (threshold != null) ? threshold.intValue() : 0;
+
+        LegendProcessor.aggregateLegendEntries(plot, AGGR_THRESHOLD);
+    }
+
+
+    /**
+     * Returns a transparently textured paint.
+     *
+     * @return a transparently textured paint.
+     */
+    protected static Paint createTransparentPaint() {
+        // TODO why not use a transparent color?
+        BufferedImage texture = new BufferedImage(
+            1, 1, BufferedImage.TYPE_4BYTE_ABGR);
+
+        return new TexturePaint(
+            texture, new Rectangle2D.Double(0d, 0d, 0d, 0d));
+    }
+
+
+    protected void preparePDFContext(CallContext context) {
+        int[] dimension = getExportDimension();
+
+        context.putContextValue("chart.width", dimension[0]);
+        context.putContextValue("chart.height", dimension[1]);
+        context.putContextValue("chart.marginLeft",   5f);
+        context.putContextValue("chart.marginRight",  5f);
+        context.putContextValue("chart.marginTop",    5f);
+        context.putContextValue("chart.marginBottom", 5f);
+        context.putContextValue(
+            "chart.page.format",
+            ChartExportHelper.DEFAULT_PAGE_SIZE);
+    }
+
+
+    protected void prepareSVGContext(CallContext context) {
+        int[] dimension = getExportDimension();
+
+        context.putContextValue("chart.width", dimension[0]);
+        context.putContextValue("chart.height", dimension[1]);
+        context.putContextValue(
+            "chart.encoding",
+            ChartExportHelper.DEFAULT_ENCODING);
     }
 }
 // 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/exports/ChartHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,200 @@
+package de.intevation.flys.exports;
+
+import org.jfree.data.Range;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.data.xy.XYSeriesCollection;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.jfree.data.time.TimeSeries;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.jfree.Bounds;
+import de.intevation.flys.jfree.DoubleBounds;
+import de.intevation.flys.jfree.TimeBounds;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class ChartHelper {
+
+    private static final Logger logger = Logger.getLogger(ChartHelper.class);
+
+
+    /**
+     * This method returns the ranges of the XYDataset <i>dataset</i> as array
+     * with [xrange, yrange].
+     *
+     * @param dataset The dataset which should be evaluated.
+     *
+     * @return an array with x and y ranges.
+     */
+    public static Bounds[] getBounds(XYSeriesCollection dataset) {
+        int seriesCount = dataset != null ? dataset.getSeriesCount() : 0;
+
+        if (seriesCount == 0) {
+            logger.warn("Dataset is empty or has no Series set.");
+            return null;
+        }
+
+        boolean foundValue = false;
+
+        double minX = Double.MAX_VALUE;
+        double maxX = -Double.MAX_VALUE;
+        double minY = Double.MAX_VALUE;
+        double maxY = -Double.MAX_VALUE;
+
+        for (int i = 0, m = seriesCount; i < m; i++) {
+            for (int j = 0, n = dataset.getItemCount(i); j < n; j++) {
+                double x = dataset.getXValue(i, j);
+                double y = dataset.getYValue(i, j);
+
+                if (Double.isNaN(x) || Double.isNaN(y)) {
+                    logger.warn("Item " + j + " in Series " + i + " is broken");
+                    continue;
+                }
+
+                foundValue = true;
+
+                if (x < minX) {
+                    minX = x;
+                }
+
+                if (x > maxX) {
+                    maxX = x;
+                }
+
+                if (y < minY) {
+                    minY = y;
+                }
+
+                if (y > maxY) {
+                    maxY = y;
+                }
+            }
+        }
+
+        return foundValue
+            ? new Bounds[] {
+                    new DoubleBounds(minX, maxX),
+                    new DoubleBounds(minY, maxY) }
+            : null;
+    }
+
+
+    public static Bounds[] getBounds(XYDataset dataset) {
+        if (dataset instanceof XYSeriesCollection) {
+            return getBounds((XYSeriesCollection) dataset);
+        }
+        else if(dataset instanceof TimeSeriesCollection) {
+            return getBounds((TimeSeriesCollection) dataset);
+        }
+        else {
+            logger.warn("Unknown XYDataset instance: " + dataset.getClass());
+            return null;
+        }
+    }
+
+
+    public static Bounds[] getBounds(TimeSeriesCollection collection) {
+        int seriesCount = collection != null ? collection.getSeriesCount() : 0;
+
+        if (seriesCount == 0) {
+            logger.warn("TimeSeriesCollection is empty or has no Series set.");
+            return null;
+        }
+
+        boolean foundValue = false;
+
+        long lowerX = Long.MAX_VALUE;
+        long upperX = -Long.MAX_VALUE;
+
+        double lowerY = Double.MAX_VALUE;
+        double upperY = -Double.MAX_VALUE;
+
+        for (int i = 0, m = seriesCount; i < m; i++) {
+            TimeSeries series = collection.getSeries(i);
+
+            for (int j = 0, n = collection.getItemCount(i); j < n; j++) {
+                RegularTimePeriod rtp = series.getTimePeriod(j);
+
+                if (rtp == null) {
+                    continue;
+                }
+
+                foundValue = true;
+
+                long start = rtp.getFirstMillisecond();
+                long end   = rtp.getLastMillisecond();
+
+                if (start < lowerX) {
+                    lowerX = start;
+                }
+
+                if (end > upperX) {
+                    upperX = end;
+                }
+
+                double y = series.getValue(j).doubleValue();
+
+                lowerY = Math.min(lowerY, y);
+                upperY = Math.max(upperY, y);
+            }
+        }
+
+        if (foundValue) {
+            return new Bounds[] {
+                new TimeBounds(lowerX, upperX),
+                new DoubleBounds(lowerY, upperY)
+            };
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Expand bounds by percent.
+     *
+     * @param bounds The bounds to expand.
+     * @param percent The percentage to expand.
+     *
+     * @return a new, expanded bounds.
+     */
+    public static Bounds expandBounds(Bounds bounds, double percent) {
+        if (bounds == null) {
+            return null;
+        }
+
+        double value  = (Double) bounds.getLower();
+        double expand = Math.abs(value / 100 * percent);
+
+        return expand != 0
+            ? new DoubleBounds(value-expand, value+expand)
+            : new DoubleBounds(-0.01 * percent, 0.01 * percent);
+    }
+
+
+    /**
+     * Expand range by percent.
+     *
+     * @param range The range to expand.
+     * @param percent The percentage to expand.
+     *
+     * @return a new, expanded range.
+     */
+    public static Range expandRange(Range range, double percent) {
+        if (range == null) {
+            return null;
+        }
+
+        double value  = range.getLowerBound();
+        double expand = Math.abs(value / 100 * percent);
+
+        return expand != 0
+            ? new Range(value-expand, value+expand)
+            : new Range(-0.01 * percent, 0.01 * percent);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,6 @@
 package de.intevation.flys.exports;
 
+import de.intevation.flys.collections.FLYSArtifactCollection;
 import de.intevation.flys.java2d.NOPGraphics2D;
 
 import java.io.IOException;
@@ -32,7 +33,7 @@
  * An OutGenerator that generates meta information for charts. A concrete
  * ChartInfoGenerator need to instantiate a concrete ChartGenerator and dispatch
  * the methods to that instance. The only thing this ChartInfoGenerator needs
- * to, is to overrite the generate() method which doesn't write the chart image
+ * to, is to overwrite the generate() method which doesn't write the chart image
  * to the OutputStream but a Document that contains some meta information of the
  * created chart.
  *
@@ -49,13 +50,13 @@
 
 
     /** The OutGenerator that creates the charts.*/
-    protected XYChartGenerator generator;
+    protected ChartGenerator generator;
 
     protected OutputStream out;
 
 
 
-    public ChartInfoGenerator(XYChartGenerator generator) {
+    public ChartInfoGenerator(ChartGenerator generator) {
         this.generator = generator;
     }
 
@@ -86,6 +87,16 @@
 
     /**
      * Dispatches the operation to the instantiated generator.
+     *
+     * @param collection The collection.
+     */
+    public void setCollection(FLYSArtifactCollection collection) {
+        generator.setCollection(collection);
+    }
+
+
+    /**
+     * Dispatches the operation to the instantiated generator.
      */
     public void doOut(
         ArtifactAndFacet artifactFacet,
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartSection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartSection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,6 @@
 package de.intevation.flys.exports;
 
+import org.apache.log4j.Logger;
 
 
 /**
@@ -7,9 +8,14 @@
  */
 public class ChartSection extends TypeSection {
 
-    public static final String TITLE_ATTR       = "title";
-    public static final String SUBTITLE_ATTR    = "subtitle";
-    public static final String DISPLAYGRID_ATTR = "display-grid";
+    private static Logger logger = Logger.getLogger(ChartSection.class);
+
+    public static final String TITLE_ATTR         = "title";
+    public static final String SUBTITLE_ATTR      = "subtitle";
+    public static final String DISPLAYGRID_ATTR   = "display-grid";
+    public static final String DISPLAYLOGO_ATTR   = "display-logo";
+    public static final String LOGOPLACEMENTH_ATTR = "logo-placeh";
+    public static final String LOGOPLACEMENTV_ATTR = "logo-placev";
 
 
     public ChartSection() {
@@ -37,7 +43,44 @@
     }
 
 
-    public void setDisplayGird(boolean displayGrid) {
+    /** Get Property-value for display-logo property. */
+    public String getDisplayLogo() {
+        return getStringValue(DISPLAYLOGO_ATTR);
+    }
+
+
+    /** Set Property-value for display-logo property. */
+    public void setDisplayLogo(String logo) {
+        logger.debug("Setting Display logo string.");
+        setChoiceStringValue(DISPLAYLOGO_ATTR, logo, "logo");
+    }
+
+
+    /** Get Property-value for horizontal logo-placement property. */
+    public String getLogoHPlacement() {
+        return getStringValue(LOGOPLACEMENTH_ATTR);
+    }
+
+
+    /** Set Property-value for horizontal logo-placement property. */
+    public void setLogoHPlacement(String place) {
+        setChoiceStringValue(LOGOPLACEMENTH_ATTR, place, "placeh");
+    }
+
+
+    /** Get Property-value for vertical logo-placement property. */
+    public String getLogoVPlacement() {
+        return getStringValue(LOGOPLACEMENTV_ATTR);
+    }
+
+
+    /** Set Property-value for vertical logo-placement property. */
+    public void setLogoVPlacement(String place) {
+        setChoiceStringValue(LOGOPLACEMENTV_ATTR, place, "placev");
+    }
+
+
+    public void setDisplayGrid(boolean displayGrid) {
         setBooleanValue(DISPLAYGRID_ATTR, displayGrid);
     }
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartSettings.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChartSettings.java	Fri Sep 28 12:15:52 2012 +0200
@@ -215,31 +215,44 @@
 
         section.setIdentifier(id);
         section.setLabel(label);
-        section.setFontSize(Integer.valueOf(fSize.length() > 0 ? fSize : "-1"));
+        section.setFontSize(Integer.parseInt(fSize.length() > 0 ? fSize : "-1"));
         section.setFixed(Boolean.valueOf(fixation));
-        section.setLowerRange(Double.valueOf(low.length() > 0 ? low : "0"));
-        section.setUpperRange(Double.valueOf(up.length() > 0 ? up : "0"));
+        section.setLowerRange(Double.parseDouble(low.length() > 0 ? low : "0"));
+        section.setUpperRange(Double.parseDouble(up.length() > 0 ? up : "0"));
 
         target.addAxisSection(section);
     }
 
 
+    /**
+     * From document chart create ChartSection and populate it with attributes.
+     * Give this object to target as chartsection.
+     */
     protected static void parseChart(ChartSettings target, Node chart) {
         ChartSection chartSection = new ChartSection();
 
         String title = XMLUtils.xpathString(chart, "chart/title", null);
         String sub   = XMLUtils.xpathString(chart, "chart/subtitle", null);
         String grid  = XMLUtils.xpathString(chart, "chart/display-grid", null);
+        String logo  = XMLUtils.xpathString(chart, "chart/display-logo", null);
+        String placeh = XMLUtils.xpathString(chart, "chart/logo-placeh", null);
+        String placev = XMLUtils.xpathString(chart, "chart/logo-placev", null);
 
         if (logger.isDebugEnabled()) {
             logger.debug("Found chart title:    '" + title + "'");
             logger.debug("Found chart subtitle: '" + sub + "'");
             logger.debug("Found chart grid:     '" + grid + "'");
+            logger.debug("Found chart logo:     '" + logo + "'");
+            logger.debug("Found chart logo placeh: '" + placeh + "'");
+            logger.debug("Found chart logo placev: '" + placev + "'");
         }
 
         chartSection.setTitle(title);
         chartSection.setSubtitle(sub);
-        chartSection.setDisplayGird(Boolean.valueOf(grid));
+        chartSection.setDisplayGrid(Boolean.valueOf(grid));
+        chartSection.setDisplayLogo(logo);
+        chartSection.setLogoHPlacement(placeh);
+        chartSection.setLogoVPlacement(placev);
 
         target.setChartSection(chartSection);
     }
@@ -250,14 +263,17 @@
 
         String vis   = XMLUtils.xpathString(legend, "legend/visibility", null);
         String fSize = XMLUtils.xpathString(legend, "legend/font-size", null);
+        String lthre = XMLUtils.xpathString(legend, "legend/aggregation-threshold", null);
 
         if (logger.isDebugEnabled()) {
             logger.debug("Found legend visibility: '" + vis + "'");
             logger.debug("Found legend font size : '" + fSize + "'");
+            logger.debug("Found legend aggregation threshold : '" + lthre + "'");
         }
 
         section.setVisibility(Boolean.valueOf(vis));
         section.setFontSize(Integer.valueOf(fSize.length() > 0 ? fSize : "-1"));
+        section.setAggregationThreshold(Integer.valueOf(lthre.length() >0 ? lthre : "-1"));
 
         target.setLegendSection(section);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ChoiceStringAttribute.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,45 @@
+package de.intevation.flys.exports;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class ChoiceStringAttribute extends StringAttribute {
+
+    /** Indicator which type of choice is dealt with. */
+    protected String choiceType;
+
+
+    public ChoiceStringAttribute(String name,
+                           String value,
+                           boolean visible,
+                           String choiceType) {
+        super(name, value, visible);
+        this.choiceType = choiceType;
+    }
+
+
+    /**
+     * Calls VisibleAttribute.toXML() and appends afterwards an attribute
+     * <i>type</i> with value <i>string</i>.
+     *
+     * @param parent The parent Node.
+     *
+     * @return the new Node that represents this Attribute.
+     */
+    @Override
+    public Node toXML(Node parent) {
+        Document owner = parent.getOwnerDocument();
+
+        Element ele = (Element) super.toXML(parent);
+        ele.setAttribute("type", "string");
+        ele.setAttribute("choice", choiceType);
+
+        return ele;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,6 +5,11 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Date;
+import java.text.DateFormat;
+import java.util.Locale;
 
 import org.w3c.dom.Document;
 
@@ -12,11 +17,24 @@
 
 import au.com.bytecode.opencsv.CSVWriter;
 
+import net.sf.jasperreports.engine.JasperExportManager;
+import net.sf.jasperreports.engine.JasperFillManager;
+import net.sf.jasperreports.engine.JasperPrint;
+import net.sf.jasperreports.engine.JRException;
+
+import de.intevation.artifacts.common.utils.Config;
+
 import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
 
 import de.intevation.flys.artifacts.model.CalculationResult;
 import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.WKmsJRDataSource;
+import de.intevation.flys.artifacts.resources.Resources;
 
+import de.intevation.flys.utils.FLYSUtils;
 import de.intevation.flys.utils.Formatter;
 
 
@@ -39,6 +57,8 @@
     public static final String DEFAULT_CSV_W_HEADER  = "W [NN + m]";
     public static final String DEFAULT_CSV_Q_HEADER  = "Q [m\u00b3/s]";
 
+    public static final String PDF_HEADER_MODE = "export.computed.discharge.pdf.mode";
+    public static final String JASPER_FILE = "export.computed.discharge.pdf.file";
 
     protected List<WQKms> data;
 
@@ -116,5 +136,85 @@
     protected NumberFormat getQFormatter() {
         return Formatter.getComputedDischargeQ(context);
     }
+
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        WKmsJRDataSource source = createJRData();
+
+        String jasperFile = Resources.getMsg(
+                                context.getMeta(),
+                                JASPER_FILE,
+                                "/jasper/computed-discharge_en.jasper");
+        String confPath = Config.getConfigDirectory().toString();
+
+        Map parameters = new HashMap();
+        parameters.put("ReportTitle", "Exported Data");
+        try {
+            JasperPrint print = JasperFillManager.fillReport(
+                confPath + jasperFile,
+                parameters,
+                source);
+            JasperExportManager.exportReportToPdfStream(print, out);
+        }
+        catch(JRException je) {
+            logger.warn("Error generating PDF Report!");
+            je.printStackTrace();
+        }
+    }
+
+
+    protected WKmsJRDataSource createJRData() {
+        WKmsJRDataSource source = new WKmsJRDataSource();
+
+        addMetaData(source);
+        addWQData(source);
+
+        return source;
+    }
+
+
+    protected void addMetaData(WKmsJRDataSource source) {
+        CallMeta meta = context.getMeta();
+
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        source.addMetaData ("river", FLYSUtils.getRivername(flys));
+
+        Locale locale = Resources.getLocale(meta);
+        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+
+        source.addMetaData("date", df.format(new Date()));
+
+        double[] kms = FLYSUtils.getKmRange(flys);
+        source.addMetaData("range", String.valueOf(kms[0]));
+
+        source.addMetaData("calculation", Resources.getMsg(
+                                            locale,
+                                            PDF_HEADER_MODE,
+                                            "Computed Discharge"));
+    }
+
+    protected void addWQData(WKmsJRDataSource source) {
+        NumberFormat wf  = getWFormatter();
+        NumberFormat qf  = getQFormatter();
+
+        double[] res = new double[3];
+
+        for (WQKms wqkms: data) {
+            int size = wqkms.size();
+
+            for (int i = 0; i < size; i++) {
+                res = wqkms.get(i, res);
+
+                source.addData(new String[] {
+                    "",   // Empty, the WKmsJRDtasource stores km here.
+                    wf.format(res[0]),
+                    qf.format(res[1])
+                });
+            }
+        }
+
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ComputedDischargeCurveGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,26 +1,22 @@
 package de.intevation.flys.exports;
 
-import java.util.List;
-import java.util.ArrayList;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-
-import org.jfree.chart.annotations.XYTextAnnotation;
-
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.title.TextTitle;
-import org.jfree.data.xy.XYSeries;
-
 import de.intevation.artifactdatabase.state.ArtifactAndFacet;
 import de.intevation.artifactdatabase.state.Facet;
-
+import de.intevation.flys.artifacts.StaticWKmsArtifact;
+import de.intevation.flys.artifacts.WINFOArtifact;
 import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.WKms;
 import de.intevation.flys.artifacts.model.WQKms;
-
 import de.intevation.flys.jfree.FLYSAnnotation;
 import de.intevation.flys.jfree.StickyAxisAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.jfree.data.xy.XYSeries;
+import org.w3c.dom.Document;
 
 
 /**
@@ -77,21 +73,14 @@
 
 
     @Override
-    protected void addSubtitles(JFreeChart chart) {
-        String subtitle = getChartSubtitle();
-
-        if (subtitle != null && subtitle.length() > 0) {
-            chart.addSubtitle(new TextTitle(subtitle));
-        }
-    }
-
-
-    @Override
     protected String getDefaultYAxisLabel(int pos) {
         return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
     }
 
 
+    /**
+     * Process data, build up plot.
+     */
     @Override
     public void doOut(
         ArtifactAndFacet artifactFacet,
@@ -110,13 +99,17 @@
         Facet facet = artifactFacet.getFacet();
 
         if (name.equals(COMPUTED_DISCHARGE_Q)) {
-            doQOut((WQKms) artifactFacet.getData(context), facet, attr, visible);
+            doQOut((WQKms) artifactFacet.getData(context), artifactFacet, attr, visible);
         }
         else if (name.equals(STATIC_WQ)) {
-            doWQOut(artifactFacet.getData(context), facet, attr, visible);
+            doWQOut(artifactFacet.getData(context), artifactFacet, attr, visible);
         }
         else if (name.equals(STATIC_WQ_ANNOTATIONS)) {
-            doWQAnnotations(artifactFacet.getData(context), facet, attr, visible);
+            doWQAnnotations(
+                artifactFacet.getData(context),
+                artifactFacet,
+                attr,
+                visible);
         }
         else if (name.equals(COMPUTED_DISCHARGE_MAINVALUES_Q)
                 || name.equals(MAINVALUES_Q)
@@ -124,10 +117,34 @@
                 || name.equals(MAINVALUES_W)
         ) {
             doAnnotations((FLYSAnnotation)
-                artifactFacet.getData(context), facet, attr, visible);
+                artifactFacet.getData(context), artifactFacet, attr, visible);
         }
-        else if (name.equals(STATIC_WKMS_INTERPOL)) {
-            doWAnnotations(artifactFacet.getData(context), facet, attr, visible);
+        else if (name.equals(STATIC_WKMS_INTERPOL) || name.equals(HEIGHTMARKS_POINTS)) {
+            doWAnnotations(
+                artifactFacet.getData(context),
+                artifactFacet,
+                attr,
+                visible);
+        }
+        else if (name.equals(STATIC_WKMS)) {
+            doWAnnotations(
+                artifactFacet.getData(context),
+                artifactFacet,
+                attr,
+                visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(artifactFacet.getData(context),
+                artifactFacet,
+                attr, visible, YAXIS.W.idx);
+        }
+        else if (name.equals(DISCHARGE_CURVE)) {
+            doDischargeOut(
+                (WINFOArtifact) artifactFacet.getArtifact(),
+                artifactFacet.getData(context),
+                artifactFacet.getFacetDescription(),
+                attr,
+                visible);
         }
         else {
             logger.warn("Unknown facet type for computed discharge: " + name);
@@ -135,19 +152,22 @@
         }
     }
 
+
     /**
      * Add WQ Data to plot.
+     * @param wqkms data as double[][]
      */
     protected void doWQOut(
-        Object   wqkms,
-        Facet    facet,
-        Document theme,
-        boolean  visible
+        Object           wqkms,
+        ArtifactAndFacet aaf,
+        Document         theme,
+        boolean          visible
     ) {
+        logger.debug("ComputedDischargeCurveGenerator: doWQOut");
         double [][] data = (double [][]) wqkms;
 
-        XYSeries series = new StyledXYSeries(facet.getDescription(), theme);
-        StyledSeriesBuilder.addPoints(series, data);
+        XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+        StyledSeriesBuilder.addPoints(series, data, true);
 
         addAxisSeries(series, YAXIS.W.idx, visible);
     }
@@ -159,12 +179,13 @@
      * @param theme theme to use.
      */
     protected void doQOut(
-        WQKms    wqkms,
-        Facet    facet,
-        Document theme,
-        boolean  visible
+        WQKms            wqkms,
+        ArtifactAndFacet aaf,
+        Document         theme,
+        boolean          visible
     ) {
-        XYSeries series = new StyledXYSeries(facet.getDescription(), theme);
+        logger.debug("ComputedDischargeCurveGenerator: doWQOut");
+        XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
         StyledSeriesBuilder.addPointsQW(series, wqkms);
 
         addAxisSeries(series, YAXIS.W.idx, visible);
@@ -178,44 +199,65 @@
      */
     protected void doWQAnnotations(
         Object   wqkms,
-        Facet    facet,
+        ArtifactAndFacet aandf,
         Document theme,
         boolean  visible
     ) {
-        List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
+        List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>();
         double [][] data = (double [][]) wqkms;
         for (int i = 0; i< data[0].length; i++) {
-            xy.add(new StickyAxisAnnotation(facet.getDescription(),
+            // TODO we need linear interpolation?
+            xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
                 (float) data[0][i], StickyAxisAnnotation.SimpleAxis.X_AXIS));
-            xy.add(new StickyAxisAnnotation(facet.getDescription(),
+            xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
                 (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS));
         }
 
-        doAnnotations(new FLYSAnnotation(facet.getDescription(), xy),
-            facet, theme, visible);
+        doAnnotations(new FLYSAnnotation(aandf.getFacetDescription(), xy),
+            aandf, theme, visible);
     }
 
 
     /**
      * Add W-Annotations to plot.
-     * @param wqkms actual data
+     * @param wqkms actual data (double[][]).
      * @param theme theme to use.
      */
     protected void doWAnnotations(
         Object   wqkms,
-        Facet    facet,
+        ArtifactAndFacet aandf,
         Document theme,
         boolean  visible
     ) {
-        List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
-        double [][] data = (double [][]) wqkms;
-        for (int i = 0; i< data[0].length; i++) {
-            xy.add(new StickyAxisAnnotation(facet.getDescription(),
-                (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS));
+        Facet facet = aandf.getFacet();
+
+        List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>();
+        // Try to find them as WKms as well...
+        if (wqkms instanceof double[][]) {
+            logger.debug("its double[][] time, baby");
+            double [][] data = (double [][]) wqkms;
+            // TODO Do we need interpolation?
+            for (int i = 0; i< data[0].length; i++) {
+                xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
+                    (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS));
+            }
+
+            doAnnotations(new FLYSAnnotation(facet.getDescription(), xy),
+                aandf, theme, visible);
         }
+        else {
+            logger.debug("its wkms time, baby");
+            WKms data = (WKms) wqkms;
+            // Assume its WKms.
+            double location = getRange()[0];
+            double w = ((StaticWKmsArtifact) aandf.getArtifact())
+                .getWAtKmLin(data, getRange()[0]);
+            xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
+              (float) w, StickyAxisAnnotation.SimpleAxis.Y_AXIS));
 
-        doAnnotations(new FLYSAnnotation(facet.getDescription(), xy),
-            facet, theme, visible);
+            doAnnotations(new FLYSAnnotation(facet.getDescription(), xy),
+                aandf, theme, visible);
+        }
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/CrossSectionGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,47 +1,59 @@
 package de.intevation.flys.exports;
 
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Paint;
+import java.awt.Stroke;
+import java.text.NumberFormat;
 import java.util.List;
 
 import org.apache.log4j.Logger;
-
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.title.TextTitle;
+import org.jfree.chart.LegendItemCollection;
+import org.jfree.chart.annotations.XYBoxAnnotation;
+import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.chart.plot.XYPlot;
 import org.jfree.data.xy.XYSeries;
-
 import org.w3c.dom.Document;
 
 import de.intevation.artifactdatabase.state.ArtifactAndFacet;
-
-
-import de.intevation.flys.model.CrossSectionLine;
+import de.intevation.artifacts.DataProvider;
+import de.intevation.flys.artifacts.geom.Lines;
+import de.intevation.flys.artifacts.model.CrossSectionFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.HYKFactory;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+import de.intevation.flys.model.FastCrossSectionLine;
+import de.intevation.flys.themes.LineStyle;
+import de.intevation.flys.themes.TextStyle;
+import de.intevation.flys.themes.ThemeAccess;
+import de.intevation.flys.utils.Formatter;
+import de.intevation.flys.utils.ThemeUtil;
 
-import de.intevation.flys.artifacts.model.FacetTypes;
-import de.intevation.flys.artifacts.model.CrossSectionFacet;
-
-import de.intevation.artifacts.DataProvider;
 
 /**
  * An OutGenerator that generates cross section graphs.
  */
 public class CrossSectionGenerator
-extends      XYChartGenerator
+extends      LongitudinalSectionGenerator
 implements   FacetTypes
 {
     /** The logger that is used in this generator. */
     private static Logger logger =
-        Logger.getLogger(CrossSectionGenerator.class);
+            Logger.getLogger(CrossSectionGenerator.class);
 
     public static final String I18N_CHART_TITLE =
-        "chart.cross_section.title";
+            "chart.cross_section.title";
 
     public static final String I18N_CHART_SUBTITLE =
-        "chart.cross_section.subtitle";
+            "chart.cross_section.subtitle";
 
     public static final String I18N_XAXIS_LABEL =
-        "chart.cross_section.xaxis.label";
+            "chart.cross_section.xaxis.label";
 
     public static final String I18N_YAXIS_LABEL =
-        "chart.cross_section.yaxis.label";
+            "chart.cross_section.yaxis.label";
 
     public static final String I18N_CHART_TITLE_DEFAULT = "Querprofildiagramm";
     public static final String I18N_XAXIS_LABEL_DEFAULT = "Abstand [m]";
@@ -75,48 +87,142 @@
      * Get localized chart title.
      */
     @Override
-    protected String getDefaultChartTitle() {
+    public String getDefaultChartTitle() {
         Object[] i18n_msg_args = new Object[] {
-            getRiverName()
+                getRiverName()
         };
         return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, i18n_msg_args);
     }
 
 
+    /** Always return default subtitle. */
     @Override
     protected String getChartSubtitle() {
         // XXX NOTE: overriding this method disables ChartSettings subtitle!
+        // The default implementation of this method in ChartGenerator returns
+        // the subtitle changed via the chart settings dialog. This method
+        // always returns the subtitle containing river and km, NEVER the
+        // ChartSettings subtitle!
         return getDefaultChartSubtitle();
     }
 
 
+    /** Get Charts default subtitle. */
     @Override
     protected String getDefaultChartSubtitle() {
         List<DataProvider> providers =
-            context.getDataProvider(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA);
+                context.getDataProvider(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA);
         double km = 0d;
         if (providers.size() > 0) {
-            CrossSectionLine csl = (CrossSectionLine) providers.get(0).
-                provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA,
-                    null, context);
-            km = csl.getKm().doubleValue();
+            FastCrossSectionLine csl = (FastCrossSectionLine) providers.get(0).
+                    provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA,
+                            null, context);
+            km = csl == null ? -1 : csl.getKm();
         }
 
         Object[] args = new Object[] {
-            getRiverName(),
-            km
+                getRiverName(),
+                km
         };
 
+        logger.debug("Locale: " + Resources.getLocale(context.getMeta()));
+
         return msg(I18N_CHART_SUBTITLE, "", args);
     }
 
 
-    @Override
-    protected void addSubtitles(JFreeChart chart) {
-        String subtitle = getChartSubtitle();
-        chart.addSubtitle(new TextTitle(subtitle));
+    /** Get color for hyk zones by their type (which is the name). */
+    protected Paint colorForHYKZone(String zoneName) {
+        if (zoneName.startsWith("R")) {
+            // Brownish.
+            return new Color(153, 60, 0);
+        }
+        else if (zoneName.startsWith("V")) {
+            // Greenish.
+            return new Color(0, 255, 0);
+        }
+        else if (zoneName.startsWith("B")) {
+            // Grayish.
+            return new Color(128, 128, 128);
+        }
+        else if (zoneName.startsWith("H")) {
+            // Blueish.
+            return new Color(0, 0, 255);
+        }
+        else {
+            // Default.
+            logger.debug("Unknown zone type found.");
+            return new Color(255, 0, 0);
+        }
     }
 
+    @Override
+    protected void addAnnotationsToRenderer(XYPlot plot) {
+        super.addAnnotationsToRenderer(plot);
+
+        // Paints for the boxes/lines.
+        Stroke basicStroke = new BasicStroke(1.0f);
+
+        Paint linePaint = new Color(255,  0,0,60);
+        Paint fillPaint = new Color(0,  255,0,60);
+        Paint tranPaint = new Color(0,    0,0, 0);
+
+        // OPTMIMIZE: Pre-calculate positions
+        ChartArea area = new ChartArea(
+                plot.getDomainAxis(0).getRange(),
+                plot.getRangeAxis().getRange());
+
+        for(FLYSAnnotation fa : this.annotations) {
+
+            // Access text styling, if any.
+            Document theme = fa.getTheme();
+            TextStyle textStyle = null;
+            LineStyle lineStyle = null;
+
+            // Get Themeing information and add legend item.
+            if (theme != null) {
+                ThemeAccess themeAccess = new ThemeAccess(theme);
+                textStyle = themeAccess.parseTextStyle();
+                lineStyle = themeAccess.parseLineStyle();
+                if (fa.getLabel() != null) {
+                    LegendItemCollection lic = new LegendItemCollection();
+                    LegendItemCollection old = plot.getFixedLegendItems();
+                    lic.add(createLegendItem(theme, fa.getLabel()));
+                    // (Re-)Add prior legend entries.
+                    if (old != null) {
+                        old.addAll(lic);
+                    }
+                    else {
+                        old = lic;
+                    }
+                    plot.setFixedLegendItems(old);
+                }
+            }
+
+            // Hyks.
+            for (HYKFactory.Zone zone: fa.getBoxes()) {
+                // For each zone, create a box to fill with color, a box to draw
+                // the lines and a text to display the type.
+                fillPaint = colorForHYKZone(zone.getName());
+
+                XYBoxAnnotation boxA = new XYBoxAnnotation(zone.getFrom(), area.atGround(),
+                        zone.getTo(), area.ofGround(0.03f), basicStroke, tranPaint, fillPaint);
+                XYBoxAnnotation boxB = new XYBoxAnnotation(zone.getFrom(), area.atGround(),
+                        zone.getTo(), area.atTop(), basicStroke, fillPaint, tranPaint);
+
+                XYTextAnnotation tex = new XYTextAnnotation(zone.getName(),
+                        zone.getFrom() + (zone.getTo() - zone.getFrom()) / 1.0d,
+                        area.ofGround(0.015f));
+                if (textStyle != null) {
+                    textStyle.apply(tex);
+                }
+
+                plot.getRenderer().addAnnotation(boxA, org.jfree.ui.Layer.BACKGROUND);
+                plot.getRenderer().addAnnotation(boxB, org.jfree.ui.Layer.BACKGROUND);
+                plot.getRenderer().addAnnotation(tex,  org.jfree.ui.Layer.BACKGROUND);
+            }
+        }
+    }
 
     @Override
     protected String getDefaultXAxisLabel() {
@@ -133,11 +239,12 @@
     /**
      * Let one facet do its job.
      */
+    @Override
     public void doOut(
-        ArtifactAndFacet artifactFacet,
-        Document         attr,
-        boolean          visible
-    ) {
+            ArtifactAndFacet artifactFacet,
+            Document         attr,
+            boolean          visible
+            ) {
         String name = artifactFacet.getFacetName();
 
         logger.debug("CrossSectionGenerator.doOut: " + name);
@@ -149,23 +256,41 @@
 
         if (name.equals(CROSS_SECTION)) {
             doCrossSectionOut(
-                artifactFacet.getData(context),
-                artifactFacet.getFacetDescription(),
-                attr,
-                visible);
+                    artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    attr,
+                    visible);
         }
         else if (name.equals(CROSS_SECTION_WATER_LINE)) {
             doCrossSectionWaterLineOut(
-                artifactFacet.getData(context),
-                artifactFacet.getFacetDescription(),
-                attr,
-                visible);
+                    artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    attr,
+                    visible);
         }
         else if (FacetTypes.IS.AREA(name)) {
             doArea(artifactFacet.getData(context),
-                artifactFacet.getFacetDescription(),
-                attr,
-                visible);
+                    artifactFacet,
+                    attr,
+                    visible);
+        }
+        else if (name.equals(HYK)) {
+            doHyk(artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    attr,
+                    visible);
+        }
+        else if (FacetTypes.IS.MANUALLINE(name)) {
+            doCrossSectionWaterLineOut(
+                    artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    attr,
+                    visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(artifactFacet.getData(context),
+                    artifactFacet,
+                    attr, visible, YAXIS.W.idx);
         }
         else {
             logger.warn("CrossSection.doOut: Unknown facet name: " + name);
@@ -174,55 +299,11 @@
     }
 
 
-    /**
-     * Do Area out.
-     */
-    protected void doArea(
-        Object     o,
-        String     seriesName,
-        Document   theme,
-        boolean    visible
-    ) {
-        logger.debug("CrossSectionGenerator.doArea");
-        StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme);
-
-        // TODO make this more stable.
-        Object[] doubles = (Object[]) o;
-        XYSeries up   = null;
-        XYSeries down = null;
-
-        if (doubles[1] != null) {
-            up = new StyledXYSeries(seriesName, false, theme);
-            StyledSeriesBuilder.addPoints(up, (double [][]) doubles[1]);
-        }
-
-        if (doubles[0] != null) {
-            // TODO: Sort this out: when the two series have the same name,
-            // the renderer (or anything in between) will not work correctly.
-            down = new StyledXYSeries(seriesName + " ", false, theme);
-            StyledSeriesBuilder.addPoints(down, (double [][]) doubles[0]);
-        }
-
-        if (up == null && down != null) {
-            area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE);
-            down.setKey(seriesName);
-            area.addSeries(down);
-        }
-        else if (up != null && down == null) {
-            area.setMode(StyledAreaSeriesCollection.FILL_MODE.UNDER);
-            area.addSeries(up);
-        }
-        else if (up != null && down != null) {
-            if (doubles[2] != null && ((Boolean)doubles[2]).booleanValue()) {
-                area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
-            }
-            else {
-                area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE);
-            }
-            area.addSeries(up);
-            area.addSeries(down);
-        }
-        addAreaSeries(area, 0, visible);
+    /** Look up the axis identifier for a given facet type. */
+    @Override
+    public int axisIdxForFacet(String facetName) {
+        // TODO Where to add thid axis too.
+        return 0;
     }
 
 
@@ -233,22 +314,82 @@
      * @param theme Theme for the data series.
      */
     protected void doCrossSectionWaterLineOut(
-        Object     o,
-        String     seriesName,
-        Document   theme,
-        boolean    visible
-    ) {
+            Object   o,
+            String   seriesName,
+            Document theme,
+            boolean  visible
+            ) {
         logger.debug("CrossSectionGenerator.doCrossSectionWaterLineOut");
 
-        // DO NOT SORT DATA! This destroys the gaps indicated by NaNs
-        XYSeries series = new StyledXYSeries(seriesName, false, theme);
+        Lines.LineData lines = (Lines.LineData) o;
+        // DO NOT SORT DATA! This destroys the gaps indicated by NaNs.
+        StyledXYSeries series = new StyledXYSeries(seriesName, false, theme);
 
-        StyledSeriesBuilder.addPoints(series, (double [][]) o);
+        if (!ThemeUtil.parseShowLineLabel(theme)) {
+            series.setLabel("");
+        }
+        if (ThemeUtil.parseShowWidth(theme)) {
+            NumberFormat nf = Formatter.getMeterFormat(this.context);
+            String labelAdd = "b=" + nf.format(lines.width) + "m";
+            if (series.getLabel().length() == 0) {
+                series.setLabel(labelAdd);
+            }
+            else {
+                series.setLabel(series.getLabel() + ", " + labelAdd);
+            }
+        }
+        if (ThemeUtil.parseShowLevel(theme) && lines.points.length > 1
+                && lines.points[1].length > 0) {
+            NumberFormat nf = Formatter.getMeterFormat(this.context);
+            String labelAdd = "W=" + nf.format(lines.points[1][0]) + "NN+m";
+            if (series.getLabel().length() == 0) {
+                series.setLabel(labelAdd);
+            }
+            else {
+                series.setLabel(series.getLabel() + ", " + labelAdd);
+            }
+        }
+        if (ThemeUtil.parseShowMiddleHeight(theme) && lines.width != 0) {
+            NumberFormat nf = Formatter.getMeterFormat(this.context);
+            String labelAdd = "T=" + nf.format(lines.area / lines.width) + "m";
+            // : " + lines.area + "/" + lines.width);
+            if (series.getLabel().length() == 0) {
+                series.setLabel(labelAdd);
+            }
+            else {
+                series.setLabel(series.getLabel() + ", " + labelAdd);
+            }
+        }
+
+        StyledSeriesBuilder.addPoints(series, lines.points, false);
 
         addAxisSeries(series, 0, visible);
     }
 
 
+    /** Add HYK-Annotations (colorize and label some areas, draw lines. */
+    protected void doHyk(
+            Object   o,
+            String   seriesName,
+            Document theme,
+            boolean  visible
+            ) {
+        logger.debug("CrossSectionGenerator.doHyk");
+
+        List<HYKFactory.Zone> zones = (List<HYKFactory.Zone>) o;
+
+        if (zones == null || zones.isEmpty()) {
+            logger.warn("CrossSectionGenerator.doHYK: empty zone list received.");
+            return;
+        }
+
+        // Actual Styling is done in XYChartGenerator.
+        if (visible) {
+            addAnnotations(new FLYSAnnotation(seriesName, null, zones, theme));
+        }
+    }
+
+
     /**
      * Do cross sections out.
      *
@@ -256,18 +397,37 @@
      * @param theme Theme for the data series.
      */
     protected void doCrossSectionOut(
-        Object     o,
-        String     seriesName,
-        Document   theme,
-        boolean    visible
-    ) {
+            Object   o,
+            String   seriesName,
+            Document theme,
+            boolean  visible
+            ) {
         logger.debug("CrossSectionGenerator.doCrossSectionOut");
 
         XYSeries series = new StyledXYSeries(seriesName, theme);
 
-        StyledSeriesBuilder.addPoints(series, (double [][]) o);
+        StyledSeriesBuilder.addPoints(series, (double [][]) o, false);
 
         addAxisSeries(series, 0, visible);
     }
+
+
+    /**
+     * Creates a new <i>ChartSection</i>.
+     *
+     * Overridden to prevent inclusion of subtitle.
+     *
+     * @return a new <i>ChartSection</i>.
+     */
+    @Override
+    protected ChartSection buildChartSection() {
+        ChartSection chartSection = new ChartSection();
+        chartSection.setTitle(getChartTitle());
+        chartSection.setDisplayGrid(isGridVisible());
+        chartSection.setDisplayLogo(showLogo());
+        chartSection.setLogoVPlacement(logoVPlace());
+        chartSection.setLogoHPlacement(logoHPlace());
+        return chartSection;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeCurveGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,30 +1,23 @@
 package de.intevation.flys.exports;
 
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.jfree.Bounds;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.River;
+import de.intevation.flys.utils.FLYSUtils;
+
 import org.apache.log4j.Logger;
-
-import java.awt.Font;
-
-import org.w3c.dom.Document;
-
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.NumberAxis;
 import org.jfree.chart.axis.ValueAxis;
 import org.jfree.chart.plot.XYPlot;
 import org.jfree.data.Range;
 import org.jfree.data.xy.XYSeries;
-
-import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import org.w3c.dom.Document;
 
-import de.intevation.flys.artifacts.model.FacetTypes;
-import de.intevation.flys.model.Gauge;
-import de.intevation.flys.model.River;
-
-import de.intevation.flys.artifacts.WINFOArtifact;
-
-import de.intevation.flys.artifacts.model.WQKms;
-
-import de.intevation.flys.utils.FLYSUtils;
-import de.intevation.flys.jfree.FLYSAnnotation;
 
 /**
  * An OutGenerator that generates discharge curves.
@@ -86,17 +79,12 @@
     }
 
 
+    /**
+     * Returns always null to suppress subtitles.
+     */
     @Override
     protected String getDefaultChartTitle() {
-        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
-    }
-
-
-    /**
-     * Empty (suppress subtitle).
-     */
-    @Override
-    protected void addSubtitles(JFreeChart chart) {
+        return null;
     }
 
 
@@ -111,9 +99,10 @@
     }
 
 
+    /* TODO is this one really needed? */
     @Override
-    protected boolean zoomX(XYPlot plot, ValueAxis axis, Range range, Range x) {
-        boolean zoomin = super.zoom(plot, axis, range, x);
+    protected boolean zoomX(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) {
+        boolean zoomin = super.zoom(plot, axis, bounds, x);
 
         if (!zoomin) {
             axis.setLowerBound(0d);
@@ -122,25 +111,8 @@
         return zoomin;
     }
 
-    /**
-     * Create Y-Axis.
-     * First Axis: W.
-     * @return Y-Axis with label.
-     */
+
     @Override
-    protected NumberAxis createYAxis(int index) {
-        Font labelFont = new Font("Tahoma", Font.BOLD, 14);
-        String label = "default";
-        if (index == YAXIS.W.idx) {
-            label = getYAxisLabel(0);
-        }
-        NumberAxis axis = createNumberAxis(index, label);
-        axis.setLabelFont(labelFont);
-        axis.setAutoRangeIncludesZero(false);
-        return axis;
-    }
-
-
     public void doOut(
         ArtifactAndFacet artifactFacet,
         Document         theme,
@@ -149,7 +121,6 @@
         String name = artifactFacet.getFacetName();
         logger.debug("DischargeCurveGenerator.doOut: " + name);
 
-
         if (name.equals(DISCHARGE_CURVE)) {
             doDischargeOut(
                 (WINFOArtifact) artifactFacet.getArtifact(),
@@ -164,7 +135,12 @@
                 || name.equals(MAINVALUES_W))
         {
             doAnnotations((FLYSAnnotation) artifactFacet.getData(context),
-                artifactFacet.getFacet(), theme, visible);
+                artifactFacet, theme, visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(artifactFacet.getData(context),
+                artifactFacet,
+                theme, visible, YAXIS.W.idx);
         }
         else {
            logger.warn("DischargeCurveGenerator.doOut: Unknown facet name: " + name);
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,15 +1,15 @@
 package de.intevation.flys.exports;
 
+import au.com.bytecode.opencsv.CSVWriter;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.WQCKms;
+import de.intevation.flys.artifacts.model.WQKms;
+
 import java.text.NumberFormat;
 
 import org.apache.log4j.Logger;
 
-import au.com.bytecode.opencsv.CSVWriter;
-
-import de.intevation.flys.artifacts.model.WQCKms;
-import de.intevation.flys.artifacts.model.WQKms;
-import de.intevation.flys.artifacts.model.CalculationResult;
-
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
@@ -66,12 +66,12 @@
     }
 
 
-    @Override
     protected void wQKms2CSV(
         CSVWriter writer,
         WQKms     wqkms,
         boolean   atGauge,
-        boolean   isQ
+        boolean   isQ,
+        boolean   isRange
     ) {
         logger.debug("WaterlevelExporter.wQKms2CSV");
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DischargeLongitudinalSectionGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -9,11 +9,14 @@
 import de.intevation.artifactdatabase.state.ArtifactAndFacet;
 import de.intevation.artifactdatabase.state.Facet;
 
+import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.WQCKms;
 import de.intevation.flys.artifacts.model.WQKms;
 import de.intevation.flys.artifacts.model.WKms;
 
 import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+
 
 
 /**
@@ -23,6 +26,7 @@
  */
 public class DischargeLongitudinalSectionGenerator
 extends      LongitudinalSectionGenerator
+implements   FacetTypes
 {
     private static Logger logger =
         Logger.getLogger(DischargeLongitudinalSectionGenerator.class);
@@ -50,10 +54,18 @@
         Facet facet = artifactFacet.getFacet();
 
         if (IS.WQ_KM(name)) {
-            doWOut((WQKms) artifactFacet.getData(context), facet, attr, visible);
+            doWOut(
+                (WQKms) artifactFacet.getData(context),
+                artifactFacet,
+                attr,
+                visible);
         }
         else if (name.equals(DISCHARGE_LONGITUDINAL_Q)) {
-            doQOut((WQKms) artifactFacet.getData(context), facet, attr, visible);
+            doQOut(
+                (WQKms) artifactFacet.getData(context),
+                artifactFacet,
+                attr,
+                visible);
         }
         else if (name.equals(DISCHARGE_LONGITUDINAL_C)) {
             doCorrectedWOut(
@@ -63,11 +75,19 @@
                 visible);
         }
         else if (IS.W_KM(name)) {
-            doWOut((WKms) artifactFacet.getData(context), facet, attr, visible);
+            doWOut(
+                (WKms) artifactFacet.getData(context),
+                artifactFacet,
+                attr, visible);
         }
         else if (name.equals(LONGITUDINAL_ANNOTATION)) {
             doAnnotations((FLYSAnnotation) artifactFacet.getData(context),
-                 facet, attr, visible);
+                 artifactFacet, attr, visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(artifactFacet.getData(context),
+                artifactFacet,
+                attr, visible, YAXIS.W.idx);
         }
         else {
             logger.warn("Unknown facet name: " + name);
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveExporter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,6 +4,11 @@
 import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Date;
+import java.text.DateFormat;
+import java.util.Locale;
 
 import org.w3c.dom.Document;
 
@@ -11,11 +16,23 @@
 
 import au.com.bytecode.opencsv.CSVWriter;
 
+import net.sf.jasperreports.engine.JasperExportManager;
+import net.sf.jasperreports.engine.JasperFillManager;
+import net.sf.jasperreports.engine.JasperPrint;
+import net.sf.jasperreports.engine.JRException;
+
 import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
 
 import de.intevation.flys.artifacts.model.WQDay;
 import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.WKmsJRDataSource;
+import de.intevation.flys.artifacts.resources.Resources;
 
+import de.intevation.flys.utils.FLYSUtils;
 import de.intevation.flys.utils.Formatter;
 
 
@@ -25,7 +42,7 @@
 public class DurationCurveExporter extends AbstractExporter {
 
     /** The logger used in this exporter. */
-    private static Logger logger = Logger.getLogger(WaterlevelExporter.class);
+    private static Logger logger = Logger.getLogger(DurationCurveExporter.class);
 
 
     public static final String CSV_DURATION_HEADER =
@@ -41,6 +58,8 @@
     public static final String DEFAULT_CSV_W_HEADER  = "W [NN + m]";
     public static final String DEFAULT_CSV_Q_HEADER  = "Q [m\u00b3/s]";
 
+    public static final String PDF_HEADER_MODE = "export.duration.pdf.mode";
+    public static final String JASPER_FILE = "export.duration.pdf.file";
 
     /** The storage that contains all WQKms objects for the different facets. */
     protected List<WQDay> data;
@@ -123,6 +142,7 @@
      *
      * @return the number formatter for W values.
      */
+    @Override
     protected NumberFormat getWFormatter() {
         return Formatter.getDurationW(context);
     }
@@ -133,6 +153,7 @@
      *
      * @return the number formatter for Q values.
      */
+    @Override
     protected NumberFormat getQFormatter() {
         return Formatter.getDurationQ(context);
     }
@@ -146,4 +167,95 @@
     protected NumberFormat getDFormatter() {
         return Formatter.getDurationD(context);
     }
+
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        WKmsJRDataSource source = createJRData();
+
+        String jasperFile = Resources.getMsg(
+                                context.getMeta(),
+                                JASPER_FILE,
+                                "/jasper/duration_en.jasper");
+        String confPath = Config.getConfigDirectory().toString();
+
+        Map parameters = new HashMap();
+        parameters.put("ReportTitle", "Exported Data");
+        try {
+            JasperPrint print = JasperFillManager.fillReport(
+                confPath + jasperFile,
+                parameters,
+                source);
+            JasperExportManager.exportReportToPdfStream(print, out);
+        }
+        catch(JRException je) {
+            logger.warn("Error generating PDF Report!");
+            je.printStackTrace();
+        }
+    }
+
+    protected WKmsJRDataSource createJRData() {
+        WKmsJRDataSource source = new WKmsJRDataSource();
+
+        addMetaData(source);
+        for (WQDay wqday: data) {
+            addWQDayData(source, wqday);
+        }
+
+        return source;
+    }
+
+
+    protected void addMetaData(WKmsJRDataSource source) {
+        CallMeta meta = context.getMeta();
+
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        source.addMetaData ("river", FLYSUtils.getRivername(flys));
+
+        Locale locale = Resources.getLocale(meta);
+        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+
+        source.addMetaData("date", df.format(new Date()));
+
+        double[] kms = FLYSUtils.getKmRange(flys);
+        source.addMetaData("range", String.valueOf(kms[0]));
+
+        source.addMetaData("calculation", Resources.getMsg(
+                                            locale,
+                                            PDF_HEADER_MODE,
+                                            "Duration"));
+    }
+
+    protected void addWQDayData(WKmsJRDataSource source, WQDay wqday) {
+        int size = wqday.size();
+
+        NumberFormat wf  = getWFormatter();
+        NumberFormat qf  = getQFormatter();
+        NumberFormat df  = getDFormatter();
+
+        if (wqday.isIncreasing()) {
+            for (int i = size-1; i >= 0; i --) {
+                source.addData(new String[] {
+                    "",
+                    wf.format(wqday.getW(i)),
+                    qf.format(wqday.getQ(i)),
+                    "", "", "",
+                    df.format(wqday.getDay(i))
+                });
+            }
+        }
+        else {
+            for (int i = 0; i < size; i ++) {
+                source.addData(new String[] {
+                    "",
+                    wf.format(wqday.getW(i)),
+                    qf.format(wqday.getQ(i)),
+                    "", "", "",
+                    df.format(wqday.getDay(i))
+                });
+            }
+        }
+    }
 }
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/DurationCurveGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,26 +1,22 @@
 package de.intevation.flys.exports;
 
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.WQDay;
+import de.intevation.flys.jfree.Bounds;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+
 import java.awt.Font;
-
-import org.w3c.dom.Document;
+import java.awt.geom.Point2D;
 
 import org.apache.log4j.Logger;
-
-import org.jfree.chart.JFreeChart;
 import org.jfree.chart.axis.NumberAxis;
 import org.jfree.chart.axis.ValueAxis;
 import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.title.TextTitle;
 import org.jfree.data.Range;
 import org.jfree.data.xy.XYSeries;
-
-import de.intevation.artifactdatabase.state.ArtifactAndFacet;
-
-import de.intevation.flys.artifacts.model.FacetTypes;
-import de.intevation.flys.artifacts.model.WQDay;
-import de.intevation.flys.artifacts.resources.Resources;
-
-import de.intevation.flys.jfree.FLYSAnnotation;
+import org.w3c.dom.Document;
 
 
 /**
@@ -35,21 +31,16 @@
     public static enum YAXIS {
         W(0),
         Q(1);
-        protected int idx;
+        public int idx;
         private YAXIS(int c) {
            idx = c;
         }
     }
 
+    /** Local logger. */
     private static Logger logger =
         Logger.getLogger(DurationCurveGenerator.class);
 
-    public static final String I18N_DURATION_W =
-        "chart.duration.curve.curve.w";
-
-    public static final String I18N_DURATION_Q =
-        "chart.duration.curve.curve.q";
-
     public static final String I18N_CHART_TITLE =
         "chart.duration.curve.title";
 
@@ -115,16 +106,6 @@
 
 
     @Override
-    protected void addSubtitles(JFreeChart chart) {
-        String subtitle = getChartSubtitle();
-
-        if (subtitle != null && subtitle.length() > 0) {
-            chart.addSubtitle(new TextTitle(subtitle));
-        }
-    }
-
-
-    @Override
     protected String getDefaultXAxisLabel() {
         return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
     }
@@ -147,8 +128,8 @@
 
 
     @Override
-    protected boolean zoomX(XYPlot plot, ValueAxis axis, Range range, Range x) {
-        boolean zoomin = super.zoom(plot, axis, range, x);
+    protected boolean zoomX(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) {
+        boolean zoomin = super.zoom(plot, axis, bounds, x);
 
         if (!zoomin) {
             axis.setLowerBound(0d);
@@ -160,6 +141,27 @@
     }
 
 
+    /**
+     * This method overrides the method in the parent class to set the lower
+     * bounds of the Q axis to 0. This axis should never display negative
+     * values on its own.
+     */
+    @Override
+    protected boolean zoomY(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) {
+        boolean zoomin = super.zoom(plot, axis, bounds, x);
+
+        if (!zoomin && axis instanceof IdentifiableNumberAxis) {
+            String id = ((IdentifiableNumberAxis) axis).getId();
+
+            if (YAXIS.Q.toString().equals(id)) {
+                axis.setLowerBound(0d);
+            }
+        }
+
+        return zoomin;
+    }
+
+
     @Override
     public void doOut(
         ArtifactAndFacet artifactFacet,
@@ -176,19 +178,41 @@
         }
 
         if (name.equals(DURATION_W)) {
-            doWOut((WQDay) artifactFacet.getData(context), attr, visible);
+            doWOut(
+                (WQDay) artifactFacet.getData(context),
+                artifactFacet,
+                attr,
+                visible);
         }
         else if (name.equals(DURATION_Q)) {
-            doQOut((WQDay) artifactFacet.getData(context), attr, visible);
+            doQOut(
+                (WQDay) artifactFacet.getData(context),
+                artifactFacet,
+                attr,
+                visible);
         }
-        else if (name.equals(COMPUTED_DISCHARGE_MAINVALUES_Q)
+        else if (name.equals(DURATION_MAINVALUES_Q)
                 || name.equals(MAINVALUES_Q)
                 || name.equals(COMPUTED_DISCHARGE_MAINVALUES_W)
                 || name.equals(MAINVALUES_W)
         ) {
             doAnnotations(
                 (FLYSAnnotation) artifactFacet.getData(context),
-                artifactFacet.getFacet(), attr, visible);
+                artifactFacet,
+                attr,
+                visible);
+        }
+        else if (name.equals(RELATIVE_POINT)) {
+            doPointOut((Point2D) artifactFacet.getData(context),
+                artifactFacet,
+                attr,
+                visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(
+                artifactFacet.getData(context),
+                artifactFacet,
+                attr, visible, YAXIS.W.idx);
         }
         else {
             logger.warn("Unknown facet name: " + name);
@@ -203,24 +227,42 @@
      * @param wqdays The WQDay store that contains the Ws.
      * @param theme
      */
-    protected void doWOut(WQDay wqdays, Document theme, boolean visible) {
+    protected void doWOut(
+        WQDay            wqdays,
+        ArtifactAndFacet aaf,
+        Document         theme,
+        boolean          visible
+    ) {
         logger.debug("DurationCurveGenerator.doWOut");
 
-        // TODO find the correct series name
-        XYSeries series = new StyledXYSeries(
-            getSeriesName(getRiverName(), DURATION_W), theme);
+        XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
 
         int size = wqdays.size();
         for (int i = 0; i < size; i++) {
             int  day = wqdays.getDay(i);
             double w = wqdays.getW(i);
 
-            series.add((double) day, w);
+            series.add(day, w);
         }
 
         addAxisSeries(series, YAXIS.W.idx, visible);
     }
 
+    protected void doPointOut(
+        Point2D point,
+        ArtifactAndFacet aandf,
+        Document theme,
+        boolean visible
+    ){
+        logger.debug("DurationCurveGenerator.doPointOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        series.add(point.getX(), point.getY());
+
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
 
     /**
      * Creates the series for a duration curve's Q facet.
@@ -228,52 +270,28 @@
      * @param wqdays The WQDay store that contains the Qs.
      * @param theme
      */
-    protected void doQOut(WQDay wqdays, Document theme, boolean visible) {
+    protected void doQOut(
+        WQDay            wqdays,
+        ArtifactAndFacet aaf,
+        Document         theme,
+        boolean          visible
+    ) {
         logger.debug("DurationCurveGenerator.doQOut");
 
-        // TODO find the correct series name
-        XYSeries series = new StyledXYSeries(
-            getSeriesName(getRiverName(), DURATION_Q), theme);
+        XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
 
         int size = wqdays.size();
         for (int i = 0; i < size; i++) {
             int  day = wqdays.getDay(i);
             double q = wqdays.getQ(i);
 
-            series.add((double) day, q);
+            series.add(day, q);
         }
 
         addAxisSeries(series, YAXIS.Q.idx, visible);
     }
 
 
-    protected String getSeriesName(String river, String type) {
-        Object[] args = new Object[] { river };
-
-        if (type == null || type.length() == 0) {
-            logger.warn("No duration curve type given.");
-            return "n/a";
-        }
-        else if (type.equals(DURATION_W)) {
-            return Resources.getMsg(
-                context.getMeta(),
-                I18N_DURATION_W,
-                "W",
-                args);
-        }
-        else if (type.equals(DURATION_Q)) {
-            return Resources.getMsg(
-                context.getMeta(),
-                I18N_DURATION_Q,
-                "W",
-                args);
-        }
-
-        logger.warn("Could not determine chart curve type: " + type);
-        return type;
-    }
-
-
     @Override
     protected YAxisWalker getYAxisWalker() {
         return new YAxisWalker() {
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/EmptySettings.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/EmptySettings.java	Fri Sep 28 12:15:52 2012 +0200
@@ -75,3 +75,4 @@
         parent.appendChild(owner.createElement("settings"));
     }
 }
+// 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/exports/FlowVelocityExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,127 @@
+package de.intevation.flys.exports;
+
+import java.io.OutputStream;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Document;
+
+import org.apache.log4j.Logger;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.FlowVelocityData;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.Formatter;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class FlowVelocityExporter extends AbstractExporter {
+
+    private static final Logger logger =
+        Logger.getLogger(FlowVelocityExporter.class);
+
+
+    public static final String CSV_KM =
+        "export.flow_velocity.csv.header.km";
+
+    public static final String CSV_V_TOTAL =
+        "export.flow_velocity.csv.header.v_total";
+
+    public static final String CSV_V_MAIN =
+        "export.flow_velocity.csv.header.v_main";
+
+    public static final String CSV_TAU_MAIN =
+        "export.flow_velocity.csv.header.tau_main";
+
+    public static final String CSV_Q =
+        "export.flow_velocity.csv.header.q";
+
+    public static final String CSV_LOCATIONS =
+        "export.flow_velocity.csv.header.locations";
+
+
+    protected List<FlowVelocityData[]> data;
+
+
+    public void init(Document request, OutputStream out, CallContext cc) {
+        super.init(request, out, cc);
+        data = new ArrayList<FlowVelocityData[]>();
+    }
+
+
+    @Override
+    protected void addData(Object d) {
+        if (d instanceof CalculationResult) {
+            d = ((CalculationResult) d).getData();
+
+            if (d instanceof FlowVelocityData[]) {
+                logger.debug("Add new data of type FlowVelocityData");
+                data.add((FlowVelocityData[]) d);
+            }
+        }
+    }
+
+
+    @Override
+    protected void writeCSVData(CSVWriter writer) {
+        logger.info("FlowVelocityExporter.writeCSVData");
+        logger.debug("CSV gets " + data.size() + " FlowVelocityData objects.");
+
+        writeCSVHeader(writer);
+
+        for (FlowVelocityData[] d: data) {
+            data2CSV(writer, d);
+        }
+    }
+
+
+    protected void writeCSVHeader(CSVWriter writer) {
+        writer.writeNext(new String[] {
+            msg(CSV_KM, CSV_KM),
+            msg(CSV_V_TOTAL, CSV_V_TOTAL),
+            msg(CSV_V_MAIN, CSV_V_MAIN),
+            msg(CSV_TAU_MAIN, CSV_TAU_MAIN),
+            msg(CSV_Q, CSV_Q),
+            msg(CSV_LOCATIONS, CSV_LOCATIONS)
+        });
+    }
+
+
+    protected void data2CSV(CSVWriter writer, FlowVelocityData[] fData) {
+        logger.debug("Add next FlowVelocityData to CSV");
+
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        for (FlowVelocityData data: fData) {
+            for (int i = 0, n = data.size(); i < n; i++) {
+                NumberFormat kmF  = Formatter.getFlowVelocityKM(context);
+                NumberFormat valF = Formatter.getFlowVelocityValues(context);
+                NumberFormat qF   = Formatter.getFlowVelocityQ(context);
+
+                writer.writeNext(new String[] {
+                    kmF.format(data.getKM(i)),
+                    valF.format(data.getVMain(i)),
+                    valF.format(data.getVTotal(i)),
+                    valF.format(data.getTauMain(i)),
+                    qF.format(data.getQ(i)) + "=" + data.getZone(),
+                    FLYSUtils.getLocationDescription(flys, data.getKM(i)),
+                });
+            }
+        }
+    }
+
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        logger.error("TODO: Implement FlowVelocityExporter.writePDF");
+    }
+}
+// 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/exports/FlowVelocityGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,348 @@
+package de.intevation.flys.exports;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.data.xy.XYSeries;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.FlowVelocityData;
+
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+
+
+/**
+ * An OutGenerator that generates flow velocity curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class FlowVelocityGenerator
+extends      XYChartGenerator
+implements   FacetTypes
+{
+    public enum YAXIS {
+        V(0),
+        T(1);
+        protected int idx;
+        private YAXIS(int c) {
+           idx = c;
+        }
+    }
+
+    /** The logger that is used in this generator. */
+    private static Logger logger = Logger.getLogger(FlowVelocityGenerator.class);
+
+    /** Key to look up internationalized String for annotations label. */
+    public static final String I18N_ANNOTATIONS_LABEL =
+        "chart.flow_velocity.annotations.label";
+
+    /**
+     * Key to look up internationalized String for LongitudinalSection diagrams
+     * titles.
+     */
+    public static final String I18N_CHART_TITLE =
+        "chart.flow_velocity.section.title";
+
+    /**
+     * Key to look up internationalized String for LongitudinalSection diagrams
+     * subtitles.
+     */
+    public static final String I18N_CHART_SUBTITLE =
+        "chart.flow_velocity.section.subtitle";
+
+    /**
+     * Key to look up internationalized String for LongitudinalSection diagrams
+     * short subtitles.
+     */
+    public static final String I18N_CHART_SHORT_SUBTITLE =
+        "chart.flow_velocity.section.shortsubtitle";
+
+    public static final String I18N_XAXIS_LABEL =
+        "chart.flow_velocity.section.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL =
+        "chart.flow_velocity.section.yaxis.label";
+
+    public static final String I18N_2YAXIS_LABEL =
+        "chart.flow_velocity.section.yaxis.second.label";
+
+    public static final String I18N_CHART_TITLE_DEFAULT  = "Geschwindigkeit- und Schubspannung";
+    public static final String I18N_XAXIS_LABEL_DEFAULT  = "km";
+    public static final String I18N_YAXIS_LABEL_DEFAULT  = "Geschwindigkeit v [m/s]";
+    public static final String I18N_2YAXIS_LABEL_DEFAULT = "Schubspannung Tau [N]";
+
+
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+
+    /**
+     * Returns the default title for this chart.
+     *
+     * @return the default title for this chart.
+     */
+    @Override
+    public String getDefaultChartTitle() {
+        Object[] args = new Object[] {
+            getRiverName()
+        };
+
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, args);
+    }
+
+
+    /**
+     * Get internationalized label for the x axis.
+     */
+    @Override
+    protected String getDefaultXAxisLabel() {
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        return msg(
+            I18N_XAXIS_LABEL,
+            I18N_XAXIS_LABEL_DEFAULT,
+            new Object[] { FLYSUtils.getRiver(flys).getName() });
+    }
+
+
+    @Override
+    protected String getDefaultYAxisLabel(int index) {
+        String label = "default";
+
+        if (index == YAXIS.V.idx) {
+            label = getVAxisLabel();
+        }
+        else if (index == YAXIS.T.idx) {
+            label = getTAxisLabel();
+        }
+
+        return label;
+    }
+
+
+    /**
+     * Get internationalized label for the y axis.
+     */
+    protected String getVAxisLabel() {
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+    }
+
+
+    /**
+     * Get internationalized label for the y axis.
+     */
+    protected String getTAxisLabel() {
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        return msg(I18N_2YAXIS_LABEL, I18N_2YAXIS_LABEL_DEFAULT);
+    }
+
+
+    /**
+     * Produce output.
+     * @param artifactAndFacet current facet.
+     * @param attr  theme for facet
+     * @param visible Whether this facets data is actually visible or not.
+     */
+    public void doOut(
+        ArtifactAndFacet artifactAndFacet,
+        Document         attr,
+        boolean          visible
+    ) {
+        String name = artifactAndFacet.getFacetName();
+
+        logger.debug("FlowVelocityGenerator.doOut: " + name);
+
+        if (name == null) {
+            logger.error("No facet name for doOut(). No output generated!");
+            return;
+        }
+
+        Facet facet = artifactAndFacet.getFacet();
+
+        if (facet == null) {
+            return;
+        }
+
+        if (name.equals(FLOW_VELOCITY_MAINCHANNEL)) {
+            doMainChannelOut(
+                (FlowVelocityData) artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
+        }
+        else if (name.equals(FLOW_VELOCITY_TOTALCHANNEL)) {
+            doTotalChannelOut(
+                (FlowVelocityData) artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
+        }
+        else if (name.equals(FLOW_VELOCITY_TAU)) {
+            doTauOut(
+                (FlowVelocityData) artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
+        }
+        else if (name.equals(FLOW_VELOCITY_ANNOTATION)) {
+            doAnnotations(
+                (FLYSAnnotation) artifactAndFacet.getData(context),
+                 artifactAndFacet,
+                 attr,
+                 visible);
+        }
+        else if (FacetTypes.IS.AREA(name)) {
+            doArea(
+                artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(
+                artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible,
+                YAXIS.V.idx);
+        }
+        else {
+            logger.warn("Unknown facet name: " + name);
+            return;
+        }
+    }
+
+
+    /**
+     * Process the output for W facets in a longitudinal section curve.
+     *
+     * @param data A FlowVelocityData object
+     * @param aandf The facet. This facet does NOT support any data objects. Use
+     * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
+     * data.
+     * @param theme The theme that contains styling information.
+     * @param visible The visibility of the curve.
+     */
+    protected void doMainChannelOut(
+        FlowVelocityData data,
+        ArtifactAndFacet aandf,
+        Document         theme,
+        boolean          visible
+    ) {
+        logger.debug("FlowVelocityGenerator.doMainChannelOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        StyledSeriesBuilder.addPoints(series, data.getMainChannelPoints(), true);
+
+        addAxisSeries(series, YAXIS.V.idx, visible);
+    }
+
+
+    /**
+     * Add items to dataseries which describes the differences.
+     */
+    protected void doTotalChannelOut(
+        FlowVelocityData data,
+        ArtifactAndFacet aandf,
+        Document         theme,
+        boolean          visible
+    ) {
+        logger.debug("FlowVelocityGenerator.doTotalChannelOut");
+
+        if (data == null) {
+            logger.warn("No data to add to FlowVelocity chart.");
+            return;
+         }
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        StyledSeriesBuilder.addPoints(series, data.getTotalChannelPoints(), true);
+
+        addAxisSeries(series, YAXIS.V.idx, visible);
+    }
+
+
+
+    /**
+     * @param data A FlowVelocityData object
+     * @param aandf The facet. This facet does NOT support any data objects. Use
+     * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
+     * data.
+     * @param theme The theme that contains styling information.
+     * @param visible The visibility of the curve.
+     */
+    protected void doTauOut(
+        FlowVelocityData data,
+        ArtifactAndFacet aandf,
+        Document         theme,
+        boolean          visible
+    ) {
+        logger.debug("FlowVelocityGenerator.doTauOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        StyledSeriesBuilder.addPoints(series, data.getTauPoints(), true);
+
+        addAxisSeries(series, YAXIS.T.idx, visible);
+    }
+
+
+    /** Look up the axis identifier for a given facet type. */
+    public int axisIdxForFacet(String facetName) {
+        if (FacetTypes.IS.V(facetName)) {
+            return YAXIS.V.idx;
+        }
+        else if (FacetTypes.IS.T(facetName)) {
+            return YAXIS.T.idx;
+        }
+        else {
+            logger.warn("Could not find axis for facet " + facetName);
+            return YAXIS.V.idx;
+        }
+    }
+
+
+    /**
+     * Do Area out.
+     * @param theme styling information.
+     * @param visible whether or not visible.
+     */
+    protected void doArea(
+        Object     o,
+        ArtifactAndFacet aandf,
+        Document   theme,
+        boolean    visible
+    ) {
+        logger.debug("FlowVelocityGenerator.doArea");
+        logger.warn("TODO: Implement FlowVelocityGenerator.doArea");
+    }
+}
+// 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/exports/FlowVelocityInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.exports;
+
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific
+ * flow velocity curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class FlowVelocityInfoGenerator
+extends      ChartInfoGenerator
+{
+    public FlowVelocityInfoGenerator() {
+        super(new FlowVelocityGenerator());
+    }
+}
+// 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/exports/HistoricalDischargeCurveExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,242 @@
+package de.intevation.flys.exports;
+
+import java.io.OutputStream;
+import java.text.NumberFormat;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Locale;
+
+import org.w3c.dom.Document;
+
+import org.apache.log4j.Logger;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+import net.sf.jasperreports.engine.JasperExportManager;
+import net.sf.jasperreports.engine.JasperFillManager;
+import net.sf.jasperreports.engine.JasperPrint;
+import net.sf.jasperreports.engine.JRException;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.Timerange;
+import de.intevation.flys.artifacts.model.WQTimerange;
+import de.intevation.flys.artifacts.model.WQTJRDataSource;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.Formatter;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalDischargeCurveExporter extends AbstractExporter {
+
+    private static final Logger logger =
+        Logger.getLogger(HistoricalDischargeCurveExporter.class);
+
+
+    public static final String CSV_TIMERANGE_HEADER =
+        "export.historical.discharge.csv.header.timerange";
+
+    public static final String CSV_WATERLEVEL_HEADER =
+        "export.historical.discharge.csv.header.waterlevel";
+
+    public static final String CSV_DISCHARGE_HEADER =
+        "export.historical.discharge.csv.header.discharge";
+
+    public static final String CSV_DIFF_HEADER =
+        "export.historical.discharge.csv.header.diff";
+
+    public static final String CSV_GAUGENAME_HEADER =
+        "export.historical.discharge.csv.header.gaugename";
+
+    public static final String PDF_HEADER_MODE =
+        "export.historical.discharge.pdf.mode";
+
+    public static final String JASPER_FILE =
+        "export.historical.discharge.pdf.file";
+
+    protected List<WQTimerange[]> data;
+
+
+    public void init(Document request, OutputStream out, CallContext cc) {
+        super.init(request, out, cc);
+
+        data = new ArrayList<WQTimerange[]>();
+    }
+
+
+    @Override
+    protected void addData(Object d) {
+        logger.debug("Add data of class: " + d.getClass());
+
+        if (d instanceof CalculationResult) {
+            d = ((CalculationResult) d).getData();
+
+            logger.debug("Internal data of CalculationResult: " + d.getClass());
+
+            if (d instanceof WQTimerange[]) {
+                logger.debug("Add new data of type WQTimerange");
+                data.add((WQTimerange[]) d);
+            }
+        }
+    }
+
+
+    @Override
+    protected void writeCSVData(CSVWriter writer) {
+        logger.info("HistoricalDischargeCurveExporter.writeCSVData");
+        logger.debug("CSV gets " + data.size() + " WQTimerange[] objects.");
+
+        writeCSVHeader(writer);
+
+        for (WQTimerange[] arr: data) {
+            for (WQTimerange wqt: arr) {
+                wqt2CSV(writer, wqt);
+            }
+        }
+    }
+
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        WQTJRDataSource source = createJRData();
+
+        String jasperFile = Resources.getMsg(
+                                context.getMeta(),
+                                JASPER_FILE,
+                                "/jasper/historical-discharge_en.jasper");
+        String confPath = Config.getConfigDirectory().toString();
+
+        Map parameters = new HashMap();
+        parameters.put("ReportTitle", "Exported Data");
+        try {
+            JasperPrint print = JasperFillManager.fillReport(
+                confPath + jasperFile,
+                parameters,
+                source);
+            JasperExportManager.exportReportToPdfStream(print, out);
+        }
+        catch(JRException je) {
+            logger.warn("Error generating PDF Report!");
+            je.printStackTrace();
+        }
+
+    }
+
+
+    protected void writeCSVHeader(CSVWriter writer) {
+        writer.writeNext(new String[] {
+            msg(CSV_TIMERANGE_HEADER, CSV_TIMERANGE_HEADER),
+            msg(CSV_WATERLEVEL_HEADER, CSV_WATERLEVEL_HEADER),
+            msg(CSV_DISCHARGE_HEADER, CSV_DISCHARGE_HEADER),
+            msg(CSV_DIFF_HEADER, CSV_DIFF_HEADER),
+            msg(CSV_GAUGENAME_HEADER, CSV_GAUGENAME_HEADER)
+        });
+    }
+
+
+    protected void wqt2CSV(CSVWriter writer, WQTimerange wqt) {
+        logger.debug("Add next WQTimerange to CSV");
+
+        DateFormat   df = Formatter.getMediumDateFormat(context);
+        NumberFormat wf = Formatter.getHistoricalDischargeW(context);
+        NumberFormat qf = Formatter.getHistoricalDischargeQ(context);
+
+        double[] wq = new double[3];
+
+        String gaugeName = getReferenceGaugename();
+
+        for (int i = 0, n = wqt.size(); i < n; i++) {
+            Timerange tr = wqt.getTimerange(i);
+            Date   start = new Date(tr.getStart());
+            Date     end = new Date(tr.getEnd());
+
+            wqt.get(i, wq);
+
+            writer.writeNext(new String[] {
+                df.format(start) + " - " + df.format(end),
+                wf.format(wq[0]),
+                qf.format(wq[1]),
+                qf.format(wq[2]),
+                gaugeName
+            });
+        }
+    }
+
+
+    protected WQTJRDataSource createJRData() {
+        WQTJRDataSource source = new WQTJRDataSource();
+
+        addMetaData(source);
+        for (WQTimerange[] arr: data) {
+            for (WQTimerange wqt: arr) {
+                addWQTData(source, wqt);
+            }
+        }
+
+        return source;
+    }
+
+
+    protected void addMetaData(WQTJRDataSource source) {
+        CallMeta meta = context.getMeta();
+
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        source.addMetaData ("river", FLYSUtils.getRivername(flys));
+
+        Locale locale = Resources.getLocale(meta);
+        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+
+        source.addMetaData("date", df.format(new Date()));
+
+        source.addMetaData("calculation", Resources.getMsg(
+                                            locale,
+                                            PDF_HEADER_MODE,
+                                            "Historical Discharge"));
+    }
+
+
+    protected void addWQTData(WQTJRDataSource source, WQTimerange wqt) {
+        DateFormat   df = Formatter.getShortDateFormat(context);
+        NumberFormat wf = Formatter.getHistoricalDischargeW(context);
+        NumberFormat qf = Formatter.getHistoricalDischargeQ(context);
+
+        double[] wq = new double[3];
+
+        String gaugeName = getReferenceGaugename();
+
+        for (int i = 0, n = wqt.size(); i < n; i++) {
+            Timerange tr = wqt.getTimerange(i);
+            Date   start = new Date(tr.getStart());
+            Date     end = new Date(tr.getEnd());
+
+            wqt.get(i, wq);
+
+            source.addData(new String[] {
+                df.format(start) + " - " + df.format(end),
+                wf.format(wq[0]),
+                qf.format(wq[1]),
+                qf.format(wq[2]),
+                gaugeName
+            });
+        }
+    }
+
+
+    public String getReferenceGaugename() {
+        return FLYSUtils.getReferenceGaugeName((FLYSArtifact) master);
+    }
+}
+// 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/exports/HistoricalDischargeCurveGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,256 @@
+package de.intevation.flys.exports;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.HistoricalWQTimerange;
+import de.intevation.flys.artifacts.model.Timerange;
+import de.intevation.flys.artifacts.model.WQTimerange;
+import de.intevation.flys.jfree.StyledTimeSeries;
+import de.intevation.flys.utils.FLYSUtils;
+
+import java.util.Date;
+
+import org.apache.log4j.Logger;
+import org.jfree.data.general.SeriesException;
+import org.jfree.data.time.Day;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.w3c.dom.Document;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalDischargeCurveGenerator
+extends      TimeseriesChartGenerator
+implements   FacetTypes
+{
+    private static Logger logger =
+        Logger.getLogger(HistoricalDischargeCurveGenerator.class);
+
+
+    public static final String I18N_CHART_TITLE =
+        "chart.historical.discharge.title";
+
+    public static final String I18N_CHART_SUBTITLE =
+        "chart.historical.discharge.subtitle";
+
+    public static final String I18N_XAXIS_LABEL =
+        "chart.historical.discharge.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL =
+        "chart.historical.discharge.yaxis.label";
+
+    public static final String I18N_YAXIS_SECOND_LABEL =
+        "chart.historical.discharge.yaxis.second.label";
+
+
+    public static enum YAXIS {
+        Q(0);
+        protected int idx;
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
+    }
+
+
+    @Override
+    protected String getDefaultChartSubtitle() {
+        String[] args = new String[] {
+            FLYSUtils.getReferenceGaugeName((FLYSArtifact) master)
+        };
+
+        return msg(I18N_CHART_SUBTITLE, "", args);
+    }
+
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL);
+    }
+
+    @Override
+    protected String getDefaultYAxisLabel(int pos) {
+        if (pos == 0) {
+            return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL);
+        }
+        else if (pos == 1) {
+            return msg(I18N_YAXIS_SECOND_LABEL, I18N_YAXIS_SECOND_LABEL);
+        }
+        else {
+            return "NO TITLE FOR Y AXIS: " + pos;
+        }
+    }
+
+
+    @Override
+    public void doOut(
+        ArtifactAndFacet artifactFacet,
+        Document         theme,
+        boolean          visible
+    ) {
+        String name = artifactFacet.getFacetName();
+        logger.debug("HistoricalDischargeCurveGenerator.doOut: " + name);
+        logger.debug("Theme description is: " + artifactFacet.getFacetDescription());
+
+
+        if (name.equals(HISTORICAL_DISCHARGE_Q)) {
+            doHistoricalDischargeOut(
+                (FLYSArtifact) artifactFacet.getArtifact(),
+                artifactFacet.getData(context),
+                artifactFacet.getFacetDescription(),
+                theme,
+                visible);
+        }
+        else if (name.equals(HISTORICAL_DISCHARGE_Q_DIFF)) {
+            doHistoricalDischargeDifferenceOut(
+                (FLYSArtifact) artifactFacet.getArtifact(),
+                artifactFacet.getData(context),
+                artifactFacet.getFacetDescription(),
+                theme,
+                visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints (artifactFacet.getData(context),
+                      artifactFacet,
+                      theme, visible, YAXIS.Q.idx);
+        }
+        // TODO ADD THE CASE FOR DISPLAYING W VALUES
+        else {
+           logger.warn("doOut(): unknown facet name: " + name);
+           return;
+        }
+    }
+
+
+    protected void doHistoricalDischargeOut(
+        FLYSArtifact artifact,
+        Object       data,
+        String       desc,
+        Document     theme,
+        boolean      visible)
+    {
+        logger.debug("doHistoricalDischargeOut(): description = " + desc);
+
+        WQTimerange wqt = (WQTimerange) data;
+
+        TimeSeriesCollection tsc = newTimeSeriesCollection(
+            wqt.getTimeranges(),
+            wqt.getQs(),
+            theme,
+            desc);
+
+        addAxisDataset(tsc, 0, visible);
+    }
+
+
+    protected void doHistoricalDischargeDifferenceOut(
+        FLYSArtifact artifact,
+        Object       data,
+        String       desc,
+        Document     theme,
+        boolean      visible
+    ) {
+        logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc);
+
+        HistoricalWQTimerange wqt = (HistoricalWQTimerange) data;
+
+        TimeSeriesCollection tsc = newTimeSeriesCollection(
+            wqt.getTimeranges(),
+            wqt.getDiffs(),
+            theme,
+            desc);
+
+        addAxisDataset(tsc, 0, visible);
+    }
+
+
+    /**
+     * Creates a new TimeSeriesCollection with a single TimeSeries. The
+     * TimeSeries will consist of two RegularTimePeriods for each W/Q value
+     * provided by <i>wqt</i>. This has the effect, that the line in the chart
+     * looks like a "step chart".
+     */
+    protected TimeSeriesCollection newTimeSeriesCollection(
+        Timerange[] timeranges,
+        double[]    values,
+        Document    theme,
+        String      desc
+    ) {
+        logger.debug("Create new TimeSeriesCollection for: " + desc);
+
+        TimeSeriesCollection tsc = new TimeSeriesCollection();
+        TimeSeries        series = new StyledTimeSeries(desc, theme);
+
+        for (int i = 0, n = timeranges.length; i < n; i++) {
+            RegularTimePeriod[] rtp = newRegularTimePeriod(timeranges[i]);
+
+            try {
+                if (Double.isNaN(values[i])) {
+                    logger.warn("Skip TimePeriod because value is NaN.");
+                    continue;
+                }
+
+                series.add(rtp[0], values[i]);
+                series.add(rtp[1], values[i]);
+
+                if (logger.isDebugEnabled()) {
+                    logger.debug("added Item to TimeSeries:");
+                    logger.debug("   TimePeriod: " + rtp[0] + " - " + rtp[1]);
+                    logger.debug("   Value:      " + values[i]);
+                }
+            }
+            catch (SeriesException se) {
+                logger.warn("Error while adding TimePeriod: " + se);
+            }
+        }
+
+        tsc.addSeries(series);
+
+        return tsc;
+    }
+
+
+    /**
+     * Creates an array that consists of two <i>Minute</i> periods [start, end].
+     *
+     * @param timerange Supports start and end time.
+     *
+     * @return an array with two <i>Minute</i> periods [start, end].
+     */
+    protected RegularTimePeriod[] newRegularTimePeriod(Timerange timerange) {
+        Date start = new Date(timerange.getStart());
+        Date end   = new Date(timerange.getEnd() - 1000 * 60 * 60 * 24);
+
+        return new RegularTimePeriod[] {
+            new Day(start),
+            new Day(end)
+        };
+    }
+}
+// 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/exports/HistoricalDischargeCurveInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.exports;
+
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific
+ * historical discharge curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class HistoricalDischargeCurveInfoGenerator
+extends      ChartInfoGenerator
+{
+    public HistoricalDischargeCurveInfoGenerator() {
+        super(new HistoricalDischargeCurveGenerator());
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/InfoGeneratorHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,6 +4,8 @@
 import java.awt.geom.NoninvertibleTransformException;
 import java.awt.geom.Rectangle2D;
 
+import java.util.Date;
+
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -11,6 +13,8 @@
 
 import org.jfree.chart.ChartRenderingInfo;
 import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.DateAxis;
+import org.jfree.chart.axis.NumberAxis;
 import org.jfree.chart.axis.ValueAxis;
 import org.jfree.chart.plot.XYPlot;
 import org.jfree.data.Range;
@@ -20,6 +24,8 @@
 import de.intevation.artifacts.common.utils.XMLUtils;
 import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
 
+import de.intevation.flys.jfree.Bounds;
+
 
 /**
  * This class helps generating chart info documents.
@@ -32,10 +38,10 @@
         Logger.getLogger(InfoGeneratorHelper.class);
 
 
-    protected XYChartGenerator generator;
+    protected ChartGenerator generator;
 
 
-    public InfoGeneratorHelper(XYChartGenerator generator) {
+    public InfoGeneratorHelper(ChartGenerator generator) {
         this.generator = generator;
     }
 
@@ -140,14 +146,38 @@
         int            pos)
     {
         logger.debug("createAxisElement " + pos);
-        Range range = axis.getRange();
+        logger.debug("Axis is from type: " + axis.getClass());
 
         Element e = cr.create(type);
         cr.addAttr(e, "pos",  String.valueOf(pos), true);
+
+        if (axis instanceof DateAxis) {
+            prepareDateAxisElement(
+                e, cr, (DateAxis) axis, dataset, type, pos);
+        }
+        else {
+            prepareNumberAxisElement(
+                e, cr, (NumberAxis) axis, dataset, type, pos);
+        }
+
+        return e;
+    }
+
+
+    protected Element prepareNumberAxisElement(
+        Element        e,
+        ElementCreator cr,
+        NumberAxis     axis,
+        XYDataset      dataset,
+        String         type,
+        int            pos
+    ) {
+        Range range = axis.getRange();
+
         cr.addAttr(e, "from", String.valueOf(range.getLowerBound()), true);
         cr.addAttr(e, "to",   String.valueOf(range.getUpperBound()), true);
+        cr.addAttr(e, "axistype", "number", true);
 
-        //Range[] rs = generator.getRangesForDataset(dataset);
         Range[] rs = generator.getRangesForAxis(pos);
         Range   r  = null;
 
@@ -165,6 +195,36 @@
     }
 
 
+    protected Element prepareDateAxisElement(
+        Element        e,
+        ElementCreator cr,
+        DateAxis       axis,
+        XYDataset      dataset,
+        String         type,
+        int            pos
+    ) {
+        Date from = axis.getMinimumDate();
+        Date to   = axis.getMaximumDate();
+
+        Bounds bounds = null;
+        if (type.equals("range")) {
+            bounds = generator.getYBounds(pos);
+        }
+        else {
+            bounds = generator.getXBounds(pos);
+        }
+
+        cr.addAttr(e, "axistype", "date", true);
+        cr.addAttr(e, "from", String.valueOf(from.getTime()), true);
+        cr.addAttr(e, "to", String.valueOf(to.getTime()), true);
+
+        cr.addAttr(e, "min", bounds.getLower().toString(), true);
+        cr.addAttr(e, "max", bounds.getUpper().toString(), true);
+
+        return e;
+    }
+
+
     /**
      * This method appends the values of a transformation matrix to transform
      * image pixel coordinates into chart coordinates.
@@ -241,6 +301,20 @@
         cr.addAttr(matrix, "tx", String.valueOf(tm[2]), true);
         cr.addAttr(matrix, "ty", String.valueOf(tm[3]), true);
 
+        if (xAxis instanceof DateAxis) {
+            cr.addAttr(matrix, "xtype", "date", true);
+        }
+        else {
+            cr.addAttr(matrix, "xtype", "number", true);
+        }
+
+        if (yAxis instanceof DateAxis) {
+            cr.addAttr(matrix, "ytype", "date", true);
+        }
+        else {
+            cr.addAttr(matrix, "ytype", "number", true);
+        }
+
         return matrix;
     }
 
@@ -250,8 +324,8 @@
      * coordinates of the chart image into chart coordinates.
      *
      * @param dataArea The rectangle that contains the data points of the chart.
-     * @param xRange The x axis range.
-     * @param yRange The y axis range.
+     * @param xAxis The x axis.
+     * @param yAxis The y axis.
      *
      * @return a double array as follows: [sx, sy, tx, ty].
      */
@@ -267,8 +341,8 @@
         double offsetY = dataArea.getY();
         double height  = dataArea.getHeight();
 
-        Range xRange = xAxis.getRange();
-        Range yRange = yAxis.getRange();
+        Range xRange = getRangeFromAxis(xAxis);
+        Range yRange = getRangeFromAxis(yAxis);
 
         double lowerX  = xRange.getLowerBound();
         double upperX  = xRange.getUpperBound();
@@ -313,5 +387,19 @@
 
         return new double[] { 1d, 1d, 0d, 0d };
     }
+
+
+    protected static Range getRangeFromAxis(ValueAxis axis) {
+        if  (axis instanceof DateAxis) {
+            DateAxis dAxis = (DateAxis) axis;
+            Date     min   = dAxis.getMinimumDate();
+            Date     max   = dAxis.getMaximumDate();
+
+            return new Range(min.getTime(), max.getTime());
+        }
+        else {
+            return axis.getRange();
+        }
+    }
 }
 // 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/exports/LegendProcessor.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,148 @@
+package de.intevation.flys.exports;
+
+import java.awt.geom.Line2D;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.LegendItem;
+import org.jfree.chart.LegendItemCollection;
+import org.jfree.chart.plot.XYPlot;
+
+
+/** Class to process Plots legends. */
+public abstract class LegendProcessor {
+
+    /** (Empty) shape for aggregated Legend Items. */
+    private static final Line2D.Double SPACE = new Line2D.Double(0,0,0,0);
+
+
+    /** Prevent instantiations. */
+    private LegendProcessor() {
+    }
+
+
+    /**
+     * Create a hash from a legenditem.
+     * This hash can then be used to merge legend items labels.
+     * @return hash for given legenditem to identify mergeables.
+     */
+    protected static String legendItemHash(LegendItem li) {
+        // TODO Do proper implementation. Ensure that only mergable sets are created.
+        // getFillPaint()
+        // getFillPaintTransformer()
+        // getLabel()
+        // getLine()
+        // getLinePaint()
+        // getLineStroke()
+        // getOutminePaint()
+        // getOutlineStroke()
+        // Shape getShape()
+        // String getToolTipText()
+        // String getURLText()
+        // boolean isLineVisible()
+        // boolean isShapeFilled()
+        // boolean isShapeOutlineVisible()
+        // boolean isShapeVisible()
+        String hash = li.getLinePaint().toString();
+        String label = li.getLabel();
+        /*if (label.startsWith("W (") || label.startsWith("W(")) {
+            hash += "-W-";
+        }
+        else if (label.startsWith("Q(") || label.startsWith("Q (")) {
+            hash += "-Q-";
+        }*/
+
+        // WQ.java holds example of using regex Matcher/Pattern.
+
+        return hash;
+    }
+
+
+    /**
+     * Create new legend entries, dependent on settings.
+     * @param plot The plot for which to modify the legend.
+     * @param threshold How many items are needed for aggregation to
+     *        be triggered?
+     */
+    public static void aggregateLegendEntries(XYPlot plot, int threshold) {
+        LegendItemCollection old = plot.getLegendItems();
+        // Find "similar" entries if aggregation is enabled.
+
+        int maxListSize = 0;
+        int AGGR_THRESHOLD = threshold;
+
+        if (AGGR_THRESHOLD > old.getItemCount() || AGGR_THRESHOLD <= 0){
+            return;
+        }
+
+        HashMap<String, List<LegendItem>> entries = new LinkedHashMap<String, List<LegendItem>>();
+        for (Iterator i = old.iterator(); i.hasNext();) {
+            LegendItem item = (LegendItem) i.next();
+            String hash = legendItemHash(item);
+            List<LegendItem> itemList = entries.get(hash);
+            if (itemList == null) {
+                itemList = new ArrayList<LegendItem>();
+            }
+            itemList.add(item);
+
+            if (itemList.size() > maxListSize) {
+                maxListSize = itemList.size();
+            }
+
+            entries.put(legendItemHash(item), itemList);
+        }
+
+        if (maxListSize < AGGR_THRESHOLD) {
+            // No need to do anything.
+            return;
+        }
+
+        // Run over collected entries, merge their names and create new
+        // entry if needed.
+        LegendItemCollection newLegend = new LegendItemCollection();
+        for (Map.Entry<String, List<LegendItem>> cursor: entries.entrySet()) {
+            List<LegendItem> itemList = cursor.getValue();
+            if (itemList.size() >= AGGR_THRESHOLD) {
+                // Now do merging.
+                LegendItem item = (LegendItem) itemList.get(0);
+                // Unfortunately we cannot clone and just setDescription, as this
+                // method was added in JFreeChart 1.0.14 (we are at .13).
+
+                // Remove the shapes of all but the first items,
+                // to prevent "overfill" of legenditemblock.
+                for (int i = 0; i < itemList.size(); i++) {
+                    if (i != 0) {
+                        LegendItem litem = itemList.get(i);
+
+                        // Make shape and line really small.
+                        LegendItem merged = new LegendItem(
+                            "," + litem.getLabel(), litem.getDescription(), litem.getToolTipText(),
+                            litem.getURLText(), false, SPACE,
+                            false, litem.getFillPaint(), false,
+                            litem.getOutlinePaint(), litem.getOutlineStroke(), false,
+                            SPACE, litem.getLineStroke(), litem.getLinePaint());
+                        newLegend.add(merged);
+                    }
+                    else {
+                        newLegend.add(itemList.get(i));
+                    }
+                }
+            }
+            else {
+                // Do not merge entries.
+                for (LegendItem li: itemList) {
+                    newLegend.add(li);
+                }
+            }
+        }
+
+        plot.setFixedLegendItems (newLegend);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/LegendSection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LegendSection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,14 +1,15 @@
 package de.intevation.flys.exports;
 
 
-
 /**
+ * Settings regarding legend of chart.
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class LegendSection extends TypeSection {
 
-    public static final String VISIBILITY_ATTR = "visibility";
-    public static final String FONTSIZE_ATTR   = "font-size";
+    public static final String VISIBILITY_ATTR  = "visibility";
+    public static final String FONTSIZE_ATTR    = "font-size";
+    public static final String AGGREGATION_ATTR = "aggregation-threshold";
 
 
     public LegendSection() {
@@ -16,6 +17,7 @@
     }
 
 
+    /** Register font size attribute and value. */
     public void setFontSize(int fontSize) {
         if (fontSize <= 0) {
             return;
@@ -30,6 +32,16 @@
     }
 
 
+    public Integer getAggregationThreshold() {
+        return getIntegerValue(AGGREGATION_ATTR);
+    }
+
+
+    public void setAggregationThreshold(int aggregationThreshold) {
+        setIntegerValue(AGGREGATION_ATTR, Math.abs(aggregationThreshold));
+    }
+
+
     public void setVisibility(boolean visibility) {
         setBooleanValue(VISIBILITY_ATTR, visibility);
     }
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/LongitudinalSectionGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,34 +1,30 @@
 package de.intevation.flys.exports;
 
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.geom.Lines;
+import de.intevation.flys.artifacts.model.AreaFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.WKms;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledAreaSeriesCollection;
+import de.intevation.flys.jfree.StyledXYSeries;
+import de.intevation.flys.utils.DataUtil;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.ThemeUtil;
 
 import org.apache.log4j.Logger;
-
-import org.jfree.chart.JFreeChart;
 import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.title.TextTitle;
 import org.jfree.chart.axis.ValueAxis;
 import org.jfree.chart.plot.XYPlot;
 import org.jfree.data.xy.XYSeries;
-
 import org.w3c.dom.Document;
 
-import de.intevation.artifactdatabase.state.ArtifactAndFacet;
-import de.intevation.artifactdatabase.state.Facet;
-
-import de.intevation.flys.artifacts.FLYSArtifact;
-
-import de.intevation.flys.artifacts.model.FacetTypes;
-import de.intevation.flys.artifacts.model.WKms;
-import de.intevation.flys.artifacts.model.WQKms;
-
-import de.intevation.flys.jfree.FLYSAnnotation;
-
-import de.intevation.flys.utils.FLYSUtils;
-import de.intevation.flys.utils.DataUtil;
-
 
 /**
- * An OutGenerator that generates discharge curves.
+ * An OutGenerator that generates longitudinal section curves.
  *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
@@ -38,11 +34,11 @@
 {
     public enum YAXIS {
         W(0),
-        Q(1),
-        D(2);
+        D(1),
+        Q(2);
         protected int idx;
         private YAXIS(int c) {
-           idx = c;
+            idx = c;
         }
     }
 
@@ -68,6 +64,13 @@
     public static final String I18N_CHART_SUBTITLE =
         "chart.longitudinal.section.subtitle";
 
+    /**
+     * Key to look up internationalized String for LongitudinalSection diagrams
+     * short subtitles.
+     */
+    public static final String I18N_CHART_SHORT_SUBTITLE =
+        "chart.longitudinal.section.shortsubtitle";
+
     public static final String I18N_XAXIS_LABEL =
         "chart.longitudinal.section.xaxis.label";
 
@@ -113,15 +116,42 @@
     }
 
 
+    /** True if x axis has been inverted. */
     public boolean isInverted() {
         return inverted;
     }
 
 
+    /** Set to true if x axis has been inverted. */
     public void setInverted(boolean inverted) {
         this.inverted = inverted;
     }
 
+    /**
+     * Return left most data points x value (on first axis).
+     * Overridden because axis could be inverted.
+     */
+    @Override
+    protected double getLeftX() {
+        if (isInverted()) {
+            return (Double)getXBounds(0).getUpper();
+        }
+        return (Double)getXBounds(0).getLower();
+    }
+
+
+    /**
+     * Return right most data points x value (on first axis).
+     * Overridden because axis could be inverted.
+     */
+    @Override
+    protected double getRightX() {
+        if (isInverted()) {
+            return (Double)getXBounds(0).getLower();
+        }
+        return (Double)getXBounds(0).getUpper();
+    }
+
 
     /**
      * Returns the default title for this chart.
@@ -143,14 +173,16 @@
     protected String getDefaultChartSubtitle() {
         double[] dist = getRange();
 
-        Object[] args = new Object[] {
+        Object[] args = null;
+        if (dist == null) {
+            args = new Object[] {getRiverName()};
+            return msg(getChartShortSubtitleKey(), "", args);
+        }
+        args = new Object[] {
             getRiverName(),
-
             dist[0],
-
             dist[1]
         };
-
         return msg(getChartSubtitleKey(), "", args);
     }
 
@@ -165,16 +197,12 @@
 
 
     /**
-     * Add (internationalized) subtitle to chart.
-     * @see getChartSubtitleKey
+     * Gets key to look up internationalized String for the charts short
+     * subtitle.
+     * @return key to look up translated subtitle.
      */
-    @Override
-    protected void addSubtitles(JFreeChart chart) {
-        String subtitle = getChartSubtitle();
-
-        if (subtitle != null && subtitle.length() > 0) {
-            chart.addSubtitle(new TextTitle(subtitle));
-        }
+    protected String getChartShortSubtitleKey() {
+        return I18N_CHART_SHORT_SUBTITLE;
     }
 
 
@@ -280,7 +308,6 @@
      * @param xaxis The domain axis.
      */
     protected void invertXAxis(ValueAxis xaxis) {
-
         if (inverted) {
             logger.debug("X-Axis.setInverted(true)");
             xaxis.setInverted(true);
@@ -290,9 +317,10 @@
 
     /**
      * Produce output.
-     * @param facet current facet.
+     * @param artifactAndFacet current facet and artifact.
      * @param attr  theme for facet
      */
+    @Override
     public void doOut(
         ArtifactAndFacet artifactAndFacet,
         Document         attr,
@@ -314,33 +342,70 @@
         }
 
         if (name.equals(LONGITUDINAL_W)) {
-            doWOut((WQKms) artifactAndFacet.getData(context), facet, attr, visible);
+            doWOut(
+                (WQKms) artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
         }
         else if (name.equals(LONGITUDINAL_Q)) {
-            doQOut((WQKms) artifactAndFacet.getData(context), facet, attr, visible);
+            doQOut(
+                (WQKms) artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
         }
         else if (name.equals(LONGITUDINAL_ANNOTATION)) {
-            doAnnotations((FLYSAnnotation) artifactAndFacet.getData(context),
-                 facet, attr, visible);
+            doAnnotations(
+                (FLYSAnnotation) artifactAndFacet.getData(context),
+                 artifactAndFacet,
+                 attr,
+                 visible);
         }
         else if (name.equals(STATIC_WKMS)
                 || name.equals(HEIGHTMARKS_POINTS)
                 || name.equals(STATIC_WQKMS)) {
-            doWOut((WKms) artifactAndFacet.getData(context), facet, attr, visible);
+            doWOut(
+                (WKms) artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
+        }
+        else if (name.equals(STATIC_WQKMS_W)) {
+            doWOut(
+                (WQKms) artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
+        }
+        else if (name.equals(STATIC_WQKMS_Q)) {
+            doQOut(
+                (WQKms) artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
         }
         else if (name.equals(W_DIFFERENCES)) {
             doWDifferencesOut(
                 (WKms) artifactAndFacet.getData(context),
-                facet,
+                artifactAndFacet,
                 attr,
                 visible);
         }
         else if (FacetTypes.IS.AREA(name)) {
-            doArea(artifactAndFacet.getData(context),
-                artifactAndFacet.getFacetDescription(),
+            doArea(
+                artifactAndFacet.getData(context),
+                artifactAndFacet,
                 attr,
                 visible);
-        
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(
+                artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible,
+                YAXIS.W.idx);
         }
         else {
             logger.warn("Unknown facet name: " + name);
@@ -352,31 +417,45 @@
     /**
      * Process the output for W facets in a longitudinal section curve.
      *
-     * @param wqkms An array of WQKms values.
-     * @param facet The facet. This facet does NOT support any data objects. Use
+     * @param wkms WKms data.
+     * @param aandf The artifact and facet. This facet does NOT support any data objects. Use
      * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
      * data.
      * @param theme The theme that contains styling information.
      * @param visible The visibility of the curve.
      */
     protected void doWOut(
-        WKms     wkms,
-        Facet    facet,
-        Document theme,
-        boolean  visible
+        WKms             wkms,
+        ArtifactAndFacet aandf,
+        Document         theme,
+        boolean          visible
     ) {
         logger.debug("LongitudinalSectionGenerator.doWOut");
 
-        XYSeries series = new StyledXYSeries(facet.getDescription(), theme);
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
 
         StyledSeriesBuilder.addPoints(series, wkms);
-
         addAxisSeries(series, YAXIS.W.idx, visible);
 
-        if (wkms instanceof WQKms) {
-            if (needInvertAxis((WQKms) wkms)) {
-                setInverted(true);
-            }
+        // If a "band around the curve shall be drawn, add according area.
+        double bandWidth = ThemeUtil.parseBandWidth(theme);
+        if (bandWidth > 0 ) {
+            XYSeries seriesDown = new StyledXYSeries(
+                "band " + aandf.getFacetDescription(), false, theme);
+            XYSeries seriesUp = new StyledXYSeries(
+                aandf.getFacetDescription()+"+/-"+bandWidth, false, theme);
+            StyledSeriesBuilder.addUpperBand(seriesUp, wkms, bandWidth);
+            StyledSeriesBuilder.addLowerBand(seriesDown, wkms, bandWidth);
+
+            StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme);
+            area.addSeries(seriesUp);
+            area.addSeries(seriesDown);
+            area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
+            addAreaSeries(area, YAXIS.W.idx, visible);
+        }
+
+        if (needInvertAxis(wkms)) {
+            setInverted(true);
         }
     }
 
@@ -386,7 +465,7 @@
      */
     protected void doWDifferencesOut(
         WKms       wkms,
-        Facet      facet,
+        ArtifactAndFacet aandf,
         Document   theme,
         boolean    visible
     ) {
@@ -396,7 +475,7 @@
             return;
          }
 
-        XYSeries series = new StyledXYSeries(facet.getDescription(), theme);
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
 
         if (logger.isDebugEnabled()) {
             if (wkms.size() > 0) {
@@ -416,12 +495,11 @@
     }
 
 
-
     /**
      * Process the output for Q facets in a longitudinal section curve.
      *
      * @param wqkms An array of WQKms values.
-     * @param facet The facet. This facet does NOT support any data objects. Use
+     * @param aandf The facet and artifact. This facet does NOT support any data objects. Use
      * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
      * data.
      * @param theme The theme that contains styling information.
@@ -429,15 +507,15 @@
      */
     protected void doQOut(
         WQKms    wqkms,
-        Facet    facet,
+        ArtifactAndFacet aandf,
         Document theme,
         boolean  visible
     ) {
         logger.debug("LongitudinalSectionGenerator.doQOut");
 
-        XYSeries series = new StyledXYSeries(facet.getDescription(), theme);
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
 
-        StyledSeriesBuilder.addPointsKmQ(series, wqkms);
+        StyledSeriesBuilder.addStepPointsKmQ(series, wqkms);
 
         addAxisSeries(series, YAXIS.Q.idx, visible);
 
@@ -446,27 +524,26 @@
         }
     }
 
-
     /**
      * This method determines - taking JFreeCharts auto x value ordering into
      * account - if the x axis need to be inverted. Waterlines in these charts
      * should decrease.
      *
-     * @param wqkms The data object that stores the x and y values used for this
+     * @param wkms The data object that stores the x and y values used for this
      * chart.
      */
-    public boolean needInvertAxis(WQKms wqkms) {
-        boolean wsUp = wqkms.guessWaterIncreasing();
-        boolean kmUp = DataUtil.guessWaterIncreasing(wqkms.allKms());
+    public boolean needInvertAxis(WKms wkms) {
+        boolean wsUp = wkms.guessWaterIncreasing();
+        boolean kmUp = DataUtil.guessWaterIncreasing(wkms.allKms());
         boolean inv = (wsUp && kmUp) || (!wsUp && !kmUp);
 
-        int size = wqkms.size();
+        int size = wkms.size();
 
         if (logger.isDebugEnabled()) {
-            logger.debug("Values  : " + size);
+            logger.debug("(Wkms)Values  : " + size);
             if (size > 0) {
-                logger.debug("Start km: " + wqkms.getKm(0));
-                logger.debug("End   km: " + wqkms.getKm(size-1));
+                logger.debug("Start km: " + wkms.getKm(0));
+                logger.debug("End   km: " + wkms.getKm(size-1));
             }
             logger.debug("wsUp: " + wsUp);
             logger.debug("kmUp: " + kmUp);
@@ -491,69 +568,119 @@
     }
 
 
+    /** Look up the axis identifier for a given facet type. */
+    public int axisIdxForFacet(String facetName) {
+        if (FacetTypes.IS.W(facetName)) {
+            return YAXIS.W.idx;
+        }
+        else if (FacetTypes.IS.Q(facetName)) {
+            return YAXIS.Q.idx;
+        }
+        else {
+            logger.warn("Could not find axis for facet " + facetName);
+            return YAXIS.W.idx;
+        }
+    }
+
+
     /**
      * Do Area out.
+     * @param theme styling information.
+     * @param visible whether or not visible.
      */
     protected void doArea(
         Object     o,
-        String     seriesName,
+        ArtifactAndFacet aandf,
         Document   theme,
         boolean    visible
     ) {
         logger.debug("LongitudinalSectionGenerator.doArea");
         StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme);
 
-        // TODO make this more stable.
-        Object[] doubles = (Object[]) o;
+        String seriesName = aandf.getFacetDescription();
+
+        AreaFacet.Data data = (AreaFacet.Data) o;
+
         XYSeries up   = null;
         XYSeries down = null;
 
-        if (doubles[1] != null) {
+        if (data.getUpperData() != null) {
             up = new StyledXYSeries(seriesName, false, theme);
-            if (doubles[1] instanceof WKms) {
-                StyledSeriesBuilder.addPoints(up, (WKms) doubles[1]);
+            if (data.getUpperData() instanceof WQKms) {
+                if (FacetTypes.IS.Q(data.getRootFacetName())) {
+                    StyledSeriesBuilder.addPointsKmQ(up, (WQKms) data.getUpperData());
+                }
+                else {
+                    StyledSeriesBuilder.addPoints(up, (WKms) data.getUpperData());
+                }
             }
-            else if (doubles[1] instanceof double[][]) {
-                StyledSeriesBuilder.addPoints(up, (double [][]) doubles[1]);
+            else if (data.getUpperData() instanceof double[][]) {
+                StyledSeriesBuilder.addPoints(up, (double [][]) data.getUpperData(), false);
+            }
+            else if (data.getUpperData() instanceof WKms) {
+                StyledSeriesBuilder.addPoints(up, (WKms) data.getUpperData());
+            }
+            else if (data.getUpperData() instanceof Lines.LineData) {
+                StyledSeriesBuilder.addPoints(up, ((Lines.LineData) data.getUpperData()).points, false);
             }
             else {
                 logger.error("Do not know how to deal with (up) area info from: "
-                    + doubles[1]);
+                    + data.getUpperData());
             }
         }
 
-        if (doubles[0] != null) {
+        // TODO Depending on style, the area (e.g. 20m^2) should be added as annotation.
+
+        if (data.getLowerData() != null) {
             // TODO: Sort this out: when the two series have the same name,
             // the renderer (or anything in between) will not work correctly.
             down = new StyledXYSeries(seriesName + " ", false, theme);
-            if (doubles[0] instanceof WQKms) {
-                StyledSeriesBuilder.addPoints(down, (WKms) doubles[0]);
+            if (data.getLowerData() instanceof WQKms) {
+                if (FacetTypes.IS.Q(data.getRootFacetName())) {
+                    StyledSeriesBuilder.addPointsKmQ(down, (WQKms) data.getLowerData());
+                }
+                else {
+                    StyledSeriesBuilder.addPoints(down, (WQKms) data.getLowerData());
+                }
             }
-            else if (doubles[0] instanceof double[][]) {
-                StyledSeriesBuilder.addPoints(down, (double[][]) doubles[0]);
+            else if (data.getLowerData() instanceof double[][]) {
+                StyledSeriesBuilder.addPoints(down, (double[][]) data.getLowerData(), false);
+            }
+            else if (data.getLowerData() instanceof WKms) {
+                StyledSeriesBuilder.addPoints(down, (WKms) data.getLowerData());
+            }
+            else if (data.getLowerData() instanceof Lines.LineData) {
+                StyledSeriesBuilder.addPoints(down, ((Lines.LineData) data.getLowerData()).points, false);
             }
             else {
                 logger.error("Do not know how to deal with (down) area info from: "
-                    + doubles[0]);
+                    + data.getLowerData());
             }
-
         }
 
         if (up == null && down != null) {
             area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE);
             down.setKey(seriesName);
             area.addSeries(down);
+            area.addSeries(StyledSeriesBuilder.createGroundAtInfinity(down));
         }
         else if (up != null && down == null) {
             area.setMode(StyledAreaSeriesCollection.FILL_MODE.UNDER);
             area.addSeries(up);
+            area.addSeries(StyledSeriesBuilder.createGroundAtInfinity(up));
         }
         else if (up != null && down != null) {
-            area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
+            if (data.doPaintBetween()) {
+                area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
+            }
+            else {
+                area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE);
+            }
             area.addSeries(up);
             area.addSeries(down);
         }
-        addAreaSeries(area, 0, visible);
+        // Add area to the respective axis.
+        addAreaSeries(area, axisIdxForFacet(data.getRootFacetName()), visible);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/MapGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/MapGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,25 @@
 package de.intevation.flys.exports;
 
+import com.vividsolutions.jts.geom.Envelope;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.artifactdatabase.state.Settings;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+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.model.FacetTypes;
+import de.intevation.flys.artifacts.model.map.WMSDBLayerFacet;
+import de.intevation.flys.artifacts.model.map.WMSLayerFacet;
+import de.intevation.flys.artifacts.model.map.WSPLGENLayerFacet;
+import de.intevation.flys.collections.FLYSArtifactCollection;
+import de.intevation.flys.utils.GeometryUtils;
+import de.intevation.flys.utils.MapfileGenerator;
+import de.intevation.flys.utils.ThemeUtil;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -7,37 +27,17 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.log4j.Logger;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-import org.apache.log4j.Logger;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-import de.intevation.artifacts.Artifact;
-import de.intevation.artifacts.CallContext;
-
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
-import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
-
-import de.intevation.artifactdatabase.state.ArtifactAndFacet;
-import de.intevation.artifactdatabase.state.Facet;
-import de.intevation.artifactdatabase.state.Settings;
-
-import de.intevation.flys.artifacts.FLYSArtifact;
-import de.intevation.flys.artifacts.model.FacetTypes;
-import de.intevation.flys.artifacts.model.WMSDBLayerFacet;
-import de.intevation.flys.artifacts.model.WMSLayerFacet;
-import de.intevation.flys.utils.GeometryUtils;
-import de.intevation.flys.utils.MapfileGenerator;
-import de.intevation.flys.utils.ThemeUtil;
-
 
 public class MapGenerator implements OutGenerator, FacetTypes {
 
     private static Logger logger = Logger.getLogger(MapGenerator.class);
 
+    protected FLYSArtifactCollection collection;
+
     protected Artifact master;
 
     protected Settings settings;
@@ -78,6 +78,10 @@
         this.master = master;
     }
 
+    @Override
+    public void setCollection(FLYSArtifactCollection collection) {
+        this.collection = collection;
+    }
 
     @Override
     public void doOut(
@@ -95,7 +99,7 @@
 
         if (nativeFacet instanceof WMSLayerFacet) {
             WMSLayerFacet wms = (WMSLayerFacet) nativeFacet;
-            Envelope   extent = wms.getExtent();
+            Envelope   extent = wms.getOriginalExtent();
 
             layers.add(wms);
 
@@ -103,15 +107,15 @@
             setSrid(wms.getSrid());
 
             if (FLOODMAP_WSPLGEN.equals(name)) {
-                if (initialExtent == null) {
-                    setInitialExtent(extent);
-                }
-
-                createWSPLGENLayer(flys, wms);
+                setInitialExtent(extent);
+                createWSPLGENLayer(flys, wms, attr);
             }
             else if (FLOODMAP_BARRIERS.equals(name)) {
                 createBarriersLayer(flys, wms);
             }
+            else if (FLOODMAP_USERSHAPE.equals(name)) {
+                createUserShapeLayer(flys, wms);
+            }
             else {
                 createDatabaseLayer(flys, wms, attr);
             }
@@ -122,10 +126,24 @@
     }
 
 
-    protected void createWSPLGENLayer(FLYSArtifact flys, WMSLayerFacet wms) {
+    protected void createWSPLGENLayer(
+        FLYSArtifact  flys,
+        WMSLayerFacet wms,
+        Document      attr
+    ) {
         try {
-            MapfileGenerator mfg = MapfileGenerator.getInstance();
-            mfg.createUeskLayer(flys, wms);
+            if(wms instanceof WSPLGENLayerFacet) {
+                MapfileGenerator mfg = MapfileGenerator.getInstance();
+                mfg.createUeskLayer(
+                    flys,
+                    (WSPLGENLayerFacet) wms,
+                    ThemeUtil.createWSPLGENStyle(attr),
+                    context);
+            }
+            else {
+                logger.warn("Cannot create WSPLGEN layer from: " +
+                            wms.getClass());
+            }
         }
         catch (IOException ioe) {
             logger.error(ioe, ioe);
@@ -148,6 +166,21 @@
     }
 
 
+    protected void createUserShapeLayer(FLYSArtifact flys, WMSLayerFacet wms) {
+        MapfileGenerator mfg = MapfileGenerator.getInstance();
+
+        try {
+            mfg.createUserShapeLayer(flys, wms);
+        }
+        catch (FileNotFoundException fnfe) {
+            logger.error(fnfe, fnfe);
+        }
+        catch (IOException ioe) {
+            logger.error(ioe, ioe);
+        }
+    }
+
+
     protected void createDatabaseLayer(
         FLYSArtifact  flys,
         WMSLayerFacet wms,
@@ -226,30 +259,19 @@
 
         if (this.maxExtent == null) {
             logger.debug("Set max extent to: " + maxExtent);
-            this.maxExtent = maxExtent;
+            this.maxExtent = new Envelope(maxExtent);
             return;
         }
 
-        logger.debug("Expand max extent by: " + maxExtent);
-        logger.debug("Max extent before expanding: " + this.maxExtent);
         this.maxExtent.expandToInclude(maxExtent);
-        logger.debug("Max extent after expanding: " + this.maxExtent);
     }
 
 
     protected void setInitialExtent(Envelope initialExtent) {
-        if (initialExtent == null) {
-            return;
-        }
-
-        if (this.initialExtent == null) {
+        if (this.initialExtent == null && initialExtent != null) {
             logger.debug("Set initial extent to: " + initialExtent);
-            this.initialExtent = initialExtent;
-            return;
+            this.initialExtent = new Envelope(initialExtent);
         }
-
-        logger.debug("Set initial extent to: " + initialExtent);
-        this.initialExtent = initialExtent;
     }
 
 
@@ -264,17 +286,16 @@
 
     protected void appendMapInformation(Element parent, ElementCreator c) {
         String mE = GeometryUtils.jtsBoundsToOLBounds(this.maxExtent);
-        logger.debug("BUILD MAX EXTENT OF:" + this.maxExtent);
-        logger.debug("BUILD MAX EXTENT:" + mE);
 
         Element maxExtent = c.create("maxExtent");
         maxExtent.setTextContent(mE);
 
-        String iE = GeometryUtils.jtsBoundsToOLBounds(this.initialExtent);
-        logger.debug("BUILD INITIAL EXTENT OF: " + this.initialExtent);
-        logger.debug("BUILD INITIAL EXTENT: " + iE);
-        Element initExtent = c.create("initialExtent");
-        initExtent.setTextContent(iE);
+        if(this.initialExtent != null) {
+            String iE = GeometryUtils.jtsBoundsToOLBounds(this.initialExtent);
+            Element initExtent = c.create("initialExtent");
+            initExtent.setTextContent(iE);
+            parent.appendChild(initExtent);
+        }
 
         Element srid = c.create("srid");
         srid.setTextContent(this.srid);
@@ -283,7 +304,6 @@
         // TODO resolutation
 
         parent.appendChild(maxExtent);
-        parent.appendChild(initExtent);
         parent.appendChild(srid);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/MiddleBedHeightExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,158 @@
+package de.intevation.flys.exports;
+
+import java.io.OutputStream;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Document;
+
+import org.apache.log4j.Logger;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.MiddleBedHeightData;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.Formatter;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class MiddleBedHeightExporter extends AbstractExporter {
+
+    /** Private logger. */
+    private static final Logger logger =
+        Logger.getLogger(MiddleBedHeightExporter.class);
+
+    public static final String CSV_KM =
+        "export.bedheight_middle.csv.header.km";
+
+    public static final String CSV_SOUNDING =
+        "export.bedheight_middle.csv.header.sounding";
+
+    public static final String CSV_HEIGHT =
+        "export.bedheight_middle.csv.header.height";
+
+    public static final String CSV_UNCERTAINTY =
+        "export.bedheight_middle.csv.header.uncertainty";
+
+    public static final String CSV_DATA_GAP =
+        "export.bedheight_middle.csv.header.datagap";
+
+    public static final String CSV_SOUNDING_WIDTH =
+        "export.bedheight_middle.csv.header.soundingwidth";
+
+    public static final String CSV_WIDTH =
+        "export.bedheight_middle.csv.header.width";
+
+    public static final String CSV_LOCATIONS =
+        "export.bedheight_middle.csv.header.locations";
+
+
+    protected List<MiddleBedHeightData[]> data;
+
+
+    public void init(Document request, OutputStream out, CallContext cc) {
+        super.init(request, out, cc);
+        data = new ArrayList<MiddleBedHeightData[]>();
+    }
+
+
+    @Override
+    protected void addData(Object d) {
+        if (d instanceof CalculationResult) {
+            d = ((CalculationResult) d).getData();
+
+            if (d instanceof MiddleBedHeightData[]) {
+                logger.debug("Add new data of type MiddleBedHeightData");
+                data.add((MiddleBedHeightData[]) d);
+            }
+        }
+    }
+
+
+    @Override
+    protected void writeCSVData(CSVWriter writer) {
+        logger.info("MiddleBedHeightExporter.writeCSVData");
+        logger.debug("CSV gets " + data.size() + " MiddleBedHeightData objects.");
+
+        writeCSVHeader(writer);
+
+        for (MiddleBedHeightData[] d: data) {
+            data2CSV(writer, d);
+        }
+    }
+
+
+    protected void writeCSVHeader(CSVWriter writer) {
+        writer.writeNext(new String[] {
+            msg(CSV_KM, CSV_KM),
+            msg(CSV_SOUNDING, CSV_SOUNDING),
+            msg(CSV_HEIGHT, CSV_HEIGHT),
+            msg(CSV_UNCERTAINTY, CSV_UNCERTAINTY),
+            msg(CSV_DATA_GAP, CSV_DATA_GAP),
+            msg(CSV_SOUNDING_WIDTH, CSV_SOUNDING_WIDTH),
+            msg(CSV_WIDTH, CSV_WIDTH),
+            msg(CSV_LOCATIONS, CSV_LOCATIONS)
+        });
+    }
+
+
+    protected void data2CSV(CSVWriter writer, MiddleBedHeightData[] mData) {
+        logger.debug("Add next MiddleBedHeightData to CSV");
+
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        NumberFormat kmF     = Formatter.getMiddleBedHeightKM(context);
+        NumberFormat heightF = Formatter.getMiddleBedHeightHeight(context);
+        NumberFormat uncertF = Formatter.getMiddleBedHeightUncert(context);
+        NumberFormat gapF    = Formatter.getMiddleBedHeightDataGap(context);
+        NumberFormat soundF  = Formatter.getMiddleBedHeightSounding(context);
+        NumberFormat widthF  = Formatter.getMiddleBedHeightWidth(context);
+
+        for (MiddleBedHeightData data: mData) {
+            for (int i = 0, n = data.size(); i < n; i++) {
+                int start = data.getStartYear();
+                int end   = data.getEndYear();
+
+                if (start == end) {
+                    writer.writeNext(new String[] {
+                        kmF.format(data.getKM(i)),
+                        data.getSoundingName(context),
+                        heightF.format(data.getMiddleHeight(i)),
+                        uncertF.format(data.getUncertainty(i)),
+                        gapF.format(data.getDataGap(i)) + "%",
+                        soundF.format(data.getSoundingWidth(i)),
+                        widthF.format(data.getWidth(i)),
+                        FLYSUtils.getLocationDescription(flys, data.getKM(i)),
+                    });
+                }
+                else {
+                    writer.writeNext(new String[] {
+                        kmF.format(data.getKM(i)),
+                        data.getSoundingName(context),
+                        heightF.format(data.getMiddleHeight(i)),
+                        "",
+                        "",
+                        "",
+                        "",
+                        FLYSUtils.getLocationDescription(flys, data.getKM(i)),
+                    });
+                }
+
+            }
+        }
+    }
+
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        logger.error("TODO: Implement FlowVelocityExporter.writePDF");
+    }
+}
+// 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/exports/MiddleBedHeightGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,248 @@
+package de.intevation.flys.exports;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.data.xy.XYSeries;
+
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.MiddleBedHeightData;
+
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+
+/**
+ * An OutGenerator that generates middle bed height charts.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class MiddleBedHeightGenerator
+extends      XYChartGenerator
+implements   FacetTypes
+{
+    public enum YAXIS {
+        H(0);
+        protected int idx;
+        private YAXIS(int c) {
+           idx = c;
+        }
+    }
+
+    /** The logger that is used in this generator. */
+    private static Logger logger = Logger.getLogger(MiddleBedHeightGenerator.class);
+
+    /** Key to look up internationalized String for annotations label. */
+    public static final String I18N_ANNOTATIONS_LABEL =
+        "chart.bedheight_middle.annotations.label";
+
+    public static final String I18N_CHART_TITLE =
+        "chart.bedheight_middle.section.title";
+
+    public static final String I18N_CHART_SUBTITLE =
+        "chart.bedheight_middle.section.subtitle";
+
+    public static final String I18N_CHART_SHORT_SUBTITLE =
+        "chart.bedheight_middle.section.shortsubtitle";
+
+    public static final String I18N_XAXIS_LABEL =
+        "chart.bedheight_middle.section.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL =
+        "chart.bedheight_middle.section.yaxis.label";
+
+    public static final String I18N_CHART_TITLE_DEFAULT  = "Mittlere Sohlöhe";
+    public static final String I18N_XAXIS_LABEL_DEFAULT  = "km";
+    public static final String I18N_YAXIS_LABEL_DEFAULT  = "mittlere Sohlhöhen [müNN]";
+
+
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+
+    /**
+     * Returns the default title for this chart.
+     *
+     * @return the default title for this chart.
+     */
+    @Override
+    public String getDefaultChartTitle() {
+        Object[] args = new Object[] {
+            getRiverName()
+        };
+
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, args);
+    }
+
+
+    /**
+     * Get internationalized label for the x axis.
+     */
+    @Override
+    protected String getDefaultXAxisLabel() {
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        return msg(
+            I18N_XAXIS_LABEL,
+            I18N_XAXIS_LABEL_DEFAULT,
+            new Object[] { FLYSUtils.getRiver(flys).getName() });
+    }
+
+
+    @Override
+    protected String getDefaultYAxisLabel(int index) {
+        String label = "default";
+
+        if (index == YAXIS.H.idx) {
+            label = getHAxisLabel();
+        }
+
+        return label;
+    }
+
+
+    /**
+     * Get internationalized label for the y axis.
+     */
+    protected String getHAxisLabel() {
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+    }
+
+
+    /**
+     * Produce output.
+     * @param artifactAndFacet current facet.
+     * @param attr  theme for facet
+     */
+    public void doOut(
+        ArtifactAndFacet artifactAndFacet,
+        Document         attr,
+        boolean          visible
+    ) {
+        String name = artifactAndFacet.getFacetName();
+
+        logger.debug("MiddleBedHeightGenerator.doOut: " + name);
+
+        if (name == null) {
+            logger.error("No facet name for doOut(). No output generated!");
+            return;
+        }
+
+        Facet facet = artifactAndFacet.getFacet();
+
+        if (facet == null) {
+            return;
+        }
+
+        if (name.equals(MIDDLE_BED_HEIGHT_SINGLE) || name.equals(MIDDLE_BED_HEIGHT_EPOCH)) {
+            doHeightOut(
+                (MiddleBedHeightData) artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
+        }
+        else if (name.equals(MIDDLE_BED_HEIGHT_ANNOTATION)) {
+            doAnnotations(
+                (FLYSAnnotation) artifactAndFacet.getData(context),
+                 artifactAndFacet,
+                 attr,
+                 visible);
+        }
+        else if (FacetTypes.IS.AREA(name)) {
+            doArea(
+                artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(
+                artifactAndFacet.getData(context),
+                artifactAndFacet,
+                attr,
+                visible,
+                YAXIS.H.idx);
+        }
+        else {
+            logger.warn("Unknown facet name: " + name);
+            return;
+        }
+    }
+
+
+    /**
+     * @param data A data object
+     * @param aandf The artifact and facet. This facet does NOT support any data objects. Use
+     * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
+     * data.
+     * @param theme The theme that contains styling information.
+     * @param visible The visibility of the curve.
+     */
+    protected void doHeightOut(
+        MiddleBedHeightData data,
+        ArtifactAndFacet    aandf,
+        Document            theme,
+        boolean             visible
+    ) {
+        logger.debug("MiddleBedHeightGenerator.doMainChannelOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        StyledSeriesBuilder.addPoints(series, data.getMiddleHeightsPoints(), false);
+
+        addAxisSeries(series, YAXIS.H.idx, visible);
+    }
+
+
+    /** Look up the axis identifier for a given facet type. */
+    public int axisIdxForFacet(String facetName) {
+        if (FacetTypes.IS.H(facetName)) {
+            return YAXIS.H.idx;
+        }
+        else {
+            logger.warn("Could not find axis for facet " + facetName);
+            return YAXIS.H.idx;
+        }
+    }
+
+
+    /**
+     * Do Area out.
+     * @param theme styling information.
+     * @param visible whether or not visible.
+     */
+    protected void doArea(
+        Object     o,
+        ArtifactAndFacet aandf,
+        Document   theme,
+        boolean    visible
+    ) {
+        logger.debug("FlowVelocityGenerator.doArea");
+        logger.warn("TODO: Implement FlowVelocityGenerator.doArea");
+    }
+}
+// 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/exports/MiddleBedHeightInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.exports;
+
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific
+ * middle bed height curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class MiddleBedHeightInfoGenerator
+extends      ChartInfoGenerator
+{
+    public MiddleBedHeightInfoGenerator() {
+        super(new MiddleBedHeightGenerator());
+    }
+}
+// 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/exports/NormalizedReferenceCurveGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.flys.exports;
+
+import org.apache.log4j.Logger;
+
+/**
+ * An OutGenerator that generates reference curves.
+ */
+public class NormalizedReferenceCurveGenerator
+extends      ReferenceCurveGenerator
+{
+    /** House logger. */
+    private static Logger logger =
+        Logger.getLogger(NormalizedReferenceCurveGenerator.class);
+
+    public static final String I18N_NORMALIZED_CHART_TITLE =
+        "chart.normalized.reference.curve.title";
+
+    public static final String I18N_NORMALIZED_CHART_TITLE_DEFAULT  =
+        "Reduzierte Bezugslinie";
+
+    public NormalizedReferenceCurveGenerator() {
+    }
+
+    /** Get default chart title. */
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(
+            I18N_NORMALIZED_CHART_TITLE,
+            I18N_NORMALIZED_CHART_TITLE_DEFAULT);
+    }
+
+    @Override
+    protected String facetName() {
+        return REFERENCE_CURVE_NORMALIZED;
+    }
+
+    @Override
+    protected boolean doNormalize() {
+        return true;
+    }
+}
+// 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/exports/NormalizedReferenceCurveInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.exports;
+
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific reference
+ * curves.
+ */
+public class NormalizedReferenceCurveInfoGenerator
+extends      ChartInfoGenerator
+{
+    public NormalizedReferenceCurveInfoGenerator() {
+        super(new NormalizedReferenceCurveGenerator());
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/OutGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/OutGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -9,6 +9,7 @@
 import de.intevation.artifactdatabase.state.Settings;
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
+import de.intevation.flys.collections.FLYSArtifactCollection;
 
 
 /**
@@ -38,10 +39,17 @@
     void setMasterArtifact(Artifact master);
 
     /**
+     * This method is used to set the Collection of the OutGenerator.
+     *
+     * @param collection A reference to the collection.
+     */
+    void setCollection(FLYSArtifactCollection collection);
+
+    /**
      * Creates the output of an Artifact and appends that single output to the
      * total output.
      *
-     * @param artifact The artifact that provides information and data for the
+     * @param bundle The Facet and artifact that provides information and data for the
      * single output.
      * @param attr A document that might contain some attributes used while
      * producing the output.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/OutputHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,519 @@
+package de.intevation.flys.exports;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifactdatabase.Backend;
+import de.intevation.artifactdatabase.Backend.PersistentArtifact;
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactDatabase;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.ClientProtocolUtils;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.artifacts.model.ManagedDomFacet;
+import de.intevation.flys.artifacts.model.ManagedFacet;
+import de.intevation.flys.themes.Theme;
+import de.intevation.flys.themes.ThemeFactory;
+
+public class OutputHelper {
+    /** The logger used in this class. */
+    private static Logger log = Logger.getLogger(OutputHelper.class);
+
+    protected String identifier;
+
+    public OutputHelper(String identifier) {
+        this.identifier = identifier;
+    }
+    /**
+     * Creates a concrete output.
+     *
+     * @param generator The OutGenerator that creates the output.
+     * @param outputName The name of the requested output.
+     * @param attributes The collection's attributes for this concrete output
+     * type.
+     * @param context The context object.
+     */
+    public void doOut(
+        OutGenerator generator,
+        String       outName,
+        String       facet,
+        Document     attributes,
+        CallContext  context)
+    throws IOException
+    {
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("FLYSArtifactCollection.doOut: " + outName);
+        }
+
+        ThemeList themeList = new ThemeList(attributes);
+
+        int size = themeList.size();
+        if (debug) {
+            log.debug("Output will contain " + size + " elements.");
+        }
+
+        List<ArtifactAndFacet> dataProviders =
+            doBlackboardPass(themeList, context);
+
+        try {
+            for (int i = 0; i < size; i++) {
+                ManagedFacet theme = themeList.get(i);
+
+                if (theme == null) {
+                    log.debug("Theme is empty - no output is generated.");
+                    continue;
+                }
+
+                String art = theme.getArtifact();
+                String facetName = theme.getName();
+
+                if (debug) {
+                    log.debug("Do output for...");
+                    log.debug("... artifact: " + art);
+                    log.debug("... facet: " + facetName);
+                }
+
+                if (outName.equals("export") && !facetName.equals(facet)) {
+                    continue;
+                }
+
+                // Skip invisible themes.
+                if (theme.getVisible() == 0) {
+                    continue;
+                }
+
+                if (outName.equals("sq_overview")) {
+                    generator.doOut(
+                        dataProviders.get(i),
+                        attributes,
+                        theme.getActive() == 1);
+                }
+                else {
+                    generator.doOut(
+                            dataProviders.get(i),
+                            getFacetThemeFromAttribute(
+                                art,
+                                outName,
+                                facetName,
+                                theme.getDescription(),
+                                theme.getIndex(),
+                                context),
+                            theme.getActive() == 1);
+                }
+            }
+        }
+        catch (ArtifactDatabaseException ade) {
+            log.error(ade, ade);
+        }
+    }
+    /**
+     * Returns the attribute that belongs to an artifact and facet stored in
+     * this collection.
+     *
+     * @param uuid The Artifact's uuid.
+     * @param outname The name of the requested output.
+     * @param facet The name of the requested facet.
+     * @param context The CallContext.
+     *
+     * @return an attribute in form of a document.
+     */
+    protected Document getFacetThemeFromAttribute(
+        String      uuid,
+        String      outName,
+        String      facet,
+        String      pattern,
+        int         index,
+        CallContext context)
+    throws    ArtifactDatabaseException
+    {
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug(
+                "FLYSArtifactCollection.getFacetThemeFromAttribute(facet="
+                + facet + ", index=" + index + ")");
+        }
+
+
+        ArtifactDatabase db = context.getDatabase();
+        CallMeta       meta = context.getMeta();
+
+        FLYSContext flysContext = context instanceof FLYSContext
+            ? (FLYSContext) context
+            : (FLYSContext) context.globalContext();
+
+        Document attr = db.getCollectionItemAttribute(identifier, uuid, meta);
+
+        if (attr == null) {
+            attr = initItemAttribute(uuid, facet, pattern, index, outName, context);
+
+            if (attr == null) {
+                return null;
+            }
+        }
+
+        if (debug) {
+            log.debug("Search attribute of collection item: " + uuid);
+        }
+
+        Node tmp = (Node) XMLUtils.xpath(
+            attr,
+            "/art:attribute",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (tmp == null) {
+            log.warn("No attribute found. Operation failed.");
+            return null;
+        }
+
+        if (debug) {
+            log.debug("Search theme for facet '" + facet + "' in attribute.");
+        }
+
+        Map<String, String> vars = new HashMap<String, String>();
+        vars.put("facet", facet);
+        vars.put("index", String.valueOf(index));
+
+        Node theme = (Node) XMLUtils.xpath(
+            tmp,
+            "art:themes/theme[@facet=$facet and @index=$index]",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE,
+            vars);
+
+        if (theme == null) {
+            log.warn("Could not find the theme in attribute of: " + facet + " " + uuid);
+
+            Theme t = getThemeForFacet(
+                uuid, facet, pattern, index, outName, context);
+
+            if (t == null) {
+                log.warn("No theme found for facet: " + facet);
+                return null;
+            }
+
+            addThemeToAttribute(uuid, attr, t, context);
+            theme = t.toXML().getFirstChild();
+        }
+
+        Document doc = XMLUtils.newDocument();
+        doc.appendChild(doc.importNode(theme, true));
+
+        return doc;
+    }
+    /**
+     * Adds the theme of a facet to a CollectionItem's attribute.
+     *
+     * @param uuid The uuid of the artifact.
+     * @param attr The current attribute of an artifact.
+     * @param t The theme to add.
+     * @param context The CallContext.
+     */
+    protected void addThemeToAttribute(
+        String      uuid,
+        Document    attr,
+        Theme       t,
+        CallContext context)
+    {
+        log.debug("FLYSArtifactCollection.addThemeToAttribute: " + uuid);
+
+        if (t == null) {
+            log.warn("Theme is empty - cancel adding it to attribute!");
+            return;
+        }
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            attr,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Node tmp = (Node) XMLUtils.xpath(
+            attr,
+            "/art:attribute",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (tmp == null) {
+            tmp = ec.create("attribute");
+            attr.appendChild(tmp);
+        }
+
+        Node themes = (Node) XMLUtils.xpath(
+            tmp,
+            "art:themes",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (themes == null) {
+            themes = ec.create("themes");
+            tmp.appendChild(themes);
+        }
+
+        themes.appendChild(attr.importNode(t.toXML().getFirstChild(), true));
+
+        try {
+            setCollectionItemAttribute(uuid, attr, context);
+        }
+        catch (ArtifactDatabaseException e) {
+            // do nothing
+            log.warn("Cannot set attribute of item: " + uuid);
+        }
+    }
+
+    /**
+     * Sets the attribute of a CollectionItem specified by <i>uuid</i> to a new
+     * value <i>attr</i>.
+     *
+     * @param uuid The uuid of the CollectionItem.
+     * @param attr The new attribute for the CollectionItem.
+     * @param context The CallContext.
+     */
+    public void setCollectionItemAttribute(
+        String      uuid,
+        Document    attr,
+        CallContext context)
+    throws ArtifactDatabaseException
+    {
+        Document doc = ClientProtocolUtils.newSetItemAttributeDocument(
+            uuid,
+            attr);
+
+        if (doc == null) {
+            log.warn("Cannot set item attribute: No attribute found.");
+            return;
+        }
+
+        ArtifactDatabase db = context.getDatabase();
+        CallMeta       meta = context.getMeta();
+
+        db.setCollectionItemAttribute(identifier, uuid, doc, meta);
+    }
+
+
+    /**
+     * Show blackboard (context) to each facet and create a list of
+     * ArtifactAndFacets on the fly (with the same ordering as the passed
+     * ThemeList).
+     * @param themeList ThemeList to create a ArtifactAndFacetList along.
+     * @param context   The "Blackboard".
+     */
+    protected List<ArtifactAndFacet> doBlackboardPass(
+        ThemeList themeList, CallContext context
+    ) {
+        ArrayList<ArtifactAndFacet> dataProviders =
+            new ArrayList<ArtifactAndFacet>();
+        int size = themeList.size();
+
+        try {
+            // Collect all ArtifactAndFacets for blackboard pass.
+            for (int i = 0; i < size; i++) {
+                ManagedFacet theme = themeList.get(i);
+                if (theme == null) {
+                    log.warn("A ManagedFacet in ThemeList is null.");
+                    continue;
+                }
+                String uuid        = theme.getArtifact();
+                Artifact artifact  = getArtifact(uuid, context);
+                FLYSArtifact flys  = (FLYSArtifact) artifact;
+
+                ArtifactAndFacet artifactAndFacet = new ArtifactAndFacet(
+                    artifact,
+                    flys.getNativeFacet(theme));
+
+                // XXX HELP ME PLEASE
+                artifactAndFacet.setFacetDescription(theme.getDescription());
+
+                // Show blackboard to facet.
+                artifactAndFacet.register(context);
+
+                // Add to themes.
+                dataProviders.add(i, artifactAndFacet);
+            }
+        }
+        catch (ArtifactDatabaseException ade) {
+            log.error("ArtifactDatabaseException!", ade);
+        }
+
+        return dataProviders;
+    }
+    /**
+     * Returns a concrete Artifact of this collection specified by its uuid.
+     *
+     * @param uuid The Artifact's uuid.
+     * @param context The CallContext.
+     *
+     * @return an Artifact.
+     */
+    protected Artifact getArtifact(String uuid, CallContext context)
+    throws    ArtifactDatabaseException
+    {
+        log.debug("FLYSArtifactCollection.getArtifact");
+
+        Backend backend               = Backend.getInstance();
+        PersistentArtifact persistent = backend.getArtifact(uuid);
+
+        return persistent != null ? persistent.getArtifact() : null;
+    }
+
+    /**
+     * Initializes the attribute of an collection item with the theme of a
+     * specific facet.
+     *
+     * @param uuid The uuid of an artifact.
+     * @param facet The name of a facet.
+     * @param context The CallContext.
+     *
+     * @param the new attribute.
+     */
+    protected Document initItemAttribute(
+        String      uuid,
+        String      facet,
+        String      pattern,
+        int         index,
+        String      outName,
+        CallContext context)
+    {
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("FLYSArtifactCollection.initItemAttribute");
+        }
+
+        Theme t = getThemeForFacet(uuid, facet, pattern, index, outName, context);
+
+        if (t == null) {
+            log.info("Could not find theme for facet. Cancel initialization.");
+            return null;
+        }
+
+        Document attr = XMLUtils.newDocument();
+        addThemeToAttribute(uuid, attr, t, context);
+
+        if (debug) {
+            log.debug("initItemAttribute for facet " + facet + ": "
+                + XMLUtils.toString(attr));
+        }
+
+        return attr;
+    }
+
+        /**
+     * Returns the theme of a specific facet.
+     *
+     * @param uuid The uuid of an artifact.
+     * @param facet The name of the facet.
+     * @param context The CallContext object.
+     *
+     * @return the desired theme.
+     */
+    protected Theme getThemeForFacet(
+        String uuid,
+        String facet,
+        String pattern,
+        int    index,
+        String outName,
+        CallContext context)
+    {
+        log.info("FLYSArtifactCollection.getThemeForFacet: " + facet);
+
+        FLYSContext flysContext = context instanceof FLYSContext
+            ? (FLYSContext) context
+            : (FLYSContext) context.globalContext();
+
+        // Push artifact in flysContext.
+        ArtifactDatabase db = context.getDatabase();
+        try {
+            FLYSArtifact artifact = (FLYSArtifact) db.getRawArtifact(uuid);
+            log.debug("Got raw artifact");
+            flysContext.put(FLYSContext.ARTIFACT_KEY, artifact);
+        }
+        catch (ArtifactDatabaseException dbe) {
+            log.error("Exception caught when trying to get art.", dbe);
+        }
+
+        Theme t = ThemeFactory.getTheme(
+                      flysContext,
+                      facet,
+                      pattern,
+                      outName,
+                      "default");
+
+        if (t != null) {
+            log.debug("found theme for facet '" + facet + "'");
+            t.setFacet(facet);
+            t.setIndex(index);
+        }
+        else {
+            log.warn("unable to find theme for facet '" + facet + "'");
+        }
+
+        return t;
+    }
+
+    /**
+     * Inner class to structure/order the themes of a chart.
+     */
+    private static class ThemeList {
+        private Logger logger = Logger.getLogger(ThemeList.class);
+        protected Map<Integer, ManagedFacet> themes;
+
+        public ThemeList(Document output) {
+            themes = new HashMap<Integer, ManagedFacet>();
+            parse(output);
+        }
+
+        protected void parse(Document output) {
+            NodeList themeList = (NodeList) XMLUtils.xpath(
+                output,
+                "art:output/art:facet",
+                XPathConstants.NODESET,
+                ArtifactNamespaceContext.INSTANCE);
+
+            int num = themeList != null ? themeList.getLength() : 0;
+
+            logger.debug("Output has " +  num + " elements.");
+
+            if (num == 0) {
+                return;
+            }
+
+            String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+
+            for (int i = 0; i < num; i++) {
+                Element theme = (Element) themeList.item(i);
+
+                ManagedDomFacet facet = new ManagedDomFacet(theme);
+                themes.put(Integer.valueOf(facet.getPosition()-1), facet);
+            }
+        }
+
+        public ManagedFacet get(int idx) {
+            return themes.get(Integer.valueOf(idx));
+        }
+
+        public int size() {
+            return themes.size();
+        }
+    }
+}
+// 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/exports/ReferenceCurveExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,370 @@
+package de.intevation.flys.exports;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.WINFOArtifact;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.WWQQ;
+import de.intevation.flys.artifacts.model.WWQQJRDataSource;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.text.DateFormat;
+import java.text.NumberFormat;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JasperExportManager;
+import net.sf.jasperreports.engine.JasperFillManager;
+import net.sf.jasperreports.engine.JasperPrint;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+/**
+ * (CSV)Exporter for Reference Curves.
+ */
+public class ReferenceCurveExporter extends AbstractExporter {
+
+    /** The logger used in this exporter. */
+    private static Logger logger = Logger.getLogger(ReferenceCurveExporter.class);
+
+    public static final String RC_CSV_KM_HEADER =
+        "export.reference_curve.csv.header.km";
+
+    public static final String RC_CSV_W_CM_HEADER =
+        "export.reference_curve.csv.header.w.cm";
+
+    public static final String RC_CSV_W_M_HEADER =
+        "export.reference_curve.csv.header.w.m";
+
+    public static final String RC_CSV_Q_HEADER =
+        "export.reference_curve.csv.header.w.q";
+
+    public static final String CSV_LOCATION_HEADER =
+        "export.waterlevel.csv.header.location";
+
+    public static final String DEFAULT_CSV_LOCATION_HEADER = "Lage";
+
+    public static final String RC_DEFAULT_CSV_KM_HEADER = "Fluss-Km";
+    public static final String RC_DEFAULT_CSV_W_M_HEADER  = "W (m + NHN)";
+    public static final String RC_DEFAULT_CSV_W_CM_HEADER  = "W (cm am Pegel)";
+    public static final String RC_DEFAULT_CSV_Q_HEADER  = "gleichw. Q (m\u00b3/s)";
+
+    public static final String PDF_HEADER_MODE = "export.reference_curve.pdf.mode";
+    public static final String JASPER_FILE = "export.reference_curve.pdf.file";
+    public static final String JASPER_FILE_GAUGE = "export.reference_curve.pdf.file.gauge";
+    public static final String JASPER_FILE_GAUGE_END = "export.reference_curve.pdf.file.gauge.end";
+    public static final String JASPER_FILE_GAUGE_START_END = "export.reference_curve.pdf.file.gauge.start.end";
+
+    /** The storage that contains all WKms objects for the different facets. */
+    protected List<WWQQ[]> data;
+
+    protected boolean startAtGauge = false;
+
+    protected boolean endAtGauge = false;
+
+
+    @Override
+    public void init(Document request, OutputStream out, CallContext context) {
+        logger.debug("ReferenceCurveExporter.init");
+
+        super.init(request, out, context);
+
+        this.data = new ArrayList<WWQQ[]>();
+    }
+
+
+    /**
+     * Genereate data in csv format.
+     */
+    @Override
+    public void generate()
+    throws IOException
+    {
+        logger.debug("ReferenceCurveExporter.generate");
+
+        if (facet == null) {
+            throw new IOException("invalid (null) facet for exporter");
+        }
+        else if (facet.equals(AbstractExporter.FACET_CSV)) {
+            generateCSV();
+        }
+        else if (facet.equals(AbstractExporter.FACET_PDF)) {
+            generatePDF();
+        }
+        else {
+            throw new IOException("invalid facet (" + facet + ") for exporter");
+        }
+    }
+
+
+    /**
+     * Adds given data.
+     * @param d A CalculationResult with WWQQ[].
+     */
+    @Override
+    protected void addData(Object d) {
+        logger.debug("ReferenceCurveExporter.addData");
+
+        if (d instanceof CalculationResult) {
+            d = ((CalculationResult)d).getData();
+            if (d instanceof WWQQ []) {
+                WWQQ[] wwqqs = (WWQQ []) d;
+                for (WWQQ wwqq: wwqqs) {
+                    if (wwqq.startAtGauge()) {
+                        startAtGauge = true;
+                    }
+                    // TODO this one probably has to be inverted.
+                    if (wwqq.endAtGauge()) {
+                        endAtGauge = true;
+                    }
+                }
+                data.add(wwqqs);
+                logger.debug("ReferenceCurveExporter.addData wwqq[].");
+            }
+            else {
+                logger.warn("ReferenceCurveExporter.addData/1 unknown type ("
+                    + d + ").");
+            }
+        }
+        else {
+            logger.warn("ReferenceCurveExporter.addData/2 unknown type ("
+                + d + ").");
+        }
+    }
+
+
+    /**
+     * Lets writer write all data (including header).
+     * @param writer Writer to write data with.
+     */
+    @Override
+    protected void writeCSVData(CSVWriter writer) {
+        logger.debug("ReferenceCurveExporter.writeData");
+
+        writeCSVHeader(writer);
+
+        for (WWQQ[] tmp: data) {
+            for (WWQQ ww: tmp) {
+                wWQQ2CSV(writer, ww);
+            }
+        }
+    }
+
+
+    /**
+     * Lets csvwriter write the header (first line in file).
+     * @param writer Writer to write header with.
+     */
+    protected void writeCSVHeader(CSVWriter writer) {
+        logger.info("ReferenceCurveExporter.writeCSVHeader");
+
+        StepCSVWriter stepWriter = new StepCSVWriter();
+        stepWriter.setCSVWriter(writer);
+
+        stepWriter.addNexts(
+            msg(RC_CSV_KM_HEADER, RC_DEFAULT_CSV_KM_HEADER),
+            msg(RC_CSV_W_M_HEADER, RC_DEFAULT_CSV_W_M_HEADER)
+            );
+        if (startAtGauge) {
+            stepWriter.addNext(
+                msg(RC_CSV_W_CM_HEADER, RC_DEFAULT_CSV_W_CM_HEADER));
+        }
+        stepWriter.addNexts(
+            msg(RC_CSV_Q_HEADER, RC_DEFAULT_CSV_Q_HEADER),
+            msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER),
+            msg(RC_CSV_KM_HEADER, RC_DEFAULT_CSV_KM_HEADER),
+            msg(RC_CSV_W_M_HEADER, RC_DEFAULT_CSV_W_M_HEADER)
+            );
+        if (endAtGauge) {
+            stepWriter.addNext(
+                msg(RC_CSV_W_CM_HEADER, RC_DEFAULT_CSV_W_CM_HEADER)
+                );
+        }
+        stepWriter.addNexts(
+                msg(RC_CSV_Q_HEADER, RC_DEFAULT_CSV_Q_HEADER),
+                msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER)
+                );
+
+        stepWriter.flush();
+    }
+
+
+    protected void wWQQ2CSV(CSVWriter writer, WWQQ ww) {
+        logger.debug("ReferenceCurveExporter.wWQQ2CSV");
+
+        NumberFormat kmf = getKmFormatter();
+        NumberFormat wf  = getWFormatter();
+        NumberFormat qf  = getQFormatter();
+
+        int         size = ww.size();
+
+        FLYSArtifact flys       = (FLYSArtifact) master;
+
+        StepCSVWriter stepWriter = new StepCSVWriter();
+        stepWriter.setCSVWriter(writer);
+
+        String startLocationDescription = FLYSUtils.getLocationDescription(
+            flys, ww.getStartKm());
+
+        String endLocationDescription = FLYSUtils.getLocationDescription(
+            flys, ww.getEndKm());
+
+        for (int i = 0; i < size; i ++) {
+            stepWriter.addNexts(kmf.format(ww.getStartKm()));
+            stepWriter.addNext(wf.format(ww.getW1(i)));
+            if (startAtGauge) {
+                stepWriter.addNext(wf.format(ww.getRelHeight1Cm(i)));
+            }
+            stepWriter.addNexts(
+                qf.format(ww.getQ1(i)), // "Q"
+                startLocationDescription,
+                kmf.format(ww.getEndKm())
+                );
+            stepWriter.addNext(wf.format(ww.getW2(i)));
+            if (endAtGauge) {
+                if (ww.endAtGauge()) {
+                    stepWriter.addNext(wf.format(ww.getRelHeight2Cm(i)));
+                }
+                else {
+                    stepWriter.addNext("-");
+                }
+            }
+            stepWriter.addNexts(
+                qf.format(ww.getQ2(i)), // "Q"
+                endLocationDescription
+                );
+            stepWriter.flush();
+        }
+    }
+
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        WWQQJRDataSource source = createJRData();
+
+        String filename = JASPER_FILE;
+        if (startAtGauge && endAtGauge) {
+            filename = JASPER_FILE_GAUGE_START_END;
+        }
+        else if (startAtGauge) {
+            filename = JASPER_FILE_GAUGE;
+        }
+        else if (endAtGauge) {
+            filename = JASPER_FILE_GAUGE_END;
+        }
+
+        String jasperFile = Resources.getMsg(
+                                context.getMeta(),
+                                filename,
+                                "/jasper/reference_en.jasper");
+        String confPath = Config.getConfigDirectory().toString();
+
+        Map parameters = new HashMap();
+        parameters.put("ReportTitle", "Exported Data");
+        try {
+            JasperPrint print = JasperFillManager.fillReport(
+                confPath + jasperFile,
+                parameters,
+                source);
+            JasperExportManager.exportReportToPdfStream(print, out);
+        }
+        catch(JRException je) {
+            logger.warn("Error generating PDF Report!");
+            je.printStackTrace();
+        }
+    }
+
+    protected WWQQJRDataSource createJRData() {
+        WWQQJRDataSource source = new WWQQJRDataSource();
+
+        addMetaData(source);
+
+        for (WWQQ[] tmp: data) {
+            for (WWQQ ww: tmp) {
+                addWWQQData(source, ww);
+            }
+        }
+        return source;
+    }
+
+
+    protected void addMetaData(WWQQJRDataSource source) {
+        CallMeta meta = context.getMeta();
+
+        WINFOArtifact flys = (WINFOArtifact) master;
+
+        source.addMetaData ("river", FLYSUtils.getRivername(flys));
+
+        Locale locale = Resources.getLocale(meta);
+        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+
+        source.addMetaData("date", df.format(new Date()));
+
+        source.addMetaData("calculation", Resources.getMsg(
+                                            locale,
+                                            PDF_HEADER_MODE,
+                                            "Reference Curve"));
+    }
+
+
+    protected void addWWQQData(WWQQJRDataSource source, WWQQ ww) {
+        NumberFormat kmf = getKmFormatter();
+        NumberFormat wf  = getWFormatter();
+        NumberFormat qf  = getQFormatter();
+
+        int          size = ww.size();
+
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        String startLocationDescription = FLYSUtils.getLocationDescription(
+            flys, ww.getStartKm());
+
+        String endLocationDescription = FLYSUtils.getLocationDescription(
+            flys, ww.getEndKm());
+
+        for (int i = 0; i < size; i ++) {
+            String start = "-";
+            String end = "-";
+            if (startAtGauge) {
+                start = wf.format(ww.getRelHeight1Cm(i));
+            }
+            if (ww.endAtGauge()) {
+                end = wf.format(ww.getRelHeight2Cm(i));
+            }
+            source.addData(new String[] {
+                kmf.format(ww.getStartKm()),
+                startLocationDescription,
+                wf.format(ww.getW1(i)),
+                qf.format(ww.getQ1(i)), // "Q"
+                kmf.format(ww.getEndKm()),
+                endLocationDescription,
+                wf.format(ww.getW2(i)),
+                qf.format(ww.getQ2(i)), // "Q"
+                start,
+                end
+            });
+        }
+    }
+}
+// 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/exports/ReferenceCurveGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,271 @@
+package de.intevation.flys.exports;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.WW;
+import de.intevation.flys.artifacts.model.WW.ApplyFunctionIterator;
+import de.intevation.flys.artifacts.model.WWAxisTypes;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+import de.intevation.flys.utils.Formatter;
+
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.axis.NumberTickUnit;
+import org.jfree.chart.axis.TickUnits;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.data.xy.XYSeries;
+import org.w3c.dom.Document;
+
+/**
+ * An OutGenerator that generates reference curves.
+ */
+public class ReferenceCurveGenerator
+extends      XYChartGenerator
+implements   FacetTypes
+{
+    public static enum YAXIS {
+        W(0);
+
+        public int idx;
+        private YAXIS(int c) {
+           idx = c;
+        }
+    }
+
+    /** House logger. */
+    private static Logger logger =
+        Logger.getLogger(ReferenceCurveGenerator.class);
+
+    public static final String I18N_CHART_TITLE =
+        "chart.reference.curve.title";
+
+    public static final String I18N_CHART_SUBTITLE =
+        "chart.reference.curve.subtitle";
+
+    public static final String I18N_X_AXIS_IN_CM =
+        "chart.reference.curve.x.axis.in.cm";
+
+    public static final String I18N_X_AXIS_IN_M =
+        "chart.reference.curve.x.axis.in.m";
+
+    public static final String I18N_Y_AXIS_IN_CM =
+        "chart.reference.curve.y.axis.in.cm";
+
+    public static final String I18N_Y_AXIS_IN_M =
+        "chart.reference.curve.y.axis.in.m";
+
+    public static final String I18N_CHART_TITLE_DEFAULT  =
+        "Bezugslinie";
+
+
+    public ReferenceCurveGenerator() {
+    }
+
+    /**
+     * Create Axis for given index.
+     * @return axis with according internationalized label.
+     */
+    @Override
+    protected NumberAxis createYAxis(int index) {
+        NumberAxis axis = super.createYAxis(index);
+        axis.setAutoRangeIncludesZero(false);
+        return axis;
+    }
+
+
+    /** Get default chart title. */
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultChartSubtitle() {
+        Object[] args = new Object[] {
+            getRiverName(),
+        };
+
+        return msg(I18N_CHART_SUBTITLE, "", args);
+    }
+
+
+    /** True if axis is in cm (because at gauge). */
+    protected boolean getInCm(int index) {
+        Object obj = context.getContextValue("reference.curve.axis.scale");
+        return obj instanceof WWAxisTypes && ((WWAxisTypes)obj).getInCm(index);
+    }
+
+
+    /** Get Label for X-axis (W). */
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(getInCm(0) ? I18N_X_AXIS_IN_CM : I18N_X_AXIS_IN_M);
+    }
+
+
+    /**
+     * Get Label for primary and other Y Axes.
+     * @param index Axis-Index (0-based).
+     */
+    @Override
+    protected String getDefaultYAxisLabel(int index) {
+        return msg(getInCm(1) ? I18N_Y_AXIS_IN_CM : I18N_Y_AXIS_IN_M);
+    }
+
+    protected String facetName() {
+        return REFERENCE_CURVE;
+    }
+
+
+    /**
+     * Called for each facet/them in the out mapped to this generator.
+     * @param artifactFacet artifact and facet for this theme.
+     * @param theme         styling info.
+     * @param visible       Whether or not the theme is visible.
+     */
+    @Override
+    public void doOut(
+        ArtifactAndFacet artifactFacet,
+        Document         theme,
+        boolean          visible
+    ) {
+        String name = artifactFacet.getFacetName();
+
+        logger.debug("ReferenceCurveGenerator.doOut: " + name);
+
+        if (name == null || name.length() == 0) {
+            logger.error("No facet given. Cannot create dataset.");
+            return;
+        }
+
+        if (name.equals(facetName())) {
+            doReferenceOut(artifactFacet.getData(context), theme, visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(
+                artifactFacet.getData(context),
+                artifactFacet,
+                theme,
+                visible,
+                YAXIS.W.idx);
+        }
+        else if (name.equals(RELATIVE_POINT)) {
+            doPointOut(
+                (Point2D) artifactFacet.getData(context),
+                artifactFacet,
+                theme,
+                visible);
+        }
+        else if (name.equals(MAINVALUES_W)) {
+            doAnnotations(
+                ((FLYSAnnotation) artifactFacet.getData(context)).flipStickyAxis(),
+                artifactFacet,
+                theme,
+                visible);
+
+        }
+        else {
+            logger.warn("Unknown facet name: " + name);
+        }
+    }
+
+    protected boolean doNormalize() {
+        return false;
+    }
+
+
+    /** Register DataSeries with (maybe transformed) points. */
+    public void doReferenceOut(
+        Object   data,
+        Document theme,
+        boolean  visible
+    ) {
+        WW ww = (WW)data;
+
+        Object obj = context.getContextValue("reference.curve.axis.scale");
+
+        WWAxisTypes wwat = obj instanceof WWAxisTypes
+            ? (WWAxisTypes)obj
+            : new WWAxisTypes(ww);
+
+        ApplyFunctionIterator iter = wwat.transform(ww, doNormalize());
+
+        XYSeries series = new StyledXYSeries(
+            ww.getName(), false, theme);
+
+        double [] values = new double[2];
+
+        while (iter.hasNext()) {
+            iter.next(values);
+            series.add(values[0], values[1], false);
+        }
+
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+    // TODO resolve duplicate in DurationCurveGenerator
+    protected void doPointOut(
+        Point2D point,
+        ArtifactAndFacet aandf,
+        Document theme,
+        boolean visible
+    ){
+        logger.debug("ReferenceCurveGenerator.doPointOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        series.add(point.getX(), point.getY());
+
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+
+    /** Set the tick units for given axis. */
+    protected void setAxisTickUnit(double tick, ValueAxis axis) {
+        TickUnits units = new TickUnits();
+        units.add(new NumberTickUnit(tick, Formatter.getWaterlevelW(context)));
+        axis.setStandardTickUnits(units);
+        axis.setAutoTickUnitSelection(true);
+    }
+
+    @Override
+    protected void localizeDomainAxis(ValueAxis domainAxis) {
+        super.localizeDomainAxis(domainAxis);
+        if (getInCm(0)) {
+            setAxisTickUnit(100d, domainAxis);
+        }
+        else {
+            setAxisTickUnit(1d, domainAxis);
+        }
+    }
+
+
+    @Override
+    protected void localizeRangeAxis(ValueAxis rangeAxis) {
+        super.localizeRangeAxis(rangeAxis);
+        setAxisTickUnit(1d, rangeAxis);
+    }
+
+    /** Get Walker to iterate over all axes. */
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            /** Get number of items. */
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            /** Get identifier for this index. */
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+}
+// 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/exports/ReferenceCurveInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.exports;
+
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific reference
+ * curves.
+ */
+public class ReferenceCurveInfoGenerator
+extends      ChartInfoGenerator
+{
+    public ReferenceCurveInfoGenerator() {
+        super(new ReferenceCurveGenerator());
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/ReportGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/ReportGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -15,6 +15,7 @@
 import de.intevation.artifactdatabase.state.Settings;
 
 import de.intevation.flys.artifacts.model.Calculation;
+import de.intevation.flys.collections.FLYSArtifactCollection;
 
 import org.w3c.dom.Document;
 
@@ -35,7 +36,7 @@
         logger.debug("init");
         this.out     = out;
         this.context = context;
-        result = XMLUtils.newDocument();
+        result       = null;
     }
 
     @Override
@@ -44,6 +45,11 @@
     }
 
     @Override
+    public void setCollection(FLYSArtifactCollection collection) {
+        // not needed
+    }
+
+    @Override
     public void doOut(
         ArtifactAndFacet artifactFacet,
         Document         attr,
@@ -53,14 +59,19 @@
         Facet facet = artifactFacet.getFacet();
         if (facet != null) {
             Calculation report = (Calculation) artifactFacet.getData(context);
-            report.toXML(result, context.getMeta());
+            if (result == null) {
+                result = XMLUtils.newDocument();
+                report.toXML(result, context.getMeta());
+            }
         }
     }
 
     @Override
     public void generate() throws IOException {
         logger.debug("generate");
-        XMLUtils.toStream(result, out);
+        XMLUtils.toStream(result != null
+            ? result
+            : XMLUtils.newDocument(), out);
     }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/StepCSVWriter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,51 @@
+package de.intevation.flys.exports;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Class to overcome shortcoming of CSVWriter to accept String-Arrays only.
+ * The StepCSVWriter buffers incoming values, such that rows in a csv can be
+ * created more dynamically. Do not forget to call flush().
+ */
+public class StepCSVWriter {
+
+    /** Writer to use when calling flush. */
+    CSVWriter writer = null;
+    /** Buffer of strings (values). */
+    ArrayList<String> buffer;
+
+
+    /** Trivial constructor. */
+    public StepCSVWriter() {
+        buffer = new ArrayList<String>();
+    }
+
+
+    /** Set writer. */
+    public void setCSVWriter(CSVWriter writer) {
+        this.writer = writer;
+    }
+
+
+    /** Add a value to next flush. */
+    public void addNext(String value) {
+        buffer.add(value);
+    }
+
+
+    /** Add many values to next flush. */
+    public void addNexts(String ... values) {
+        buffer.addAll(Arrays.asList(values));
+    }
+
+
+    /** Write the row with csvwriter. */
+    public void flush() {
+        writer.writeNext(buffer.toArray(new String[buffer.size()]));
+        buffer.clear();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/StyledAreaSeriesCollection.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-package de.intevation.flys.exports;
-
-import java.awt.Color;
-import java.awt.Stroke;
-import java.awt.BasicStroke;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-
-import org.jfree.data.xy.XYSeriesCollection;
-
-import de.intevation.flys.utils.ThemeUtil;
-import de.intevation.flys.jfree.StableXYDifferenceRenderer;
-
-
-/**
- * One or more dataseries to draw a polygon (either "open up/downwards", or
- * the area between two curves), a theme-document and further display options.
- * The theme-document will later "style" the graphical representation.
- * The display options can be used to control the z-order and the axis of the 
- * dataset.
- */
-public class StyledAreaSeriesCollection extends XYSeriesCollection {
-    /** Mode, how to draw/which areas to fill. */
-    public enum FILL_MODE {UNDER, ABOVE, BETWEEN};
-
-    /** MODE in use. */
-    protected FILL_MODE mode;
-
-    /** The theme-document with attributes about actual visual representation. */
-    protected Document theme;
-
-    /** Own logger. */
-    private static final Logger logger =
-        Logger.getLogger(StyledAreaSeriesCollection.class);
-
-
-    /**
-     * @param theme the theme-document.
-     */
-    public StyledAreaSeriesCollection(Document theme) {
-        this.theme = theme;
-        this.mode = FILL_MODE.BETWEEN;
-   }
-
-
-    /** Gets the Fill mode. */
-    public FILL_MODE getMode() {
-        return this.mode;
-    }
-
-
-    /** Sets the Fill mode. */
-    public void setMode(FILL_MODE fMode) {
-        this.mode = fMode;
-    }
-
-
-    /**
-     * Applies line color, size and type attributes to renderer, also
-     * whether to draw lines and/or points.
-     */
-    public StableXYDifferenceRenderer applyTheme(
-        StableXYDifferenceRenderer renderer
-    ) {
-        applyFillColor(renderer);
-        applyShowShape(renderer);
-        applyOutlineColor(renderer);
-        applyOutlineStyle(renderer);
-
-        return renderer;
-    }
-
-
-    /**
-     * Blindly (for now) apply the postiviepaint of renderer.
-     */
-    protected void applyFillColor(StableXYDifferenceRenderer renderer) {
-        // Get color.
-        Color paint = ThemeUtil.parseFillColorField(theme);
-        // Get half-transparency flag.
-        if (ThemeUtil.parseTransparency(theme)) {
-            paint = new Color(paint.getRed(), paint.getGreen(), paint.getBlue(),
-                128);
-        }
-        if (paint != null && this.getMode() == FILL_MODE.ABOVE) {
-            renderer.setPositivePaint(paint);
-            renderer.setNegativePaint(new Color(0,0,0,0));
-        }
-        else if (paint != null && this.getMode() == FILL_MODE.UNDER) {
-            renderer.setNegativePaint(paint);
-            renderer.setPositivePaint(new Color(0,0,0,0));
-        }
-        else {
-            if (paint == null) paint = new Color(177, 117, 102);
-            renderer.setPositivePaint(paint);
-            renderer.setNegativePaint(paint);
-        }
-    }
-
-    /**
-     * Blindly (for now) apply the postiviepaint of renderer.
-     */
-    protected void applyShowShape(StableXYDifferenceRenderer renderer) {
-        boolean show = ThemeUtil.parseShowBorder(theme);
-        renderer.setDrawOutline(show);
-    }
-
-    protected void applyShowLine(StableXYDifferenceRenderer renderer) {
-        boolean show = ThemeUtil.parseShowLine(theme);
-        renderer.setShapesVisible(show);
-    }
-
-    /**
-     *
-     */
-    protected void applyOutlineColor(StableXYDifferenceRenderer renderer) {
-        Color c = ThemeUtil.parseLineColorField(theme);
-        renderer.setOutlinePaint(c);
-    }
-
-    protected void applyOutlineWidth(StableXYDifferenceRenderer renderer) {
-        int size = ThemeUtil.parseLineWidth(theme);
-    }
-
-    protected void applyOutlineStyle(StableXYDifferenceRenderer renderer) {
-        float[] dashes = ThemeUtil.parseLineStyle(theme);
-        int size       = ThemeUtil.parseLineWidth(theme);
-
-        Stroke stroke = null;
-
-        if (dashes.length <= 1) {
-            stroke = new BasicStroke(Integer.valueOf(size));
-        }
-        else {
-            stroke = new BasicStroke(Integer.valueOf(size),
-                BasicStroke.CAP_BUTT,
-                BasicStroke.JOIN_ROUND,
-                1.0f,
-                dashes,
-                0.0f);
-        }
-
-        renderer.setOutlineStroke(stroke);
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/StyledSeriesBuilder.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,15 +4,24 @@
 
 import org.jfree.data.xy.XYSeries;
 
-import de.intevation.flys.artifacts.model.WKms; 
-import de.intevation.flys.artifacts.model.WQKms; 
+import de.intevation.flys.artifacts.model.WKms;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.WWQQ;
 
 /**
  * Helper to create and modify StyledXYSeries.
  */
 public class StyledSeriesBuilder {
 
-    private static final Logger logger = Logger.getLogger(StyledSeriesBuilder.class);
+    /**
+     * JFreeChart and the area calculation will fail if we use Double.INFINITY
+     * or Double.MAX_VALUE (probably because these are really used in
+     * calculations). We define and use a more handy value instead.
+     */
+    final static double BIG_DOUBLE_VALUE = 1234567d;
+
+    private static final Logger logger = Logger.getLogger
+        (StyledSeriesBuilder.class);
 
 
     /**
@@ -28,14 +37,20 @@
      * @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) {
+    public static void addPoints(XYSeries series, double[][] points, boolean skipNANs) {
         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], yPoints[i], false);
         }
     }
@@ -45,9 +60,13 @@
      * Add points to series (km to 1st dim, w to 2nd dim).
      *
      * @param series Series to add points to.
-     * @param points Points to add to series.
+     * @param wkms WKms to add to series.
      */
     public static void addPoints(XYSeries series, WKms wkms) {
+        if (wkms == null) {
+            return;
+        }
+
         int size = wkms.size();
 
         for (int i = 0; i < size; i++) {
@@ -57,17 +76,83 @@
 
 
     /**
+     * Add points to dataset with an offset (shift all points by given amount).
+     * @param series series to add data to.
+     * @param wkms WKms of which the Ws will be shifted.
+     * @param off the offset.
+     */
+    public static void addUpperBand(XYSeries series, WKms wkms, double off) {
+        if (wkms == null) {
+            return;
+        }
+
+        int size = wkms.size();
+
+        for (int i = 0; i < size; i++) {
+            series.add(wkms.getKm(i), wkms.getW(i)+off, false);
+        }
+    }
+
+
+    /**
+     * Add points to dataset with an offset (shift all points 'down' by given
+     * amount).
+     * @param series series to add data to.
+     * @param wkms WKms of which the Ws will be shifted.
+     * @param off the offset.
+     */
+    public static void addLowerBand(XYSeries series, WKms wkms, double off) {
+        addUpperBand(series, wkms, -off);
+    }
+
+
+    /**
      * Add points to series (km to 1st dim, q to 2nd dim).
      *
      * @param series Series to add points to.
-     * @param points Points to add to series.
+     * @param wqkms WQKms to add to series.
      */
     public static void addPointsKmQ(XYSeries series, WQKms wqkms) {
-       int size = wqkms.size();
+        if (wqkms == null) {
+            return;
+        }
 
-       for (int i = 0; i < size; i++) {
-           series.add(wqkms.getKm(i), wqkms.getQ(i), false);
-       }
+        int size = wqkms.size();
+
+        for (int i = 0; i < size; i++) {
+            series.add(wqkms.getKm(i), wqkms.getQ(i), false);
+        }
+    }
+
+
+    /**
+     * Add points to series (km to 1st dim, q to 2nd dim), adding points
+     * to achieve a step-like curve.
+     *
+     * @param series Series to add points to.
+     * @param wqkms WQKms to add to series.
+     */
+    public static void addStepPointsKmQ(XYSeries series, WQKms wqkms) {
+        if (wqkms == null) {
+            return;
+        }
+
+        int size = wqkms.size();
+
+        for (int i = 0; i < size; i++) {
+            if (i==0) {
+                series.add(wqkms.getKm(i), wqkms.getQ(i), false);
+            }
+            else {
+                //Add two points.
+                double halveX = (wqkms.getKm(i-1) + wqkms.getKm(i)) / 2d;
+                series.add(halveX, wqkms.getQ(i-1));
+                series.add(halveX, wqkms.getQ(i));
+            }
+            if (i == size-1) {
+                series.add(wqkms.getKm(i), wqkms.getQ(i), false);
+            }
+        }
     }
 
 
@@ -75,14 +160,61 @@
      * Add points to series (q to 1st dim, w to 2nd dim).
      *
      * @param series Series to add points to.
-     * @param points Points to add to series.
+     * @param wqkms WQKms to add to series.
      */
     public static void addPointsQW(XYSeries series, WQKms wqkms) {
+        if (wqkms == null) {
+            return;
+        }
+
         int size = wqkms.size();
 
         for (int i = 0; i < size; i++) {
             series.add(wqkms.getQ(i), wqkms.getW(i));
         }
     }
+
+
+    /**
+     * Add points to series (q to 1st dim, w to 2nd dim).
+     *
+     * @param series Series to add points to.
+     * @param wwqq WWQQ to add to series.
+     */
+    public static void addPoints(XYSeries series, WWQQ wwqq) {
+        if (wwqq == null) {
+            return;
+        }
+
+        int size = wwqq.size();
+
+        for (int i = 0; i < size; i++) {
+            series.add(wwqq.getW1(i), wwqq.getW2(i));
+        }
+    }
+
+
+    /**
+     * Create a Series such that an infinitely big area can be filled
+     * between the newly created and the given series.
+     */
+    public static XYSeries createGroundAtInfinity(XYSeries series) {
+        XYSeries ground = new XYSeries(series.getKey() + /** TODO rand + */ "INF");
+        ground.add(series.getMinX(), -BIG_DOUBLE_VALUE);
+        ground.add(series.getMaxX(), -BIG_DOUBLE_VALUE);
+        return ground;
+    }
+
+
+    /**
+     * Create a Series such that an infinitely big area can be filled
+     * between the newly created and the given series.
+     */
+    public static XYSeries createCeilingAtInfinity(XYSeries series) {
+        XYSeries ground = new XYSeries(series.getKey() + /** TODO rand + */ "INF");
+        ground.add(series.getMinX(), BIG_DOUBLE_VALUE);
+        ground.add(series.getMaxX(), BIG_DOUBLE_VALUE);
+        return ground;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/StyledXYSeries.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-package de.intevation.flys.exports;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.geom.Ellipse2D;
-
-import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-
-import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
-import org.jfree.data.xy.XYSeries;
-
-import de.intevation.flys.utils.ThemeUtil;
-
-/**
- * Dataseries in two dimensions with additional theme-document and further
- * display options.
- * The theme-document will later "style" the graphical representation.
- * The display options can be used to control the z-order and the axis of the 
- * dataseries.
- */
-public class StyledXYSeries extends XYSeries {
-
-    protected Document theme;
-
-    private static final Logger logger = Logger.getLogger(StyledXYSeries.class);
-
-
-    public StyledXYSeries(String key, Document theme) {
-        this(key, true, theme);
-    }
-
-
-    /**
-     * @param sorted whether or not to sort the points. Sorting will move NANs
-     *               to one extrema which can cause problems in certain
-     *               algorithms.
-     */
-    public StyledXYSeries(String key, boolean sorted, Document theme) {
-        super(key, sorted);
-        this.theme = theme;
-    }
-
-
-    /**
-     * Applies line color, size and type attributes to renderer, also
-     * whether to draw lines and/or points.
-     */
-    public XYLineAndShapeRenderer applyTheme(XYLineAndShapeRenderer r, int idx){
-        applyLineColor(r, idx);
-        applyLineSize(r, idx);
-        applyLineType(r, idx);
-        applyShowLine(r, idx);
-        applyShowPoints(r, idx);
-
-        return r;
-    }
-
-
-    /** Set line color to renderer. */
-    protected void applyLineColor(XYLineAndShapeRenderer r, int idx) {
-        Color c = ThemeUtil.parseLineColorField(theme);
-        r.setSeriesPaint(idx, c);
-    }
-
-
-    protected void applyLineSize(XYLineAndShapeRenderer r, int idx) {
-        int size = ThemeUtil.parseLineWidth(theme);
-        r.setSeriesStroke(
-            idx,
-            new BasicStroke(Integer.valueOf(size)));
-    }
-
-
-    protected void applyLineType(XYLineAndShapeRenderer r, int idx) {
-        int size = ThemeUtil.parseLineWidth(theme);
-        float[] dashes = ThemeUtil.parseLineStyle(theme);
-
-        // Do not apply the dashed style.
-        if (dashes.length <= 1) {
-            return;
-        }
-
-        r.setSeriesStroke(
-            idx,
-            new BasicStroke(Integer.valueOf(size),
-                            BasicStroke.CAP_BUTT,
-                            BasicStroke.JOIN_ROUND,
-                            1.0f,
-                            dashes,
-                            0.0f));
-    }
-
-
-    /**
-     * Sets form and visibility of points.
-     */
-    protected void applyShowPoints(XYLineAndShapeRenderer r, int idx) {
-        boolean show = ThemeUtil.parseShowPoints(theme);
-        int size = ThemeUtil.parseLineWidth(theme);
-        r.setSeriesShape(idx, new Ellipse2D.Double(- size,
-                                                   - size,
-                                                   2 * size,
-                                                   2 * size));
-        r.setSeriesShapesVisible(idx, show);
-        r.setDrawOutlines(true);
-    }
-
-
-    protected void applyShowLine(XYLineAndShapeRenderer r, int idx) {
-        boolean show = ThemeUtil.parseShowLine(theme);
-        r.setSeriesLinesVisible(idx, show);
-    }
-}
-// 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/exports/TimeseriesChartGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,826 @@
+package de.intevation.flys.exports;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.flys.jfree.Bounds;
+import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation;
+import de.intevation.flys.jfree.DoubleBounds;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledTimeSeries;
+import de.intevation.flys.jfree.TimeBounds;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.ImageIcon;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.annotations.XYAnnotation;
+import org.jfree.chart.annotations.XYImageAnnotation;
+import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.Marker;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.Range;
+import org.jfree.data.general.Series;
+import org.jfree.data.time.Day;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.ui.Layer;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.w3c.dom.Document;
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public abstract class TimeseriesChartGenerator extends ChartGenerator {
+
+
+    /**
+     * Inner class TimeseriesAxisDataset stores TimeSeriesCollection.
+     */
+    public class TimeseriesAxisDataset implements AxisDataset {
+
+        protected int axisSymbol;
+
+        protected List<TimeSeriesCollection> datasets;
+
+        protected Range range;
+
+        protected int plotAxisIndex;
+
+        public TimeseriesAxisDataset(int axisSymbol) {
+            this.axisSymbol = axisSymbol;
+            this.datasets   = new ArrayList<TimeSeriesCollection>();
+        }
+
+
+        @Override
+        public void addDataset(XYDataset dataset) {
+            if (!(dataset instanceof TimeSeriesCollection)) {
+                logger.warn("Skip non TimeSeriesCollection dataset.");
+                return;
+            }
+
+            TimeSeriesCollection tsc = (TimeSeriesCollection) dataset;
+
+            datasets.add(tsc);
+            mergeRanges(tsc);
+        }
+
+
+        @Override
+        public XYDataset[] getDatasets() {
+            return datasets.toArray(new XYDataset[datasets.size()]);
+        }
+
+
+        @Override
+        public boolean isEmpty() {
+            return datasets.isEmpty();
+        }
+
+
+        @Override
+        public void setRange(Range range) {
+            this.range = range;
+        }
+
+
+        @Override
+        public Range getRange() {
+            return range;
+        }
+
+
+        @Override
+        public void setPlotAxisIndex(int plotAxisIndex) {
+            this.plotAxisIndex = plotAxisIndex;
+        }
+
+
+        @Override
+        public int getPlotAxisIndex() {
+            return plotAxisIndex;
+        }
+
+
+        @Override
+        public boolean isArea(XYDataset dataset) {
+            logger.warn("This AxisDataset doesn't support Areas yet!");
+            return false;
+        }
+
+
+        protected void mergeRanges(TimeSeriesCollection dataset) {
+            logger.debug("Range before merging: " + range);
+            Range subRange = null;
+
+            // Determine min/max of range axis.
+            for (int i = 0; i < dataset.getSeriesCount(); i++) {
+                if (dataset.getSeries(i).getItemCount() == 0) {
+                    continue;
+                }
+                double min = Double.MAX_VALUE;
+                double max = -Double.MAX_VALUE;
+                TimeSeries series = dataset.getSeries(i);
+                for (int j = 0; j < series.getItemCount(); j++) {
+                    double tmp = series.getValue(j).doubleValue();
+                    min = tmp < min ? tmp : min;
+                    max = tmp > max ? tmp : max;
+                }
+                if (subRange != null) {
+                    subRange = new Range(
+                        min < subRange.getLowerBound() ?
+                            min : subRange.getLowerBound(),
+                        max > subRange.getUpperBound() ?
+                            max : subRange.getUpperBound());
+                }
+                else {
+                    subRange = new Range(min, max);
+                }
+            }
+
+            // Avoid merging NaNs, as they take min/max place forever.
+            if (subRange == null ||
+                Double.isNaN(subRange.getLowerBound()) ||
+                Double.isNaN(subRange.getUpperBound())) {
+                return;
+            }
+            if (range == null) {
+                range = subRange;
+                return;
+            }
+            range = Range.combine(range, subRange);
+        }
+
+    } // end of TimeseriesAxisDataset class
+
+    protected List<Marker> domainMarker;
+
+    protected List<Marker> valueMarker;
+
+    protected Map<String, String> attributes;
+
+    protected boolean domainZeroLineVisible;
+
+    private static final Logger logger =
+        Logger.getLogger(TimeseriesChartGenerator.class);
+
+    public static final int AXIS_SPACE = 5;
+
+    protected Map<Integer, Bounds> xBounds;
+
+    protected Map<Integer, Bounds> yBounds;
+
+
+    /**
+     * The default constructor that initializes internal datastructures.
+     */
+    public TimeseriesChartGenerator() {
+        super();
+
+        xBounds = new HashMap<Integer, Bounds>();
+        yBounds = new HashMap<Integer, Bounds>();
+        domainMarker = new ArrayList<Marker>();
+        valueMarker = new ArrayList<Marker>();
+        attributes = new HashMap<String, String>();
+    }
+
+
+
+    @Override
+    public JFreeChart generateChart() {
+        logger.info("Generate Timeseries Chart.");
+
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(
+            getChartTitle(),
+            getXAxisLabel(),
+            getYAxisLabel(0),
+            null,
+            isLegendVisible(),
+            false,
+            false);
+
+        XYPlot plot = (XYPlot) chart.getPlot();
+
+        chart.setBackgroundPaint(Color.WHITE);
+        plot.setBackgroundPaint(Color.WHITE);
+
+        addSubtitles(chart);
+        adjustPlot(plot);
+        addDatasets(plot);
+        adjustAxes(plot);
+        addDomainAxisMarker(plot);
+        addValueAxisMarker(plot);
+        adaptZoom(plot);
+
+        applySeriesAttributes(plot);
+        addAnnotationsToRenderer(plot);
+        addLogo(plot);
+        aggregateLegendEntries(plot);
+        return chart;
+    }
+
+
+    /**
+     * Return left most data points x value (on first axis).
+     * Shortcut, especially to be overridden in (LS) charts where
+     * axis could be inverted.
+     */
+    protected double getLeftX() {
+        return (Long)getXBounds(0).getLower();
+    }
+
+
+    /**
+     * Return right most data points x value (on first axis).
+     * Shortcut, especially to be overridden in (LS) charts where
+     * axis could be inverted.
+     */
+    protected double getRightX() {
+        return (Long)getXBounds(0).getUpper();
+    }
+
+
+    /**
+     * Add a logo as background annotation to plot.
+     * Copy from XYChartGenerator.
+     */
+    protected void addLogo(XYPlot plot) {
+        String logo = showLogo();
+        if (logo  == null) {
+            logger.debug("No logo to show chosen");
+            return;
+        }
+
+        ImageIcon imageIcon = null;
+        if (logo.equals("none")) {
+            return;
+        }
+        /*
+         If you want to add images, remember to change code in these places:
+         flys-artifacts:
+         XYChartGenerator.java
+         Timeseries*Generator.java and
+         in the flys-client projects Chart*Propert*Editor.java.
+         Also, these images have to be put in
+         flys-artifacts/src/main/resources/images/
+         flys-client/src/main/webapp/images/
+         */
+        java.net.URL imageURL;
+        if (logo.equals("Intevation")) {
+            imageURL = XYChartGenerator.class.getResource("/images/intevation.png");
+        }
+        else { // TODO else if ...
+            imageURL = XYChartGenerator.class.getResource("/images/bfg_logo.gif");
+        }
+        imageIcon = new ImageIcon(imageURL);
+        double xPos = 0d, yPos = 0d;
+
+        String placeh = logoHPlace();
+        String placev = logoVPlace();
+
+        if (placev == null || placev.equals("none")) {
+            placev = "top";
+        }
+        if (placev.equals("top")) {
+            yPos = (Double)getYBounds(0).getUpper();
+        }
+        else if (placev.equals("bottom")) {
+            yPos = (Double)getYBounds(0).getLower();
+        }
+        else if (placev.equals("center")) {
+            yPos = ((Double)getYBounds(0).getUpper() + (Double)getYBounds(0).getLower())/2d;
+        }
+        else {
+            logger.debug("Unknown place-v value: " + placev);
+        }
+
+        if (placeh == null || placeh.equals("none")) {
+            placeh = "center";
+        }
+        if (placeh.equals("left")) {
+            xPos = getLeftX();
+        }
+        else if (placeh.equals("right")) {
+            xPos = getRightX();
+        }
+        else if (placeh.equals("center")) {
+            xPos = ((Long)getXBounds(0).getUpper() + (Long)getXBounds(0).getLower())/2d;
+        }
+        else {
+            logger.debug("Unknown place-h value: " + placeh);
+        }
+
+        logger.debug("logo position: " + xPos + "/" + yPos);
+
+        org.jfree.ui.RectangleAnchor anchor
+            = org.jfree.ui.RectangleAnchor.TOP;
+        if (placev.equals("top")) {
+            if (placeh.equals("left")) {
+                anchor = org.jfree.ui.RectangleAnchor.TOP_LEFT;
+            }
+            else if (placeh.equals("right")) {
+                anchor = org.jfree.ui.RectangleAnchor.TOP_RIGHT;
+            }
+            else if (placeh.equals("center")) {
+                anchor = org.jfree.ui.RectangleAnchor.TOP;
+            }
+        }
+        else if (placev.equals("bottom")) {
+            if (placeh.equals("left")) {
+                anchor = org.jfree.ui.RectangleAnchor.BOTTOM_LEFT;
+            }
+            else if (placeh.equals("right")) {
+                anchor = org.jfree.ui.RectangleAnchor.BOTTOM_RIGHT;
+            }
+            else if (placeh.equals("center")) {
+                anchor = org.jfree.ui.RectangleAnchor.BOTTOM;
+            }
+        }
+        else if (placev.equals("center")) {
+            if (placeh.equals("left")) {
+                anchor = org.jfree.ui.RectangleAnchor.LEFT;
+            }
+            else if (placeh.equals("right")) {
+                anchor = org.jfree.ui.RectangleAnchor.RIGHT;
+            }
+            else if (placeh.equals("center")) {
+                anchor = org.jfree.ui.RectangleAnchor.CENTER;
+            }
+        }
+
+        XYAnnotation xyannotation =
+            new XYImageAnnotation(xPos, yPos, imageIcon.getImage(), anchor);
+        plot.getRenderer().addAnnotation(xyannotation, org.jfree.ui.Layer.BACKGROUND);
+    }
+
+
+    @Override
+    protected Series getSeriesOf(XYDataset dataset, int idx) {
+        return ((TimeSeriesCollection) dataset).getSeries(idx);
+    }
+
+
+    /**
+     * This method creates new instances of TimeseriesAxisDataset.
+     *
+     * @param idx The symbol for the new TimeseriesAxisDataset.
+     */
+    @Override
+    protected AxisDataset createAxisDataset(int idx) {
+        logger.debug("Create a new AxisDataset for index: " + idx);
+        return new TimeseriesAxisDataset(idx);
+    }
+
+
+    @Override
+    protected void combineXBounds(Bounds bounds, int index) {
+        if (bounds != null) {
+            Bounds old = getXBounds(index);
+
+            if (old != null) {
+                bounds = bounds.combine(old);
+            }
+
+            setXBounds(index, bounds);
+        }
+    }
+
+
+    @Override
+    protected void combineYBounds(Bounds bounds, int index) {
+        if (bounds != null) {
+            Bounds old = getYBounds(index);
+
+            if (old != null) {
+                bounds = bounds.combine(old);
+            }
+
+            setYBounds(index, bounds);
+        }
+    }
+
+
+    // TODO REPLACE THIS METHOD WITH getBoundsForAxis(index)
+    @Override
+    public Range[] getRangesForAxis(int index) {
+        // TODO
+        Bounds[] bounds = getBoundsForAxis(index);
+
+        return new Range[] {
+            new Range(
+                bounds[0].getLower().doubleValue(),
+                bounds[0].getUpper().doubleValue()),
+            new Range(
+                bounds[1].getLower().doubleValue(),
+                bounds[1].getUpper().doubleValue())
+        };
+    }
+
+
+    @Override
+    public Bounds getXBounds(int axis) {
+        return xBounds.get(axis);
+    }
+
+
+    @Override
+    protected void setXBounds(int axis, Bounds bounds) {
+        xBounds.put(axis, bounds);
+    }
+
+
+    @Override
+    public Bounds getYBounds(int axis) {
+        return yBounds.get(axis);
+    }
+
+
+    @Override
+    protected void setYBounds(int axis, Bounds bounds) {
+        if (bounds != null) {
+            yBounds.put(axis, bounds);
+        }
+    }
+
+
+    public Bounds[] getBoundsForAxis(int index) {
+        logger.debug("Return x and y bounds for axis at: " + index);
+
+        Bounds rx = getXBounds(Integer.valueOf(index));
+        Bounds ry = getYBounds(Integer.valueOf(index));
+
+        if (rx == null) {
+            logger.warn("Range for x axis not set." +
+                        " Using default values: 0 - 1.");
+            rx = new TimeBounds(0l, 1l);
+        }
+
+        if (ry == null) {
+            logger.warn("Range for y axis not set." +
+                        " Using default values: 0 - 1.");
+            ry = new DoubleBounds(0l, 1l);
+        }
+
+        logger.debug("X Bounds at index " + index + " is: " + rx);
+        logger.debug("Y Bounds at index " + index + " is: " + ry);
+
+        return new Bounds[] {rx, ry};
+    }
+
+
+    /** Get (zoom)values from request. */
+    public Bounds getDomainAxisRange() {
+        String[] ranges = getDomainAxisRangeFromRequest();
+
+        if (ranges == null || ranges.length < 2) {
+            logger.debug("No zoom range for domain axis specified.");
+            return null;
+        }
+
+        if (ranges[0] == null || ranges[1] == null) {
+            logger.warn("Invalid ranges for domain axis specified!");
+            return null;
+        }
+
+        try {
+            double lower = Double.parseDouble(ranges[0]);
+            double upper = Double.parseDouble(ranges[1]);
+
+            return new DoubleBounds(lower, upper);
+        }
+        catch (NumberFormatException nfe) {
+            logger.warn("Invalid ranges for domain axis specified: " + nfe);
+        }
+
+        return null;
+    }
+
+
+    public Bounds getValueAxisRange() {
+        String[] ranges = getValueAxisRangeFromRequest();
+
+        if (ranges == null || ranges.length < 2) {
+            logger.debug("No zoom range for domain axis specified.");
+            return null;
+        }
+
+        if (ranges[0] == null || ranges[1] == null) {
+            logger.warn("Invalid ranges for domain axis specified!");
+            return null;
+        }
+
+        try {
+            double lower = Double.parseDouble(ranges[0]);
+            double upper = Double.parseDouble(ranges[1]);
+
+            return new DoubleBounds(lower, upper);
+        }
+        catch (NumberFormatException nfe) {
+            logger.warn("Invalid ranges for domain axis specified: " + nfe);
+        }
+
+        return null;
+    }
+
+
+    protected void adaptZoom(XYPlot plot) {
+        logger.debug("Adapt zoom of Timeseries chart.");
+
+        zoomX(plot, plot.getDomainAxis(), getXBounds(0), getDomainAxisRange());
+
+        Bounds valueAxisBounds = getValueAxisRange();
+
+        for (int j = 0, n = plot.getRangeAxisCount(); j < n; j++) {
+            zoomY(
+                plot,
+                plot.getRangeAxis(j),
+                getYBounds(j),
+                valueAxisBounds);
+        }
+    }
+
+
+    /**
+     * @param plot the plot.
+     * @param axis the value (x, time) axis of which to set bounds.
+     * @param total the current bounds (?).
+     */
+    protected void zoomX(
+        XYPlot    plot,
+        ValueAxis axis,
+        Bounds    total,//we could equally nicely getXBounds(0)
+        Bounds    user
+    ) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("== Zoom X axis ==");
+            logger.debug("    Total axis range  : " + total);
+            logger.debug("    User defined range: " + user);
+        }
+
+        if (user != null) {
+            long min  = total.getLower().longValue();
+            long max  = total.getUpper().longValue();
+            long diff = max > min ? max - min : min - max;
+
+            long newMin = Math.round(min + user.getLower().doubleValue() * diff);
+            long newMax = Math.round(min + user.getUpper().doubleValue() * diff);
+
+            TimeBounds newBounds = new TimeBounds(newMin, newMax);
+
+            logger.debug("    Zoom axis to: " + newBounds);
+
+            newBounds.applyBounds(axis, AXIS_SPACE);
+        }
+        else {
+            logger.debug("No user specified zoom values found!");
+            if (total != null && axis != null) {
+                total.applyBounds(axis, AXIS_SPACE);
+            }
+        }
+    }
+
+
+    /**
+     * @param user zoom values in percent.
+     */
+    protected void zoomY(
+        XYPlot    plot,
+        ValueAxis axis,
+        Bounds    total,
+        Bounds    user
+    ) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("== Zoom Y axis ==");
+            logger.debug("    Total axis range  : " + total);
+            logger.debug("    User defined range: " + user);
+        }
+
+        if (user != null) {
+            double min  = total.getLower().doubleValue();
+            double max  = total.getUpper().doubleValue();
+            double diff = max > min ? max - min : min - max;
+
+            double newMin = min + user.getLower().doubleValue() * diff;
+            double newMax = min + user.getUpper().doubleValue() * diff;
+
+            DoubleBounds newBounds = new DoubleBounds(newMin, newMax);
+
+            logger.debug("    Zoom axis to: " + newBounds);
+
+            newBounds.applyBounds(axis, AXIS_SPACE);
+        }
+        else {
+            logger.debug("No user specified zoom values found!");
+            if (total != null && axis != null) {
+                total.applyBounds(axis, AXIS_SPACE);
+            }
+        }
+    }
+
+
+    /**
+     * Adjusts the axes of a plot. This method sets the <i>labelFont</i> of the
+     * X axis.
+     *
+     * (Duplicate in XYChartGenerator).
+     *
+     * @param plot The XYPlot of the chart.
+     */
+    protected void adjustAxes(XYPlot plot) {
+        ValueAxis xaxis = plot.getDomainAxis();
+
+        ChartSettings chartSettings = getChartSettings();
+        if (chartSettings == null) {
+            return;
+        }
+
+        Font labelFont = new Font(
+            DEFAULT_FONT_NAME,
+            Font.BOLD,
+            getXAxisLabelFontSize());
+
+        xaxis.setLabelFont(labelFont);
+        xaxis.setTickLabelFont(labelFont);
+    }
+
+
+    /**
+     * Do Points out.
+     */
+    protected void doPoints(
+        Object     o,
+        ArtifactAndFacet aandf,
+        Document   theme,
+        boolean    visible,
+        int        axisIndex
+    ) {
+        String seriesName = aandf.getFacetDescription();
+        TimeSeries series = new StyledTimeSeries(seriesName, theme);
+
+        // Add text annotations for single points.
+        List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
+        HashMap<Day, String> names = new HashMap<Day, String>();
+
+        try {
+            JSONArray points = new JSONArray((String) o);
+            for (int i = 0, P = points.length(); i < P; i++) {
+                JSONArray array = points.getJSONArray(i);
+                double x    = array.getDouble(0);
+                double y    = array.getDouble(1);
+                String name = array.getString(2);
+                boolean act = array.getBoolean(3);
+                if (!act) {
+                    continue;
+                }
+                long l = (new Double(x)).longValue();
+                Date date = new Date(l);
+                Day day = new Day(date);
+                series.add(day, y, false);
+                names.put(day, name);
+            }
+        }
+        catch(JSONException e){
+            logger.error("Could not decode json.");
+        }
+
+        TimeSeriesCollection tsc = new TimeSeriesCollection();
+        tsc.addSeries(series);
+        // Add Annotations.
+        for (int i = 0, S = series.getItemCount(); i < S; i++) {
+            double x = tsc.getXValue(0, i);
+            double y = tsc.getYValue(0, i);
+            xy.add(new CollisionFreeXYTextAnnotation(
+                       names.get(series.getTimePeriod(i)), x, y));
+        }
+        FLYSAnnotation annotations =
+            new FLYSAnnotation(null, null, null, theme);
+        annotations.setTextAnnotations(xy);
+
+        // Do not generate second legend entry. (null was passed for the aand before).
+        doAnnotations(annotations, null, theme, visible);
+
+        addAxisDataset(tsc, axisIndex, visible);
+    }
+
+    public void addDomainAxisMarker(XYPlot plot) {
+        logger.debug("domainmarkers: " + domainMarker.size());
+        for (Marker marker: domainMarker) {
+            logger.debug("adding domain marker");
+            plot.addDomainMarker(marker, Layer.BACKGROUND);
+        }
+        domainMarker.clear();
+    }
+
+    public void addValueAxisMarker(XYPlot plot) {
+        for (Marker marker: valueMarker) {
+            logger.debug("adding value marker..");
+            plot.addRangeMarker(marker, Layer.BACKGROUND);
+        }
+        valueMarker.clear();
+    }
+
+    public void addAttribute(String seriesKey, String name) {
+        attributes.put(seriesKey, name);
+    }
+
+    protected void applySeriesAttributes(XYPlot plot) {
+        int count  = plot.getDatasetCount();
+        for (int i = 0; i < count; i++) {
+            XYDataset data = plot.getDataset(i);
+            if (data == null) {
+                continue;
+            }
+            int seriesCount = data.getSeriesCount();
+            for (int j = 0; j < seriesCount; j++) {
+                StyledTimeSeries series =
+                    (StyledTimeSeries)getSeriesOf(data, j);
+                String key = series.getKey().toString();
+                if (attributes.containsKey(key)) {
+                    if (attributes.get(key).equals("interpolate")) {
+                        XYLineAndShapeRenderer renderer =
+                            series.getStyle().getRenderer();
+                        renderer.setSeriesPaint(
+                            j,
+                            renderer.getSeriesFillPaint(j));
+                        renderer.setSeriesShapesFilled(j, false);
+                    }
+                }
+                if (attributes.containsKey(key)) {
+                    if(attributes.get(key).equals("outline")) {
+                        XYLineAndShapeRenderer renderer =
+                            series.getStyle().getRenderer();
+                        renderer.setSeriesPaint(
+                            j,
+                            renderer.getSeriesFillPaint(j));
+                        renderer.setDrawOutlines(true);
+                    }
+                }
+            }
+        }
+    }
+
+    /** Two Ranges that span a rectangular area. */
+    public static class Area {
+        protected Range xRange;
+        protected Range yRange;
+
+        public Area(Range rangeX, Range rangeY) {
+            this.xRange = rangeX;
+            this.yRange = rangeY;
+        }
+
+        public Area(ValueAxis axisX, ValueAxis axisY) {
+            this.xRange = axisX.getRange();
+            this.yRange = axisY.getRange();
+        }
+
+        public double ofLeft(double percent) {
+            return xRange.getLowerBound()
+                + xRange.getLength() * percent;
+        }
+
+        public double ofRight(double percent) {
+            return xRange.getUpperBound()
+                - xRange.getLength() * percent;
+        }
+
+        public double ofGround(double percent) {
+            return yRange.getLowerBound()
+                + yRange.getLength() * percent;
+        }
+
+        public double atTop() {
+            return yRange.getUpperBound();
+        }
+
+        public double atGround() {
+            return yRange.getLowerBound();
+        }
+
+        public double atRight() {
+            return xRange.getUpperBound();
+        }
+
+        public double atLeft() {
+            return xRange.getLowerBound();
+        }
+
+        public double above(double percent, double base) {
+            return base + yRange.getLength() * percent;
+        }
+    }
+
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/TypeSection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/TypeSection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,7 @@
 package de.intevation.flys.exports;
 
+import org.apache.log4j.Logger;
+
 import de.intevation.artifactdatabase.state.Attribute;
 import de.intevation.artifactdatabase.state.DefaultSection;
 
@@ -9,11 +11,30 @@
  */
 public class TypeSection extends DefaultSection {
 
+    private static final Logger logger = Logger.getLogger(TypeSection.class);
+
     public TypeSection(String key) {
         super(key);
     }
 
 
+    /** Set a string value for a attribute with additional (choice) type. */
+    public void setChoiceStringValue(String key, String value, String choiceType) {
+        if (value == null || value.length() == 0) {
+            return;
+        }
+
+        Attribute attr = getAttribute(key);
+        if (attr == null) {
+            attr = new ChoiceStringAttribute(key, value, true, choiceType);
+            addAttribute(key, attr);
+        }
+        else {
+            attr.setValue(value);
+        }
+    }
+
+
     public void setStringValue(String key, String value) {
         if (value == null || value.length() == 0) {
             return;
@@ -37,6 +58,8 @@
             return (String) attr.getValue();
         }
 
+        logger.debug("attribute " + key + " not found in typesection.getString");
+
         return null;
     }
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesCurveGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,15 +1,12 @@
 package de.intevation.flys.exports;
 
-import org.apache.log4j.Logger;
-
-import org.jfree.chart.title.TextTitle;
-
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.plot.XYPlot;
-
 import de.intevation.flys.artifacts.model.FacetTypes;
 import de.intevation.flys.artifacts.model.WKms;
 
+import org.apache.log4j.Logger;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.XYPlot;
+
 
 /**
  * An OutGenerator that generates w differences curves.
@@ -86,22 +83,7 @@
 
 
     /**
-     * Add (internationalized) subtitle to chart.
-     * Overridden to avoid trying to access the range of masterartifact.
-     * @see getChartSubtitleKey
-     */
-    @Override
-    protected void addSubtitles(JFreeChart chart) {
-        String subtitle = getChartSubtitle();
-
-        if (subtitle != null && subtitle.length() > 0) {
-            chart.addSubtitle(new TextTitle(subtitle));
-        }
-    }
-
-
-    /**
-     * 
+     *
      */
     @Override
     public JFreeChart generateChart() {
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesExporter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WDifferencesExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,6 +5,11 @@
 import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Date;
+import java.text.DateFormat;
+import java.util.Locale;
 
 import org.w3c.dom.Document;
 
@@ -12,11 +17,23 @@
 
 import au.com.bytecode.opencsv.CSVWriter;
 
+import net.sf.jasperreports.engine.JasperExportManager;
+import net.sf.jasperreports.engine.JasperFillManager;
+import net.sf.jasperreports.engine.JasperPrint;
+import net.sf.jasperreports.engine.JRException;
+
 import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.flys.artifacts.WINFOArtifact;
 
 import de.intevation.flys.artifacts.model.CalculationResult;
 import de.intevation.flys.artifacts.model.WKms;
+import de.intevation.flys.artifacts.model.WKmsJRDataSource;
+import de.intevation.flys.artifacts.resources.Resources;
 
+import de.intevation.flys.utils.FLYSUtils;
 import de.intevation.flys.utils.Formatter;
 
 /**
@@ -37,6 +54,8 @@
     public static final String WDIFF_DEFAULT_CSV_KM_HEADER = "Fluss-Km";
     public static final String WDIFF_DEFAULT_CSV_W_HEADER  = "m";
 
+    public static final String PDF_HEADER_MODE = "export.wdifferences.pdf.mode";
+    public static final String JASPER_FILE = "export.wdifferences.pdf.file";
 
     /** The storage that contains all WKms objects for the different facets. */
     protected List<WKms[]> data;
@@ -66,6 +85,9 @@
         else if (facet.equals(AbstractExporter.FACET_CSV)) {
             generateCSV();
         }
+        else if (facet.equals(AbstractExporter.FACET_PDF)) {
+            generatePDF();
+        }
         else {
             throw new IOException("invalid facet (" + facet + ") for exporter");
         }
@@ -110,7 +132,7 @@
 
     /**
      * Lets csvwriter write the header (first line in file).
-     * @param write Writer to write header with.
+     * @param writer Writer to write header with.
      */
     protected void writeCSVHeader(CSVWriter writer) {
         logger.info("WDifferencesExporter.writeCSVHeader");
@@ -123,7 +145,7 @@
 
 
     protected void wKms2CSV(CSVWriter writer, WKms wkms) {
-        logger.debug("WDifferencesExporter.wQKms2CSV");
+        logger.debug("WDifferencesExporter.wKms2CSV");
 
         NumberFormat kmf  = getKmFormatter();
         NumberFormat wf   = getWFormatter();
@@ -157,5 +179,80 @@
     protected NumberFormat getWFormatter() {
         return Formatter.getWaterlevelW(context);
     }
+
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        WKmsJRDataSource source = createJRData();
+
+        String jasperFile = Resources.getMsg(
+                                context.getMeta(),
+                                JASPER_FILE,
+                                "/jasper/wdifferences_en.jasper");
+        String confPath = Config.getConfigDirectory().toString();
+
+        Map parameters = new HashMap();
+        parameters.put("ReportTitle", "Exported Data");
+        try {
+            JasperPrint print = JasperFillManager.fillReport(
+                confPath + jasperFile,
+                parameters,
+                source);
+            JasperExportManager.exportReportToPdfStream(print, out);
+        }
+        catch(JRException je) {
+            logger.warn("Error generating PDF Report!");
+            je.printStackTrace();
+        }
+    }
+
+    protected WKmsJRDataSource createJRData() {
+        WKmsJRDataSource source = new WKmsJRDataSource();
+
+        addMetaData(source);
+        for (WKms[] tmp: data) {
+            for (WKms wkms: tmp) {
+                addWKmsData(source, wkms);
+            }
+        }
+        return source;
+    }
+
+
+    protected void addMetaData(WKmsJRDataSource source) {
+        CallMeta meta = context.getMeta();
+
+        WINFOArtifact flys = (WINFOArtifact) master;
+
+        source.addMetaData ("river", FLYSUtils.getRivername(flys));
+
+        Locale locale = Resources.getLocale(meta);
+        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+
+        source.addMetaData("date", df.format(new Date()));
+
+        String differences = FLYSUtils.getWDifferences(flys, context);
+        source.addMetaData("differences", differences);
+
+        source.addMetaData("calculation", Resources.getMsg(
+                                            locale,
+                                            PDF_HEADER_MODE,
+                                            "W Differences"));
+    }
+
+    protected void addWKmsData(WKmsJRDataSource source, WKms wkms) {
+        NumberFormat kmf  = getKmFormatter();
+        NumberFormat wf   = getWFormatter();
+        int          size = wkms.size();
+
+        for (int i = 0; i < size; i ++) {
+
+            source.addData(new String[] {
+                kmf.format(wkms.getKm(i)),
+                wf.format(wkms.getW(i))
+            });
+        }
+    }
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/WaterlevelExporter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WaterlevelExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,6 +5,8 @@
 import java.text.DateFormat;
 import java.text.NumberFormat;
 import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
@@ -17,8 +19,14 @@
 
 import au.com.bytecode.opencsv.CSVWriter;
 
+import net.sf.jasperreports.engine.JasperExportManager;
+import net.sf.jasperreports.engine.JasperFillManager;
+import net.sf.jasperreports.engine.JasperPrint;
+import net.sf.jasperreports.engine.JRException;
+
 import de.intevation.artifacts.CallContext;
 import de.intevation.artifacts.CallMeta;
+import de.intevation.artifacts.common.utils.Config;
 
 import de.intevation.flys.model.Gauge;
 
@@ -27,6 +35,8 @@
 import de.intevation.flys.artifacts.model.CalculationResult;
 import de.intevation.flys.artifacts.model.WQCKms;
 import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.WKmsJRDataSource;
+import de.intevation.flys.artifacts.model.fixings.FixRealizingResult;
 import de.intevation.flys.artifacts.resources.Resources;
 
 import de.intevation.flys.utils.FLYSUtils;
@@ -35,6 +45,9 @@
 
 
 /**
+ * Generates different output formats (wst, csv, pdf) of data that resulted from
+ * a waterlevel computation.
+ *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class WaterlevelExporter extends AbstractExporter {
@@ -42,10 +55,8 @@
     /** The logger used in this exporter.*/
     private static Logger logger = Logger.getLogger(WaterlevelExporter.class);
 
-
     public static final String FACET_WST = "wst";
 
-
     public static final String CSV_KM_HEADER =
         "export.waterlevel.csv.header.km";
 
@@ -108,6 +119,8 @@
     public static final String DEFAULT_CSV_NOT_IN_GAUGE_RANGE =
         "außerhalb des gewählten Bezugspegels";
 
+    public static final String PDF_HEADER_MODE = "export.waterlevel.pdf.mode";
+    public static final String JASPER_FILE     = "export.waterlevel.pdf.file";
 
     /** The storage that contains all WQKms objects for the different facets.*/
     protected List<WQKms[]> data;
@@ -134,6 +147,9 @@
         else if (facet != null && facet.equals(FACET_WST)) {
             generateWST();
         }
+        else if (facet != null && facet.equals(AbstractExporter.FACET_PDF)) {
+            generatePDF();
+        }
         else {
             throw new IOException("invalid facet for exporter");
         }
@@ -147,6 +163,9 @@
             if (d instanceof WQKms []) {
                 data.add((WQKms [])d);
             }
+            else if (d instanceof FixRealizingResult) {
+                data.add(((FixRealizingResult) d).getWQKms());
+            }
         }
     }
 
@@ -183,7 +202,8 @@
                 String nmv = FLYSUtils.getNamedMainValue(winfo, v);
 
                 if (nmv != null && nmv.length() > 0) {
-                    nmv = FLYSUtils.stripNamedMainValue(nmv);
+                    nmv  = FLYSUtils.stripNamedMainValue(nmv);
+                    nmv += "=" + String.valueOf(v);
                     logger.debug("Set named main value '" + nmv + "'");
 
                     return nmv;
@@ -198,6 +218,57 @@
     }
 
 
+    protected String getCSVRowTitle(WINFOArtifact winfo, WQKms wqkms) {
+        logger.debug("WaterlevelExporter.prepareNamedValue");
+
+        String name = wqkms.getName();
+
+        logger.debug("Name of WQKms = '" + name + "'");
+
+        WQ_MODE wqmode = FLYSUtils.getWQMode(winfo);
+
+        if (wqmode == WQ_MODE.WFREE || wqmode == WQ_MODE.QGAUGE) {
+            return localizeWQKms(winfo, wqkms);
+        }
+
+        Double v = wqkms.getRawValue();
+
+        String nmv = FLYSUtils.getNamedMainValue(winfo, v);
+
+        if (nmv != null && nmv.length() > 0) {
+            nmv = FLYSUtils.stripNamedMainValue(nmv);
+            logger.debug("Set named main value '" + nmv + "'");
+
+            return nmv;
+        }
+
+        return localizeWQKms(winfo, wqkms);
+    }
+
+
+    /**
+     * Get a string like 'W=' or 'Q=' with a number following in localized
+     * format.
+     */
+    protected String localizeWQKms(WINFOArtifact winfo, WQKms wqkms) {
+        WQ_MODE wqmode   = FLYSUtils.getWQMode(winfo);
+        Double  rawValue = wqkms.getRawValue();
+
+        if (rawValue == null) {
+            return wqkms.getName();
+        }
+
+        NumberFormat nf = Formatter.getRawFormatter(context);
+
+        if (wqmode == WQ_MODE.WFREE || wqmode == WQ_MODE.WGAUGE) {
+            return "W=" + nf.format(rawValue);
+        }
+        else {
+            return "Q=" + nf.format(rawValue);
+        }
+    }
+
+
     @Override
     protected void writeCSVData(CSVWriter writer) {
         logger.info("WaterlevelExporter.writeData");
@@ -205,6 +276,8 @@
         WQ_MODE mode    = FLYSUtils.getWQMode((FLYSArtifact)master);
         boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE;
         boolean isQ     = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE;
+        FLYSUtils.WQ_INPUT input
+            = FLYSUtils.getWQInputMode((FLYSArtifact)master);
 
         writeCSVMeta(writer);
         writeCSVHeader(writer, atGauge, isQ);
@@ -279,13 +352,22 @@
         FLYSUtils.WQ_MODE wq = FLYSUtils.getWQMode(flys);
         if (wq == FLYSUtils.WQ_MODE.QFREE || wq == FLYSUtils.WQ_MODE.QGAUGE) {
             double[] qs  = FLYSUtils.getQs(flys);
+            FLYSUtils.WQ_INPUT input = FLYSUtils.getWQInputMode(flys);
 
-            String lower = "";
-            String upper = "";
+            String data = "";
 
-            if (qs != null && qs.length > 0) {
-                lower = String.valueOf(qs[0]);
-                upper = String.valueOf(qs[qs.length-1]);
+            if ((input == FLYSUtils.WQ_INPUT.ADAPTED ||
+                input == FLYSUtils.WQ_INPUT.RANGE) &&
+                qs != null && qs.length > 0)
+            {
+                data = String.valueOf(qs[0]);
+                data += " - " + String.valueOf(qs[qs.length-1]);
+            }
+            else if (input == FLYSUtils.WQ_INPUT.SINGLE && qs != null){
+                data = String.valueOf(qs[0]);
+                for (int i = 1; i < qs.length; i++) {
+                    data += ", " + String.valueOf(qs[i]);
+                }
             }
             else {
                 logger.warn("Could not determine Q range!");
@@ -296,7 +378,7 @@
                     meta,
                     CSV_META_Q,
                     CSV_META_Q,
-                    new Object[] { lower, upper })
+                    new Object[] {data})
             });
         }
         else {
@@ -356,6 +438,9 @@
     }
 
 
+    /**
+     * Write "rows" of csv data from wqkms with writer.
+     */
     protected void wQKms2CSV(
         CSVWriter writer,
         WQKms     wqkms,
@@ -383,7 +468,7 @@
         double b = gauge.getRange().getB().doubleValue();
 
         if (flys instanceof WINFOArtifact && isQ) {
-            desc = getColumnTitle((WINFOArtifact)flys, wqkms);
+            desc = getCSVRowTitle((WINFOArtifact)flys, wqkms);
         }
         else if (!isQ) {
             Double value = FLYSUtils.getValueFromWQ(wqkms);
@@ -391,6 +476,16 @@
                 ? Formatter.getWaterlevelW(context).format(value) : null;
         }
 
+        long startTime = System.currentTimeMillis();
+
+        String colDesc = desc;
+        if (flys instanceof WINFOArtifact) {
+            if (wqkms != null && wqkms.getRawValue() != null) {
+                WINFOArtifact winfo = (WINFOArtifact) flys;
+                colDesc = FLYSUtils.getNamedMainValue(winfo, wqkms.getRawValue());
+            }
+        }
+
         for (int i = 0; i < size; i ++) {
             result = wqkms.get(i, result);
 
@@ -399,7 +494,7 @@
                     kmf.format(result[2]),
                     wf.format(result[0]),
                     qf.format(result[1]),
-                    desc,
+                    colDesc,
                     FLYSUtils.getLocationDescription(flys, result[2]),
                     result[2] >= a && result[2] <= b
                         ? gaugeName
@@ -415,6 +510,13 @@
                 });
             }
         }
+
+        long stopTime = System.currentTimeMillis();
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Writing CSV took " +
+                (float)(stopTime-startTime)/1000f + " secs.");
+        }
     }
 
 
@@ -487,32 +589,146 @@
 
 
     /**
-     * Returns the number formatter for kilometer values.
      *
-     * @return the number formatter for kilometer values.
      */
-    protected NumberFormat getKmFormatter() {
-        return Formatter.getWaterlevelKM(context);
-    }
+    @Override
+    protected void writePDF(OutputStream out) {
+        logger.debug("write PDF");
+        WKmsJRDataSource source = createJRData();
+
+        String jasperFile = Resources.getMsg(
+                                context.getMeta(),
+                                JASPER_FILE,
+                                "/jasper/waterlevel_en.jasper");
+        String confPath = Config.getConfigDirectory().toString();
 
 
-    /**
-     * Returns the number formatter for W values.
-     *
-     * @return the number formatter for W values.
-     */
-    protected NumberFormat getWFormatter() {
-        return Formatter.getWaterlevelW(context);
+        Map parameters = new HashMap();
+        parameters.put("ReportTitle", "Exported Data");
+        try {
+            JasperPrint print = JasperFillManager.fillReport(
+                confPath + jasperFile,
+                parameters,
+                source);
+            JasperExportManager.exportReportToPdfStream(print, out);
+        }
+        catch(JRException je) {
+            logger.warn("Error generating PDF Report!");
+            je.printStackTrace();
+        }
     }
 
+    protected WKmsJRDataSource createJRData() {
+        WKmsJRDataSource source = new WKmsJRDataSource();
 
-    /**
-     * Returns the number formatter for Q values.
-     *
-     * @return the number formatter for Q values.
-     */
-    protected NumberFormat getQFormatter() {
-        return Formatter.getWaterlevelQ(context);
+        WQ_MODE mode    = FLYSUtils.getWQMode((FLYSArtifact)master);
+        boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE;
+        boolean isQ     = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE;
+
+        addMetaData(source);
+        for (WQKms[] tmp: data) {
+            for (WQKms wqkms: tmp) {
+                addWKmsData(wqkms, atGauge, isQ, source);
+            }
+        }
+        return source;
+    }
+
+    protected void addMetaData(WKmsJRDataSource source) {
+        CallMeta meta = context.getMeta();
+
+        FLYSArtifact flys = (FLYSArtifact) master;
+
+        source.addMetaData ("river", FLYSUtils.getRivername(flys));
+
+        Locale locale = Resources.getLocale(meta);
+        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+
+        source.addMetaData("date", df.format(new Date()));
+
+        double[] kms = FLYSUtils.getKmRange(flys);
+        source.addMetaData("range", kms[0] + " - " + kms[kms.length-1]);
+
+        source.addMetaData("gauge", FLYSUtils.getGaugename(flys));
+
+        source.addMetaData("calculation", Resources.getMsg(
+                                            locale,
+                                            PDF_HEADER_MODE,
+                                            "Waterlevel"));
+    }
+
+    protected void addWKmsData(
+        WQKms wqkms,
+        boolean atGauge,
+        boolean isQ,
+        WKmsJRDataSource source)
+    {
+        logger.debug("WaterlevelExporter.addWKmsData");
+
+        NumberFormat kmf = getKmFormatter();
+        NumberFormat wf  = getWFormatter();
+        NumberFormat qf  = getQFormatter();
+
+        int      size   = wqkms.size();
+        double[] result = new double[3];
+
+        FLYSArtifact flys       = (FLYSArtifact) master;
+        Gauge        gauge      = FLYSUtils.getGauge(flys);
+        String       gaugeName  = gauge.getName();
+        String       desc       = "";
+        String       notinrange = msg(
+            CSV_NOT_IN_GAUGE_RANGE,
+            DEFAULT_CSV_NOT_IN_GAUGE_RANGE);
+
+        double a = gauge.getRange().getA().doubleValue();
+        double b = gauge.getRange().getB().doubleValue();
+
+        if (flys instanceof WINFOArtifact && isQ) {
+            desc = getCSVRowTitle((WINFOArtifact)flys, wqkms);
+        }
+        else if (!isQ) {
+            Double value = FLYSUtils.getValueFromWQ(wqkms);
+            desc         = value != null
+                ? Formatter.getWaterlevelW(context).format(value) : null;
+        }
+
+        long startTime = System.currentTimeMillis();
+
+        for (int i = 0; i < size; i ++) {
+            result = wqkms.get(i, result);
+
+            if (atGauge) {
+                source.addData(new String[] {
+                    kmf.format(result[2]),
+                    wf.format(result[0]),
+                    qf.format(result[1]),
+                    desc,
+                    FLYSUtils.getLocationDescription(flys, result[2]),
+                    result[2] >= a && result[2] <= b
+                        ? gaugeName
+                        : notinrange
+                });
+            }
+            else {
+                source.addData(new String[] {
+                    kmf.format(result[2]),
+                    wf.format(result[0]),
+                    qf.format(result[1]),
+                    desc,
+                    FLYSUtils.getLocationDescription(flys, result[2]),
+                    result[2] >= a && result[2] <= b
+                        ? gaugeName
+                        : notinrange
+                });
+            }
+        }
+
+        long stopTime = System.currentTimeMillis();
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Writing PDF data took " +
+                (float)(stopTime-startTime)/1000f + " secs.");
+        }
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/WstWriter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/WstWriter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -25,36 +25,32 @@
  */
 public class WstWriter {
 
-    /** The logger used in this class.*/
+    /** The logger used in this class. */
     private static Logger logger = Logger.getLogger(WstWriter.class);
 
-
-    /** The default unit that is written into the header of the WST.*/
+    /** The default unit that is written into the header of the WST. */
     public static final String DEFAULT_UNIT = "Wassserstand [NN + m]";
 
-
-    /** The lines that need to be included for the export.*/
+    /** The lines that need to be included for the export. */
     protected Map<Double, WstLine> lines;
 
-    /** The column names.*/
+    /** The column names. */
     protected List<String> columnNames;
 
-    /** The locale used to format the values.*/
+    /** The locale used to format the values. */
     protected Locale locale;
 
-    /** The number of discharge columns.*/
+    /** The number of discharge columns. */
     protected int cols;
 
-    /** The last Q values.*/
+    /** The last Q values. */
     protected double[] qs;
 
 
 
     /**
-     * This constructor creates a new WstWriter with an OutputStream and a
-     * number of Q columns.
+     * This constructor creates a new WstWriter with a number of Q columns.
      *
-     * @param out The output stream where the WST is written to.
      * @param cols The number of columns of the resulting WST.
      */
     public WstWriter(int cols) {
@@ -68,6 +64,7 @@
     /**
      * This method is used to create the WST from the data that has been
      * inserted using add(double[]) before.
+     * @param out Where to write to.
      */
     public void write(OutputStream out) {
         logger.info("WstWriter.write");
--- a/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,62 +1,44 @@
 package de.intevation.flys.exports;
 
-import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Font;
-import java.awt.Paint;
-import java.awt.Stroke;
-import java.awt.TexturePaint;
-
-import java.awt.geom.Rectangle2D;
-
-import java.awt.image.BufferedImage;
-
-import java.io.IOException;
-
 import java.text.NumberFormat;
-
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.TreeMap;
 import java.util.List;
 import java.util.Map;
-import java.util.SortedMap;
 
-import org.w3c.dom.Document;
+import javax.swing.ImageIcon;
 
 import org.apache.log4j.Logger;
-
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.LegendItem;
-import org.jfree.chart.LegendItemCollection;
+import org.jfree.chart.annotations.XYAnnotation;
+import org.jfree.chart.annotations.XYImageAnnotation;
 import org.jfree.chart.annotations.XYTextAnnotation;
 import org.jfree.chart.axis.NumberAxis;
 import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.Marker;
 import org.jfree.chart.plot.PlotOrientation;
 import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.xy.XYItemRenderer;
-import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
 import org.jfree.data.Range;
+import org.jfree.data.general.Series;
+import org.jfree.data.xy.XYDataset;
 import org.jfree.data.xy.XYSeries;
 import org.jfree.data.xy.XYSeriesCollection;
-import org.jfree.data.xy.XYDataset;
-
-import org.jfree.ui.RectangleInsets;
-
-import de.intevation.artifacts.CallContext;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.w3c.dom.Document;
 
-import de.intevation.artifactdatabase.state.Facet;
-import de.intevation.artifactdatabase.state.Section;
-import de.intevation.artifactdatabase.state.Settings;
-
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.flys.jfree.Bounds;
+import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation;
+import de.intevation.flys.jfree.DoubleBounds;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledAreaSeriesCollection;
+import de.intevation.flys.jfree.StyledXYSeries;
 
-import de.intevation.flys.exports.ChartExportHelper;
-import de.intevation.flys.jfree.FLYSAnnotation;
-import de.intevation.flys.jfree.StableXYDifferenceRenderer;
-import de.intevation.flys.jfree.StickyAxisAnnotation;
-
-import de.intevation.flys.utils.ThemeAccess;
 
 /**
  * An abstract base class for creating XY charts.
@@ -75,17 +57,21 @@
  */
 public abstract class XYChartGenerator extends ChartGenerator {
 
-    // TODO Consider storing the renderer here.
-    private class AxisDataset {
+    public class XYAxisDataset implements AxisDataset {
         /** Symbolic integer, but also coding the priority (0 goes first). */
         protected int axisSymbol;
+
         /** List of assigned datasets (in order). */
         protected List<XYDataset> datasets;
+
         /** Range to use to include all given datasets. */
         protected Range range;
 
+        /** Index of axis in plot. */
+        protected int plotAxisIndex;
+
         /** Create AxisDataset. */
-        public AxisDataset(int symb) {
+        public XYAxisDataset(int symb) {
             this.axisSymbol = symb;
             datasets        = new ArrayList<XYDataset>();
         }
@@ -105,18 +91,53 @@
             range = Range.combine(range, subRange);
         }
 
-        /** Add a dataset, include its range. */
-        public void addDataset(XYSeries dataset) {
-            this.datasets.add(new XYSeriesCollection(dataset));
-            includeYRange(dataset);
+
+        /** Add a dataset to internal list for this axis. */
+        @Override
+        public void addDataset(XYDataset dataset) {
+            datasets.add(dataset);
+            includeYRange(((XYSeriesCollection) dataset).getSeries(0));
         }
 
+        /** Add a dataset, include its range. */
+        public void addDataset(XYSeries series) {
+            addDataset(new XYSeriesCollection(series));
+        }
+
+
+        /** Set Range for this axis. */
+        @Override
+        public void setRange(Range range) {
+            this.range = range;
+        }
+
+
+        /** Get Range for this axis. */
+        @Override
+        public Range getRange() {
+            return range;
+        }
+
+
+        /** Get Array of Datasets. */
+        @Override
+        public XYDataset[] getDatasets() {
+            return datasets.toArray(new XYDataset[datasets.size()]);
+        }
+
+
+        /** Add a Dataset that describes an area. */
         public void addArea(StyledAreaSeriesCollection series) {
             this.datasets.add(series);
+            List<?> allSeries = series.getSeries();
+            for (int n = 0; n < allSeries.size(); n++) {
+                includeYRange((XYSeries)allSeries.get(n));
+            }
         }
 
-        /** True if to be renedered as area. */
-        public boolean isArea(XYSeriesCollection series) {
+        /** True if to be rendered as area. */
+        @Override
+        public boolean isArea(XYDataset series) {
             return (series instanceof StyledAreaSeriesCollection);
         }
 
@@ -126,354 +147,55 @@
         }
 
         /** True if no datasets given. */
+        @Override
         public boolean isEmpty() {
             return this.datasets.isEmpty();
         }
+
+        /** Set the 'real' axis index that this axis is mapped to. */
+        @Override
+        public void setPlotAxisIndex(int axisIndex) {
+            this.plotAxisIndex = axisIndex;
+        }
+
+        /** Get the 'real' axis index that this axis is mapped to. */
+        @Override
+        public int getPlotAxisIndex() {
+            return this.plotAxisIndex;
+        }
     } // class AxisDataset
 
-
-    /**
-     * A mini interface that allows to walk over the YAXIS enums defined in
-     * subclasses.
-     */
-    public interface YAxisWalker {
-        int length();
-        String getId(int idx);
-    }
-
+    /** Enumerator over existing axes. */
+    @Override
+    protected abstract YAxisWalker getYAxisWalker();
 
-    /** Override to make axis information available. */
-    protected YAxisWalker getYAxisWalker() {
-        return new YAxisWalker() {
-            /** Get number of items. */
-            @Override
-            public int length() {
-                return 0;
-            }
-
-            /** Get identifier for this index. */
-            @Override
-            public String getId(int idx) {
-                return null;
-            }
-        };
-    }
-
+    public static final int AXIS_SPACE = 5;
 
     /** The logger that is used in this generator. */
     private static Logger logger = Logger.getLogger(XYChartGenerator.class);
 
-    /** Map of datasets ("index"). */
-    protected SortedMap<Integer, AxisDataset> datasets;
+    protected List<Marker> domainMarkers = new ArrayList<Marker>();
 
-    /** List of annotations to insert in plot. */
-    protected List<FLYSAnnotation> annotations;
+    protected List<Marker> valueMarkers = new ArrayList<Marker>();
 
     /** The max X range to include all X values of all series for each axis. */
-    protected Map<Integer, Range> xRanges;
+    protected Map<Integer, Bounds> xBounds;
 
     /** The max Y range to include all Y values of all series for each axis. */
-    protected Map<Integer, Range> yRanges;
-
-    public static final Color  DEFAULT_GRID_COLOR      = Color.GRAY;
-    public static final float  DEFAULT_GRID_LINE_WIDTH = 0.3f;
-    public static final int    DEFAULT_FONT_SIZE       = 12;
-    public static final String DEFAULT_FONT_NAME       = "Tahoma";
-
+    protected Map<Integer, Bounds> yBounds;
 
     public XYChartGenerator() {
-        xRanges  = new HashMap<Integer, Range>();
-        yRanges  = new HashMap<Integer, Range>();
-        datasets = new TreeMap<Integer, AxisDataset>();
-    }
-
-
-    /**
-     * Returns the title of a chart. The return value depends on the existence
-     * of ChartSettings: if there are ChartSettings set, this method returns the
-     * chart title provided by those settings. Otherwise, this method returns
-     * getDefaultChartTitle().
-     *
-     * @return the title of a chart.
-     */
-    protected String getChartTitle() {
-        ChartSettings chartSettings = getChartSettings();
-
-        if (chartSettings != null) {
-            return getChartTitle(chartSettings);
-        }
-
-        return getDefaultChartTitle();
-    }
-
-
-    protected abstract String getDefaultChartTitle();
-
-
-    /**
-     * Returns the subtitle of a chart. The return value depends on the
-     * existence of ChartSettings: if there are ChartSettings set, this method
-     * returns the chart title provided by those settings. Otherwise, this
-     * method returns getDefaultChartSubtitle().
-     *
-     * @return the subtitle of a chart.
-     */
-    protected String getChartSubtitle() {
-        ChartSettings chartSettings = getChartSettings();
-
-        if (chartSettings != null) {
-            return getChartSubtitle(chartSettings);
-        }
-
-        return getDefaultChartSubtitle();
-    }
-
-
-    /**
-     * This method always returns null. Override it in subclasses that require
-     * subtitles.
-     *
-     * @return null.
-     */
-    protected String getDefaultChartSubtitle() {
-        // Override this method in subclasses
-        return null;
-    }
-
-
-    /**
-     * This method is used to determine, if the chart's legend is visible or
-     * not. If a <i>settings</i> instance is set, this instance determines the
-     * visibility otherwise, this method returns true as default if no
-     * <i>settings</i> is set.
-     *
-     * @return true, if the legend should be visible, otherwise false.
-     */
-    protected boolean isLegendVisible() {
-        ChartSettings chartSettings = getChartSettings();
-        if (chartSettings != null) {
-            return isLegendVisible(chartSettings);
-        }
-
-        return true;
-    }
-
-
-    /**
-     * This method is used to determine the font size of the chart's legend. If
-     * a <i>settings</i> instance is set, this instance determines the font
-     * size, otherwise this method returns 12 as default if no <i>settings</i>
-     * is set or if it doesn't provide a legend font size.
-     *
-     * @return a legend font size.
-     */
-    protected int getLegendFontSize() {
-        Integer fontSize = null;
-
-        ChartSettings chartSettings = getChartSettings();
-        if (chartSettings != null) {
-            fontSize = getLegendFontSize(chartSettings);
-        }
-
-        return fontSize != null ? fontSize : DEFAULT_FONT_SIZE;
-    }
-
-
-    /**
-     * This method is used to determine if the resulting chart should display
-     * grid lines or not. <b>Note: this method always returns true!</b>
-     *
-     * @return true, if the chart should display grid lines, otherwise false.
-     */
-    protected boolean isGridVisible() {
-        return true;
-    }
-
-
-    /**
-     * Returns the X-Axis label of a chart.
-     *
-     * @return the X-Axis label of a chart.
-     */
-    protected String getXAxisLabel() {
-        ChartSettings chartSettings = getChartSettings();
-        if (chartSettings == null) {
-            return getDefaultXAxisLabel();
-        }
-
-        AxisSection as = chartSettings.getAxisSection("X");
-        if (as != null) {
-            String label = as.getLabel();
-
-            if (label != null) {
-                return label;
-            }
-        }
-
-        return getDefaultXAxisLabel();
-    }
-
-
-    /**
-     * Returns the default X-Axis label of a chart.
-     *
-     * @return the default X-Axis label of a chart.
-     */
-    protected abstract String getDefaultXAxisLabel();
-
+        super();
 
-    /**
-     * Returns the Y-Axis label of a chart at position <i>pos</i>.
-     *
-     * @return the Y-Axis label of a chart at position <i>0</i>.
-     */
-    protected String getYAxisLabel(int pos) {
-        ChartSettings chartSettings = getChartSettings();
-        if (chartSettings == null) {
-            return getDefaultYAxisLabel(pos);
-        }
-
-        YAxisWalker walker = getYAxisWalker();
-        AxisSection     as = chartSettings.getAxisSection(walker.getId(pos));
-        if (as != null) {
-            String label = as.getLabel();
-
-            if (label != null) {
-                return label;
-            }
-        }
-
-        return getDefaultYAxisLabel(pos);
-    }
-
-
-    /**
-     * This method is called to retrieve the default label for an Y axis at
-     * position <i>pos</i>.
-     *
-     * @param pos The position of an Y axis.
-     *
-     * @return the default Y axis label at position <i>pos</i>.
-     */
-    protected abstract String getDefaultYAxisLabel(int pos);
-
-
-    /**
-     * This method returns the font size for the X axis. If the font size is
-     * specified in ChartSettings (if <i>chartSettings</i> is set), this size is
-     * returned. Otherwise the default font size 12 is returned.
-     *
-     * @return the font size for the x axis.
-     */
-    protected int getXAxisLabelFontSize() {
-        ChartSettings chartSettings = getChartSettings();
-        if (chartSettings == null) {
-            return DEFAULT_FONT_SIZE;
-        }
-
-        AxisSection   as = chartSettings.getAxisSection("X");
-        Integer fontSize = as.getFontSize();
-
-        return fontSize != null ? fontSize : DEFAULT_FONT_SIZE;
-    }
-
-
-    /**
-     * This method returns the font size for an Y axis. If the font size is
-     * specified in ChartSettings (if <i>chartSettings</i> is set), this size is
-     * returned. Otherwise the default font size 12 is returned.
-     *
-     * @return the font size for the x axis.
-     */
-    protected int getYAxisFontSize(int pos) {
-        ChartSettings chartSettings = getChartSettings();
-        if (chartSettings == null) {
-            return DEFAULT_FONT_SIZE;
-        }
-
-        YAxisWalker walker = getYAxisWalker();
-
-        AxisSection   as = chartSettings.getAxisSection(walker.getId(pos));
-        Integer fontSize = as.getFontSize();
-
-        return fontSize != null ? fontSize : DEFAULT_FONT_SIZE;
-    }
-
-
-    /**
-     * This method returns the export dimension specified in ChartSettings as
-     * int array [width,height].
-     *
-     * @return an int array with [width,height].
-     */
-    protected int[] getExportDimension() {
-        ChartSettings chartSettings = getChartSettings();
-        if (chartSettings == null) {
-            return new int[] { 600, 400 };
-        }
-
-        ExportSection export = chartSettings.getExportSection();
-        Integer width  = export.getWidth();
-        Integer height = export.getHeight();
-
-        if (width != null && height != null) {
-            return new int[] { width, height };
-        }
-
-        return new int[] { 600, 400 };
-    }
-
-
-    /**
-     * Generate chart.
-     */
-    public void generate()
-    throws IOException
-    {
-        logger.debug("XYChartGenerator.generate");
-
-        JFreeChart chart = generateChart();
-
-        String format = getFormat();
-        int[]  size   = getSize();
-
-        if (size == null) {
-            size = getExportDimension();
-        }
-
-        context.putContextValue("chart.width",  size[0]);
-        context.putContextValue("chart.height", size[1]);
-
-        if (format.equals(ChartExportHelper.FORMAT_PNG)) {
-            context.putContextValue("chart.image.format", "png");
-
-            ChartExportHelper.exportImage(
-                out,
-                chart,
-                context);
-        }
-        else if (format.equals(ChartExportHelper.FORMAT_PDF)) {
-            preparePDFContext(context);
-
-            ChartExportHelper.exportPDF(
-                out,
-                chart,
-                context);
-        }
-        else if (format.equals(ChartExportHelper.FORMAT_SVG)) {
-            prepareSVGContext(context);
-
-            ChartExportHelper.exportSVG(
-                out,
-                chart,
-                context);
-        }
+        xBounds  = new HashMap<Integer, Bounds>();
+        yBounds  = new HashMap<Integer, Bounds>();
     }
 
 
     /**
      * Generate the chart anew (including localized axis and all).
      */
+    @Override
     public JFreeChart generateChart() {
         logger.debug("XYChartGenerator.generateChart");
 
@@ -488,6 +210,8 @@
             false);
 
         XYPlot plot = (XYPlot) chart.getPlot();
+        plot.setDomainAxis(createXAxis(getXAxisLabel()));
+
         chart.setBackgroundPaint(Color.WHITE);
         plot.setBackgroundPaint(Color.WHITE);
         addSubtitles(chart);
@@ -499,44 +223,179 @@
 
         //debugDatasets(plot);
 
+        addMarkers(plot);
+
         recoverEmptyPlot(plot);
         preparePointRanges(plot);
 
-        addAnnotationsToRenderer(plot);
-
         //debugAxis(plot);
 
         localizeAxes(plot);
         adjustAxes(plot);
         autoZoom(plot);
 
+        //debugAxis(plot);
+
+        // These have to go after the autozoom.
+        addAnnotationsToRenderer(plot);
+
+        // Add a logo (maybe).
+        addLogo(plot);
+
+        aggregateLegendEntries(plot);
+
         return chart;
     }
 
 
-    protected void preparePDFContext(CallContext context) {
-        int[] dimension = getExportDimension();
-
-        context.putContextValue("chart.width", dimension[0]);
-        context.putContextValue("chart.height", dimension[1]);
-        context.putContextValue("chart.marginLeft",   5f);
-        context.putContextValue("chart.marginRight",  5f);
-        context.putContextValue("chart.marginTop",    5f);
-        context.putContextValue("chart.marginBottom", 5f);
-        context.putContextValue(
-            "chart.page.format",
-            ChartExportHelper.DEFAULT_PAGE_SIZE);
+    /**
+     * Return left most data points x value (on first axis).
+     * Shortcut, especially to be overridden in (LS) charts where
+     * axis could be inverted.
+     */
+    protected double getLeftX() {
+        return (Double)getXBounds(0).getLower();
     }
 
 
-    protected void prepareSVGContext(CallContext context) {
-        int[] dimension = getExportDimension();
+    /**
+     * Return right most data points x value (on first axis).
+     * Shortcut, especially to be overridden in (LS) charts where
+     * axis could be inverted.
+     */
+    protected double getRightX() {
+        return (Double)getXBounds(0).getUpper();
+    }
 
-        context.putContextValue("chart.width", dimension[0]);
-        context.putContextValue("chart.height", dimension[1]);
-        context.putContextValue(
-            "chart.encoding",
-            ChartExportHelper.DEFAULT_ENCODING);
+
+    /** Add a logo as background annotation to plot. */
+    protected void addLogo(XYPlot plot) {
+        String logo = showLogo();
+        if (logo  == null) {
+            logger.debug("No logo to show chosen");
+            return;
+        }
+
+        ImageIcon imageIcon = null;
+        if (logo.equals("none")) {
+            return;
+        }
+        /*
+         If you want to add images, remember to change code in these places:
+         flys-artifacts:
+         XYChartGenerator.java
+         Timeseries*Generator.java and
+         in the flys-client projects Chart*Propert*Editor.java.
+         Also, these images have to be put in
+         flys-artifacts/src/main/resources/images/
+         flys-client/src/main/webapp/images/
+         */
+        java.net.URL imageURL;
+        if (logo.equals("Intevation")) {
+            imageURL = XYChartGenerator.class.getResource("/images/intevation.png");
+        }
+        else { // TODO else if ...
+            imageURL = XYChartGenerator.class.getResource("/images/bfg_logo.gif");
+        }
+        imageIcon = new ImageIcon(imageURL);
+
+
+        double xPos = 0d, yPos = 0d;
+
+        String placeh = logoHPlace();
+        String placev = logoVPlace();
+
+        if (placev == null || placev.equals("none")) {
+            placev = "top";
+        }
+        if (placev.equals("top")) {
+            yPos = (Double)getYBounds(0).getUpper();
+        }
+        else if (placev.equals("bottom")) {
+            yPos = (Double)getYBounds(0).getLower();
+        }
+        else if (placev.equals("center")) {
+            yPos = ((Double)getYBounds(0).getUpper() + (Double)getYBounds(0).getLower())/2d;
+        }
+        else {
+            logger.debug("Unknown place-v value: " + placev);
+        }
+
+        if (placeh == null || placeh.equals("none")) {
+            placeh = "center";
+        }
+        if (placeh.equals("left")) {
+            xPos = getLeftX();
+        }
+        else if (placeh.equals("right")) {
+            xPos = getRightX();
+        }
+        else if (placeh.equals("center")) {
+            xPos = ((Double)getXBounds(0).getUpper() + (Double)getXBounds(0).getLower())/2d;
+        }
+        else {
+            logger.debug("Unknown place-h value: " + placeh);
+        }
+
+        logger.debug("logo position: " + xPos + "/" + yPos);
+
+        org.jfree.ui.RectangleAnchor anchor
+            = org.jfree.ui.RectangleAnchor.TOP;
+        if (placev.equals("top")) {
+            if (placeh.equals("left")) {
+                anchor = org.jfree.ui.RectangleAnchor.TOP_LEFT;
+            }
+            else if (placeh.equals("right")) {
+                anchor = org.jfree.ui.RectangleAnchor.TOP_RIGHT;
+            }
+            else if (placeh.equals("center")) {
+                anchor = org.jfree.ui.RectangleAnchor.TOP;
+            }
+        }
+        else if (placev.equals("bottom")) {
+            if (placeh.equals("left")) {
+                anchor = org.jfree.ui.RectangleAnchor.BOTTOM_LEFT;
+            }
+            else if (placeh.equals("right")) {
+                anchor = org.jfree.ui.RectangleAnchor.BOTTOM_RIGHT;
+            }
+            else if (placeh.equals("center")) {
+                anchor = org.jfree.ui.RectangleAnchor.BOTTOM;
+            }
+        }
+        else if (placev.equals("center")) {
+            if (placeh.equals("left")) {
+                anchor = org.jfree.ui.RectangleAnchor.LEFT;
+            }
+            else if (placeh.equals("right")) {
+                anchor = org.jfree.ui.RectangleAnchor.RIGHT;
+            }
+            else if (placeh.equals("center")) {
+                anchor = org.jfree.ui.RectangleAnchor.CENTER;
+            }
+        }
+
+        XYAnnotation xyannotation =
+            new XYImageAnnotation(xPos, yPos, imageIcon.getImage(), anchor);
+        plot.getRenderer().addAnnotation(xyannotation, org.jfree.ui.Layer.BACKGROUND);
+    }
+
+
+    protected NumberAxis createXAxis(String label) {
+        return new NumberAxis(label);
+    }
+
+
+    @Override
+    protected Series getSeriesOf(XYDataset dataset, int idx) {
+        return ((XYSeriesCollection) dataset).getSeries(idx);
+    }
+
+
+    @Override
+    protected AxisDataset createAxisDataset(int idx) {
+        logger.debug("Create new XYAxisDataset for index: " + idx);
+        return new XYAxisDataset(idx);
     }
 
 
@@ -545,7 +404,7 @@
      */
     public void debugDatasets(XYPlot plot) {
         logger.debug("Number of datasets: " + plot.getDatasetCount());
-        for (int i = 0; i < plot.getDatasetCount(); i++) {
+        for (int i = 0, P = plot.getDatasetCount(); i < P; i++) {
             if (plot.getDataset(i) == null) {
                 logger.debug("Dataset #" + i + " is null");
                 continue;
@@ -565,7 +424,7 @@
      */
     public void debugAxis(XYPlot plot) {
         logger.debug("...............");
-        for (int i = 0; i < plot.getRangeAxisCount(); i++) {
+        for (int i = 0, P =  plot.getRangeAxisCount(); i < P; i++) {
             if (plot.getRangeAxis(i) == null)
                 logger.debug("Range-Axis #" + i + " == null");
             else {
@@ -574,64 +433,34 @@
                     "  " + plot.getRangeAxis(i).getRange().getUpperBound() +
                     "]");
             }
-
+        }
+        for (int i = 0, P =  plot.getDomainAxisCount(); i < P; i++) {
+            if (plot.getDomainAxis(i) == null)
+                logger.debug("Domain-Axis #" + i + " == null");
+            else {
+                logger.debug("Domain-Axis " + i + " != null [" +
+                    plot.getDomainAxis(i).getRange().getLowerBound() +
+                    "  " + plot.getDomainAxis(i).getRange().getUpperBound() +
+                    "]");
+            }
         }
         logger.debug("...............");
     }
 
 
     /**
-     * Add datasets to plot.
-     * @param plot plot to add datasets to.
-     */
-    protected void addDatasets(XYPlot plot) {
-        // AxisDatasets are sorted, but some might be empty.
-        // Thus, generate numbering on the fly.
-        int axisIndex    = 0;
-        int datasetIndex = 0;
-        for (Map.Entry<Integer, AxisDataset> entry: datasets.entrySet()) {
-            if (!entry.getValue().isEmpty()) {
-                // Add axis and range information.
-                AxisDataset axisDataset = entry.getValue();
-                NumberAxis axis = createYAxis(entry.getKey());
-
-                plot.setRangeAxis(axisIndex, axis);
-                if (axis.getAutoRangeIncludesZero()) {
-                    axisDataset.range = Range.expandToInclude(axisDataset.range, 0d);
-                }
-                yRanges.put(axisIndex, expandPointRange(axisDataset.range));
-
-                // Add contained datasets, mapping to axis.
-                for (XYDataset dataset: axisDataset.datasets) {
-                    plot.setDataset(datasetIndex, dataset);
-                    plot.mapDatasetToRangeAxis(datasetIndex, axisIndex);
-                    applyThemes(plot, (XYSeriesCollection) dataset,
-                        datasetIndex,
-                        axisDataset.isArea((XYSeriesCollection)dataset));
-                    datasetIndex++;
-                }
-                axisIndex++;
-            }
-        }
-    }
-
-
-    /**
      * Registers an area to be drawn.
-     * @param lower the lower curve to draw the area from.
-     * @param upper the upper curve to draw the ara from.
+     * @param area Area to be drawn.
+     * @param index 'axis index'
+     * @param visible Whether or not to be visible (important for range calculations).
      */
     public void addAreaSeries(StyledAreaSeriesCollection area, int index, boolean visible) {
         if (area == null) {
             logger.warn("Cannot yet render above/under curve.");
             return;
         }
-        AxisDataset axisDataset = datasets.get(index);
 
-        if (axisDataset == null) {
-            axisDataset = new AxisDataset(index);
-            datasets.put(index, axisDataset);
-        }
+        XYAxisDataset axisDataset = (XYAxisDataset) getAxisDataset(index);
 
         if (visible) {
             axisDataset.addArea(area);
@@ -646,8 +475,8 @@
     /**
      * Add given series if visible, if not visible adjust ranges (such that
      * all points in data would be plotted once visible).
-     * @param series the dataseries to include in plot.
-     * @param index  index of the series and of its axis.
+     * @param series the data series to include in plot.
+     * @param index  ('symbolic') index of the series and of its axis.
      * @param visible whether or not the data should be plotted.
      */
     public void addAxisSeries(XYSeries series, int index, boolean visible) {
@@ -655,97 +484,108 @@
             return;
         }
 
-        AxisDataset axisDataset = datasets.get(index);
-
-        if (axisDataset == null) {
-            axisDataset = new AxisDataset(index);
-            datasets.put(index, axisDataset);
-        }
+        logger.debug("Y Range of XYSeries: " +
+            series.getMinY() + " | " + series.getMaxY());
 
-        logger.debug("addAxisSeries: extent X " + series.getMinX() + " : " + series.getMaxX()
-            + " extent y " + series.getMinY() + " : " + series.getMaxY());
+        addAxisDataset(new XYSeriesCollection(series), index, visible);
 
-        if (visible) {
-            axisDataset.addDataset(series);
-        }
-        else {
+        XYAxisDataset axisDataset = (XYAxisDataset) getAxisDataset(index);
+
+        if (!visible) {
             // Do this also when not visible to have axis scaled by default such
             // that every data-point could be seen (except for annotations).
             axisDataset.includeYRange(series);
         }
+    }
 
-        combineXRanges(new Range(series.getMinX(), series.getMaxX()), 0);
+
+    /**
+     * Add the given vertical marker to the chart.
+     */
+    public void addDomainMarker(Marker marker) {
+        if (marker == null) {
+            return;
+        }
+
+        domainMarkers.add(marker);
+    }
+
+
+    /**
+     * Add the given vertical marker to the chart.
+     */
+    public void addValueMarker(Marker marker) {
+        if (marker == null) {
+            return;
+        }
+
+        valueMarkers.add(marker);
+    }
+
+
+    protected void addMarkers(XYPlot plot) {
+        for(Marker marker : domainMarkers) {
+            plot.addDomainMarker(marker);
+        }
+        for(Marker marker : valueMarkers) {
+            plot.addRangeMarker(marker);
+        }
     }
 
 
     /**
      * Effect: extend range of x axis to include given limits.
-     * @param range the given ("minimal") range.
+     *
+     * @param bounds the given ("minimal") bounds.
      * @param index index of axis to be merged.
      */
-    private void combineXRanges(Range range, int index) {
-
-        if (range == null
-            || Double.isNaN(range.getLowerBound())
-            || Double.isNaN(range.getUpperBound())) {
-            return;
-        }
-
-        Range old = xRanges.get(index);
-
-        if (old != null) {
-            range = Range.combine(old, range);
-        }
-
-        xRanges.put(index, range);
-    }
-
-
-    /**
-     * Adds annotations to list (if visible is true).
-     */
-    public void addAnnotations(FLYSAnnotation annotation, boolean visible) {
-        if (!visible) {
+    @Override
+    protected void combineXBounds(Bounds bounds, int index) {
+        if (!(bounds instanceof DoubleBounds)) {
+            logger.warn("Unsupported Bounds type: " + bounds.getClass());
             return;
         }
 
-        if (annotations == null) {
-            annotations = new ArrayList<FLYSAnnotation>();
+        DoubleBounds dBounds = (DoubleBounds) bounds;
+
+        if (dBounds == null
+            || Double.isNaN((Double) dBounds.getLower())
+            || Double.isNaN((Double) dBounds.getUpper())) {
+            return;
         }
 
-        annotations.add(annotation);
+        Bounds old = getXBounds(index);
+
+        if (old != null) {
+            dBounds = (DoubleBounds) dBounds.combine(old);
+        }
+
+        setXBounds(index, dBounds);
     }
 
 
-    /**
-     * Create Y (range) axis for given index.
-     * Shall be overriden by subclasses.
-     */
-    protected NumberAxis createYAxis(int index) {
-        YAxisWalker walker = getYAxisWalker();
-
-        Font labelFont = new Font(
-            DEFAULT_FONT_NAME,
-            Font.BOLD,
-            getYAxisFontSize(index));
+    @Override
+    protected void combineYBounds(Bounds bounds, int index) {
+        if (!(bounds instanceof DoubleBounds)) {
+            logger.warn("Unsupported Bounds type: " + bounds.getClass());
+            return;
+        }
 
-        IdentifiableNumberAxis axis = new IdentifiableNumberAxis(
-            walker.getId(index),
-            getYAxisLabel(index));
-
-        axis.setAutoRangeIncludesZero(false);
-        axis.setLabelFont(labelFont);
+        DoubleBounds dBounds = (DoubleBounds) bounds;
 
-        return axis;
-    }
-
+        if (dBounds == null
+            || Double.isNaN((Double) dBounds.getLower())
+            || Double.isNaN((Double) dBounds.getUpper())) {
+            return;
+        }
 
-    protected Font createLegendLabelFont() {
-        return new Font(
-            DEFAULT_FONT_NAME,
-            Font.PLAIN,
-            getLegendFontSize()
-        );
+        Bounds old = getYBounds(index);
+
+        if (old != null) {
+            dBounds = (DoubleBounds) dBounds.combine(old);
+        }
+
+        setYBounds(index, dBounds);
     }
 
 
@@ -761,47 +601,20 @@
 
 
     /**
-     * Expands a given range if it collapses into one point.
-     * @param Range to be expanded if upper == lower bound.
-     */
-    private Range expandPointRange(Range range) {
-        if (range != null && range.getLowerBound() == range.getUpperBound()) {
-            return expandRange(range, 5);
-        }
-        return range;
-    }
-
-
-    /**
      * Expands X axes if only a point is shown.
      */
     private void preparePointRanges(XYPlot plot) {
         for (int i = 0, num = plot.getDomainAxisCount(); i < num; i++) {
-            logger.debug("Check whether to expand a x axis.");
-            Integer key = Integer.valueOf(i);
 
-            Range r = xRanges.get(key);
-            if (r != null && r.getLowerBound() == r.getUpperBound()) {
-                xRanges.put(key, expandRange(r, 5));
-            }
-        }
-    }
+            Integer key = Integer.valueOf(i);
+            Bounds  b   = getXBounds(key);
 
 
-    /**
-     * Expand range by percent.
-     */
-    public static Range expandRange(Range range, double percent) {
-        if (range == null) {
-            return null;
+            if (b != null && b.getLower().equals(b.getUpper())) {
+                logger.debug("Check whether to expand a x axis.i ("+b.getLower() + "-" + b.getUpper()+")");
+                setXBounds(key, ChartHelper.expandBounds(b, 5));
+            }
         }
-
-        double value  = range.getLowerBound();
-        double expand = value / 100 * percent;
-
-        return expand != 0
-            ? new Range(value-expand, value+expand)
-            : new Range(-0.01 * percent, 0.01 * percent);
     }
 
 
@@ -827,7 +640,7 @@
             xAxis.setRange(fixedXRange);
         }
         else {
-            zoomX(plot, xAxis, xRanges.get(0), xrange);
+            zoomX(plot, xAxis, getXBounds(0), xrange);
         }
 
         for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) {
@@ -849,18 +662,84 @@
             }
 
             logger.debug("Prepare zoom settings for y axis at index: " + i);
-            zoomY(plot, yaxis, yRanges.get(Integer.valueOf(i)), yrange);
+            zoomY(plot, yaxis, getYBounds(Integer.valueOf(i)), yrange);
         }
     }
 
 
-    protected boolean zoomX(XYPlot plot, ValueAxis axis, Range range, Range x) {
-        return zoom(plot, axis, range, x);
+    protected Range getDomainAxisRange() {
+        String[] ranges = getDomainAxisRangeFromRequest();
+
+        if (ranges == null || ranges.length < 2) {
+            logger.debug("No zoom range for domain axis specified.");
+            return null;
+        }
+
+        if (ranges[0].length() > 0 && ranges[1].length() > 0) {
+            try {
+                double from = Double.parseDouble(ranges[0]);
+                double to   = Double.parseDouble(ranges[1]);
+
+                if (from == 0 && to == 0) {
+                    logger.debug("No range specified. Lower and upper X == 0");
+                    return null;
+                }
+
+                if (from > to) {
+                    double tmp = to;
+                    to         = from;
+                    from       = tmp;
+                }
+
+                return new Range(from, to);
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("Wrong values for domain axis range.");
+            }
+        }
+
+        return null;
     }
 
 
-    protected boolean zoomY(XYPlot plot, ValueAxis axis, Range range, Range x) {
-        return zoom(plot, axis, range, x);
+    protected Range getValueAxisRange() {
+        String[] ranges = getValueAxisRangeFromRequest();
+
+        if (ranges == null || ranges.length < 2) {
+            logger.debug("No range specified. Lower and upper Y == 0");
+            return null;
+        }
+
+        if (ranges[0].length() > 0 && ranges[1].length() > 0) {
+            try {
+                double from = Double.parseDouble(ranges[0]);
+                double to   = Double.parseDouble(ranges[1]);
+
+                if (from == 0 && to == 0) {
+                    logger.debug("No range specified. Lower and upper Y == 0");
+                    return null;
+                }
+
+                return from > to
+                       ? new Range(to, from)
+                       : new Range(from, to);
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("Wrong values for value axis range.");
+            }
+        }
+
+        return null;
+    }
+
+
+    protected boolean zoomX(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) {
+        return zoom(plot, axis, bounds, x);
+    }
+
+
+    protected boolean zoomY(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) {
+        return zoom(plot, axis, bounds, x);
     }
 
 
@@ -869,145 +748,109 @@
      *
      * @param plot  The XYPlot.
      * @param axis  The axis the shoud be modified.
-     * @param range The whole range specified by a dataset.
+     * @param bounds The whole range specified by a dataset.
      * @param x     A user defined range (null permitted).
      *
      * @return true, if a zoom range was specified, otherwise false.
      */
-    protected boolean zoom(XYPlot plot, ValueAxis axis, Range range, Range x) {
+    protected boolean zoom(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) {
 
-        if (range == null) {
+        if (bounds == null) {
             return false;
         }
 
         if (x != null) {
-            double min  = range.getLowerBound();
-            double max  = range.getUpperBound();
+            double min  = bounds.getLower().doubleValue();
+            double max  = bounds.getUpper().doubleValue();
+
+            if (logger.isDebugEnabled()) {
+                logger.debug("Minimum is: " + min);
+                logger.debug("Maximum is: " + max);
+                logger.debug("Lower zoom is: " + x.getLowerBound());
+                logger.debug("Upper zoom is: " + x.getUpperBound());
+            }
+
             double diff = max > min ? max - min : min - max;
 
-            Range computed = new Range(
+            DoubleBounds computed = new DoubleBounds(
                 min + x.getLowerBound() * diff,
                 min + x.getUpperBound() * diff);
 
-            axis.setRangeWithMargins(computed);
+            computed.applyBounds(axis, AXIS_SPACE);
 
             logger.debug("Zoom axis to: " + computed);
 
             return true;
         }
 
-        axis.setRangeWithMargins(range);
+        bounds.applyBounds(axis, AXIS_SPACE);
         return false;
     }
 
 
     /**
-     * This method extracts the minimum and maximum values for x and y axes
+     * Extract the minimum and maximum values for x and y axes
      * which are stored in <i>xRanges</i> and <i>yRanges</i>.
      *
      * @param index The index of the y-Axis.
      *
      * @return a Range[] as follows: [x-Range, y-Range].
      */
+    @Override
     public Range[] getRangesForAxis(int index) {
         logger.debug("getRangesForAxis " + index);
+
+        Bounds rx = getXBounds(Integer.valueOf(0));
+        Bounds ry = getYBounds(Integer.valueOf(index));
+
+        if (rx == null) {
+            logger.warn("Range for x axis not set." +
+                        " Using default values: 0 - 1.");
+            rx = new DoubleBounds(0, 1);
+        }
+        if (ry == null) {
+            logger.warn("Range for y" + index +
+                        " axis not set. Using default values: 0 - 1.");
+            ry = new DoubleBounds(0, 1);
+        }
+
         return new Range[] {
-            xRanges.get(Integer.valueOf(0)),
-            yRanges.get(Integer.valueOf(index))
+            new Range(rx.getLower().doubleValue(), rx.getUpper().doubleValue()),
+            new Range(ry.getLower().doubleValue(), ry.getUpper().doubleValue())
         };
     }
 
 
-    /**
-     * This method searches for a specific axis in the <i>settings</i> if
-     * <i>settings</i> is set. If the axis was found, this method returns the
-     * specified axis range if the axis range is fixed. Otherwise, this method
-     * returns null.
-     *
-     * @param axisId The identifier of an axis.
-     *
-     * @return the specified axis range from <i>settings</i> if the axis is
-     * fixed, otherwise null.
-     */
-    public Range getRangeForAxisFromSettings(String axisId) {
-        ChartSettings chartSettings = getChartSettings();
-        if (chartSettings == null) {
-            return null;
-        }
-
-        AxisSection as = chartSettings.getAxisSection(axisId);
-        Boolean  fixed = as.isFixed();
-
-        if (fixed != null && fixed) {
-            Double upper = as.getUpperRange();
-            Double lower = as.getLowerRange();
-
-            if (upper != null && lower != null) {
-                return lower < upper
-                    ? new Range(lower, upper)
-                    : new Range(upper, lower);
-            }
-        }
-
-        return null;
+    /** Get X (usually horizontal) extent for given axis. */
+    @Override
+    public Bounds getXBounds(int axis) {
+        return xBounds.get(axis);
     }
 
 
-    /**
-     * Add annotations to Renderer.
-     */
-    protected void addAnnotationsToRenderer(XYPlot plot) {
-        plot.clearAnnotations();
-
-        if (annotations == null) {
-            logger.debug("No Annotations given.");
-            return;
-        }
-
-        Font labelFont = createLegendLabelFont();
-
-        LegendItemCollection lic = new LegendItemCollection();
-        LegendItemCollection old = plot.getFixedLegendItems();
-
-        XYItemRenderer renderer = plot.getRenderer(0);
-
-        for (FLYSAnnotation fa: annotations) {
-            Document theme = fa.getTheme();
-
-            ThemeAccess themeAccess = new ThemeAccess(theme);
-
-            Color color   = themeAccess.parseLineColorField();
-            int lineWidth = themeAccess.parseLineWidth();
-
-            LegendItem li = new LegendItem(fa.getLabel(), color);
-            li.setLabelFont(labelFont);
-
-            lic.add(li);
-
-            for (XYTextAnnotation ta: fa.getAnnotations()) {
-                if(ta instanceof StickyAxisAnnotation) {
-                    StickyAxisAnnotation sta = (StickyAxisAnnotation)ta;
-                    sta.applyTheme(themeAccess);
-                    renderer.addAnnotation(sta);
-                }
-                else {
-                    ta.setPaint(color);
-                    ta.setOutlineStroke(new BasicStroke((float) lineWidth));
-                    renderer.addAnnotation(ta);
-                }
-            }
-
-        }
-
-        // (Re-)Add prior legend entries.
-        if (old != null) {
-            old.addAll(lic);
+    /** Set X (usually horizontal) extent for given axis. */
+    @Override
+    protected void setXBounds(int axis, Bounds bounds) {
+        if (bounds.getLower() == bounds.getUpper()) {
+            xBounds.put(axis, ChartHelper.expandBounds(bounds, 5d));
         }
         else {
-            old = lic;
+            xBounds.put(axis, bounds);
         }
+    }
 
-        plot.setFixedLegendItems(old);
+
+    /** Get Y (usually vertical) extent for given axis. */
+    @Override
+    public Bounds getYBounds(int axis) {
+        return yBounds.get(axis);
+    }
+
+
+    /** Set Y (usually vertical) extent for given axis. */
+    @Override
+    protected void setYBounds(int axis, Bounds bounds) {
+        yBounds.put(axis, bounds);
     }
 
 
@@ -1015,6 +858,8 @@
      * Adjusts the axes of a plot. This method sets the <i>labelFont</i> of the
      * X axis.
      *
+     * (Duplicate in TimeseriesChartGenerator)
+     *
      * @param plot The XYPlot of the chart.
      */
     protected void adjustAxes(XYPlot plot) {
@@ -1031,39 +876,7 @@
             getXAxisLabelFontSize());
 
         xaxis.setLabelFont(labelFont);
-    }
-
-
-    /**
-     * Set some Stroke/Grid defaults.
-     */
-    protected void adjustPlot(XYPlot plot) {
-        Stroke gridStroke = new BasicStroke(
-            DEFAULT_GRID_LINE_WIDTH,
-            BasicStroke.CAP_BUTT,
-            BasicStroke.JOIN_MITER,
-            3.0f,
-            new float[] { 3.0f },
-            0.0f);
-
-        ChartSettings      cs = getChartSettings();
-        boolean isGridVisible = cs != null ? isGridVisible(cs) : true;
-
-        plot.setDomainGridlineStroke(gridStroke);
-        plot.setDomainGridlinePaint(DEFAULT_GRID_COLOR);
-        plot.setDomainGridlinesVisible(isGridVisible);
-
-        plot.setRangeGridlineStroke(gridStroke);
-        plot.setRangeGridlinePaint(DEFAULT_GRID_COLOR);
-        plot.setRangeGridlinesVisible(isGridVisible);
-
-        plot.setAxisOffset(new RectangleInsets(0d, 0d, 0d, 0d));
-    }
-
-
-    /** Override to handle subtitle adding. */
-    protected void addSubtitles(JFreeChart chart) {
-        // override this method in subclasses that need subtitles
+        xaxis.setTickLabelFont(labelFont);
     }
 
 
@@ -1115,7 +928,7 @@
      * Overrides the NumberFormat with the NumberFormat for the current locale
      * that is provided by getLocale().
      *
-     * @param domainAxis The domain axis that needs localization.
+     * @param rangeAxis The domain axis that needs localization.
      */
     protected void localizeRangeAxis(ValueAxis rangeAxis) {
         NumberFormat nf = NumberFormat.getInstance(getLocale());
@@ -1124,327 +937,85 @@
 
 
     /**
-     * @param idx "index" of dataset/series (first dataset to be drawn has
-     *            index 0), correlates with renderer index.
-     * @param isArea true if the series describes an area and shall be rendered
-     *                as such.
-     * @return idx increased by number of items addded.
+     * Do Points out.
      */
-    protected int applyThemes(
-        XYPlot plot,
-        XYSeriesCollection series,
-        int idx,
-        boolean isArea
+    protected void doPoints(
+        Object     o,
+        ArtifactAndFacet aandf,
+        Document   theme,
+        boolean    visible,
+        int        axisIndex
     ) {
-        LegendItemCollection lic  = new LegendItemCollection();
-        LegendItemCollection anno = plot.getFixedLegendItems();
-
-        Font legendFont = createLegendLabelFont();
-
-        int retidx = idx;
+        String seriesName = aandf.getFacetDescription();
+        XYSeries series = new StyledXYSeries(seriesName, theme);
 
-        if (isArea) {
-            logger.debug("Registering an 'area'renderer at idx: " + idx);
-            StyledAreaSeriesCollection area = (StyledAreaSeriesCollection) series;
-            
-            StableXYDifferenceRenderer dRenderer = new StableXYDifferenceRenderer();
-            if (area.getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) {
-                dRenderer.setPositivePaint(createTransparentPaint());
-            }
-            plot.setRenderer(idx, dRenderer);
-
-            area.applyTheme(dRenderer);
+        // Add text annotations for single points.
+        List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
 
-            LegendItem legendItem = dRenderer.getLegendItem(idx, 0);
-            if (legendItem != null) {
-                lic.add(legendItem);
+        try {
+            JSONArray points = new JSONArray((String) o);
+            for (int i = 0, P = points.length(); i < P; i++) {
+                JSONArray array = points.getJSONArray(i);
+                double x    = array.getDouble(0);
+                double y    = array.getDouble(1);
+                String name = array.getString(2);
+                boolean act = array.getBoolean(3);
+                if (!act) {
+                    continue;
+                }
+                //logger.debug(" x " + x + " y " + y );
+                series.add(x, y, false);
+                xy.add(new CollisionFreeXYTextAnnotation(name, x, y));
             }
-            else {
-                logger.warn("Could not get LegentItem for renderer: "
-                    + idx + ", series-idx " + 0);
-            }
-            if (anno != null) {
-                lic.addAll(anno);
-            }
-            plot.setFixedLegendItems(lic);
-            return retidx + 1;
+        }
+        catch(JSONException e){
+            logger.error("Could not decode json.");
         }
 
-        XYLineAndShapeRenderer renderer = getRenderer(plot, idx);
-
-        for (int s = 0, num = series.getSeriesCount(); s < num; s++) {
-            XYSeries serie = series.getSeries(s);
-
-            if (serie instanceof StyledXYSeries) {
-                ((StyledXYSeries) serie).applyTheme(renderer, s);
-            }
-
-            // special case: if there is just one single item, we need to enable
-            // points for this series, otherwise we would not see anything in
-            // the chart area.
-            if (serie.getItemCount() == 1) {
-                renderer.setSeriesShapesVisible(s, true);
-            }
-
-            LegendItem legendItem = renderer.getLegendItem(idx, s);
-            if (legendItem != null) {
-                legendItem.setLabelFont(legendFont);
-                lic.add(legendItem);
-            }
-            else {
-                logger.warn("Could not get LegentItem for renderer: "
-                    + idx + ", series-idx " + s);
-            }
-            // TODO: why that? isnt renderer set per dataset not per series?
-            retidx++;
-        }
-
-        if (anno != null) {
-            lic.addAll(anno);
-        }
-
-        plot.setFixedLegendItems(lic);
-
-        plot.setRenderer(idx, renderer);
-
-        return retidx;
-    }
-
+        FLYSAnnotation annotations = new FLYSAnnotation(null, null, null, theme);
+        annotations.setTextAnnotations(xy);
 
-    /** Returns a transparently textured paint. */
-    // TODO why not use a transparent color?
-    protected static Paint createTransparentPaint() {
-        BufferedImage texture = new BufferedImage(
-            1, 1, BufferedImage.TYPE_4BYTE_ABGR);
-
-        return new TexturePaint(
-            texture, new Rectangle2D.Double(0d, 0d, 0d, 0d));
-    }
-
-
-    /**
-     * Get renderer, from plot or cloned default renderer otherwise.
-     */
-    protected XYLineAndShapeRenderer getRenderer(XYPlot plot, int idx) {
-        logger.debug("getRenderer: " + idx);
-
-        XYLineAndShapeRenderer r =
-            (XYLineAndShapeRenderer) plot.getRenderer(idx);
-
-        if (r != null) {
-            return r;
-        }
-
-        // Need a new renderer.
-        if (idx == 0) {
-            logger.warn("No default renderer set!");
-            return new XYLineAndShapeRenderer();
-        }
-
-        // 'Default' (first) renderer is an area-renderer.
-        XYItemRenderer renderer = (XYItemRenderer) plot.getRenderer(0);
-        if (renderer instanceof StableXYDifferenceRenderer) {
-            return new XYLineAndShapeRenderer();
-        }
-
-        r = (XYLineAndShapeRenderer) renderer;
-
-        try {
-            return (XYLineAndShapeRenderer) r.clone();
-        }
-        catch (CloneNotSupportedException cnse) {
-            logger.warn(cnse, cnse);
-        }
-
-        logger.warn("No applicalable renderer found!");
-
-        return new XYLineAndShapeRenderer();
+        // Do not generate second legend entry. (null was passed for the aand before).
+        doAnnotations(annotations, null, theme, visible);
+        addAxisSeries(series, axisIndex, visible);
     }
 
 
     /**
-     * Register annotations like MainValues for later plotting
-     *
-     * @param o     list of annotations (data of facet).
-     * @param facet The facet. This facet does NOT support any data objects. Use
-     * FLYSArtifact.getNativeFacet() instead to retrieve a Facet which supports
-     * data.
-     * @param theme   Theme document for given annotations.
-     * @param visible The visibility of the annotations.
+     * Create a hash from a legenditem.
+     * This hash can then be used to merge legend items labels.
+     * @return hash for given legenditem to identify mergeables.
      */
-    protected void doAnnotations(
-        FLYSAnnotation annotations,
-        Facet facet,
-        Document theme,
-        boolean visible
-    ){
-        logger.debug("doAnnotations");
-
-        // Add all annotations to our annotation pool.
-        annotations.setTheme(theme);
-        annotations.setLabel(facet.getDescription());
-        addAnnotations(annotations, visible);
-    }
-
-
-    /**
-     * Creates a new instance of <i>IdentifiableNumberAxis</i>.
-     *
-     * @param idx The index of the new axis.
-     * @param label The label of the new axis.
-     *
-     * @return an instance of IdentifiableNumberAxis.
-     */
-    protected NumberAxis createNumberAxis(int idx, String label) {
-        YAxisWalker walker = getYAxisWalker();
-
-        return new IdentifiableNumberAxis(walker.getId(idx), label);
-    }
-
-
-    /**
-     * Returns an instance of <i>ChartSettings</i> with a chart specific section
-     * but with no axes settings.
-     *
-     * @return an instance of <i>ChartSettings</i>.
-     */
-    public Settings getSettings() {
-        if (this.settings != null) {
-            return this.settings;
+    public static String legendItemHash(LegendItem li) {
+        // TODO Do proper implementation. Ensure that only mergable sets are created.
+        // getFillPaint()
+        // getFillPaintTransformer()
+        // getLabel()
+        // getLine()
+        // getLinePaint()
+        // getLineStroke()
+        // getOutlinePaint()
+        // getOutlineStroke()
+        // Shape getShape()
+        // String getToolTipText()
+        // String getURLText()
+        // boolean isLineVisible()
+        // boolean isShapeFilled()
+        // boolean isShapeOutlineVisible()
+        // boolean isShapeVisible()
+        String hash = li.getLinePaint().toString();
+        String label = li.getLabel();
+        if (label.startsWith("W (") || label.startsWith("W(")) {
+            hash += "-W-";
+        }
+        else if (label.startsWith("Q(") || label.startsWith("Q (")) {
+            hash += "-Q-";
         }
 
-        ChartSettings settings = new ChartSettings();
-
-        ChartSection  chartSection  = buildChartSection();
-        LegendSection legendSection = buildLegendSection();
-        ExportSection exportSection = buildExportSection();
-
-        settings.setChartSection(chartSection);
-        settings.setLegendSection(legendSection);
-        settings.setExportSection(exportSection);
-
-        List<AxisSection> axisSections = buildAxisSections();
-        for (AxisSection axisSection: axisSections) {
-            settings.addAxisSection(axisSection);
-        }
+        // WQ.java holds example of using regex Matcher/Pattern.
 
-        return settings;
-    }
-
-
-    /**
-     * Creates a new <i>ChartSection</i>.
-     *
-     * @return a new <i>ChartSection</i>.
-     */
-    protected ChartSection buildChartSection() {
-        ChartSection chartSection = new ChartSection();
-        chartSection.setTitle(getChartTitle());
-        chartSection.setSubtitle(getChartSubtitle());
-        chartSection.setDisplayGird(isGridVisible());
-        return chartSection;
+        return hash;
     }
 
-
-    /**
-     * Creates a new <i>LegendSection</i>.
-     *
-     * @return a new <i>LegendSection</i>.
-     */
-    protected LegendSection buildLegendSection() {
-        LegendSection legendSection = new LegendSection();
-        legendSection.setVisibility(isLegendVisible());
-        legendSection.setFontSize(getLegendFontSize());
-        return legendSection;
-    }
-
-
-    /**
-     * Creates a new <i>ExportSection</i> with default values <b>WIDTH=600</b>
-     * and <b>HEIGHT=400</b>.
-     *
-     * @return a new <i>ExportSection</i>.
-     */
-    protected ExportSection buildExportSection() {
-        ExportSection exportSection = new ExportSection();
-        exportSection.setWidth(600);
-        exportSection.setHeight(400);
-        return exportSection;
-    }
-
-
-    /**
-     * Creates a list of Sections that contains all axes of the chart (including
-     * X and Y axes).
-     *
-     * @return a list of Sections for each axis in this chart.
-     */
-    protected List<AxisSection> buildAxisSections() {
-        List<AxisSection> axisSections = new ArrayList<AxisSection>();
-
-        axisSections.addAll(buildXAxisSections());
-        axisSections.addAll(buildYAxisSections());
-
-        return axisSections;
-    }
-
-
-    /**
-     * Creates a new Section for chart's X axis.
-     *
-     * @return a List that contains a Section for the X axis.
-     */
-    protected List<AxisSection> buildXAxisSections() {
-        List<AxisSection> axisSections = new ArrayList<AxisSection>();
-
-        String identifier = "X";
-
-        AxisSection axisSection = new AxisSection();
-        axisSection.setIdentifier(identifier);
-        axisSection.setLabel(getXAxisLabel());
-        axisSection.setFontSize(14);
-        axisSection.setFixed(false);
-
-        // XXX We are able to find better default ranges that [0,0], but the Y
-        // axes currently have no better ranges set.
-        axisSection.setUpperRange(0d);
-        axisSection.setLowerRange(0d);
-
-        axisSections.add(axisSection);
-
-        return axisSections;
-    }
-
-
-    /**
-     * Creates a list of Section for the chart's Y axes. This method makes use
-     * of <i>getYAxisWalker</i> to be able to access all Y axes defined in
-     * subclasses.
-     *
-     * @return a list of Y axis sections.
-     */
-    protected List<AxisSection> buildYAxisSections() {
-        List<AxisSection> axisSections = new ArrayList<AxisSection>();
-
-        YAxisWalker walker = getYAxisWalker();
-        for (int i = 0, n = walker.length(); i < n; i++) {
-            AxisSection ySection = new AxisSection();
-            ySection.setIdentifier(walker.getId(i));
-            ySection.setLabel(getYAxisLabel(i));
-            ySection.setFontSize(14);
-            ySection.setFixed(false);
-
-            // XXX We are able to find better default ranges that [0,0], the
-            // only problem is, that we do NOT have a better range than [0,0]
-            // for each axis, because the initial chart will not have a dataset
-            // for each axis set!
-            ySection.setUpperRange(0d);
-            ySection.setLowerRange(0d);
-
-            axisSections.add(ySection);
-        }
-
-        return axisSections;
-    }
 }
 // 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/exports/fixings/DeltaWtExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,267 @@
+package de.intevation.flys.exports.fixings;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+
+import de.intevation.flys.artifacts.model.fixings.AnalysisPeriod;
+import de.intevation.flys.artifacts.model.fixings.FixAnalysisResult;
+import de.intevation.flys.artifacts.model.fixings.QWD;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import de.intevation.flys.exports.AbstractExporter;
+
+import de.intevation.flys.utils.Formatter;
+import de.intevation.flys.utils.KMIndex;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.text.NumberFormat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+/** Exports fixation analysis deltaw(t) computation results to csv. */
+public class DeltaWtExporter
+extends      AbstractExporter
+{
+    /** Private logger. */
+    private static Logger log = Logger.getLogger(DeltaWtExporter.class);
+
+    public static final String CSV_KM_HEADER =
+        "export.fixings.deltawt.csv.header.km";
+
+    public static final String CSV_DELTA_W_HEADER =
+        "export.fixings.deltawt.csv.header.deltaw";
+
+    public static final String CSV_Q_HEADER =
+        "export.fixings.deltawt.csv.header.q";
+
+    public static final String CSV_W_HEADER =
+        "export.fixings.deltawt.csv.header.w";
+
+    public static final String CSV_TRANGE_HEADER =
+        "export.fixings.deltawt.csv.header.time.range";
+
+    public static final String CSV_T_HEADER =
+        "export.fixings.deltawt.csv.header.t";
+
+    public static final String CSV_T_FORMAT =
+        "export.fixings.deltawt.csv.t.format";
+
+    public static final String DEFAULT_CSV_KM_HEADER = "km";
+
+    public static final String DEFAULT_CSV_DELTA_W_HEADER = "\u0394 W [cm]";
+
+    public static final String DEFAULT_CSV_W_HEADER = "Wasserstand [m]";
+
+    public static final String DEFAULT_CSV_Q_HEADER = "Abfluss [m\u00b3/s]";
+
+    public static final String DEFAULT_CSV_T_HEADER = "Datum";
+
+    public static final String DEFAULT_CSV_TRANGE_DESC_HEADER =
+        "Status";
+
+    public static final String CSV_REFERENCE =
+        "export.fixings.deltawt.csv.reference";
+
+    public static final String CSV_ANALYSIS =
+        "export.fixings.deltawt.csv.analysis";
+
+    public static final String DEFAULT_CSV_REFERENCE =
+        "B";
+
+    public static final String DEFAULT_CSV_ANALYSIS =
+        "A{0,number,integer}";
+
+    public static final String DEFAULT_CSV_T_FORMAT =
+        "dd.MM.yyyy";
+
+    protected List<KMIndex<AnalysisPeriod []>> analysisPeriods;
+
+    protected List<KMIndex<QWD[]>> referenceEvents;
+
+    @Override
+    public void init(Document request, OutputStream out, CallContext context) {
+        log.debug("DeltaWtExporter.init");
+        super.init(request, out, context);
+        analysisPeriods = new ArrayList<KMIndex<AnalysisPeriod []>>();
+        referenceEvents = new ArrayList<KMIndex<QWD[]>>();
+    }
+
+    @Override
+    protected void addData(Object d) {
+        log.debug("DeltaWtExporter.addData");
+        if (!(d instanceof CalculationResult)) {
+            log.warn("Invalid data type");
+            return;
+        }
+
+        Object data = ((CalculationResult)d).getData();
+        if (!(data instanceof FixAnalysisResult)) {
+            log.warn("Invalid data stored in result.");
+        }
+        FixAnalysisResult result = (FixAnalysisResult)data;
+        analysisPeriods.add(result.getAnalysisPeriods());
+        referenceEvents.add(result.getReferenced());
+    }
+
+    @Override
+    protected void writeCSVData(CSVWriter writer) throws IOException {
+
+        boolean debug = log.isDebugEnabled();
+
+        writeCSVHeader(writer);
+
+        NumberFormat kmF = getKMFormatter();
+        NumberFormat dwF = getDeltaWFormatter();
+        NumberFormat qF  = getQFormatter();
+        NumberFormat wF  = getWFormatter();
+
+        DateFormat dF = getDateFormatter();
+
+        String referenceS = getReference();
+
+        for (KMIndex<QWD[]> reference: referenceEvents) {
+
+            for (KMIndex.Entry<QWD[]> kmEntry: reference) {
+
+               String kmS = kmF.format(kmEntry.getKm());
+               for (QWD qwd: kmEntry.getValue()) {
+                    String deltaWS = dwF.format(qwd.getDeltaW());
+                    String qS      = qF.format(qwd.getQ());
+                    String wS      = wF.format(qwd.getW());
+                    String dateS   = dF.format(qwd.getDate());
+
+                    writer.writeNext(new String[] {
+                        kmS,
+                        dateS,
+                        qS,
+                        wS,
+                        referenceS,
+                        deltaWS
+                        });
+               }
+            }
+        }
+
+        if (debug) {
+            log.debug("AnalysisPeriods: " + analysisPeriods.size());
+        }
+
+        String analysisTemplate = getAnalysisTemplate();
+
+        int analysisCount = 1;
+
+        for (KMIndex<AnalysisPeriod []> periods: analysisPeriods) {
+
+            // Typically resulting in A1,A2...
+            String analyisS = MessageFormat.format(
+                analysisTemplate, analysisCount);
+
+            for (KMIndex.Entry<AnalysisPeriod []> kmEntry: periods) {
+
+                String kmS = kmF.format(kmEntry.getKm());
+
+                for (AnalysisPeriod period: kmEntry.getValue()) {
+                    QWD [] qwds = period.getQWDs();
+                    /* issue825
+                    km; Ereignis, Abfluss, GEMESSENER Wasserstand; Status (RECHTSBÃœNDIG), del W
+                    */
+
+                    if (qwds != null) {
+                        for (QWD qwd: qwds) {
+                            String deltaWS = dwF.format(qwd.getDeltaW());
+                            String qS      = qF.format(qwd.getQ());
+                            String wS      = wF.format(qwd.getW());
+                            String dateS   = dF.format(qwd.getDate());
+
+                            writer.writeNext(new String[] {
+                                kmS,
+                                dateS,
+                                qS,
+                                wS,
+                                analyisS,
+                                deltaWS });
+                        }
+                    }
+                }
+            }
+            ++analysisCount;
+        }
+        writer.flush();
+    }
+
+    /** Template to create "State" strings like A1,A2... */
+    protected String getAnalysisTemplate() {
+        return Resources.getMsg(
+            context.getMeta(),
+            CSV_ANALYSIS, DEFAULT_CSV_ANALYSIS);
+    }
+
+    protected String getReference() {
+        return Resources.getMsg(
+            context.getMeta(),
+            CSV_REFERENCE, DEFAULT_CSV_REFERENCE);
+    }
+
+    protected NumberFormat getKMFormatter() {
+        return Formatter.getFixDeltaWKM(context);
+    }
+
+    protected NumberFormat getDeltaWFormatter() {
+        return Formatter.getFixDeltaWDeltaW(context);
+    }
+
+    protected NumberFormat getQFormatter() {
+        return Formatter.getFixDeltaWQ(context);
+    }
+
+    protected NumberFormat getWFormatter() {
+        return Formatter.getFixDeltaWW(context);
+    }
+
+    protected DateFormat getDateFormatter() {
+        CallMeta meta = context.getMeta();
+        return Formatter.getDateFormatter(
+            meta,
+            Resources.getMsg(
+                meta,
+                CSV_T_FORMAT,
+                DEFAULT_CSV_T_FORMAT));
+    }
+
+    protected void writeCSVHeader(CSVWriter writer) {
+        log.debug("DeltaWtExporter.writeCSVHeader");
+
+        /* issue825
+        km; Ereignis, Abfluss, GEMESSENER Wasserstand; Status (RECHTSBÃœNDIG), del W
+        */
+
+        writer.writeNext(new String[] {
+            msg(CSV_KM_HEADER,      DEFAULT_CSV_KM_HEADER),
+            msg(CSV_T_HEADER,       DEFAULT_CSV_T_HEADER),
+            msg(CSV_Q_HEADER,       DEFAULT_CSV_Q_HEADER),
+            msg(CSV_W_HEADER,       DEFAULT_CSV_W_HEADER),
+            msg(CSV_TRANGE_HEADER,  DEFAULT_CSV_TRANGE_DESC_HEADER),
+            msg(CSV_DELTA_W_HEADER, DEFAULT_CSV_DELTA_W_HEADER)
+        });
+    }
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        // TODO: Implement me!
+    }
+}
+// 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/exports/fixings/FixATExport.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,101 @@
+package de.intevation.flys.exports.fixings;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+
+import de.intevation.flys.artifacts.FLYSArtifact;
+
+import de.intevation.flys.artifacts.access.FixAccess;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+import de.intevation.flys.artifacts.math.fitting.FunctionFactory;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.artifacts.model.fixings.FixAnalysisResult;
+
+import de.intevation.flys.exports.AbstractExporter;
+
+import de.intevation.flys.utils.FLYSUtils;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+
+/** Export result of fixation analysis. */
+public class FixATExport extends AbstractExporter {
+
+    /** Private logger. */
+    private static Logger logger =
+        Logger.getLogger(FixATExport.class);
+
+    protected Function function;
+    protected Parameters parameters;
+
+
+    @Override
+    public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) {
+        logger.debug("AT Export doOut().");
+        Object data = bundle.getData(context);
+        if (data instanceof CalculationResult) {
+            CalculationResult cr = (CalculationResult)data;
+            Object resData = cr.getData();
+            if (resData instanceof FixAnalysisResult) {
+                this.parameters = ((FixAnalysisResult)resData).getParameters();
+            }
+        }
+        else {
+            logger.debug("No CalculationResult found for AT export.");
+            return;
+        }
+        FixAccess access = new FixAccess((FLYSArtifact)this.master);
+        String f = access.getFunction();
+        if (f == null || f.length() == 0) {
+            logger.debug("No function found for AT export.");
+            return;
+        }
+        this.function = FunctionFactory.getInstance().getFunction(f);
+    }
+
+    @Override
+    public void generate() throws IOException {
+        if (this.function == null || this.parameters == null) {
+            logger.debug("No function or paramters for AT export.");
+            return;
+        }
+
+        Writer writer = new OutputStreamWriter(out, DEFAULT_CSV_CHARSET);
+
+        FixATWriter atWriter = new FixATWriter(this.function, this.parameters);
+        NodeList nodes = request.getElementsByTagName("km");
+        String km = nodes.item(0).getTextContent();
+        double dkm = Double.parseDouble(km);
+        String river = FLYSUtils.getRivername((FLYSArtifact)master);
+        atWriter.write(writer, context.getMeta(), river, dkm);
+        writer.close();
+    }
+
+    @Override
+    protected void writeCSVData(CSVWriter writer) throws IOException {
+        // The concrete writer is used to write csv data.
+    }
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        // Implement me!
+    }
+
+    @Override
+    protected void addData(Object data) {
+        // Nothing to do here.
+    }
+}
+// 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/exports/fixings/FixATWriter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,187 @@
+package de.intevation.flys.exports.fixings;
+
+import de.intevation.artifacts.CallMeta;
+
+import de.intevation.flys.artifacts.math.fitting.Function;
+
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import de.intevation.flys.exports.ATWriter;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+import java.util.Locale;
+
+import org.apache.log4j.Logger;
+
+/** Export Fixation Analysis Results to AT. */
+public class FixATWriter
+{
+    /** Private logger. */
+    private static Logger log = Logger.getLogger(FixATWriter.class);
+
+    public static final String I18N_HEADER_KEY =
+        "fix.export.at.header";
+
+    public static final String I18N_HEADER_DEFAULT =
+        "Exported fixings discharge curve for {0} {0}-km: {1}";
+
+    public static final String [] Q_MAX_COLUMN = new String [] { "max_q" };
+
+    private static final int    MAX_ITERATIONS = 10000;
+    private static final double EPSILON        = 1e-8;
+    private static final double MIN_Q          = 1e-4;
+
+    protected Function   function;
+    protected Parameters parameters;
+
+    public FixATWriter() {
+    }
+
+    public FixATWriter(Function function, Parameters parameters) {
+        this.function   = function;
+        this.parameters = parameters;
+    }
+
+    public void write(
+        Writer   writer,
+        CallMeta meta,
+        String   river,
+        double   km
+    )
+    throws IOException {
+        PrintWriter out = new PrintWriter(writer);
+        printHeader(out, meta, river, km);
+
+        double [] coeffs = parameters.interpolate(
+            "km", km, function.getParameterNames());
+
+        double [] qMax = parameters.interpolate(
+            "km", km, Q_MAX_COLUMN);
+
+        if (coeffs == null || qMax == null) {
+            log.debug("No data found at km " + km + ".");
+            return;
+        }
+
+        de.intevation.flys.artifacts.math.Function funcInst =
+            function.instantiate(coeffs);
+
+        // Increase Q max about 5%.
+        qMax[0] += Math.abs(qMax[0])*0.05;
+
+        double wMax = funcInst.value(qMax[0]);
+
+        if (Double.isNaN(wMax) || wMax < 0d) {
+            log.debug("function '" + function.getName() +
+                "' eval failed at " + wMax);
+            return;
+        }
+
+        Function inverse = function.getInverse();
+
+        de.intevation.flys.artifacts.math.Function invInst =
+            inverse.instantiate(coeffs);
+
+        double wMin = minW(invInst, wMax, qMax[0]);
+
+        double wMinCM = wMin * 100d;
+        double wMaxCM = wMax * 100d;
+
+        int wRow = ((int)wMinCM / 10) * 10;
+
+        if ((wMinCM - (int)wMinCM) > 0d) {
+            wMinCM = (int)wMinCM + 1d;
+        }
+
+        double w = wMinCM / 100.0;
+
+        int wcm = ((int)wMinCM) % 10;
+
+        if (log.isDebugEnabled()) {
+            log.debug("wMinCM: " + wMinCM);
+            log.debug("wMaxCM: " + wMaxCM);
+            log.debug("wcm: " + wcm);
+        }
+
+        out.printf(Locale.US, "%8d", wRow);
+
+        if (wcm > 0) {
+            int rest = 10 - wcm;
+            while (rest-- > 0) {
+                out.print(ATWriter.EMPTY);
+            }
+        }
+
+        for (;;) {
+            while (wcm++ < 10) {
+                if (w > wMax) {
+                    break;
+                }
+                double q = invInst.value(w);
+                if (Double.isNaN(w)) {
+                    out.print(ATWriter.EMPTY);
+                }
+                else {
+                    ATWriter.printQ(out, q);
+                }
+                w += 0.01d;
+            }
+            out.println();
+            if (w > wMax) {
+                break;
+            }
+            out.printf(Locale.US, "%8d", wRow += 10);
+            wcm = 0;
+        }
+
+        out.flush();
+    }
+
+    protected void printHeader(
+        PrintWriter out,
+        CallMeta    meta,
+        String      river,
+        double      km
+    ) {
+        out.println(Resources.format(
+            meta,
+            I18N_HEADER_KEY,
+            I18N_HEADER_DEFAULT,
+            river, km));
+    }
+
+    private static double minW(
+        de.intevation.flys.artifacts.math.Function function,
+        double maxW,
+        double maxQ
+    ) {
+        double stepWidth = 10d;
+
+        double lastW = maxW;
+        double lastQ = maxQ;
+
+        for (int i = 0; i < MAX_ITERATIONS; ++i) {
+            double w = lastW - stepWidth;
+            double q = function.value(w);
+
+            if (Double.isNaN(q) || q > lastQ || q < MIN_Q) {
+                if (stepWidth < EPSILON) {
+                    break;
+                }
+                stepWidth *= 0.5d;
+                continue;
+            }
+
+            lastW = w;
+            lastQ = q;
+        }
+
+        return lastW;
+    }
+}
+// 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/exports/fixings/FixChartGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,59 @@
+package de.intevation.flys.exports.fixings;
+
+import de.intevation.artifacts.ArtifactNamespaceContext;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.flys.exports.XYChartGenerator;
+
+import java.io.OutputStream;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+
+/**
+ * Base class for FixChartGenerator.
+ */
+public abstract class FixChartGenerator
+extends XYChartGenerator
+{
+    /** Private logger. */
+    private static Logger logger = Logger.getLogger(FixChartGenerator.class);
+
+    public static final Double INVALID_KM = Double.valueOf(-1d);
+    public static final String CURRENT_KM = "currentKm";
+    public static final String XPATH_CHART_CURRENTKM =
+        "/art:action/art:attributes/art:currentKm/@art:km";
+
+    @Override
+    public void init(Document request, OutputStream out, CallContext context) {
+        super.init(request, out, context);
+
+        Double currentKm = getCurrentKmFromRequest(request);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("currentKm = " + currentKm);
+        }
+
+        context.putContextValue(CURRENT_KM, currentKm);
+    }
+
+    public static final Double getCurrentKmFromRequest(Document request) {
+
+        String km = XMLUtils.xpathString(
+            request,
+            XPATH_CHART_CURRENTKM,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (km == null) {
+            return INVALID_KM;
+        }
+
+        try {
+            return Double.valueOf(km);
+        }
+        catch (NumberFormatException nfe) {
+            return INVALID_KM;
+        }
+    }
+}
+// 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/exports/fixings/FixDeltaWtGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,460 @@
+package de.intevation.flys.exports.fixings;
+
+import java.io.OutputStream;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.data.time.Day;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+import de.intevation.flys.artifacts.model.DateRange;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.QWDDateRange;
+import de.intevation.flys.artifacts.model.fixings.QWD;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.exports.TimeseriesChartGenerator;
+import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledDomainMarker;
+import de.intevation.flys.jfree.StyledTimeSeries;
+import de.intevation.flys.jfree.StyledValueMarker;
+import de.intevation.flys.utils.ThemeUtil;
+
+
+/**
+ * Generator for Delta W(t) charts.
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixDeltaWtGenerator
+extends      TimeseriesChartGenerator
+implements   FacetTypes
+{
+    /** Private logger. */
+    private static Logger logger =
+            Logger.getLogger(FixDeltaWtGenerator.class);
+
+    public static final String I18N_CHART_TITLE =
+            "chart.fix.deltawt.title";
+
+    public static final String I18N_CHART_SUBTITLE =
+            "chart.fix.deltawt.subtitle";
+
+    public static final String I18N_XAXIS_LABEL =
+            "chart.fix.deltawt.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL =
+            "chart.fix.deltawt.yaxis.label";
+
+    public static final String I18N_YAXIS_SECOND_LABEL =
+            "chart.fix.deltawt.yaxis.second.label";
+
+
+    public static enum YAXIS {
+        dW(0);
+        protected int idx;
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+
+    private FLYSArtifact artifact = null;
+
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
+    }
+
+
+    @Override
+    protected String getChartTitle() {
+        return Resources.format(
+                context.getMeta(),
+                I18N_CHART_TITLE,
+                "",
+                FixChartGenerator
+                .getCurrentKmFromRequest(request).doubleValue());
+    }
+
+
+    @Override
+    protected String getDefaultChartSubtitle() {
+        FixAnalysisAccess access = new FixAnalysisAccess(artifact);
+        DateRange dateRange = access.getDateRange();
+        DateRange refRange  = access.getReferencePeriod();
+        return Resources.format(
+                context.getMeta(),
+                I18N_CHART_SUBTITLE,
+                "",
+                access.getRiver(),
+                dateRange.getFrom(),
+                dateRange.getTo(),
+                refRange.getFrom(),
+                refRange.getTo());
+    }
+
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL);
+    }
+
+    @Override
+    protected String getDefaultYAxisLabel(int pos) {
+        if (pos == 0) {
+            return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL);
+        }
+        else if (pos == 1) {
+            return msg(I18N_YAXIS_SECOND_LABEL, I18N_YAXIS_SECOND_LABEL);
+        }
+        else {
+            return "NO TITLE FOR Y AXIS: " + pos;
+        }
+    }
+
+
+    @Override
+    public void doOut(
+            ArtifactAndFacet artifactFacet,
+            Document         theme,
+            boolean          visible
+            ) {
+        String name = artifactFacet.getFacetName();
+        logger.debug("FixDeltaWtGenerator.doOut: " + name);
+        logger.debug("Theme description is: " + artifactFacet.getFacetDescription());
+
+        this.artifact = (FLYSArtifact)artifactFacet.getArtifact();
+
+        if (name.contains(FIX_SECTOR_AVERAGE_DWT)) {
+            doSectorAverageOut(
+                    (FLYSArtifact) artifactFacet.getArtifact(),
+                    artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    theme,
+                    visible);
+        }
+        else if (name.equals(FIX_REFERENCE_EVENTS_DWT)) {
+            doReferenceEventsOut(
+                    (FLYSArtifact) artifactFacet.getArtifact(),
+                    artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    theme,
+                    visible);
+        }
+        else if (name.equals(FIX_ANALYSIS_EVENTS_DWT)) {
+            doAnalysisEventsOut(
+                    (FLYSArtifact) artifactFacet.getArtifact(),
+                    artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    theme,
+                    visible);
+        }
+        else if (name.equals(FIX_DEVIATION_DWT)) {
+            doDeviationOut(
+                    (FLYSArtifact) artifactFacet.getArtifact(),
+                    artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    theme,
+                    visible);
+        }
+        else if (name.equals(FIX_ANALYSIS_PERIODS_DWT)) {
+            doAnalysisPeriodsOut(
+                    (FLYSArtifact) artifactFacet.getArtifact(),
+                    artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    theme,
+                    visible);
+        }
+        else if (name.equals(FIX_REFERENCE_PERIOD_DWT)) {
+            doReferencePeriodsOut(
+                    (FLYSArtifact) artifactFacet.getArtifact(),
+                    artifactFacet.getData(context),
+                    artifactFacet.getFacetDescription(),
+                    theme,
+                    visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints (artifactFacet.getData(context),
+                    artifactFacet,
+                    theme, visible, YAXIS.dW.idx);
+        }
+        else {
+            logger.warn("doOut(): unknown facet name: " + name);
+            return;
+        }
+    }
+
+
+    protected void doReferencePeriodsOut(
+            FLYSArtifact artifact,
+            Object       data,
+            String       desc,
+            Document     theme,
+            boolean      visible)
+    {
+        logger.debug("doReferencePeriodsOut()");
+
+        FixAnalysisAccess access = new FixAnalysisAccess(artifact);
+        DateRange refRange  = access.getReferencePeriod();
+
+        RegularTimePeriod start = new Day(refRange.getFrom());
+        RegularTimePeriod end = new Day(refRange.getTo());
+        StyledDomainMarker marker = new StyledDomainMarker(
+                start.getMiddleMillisecond(),
+                end.getMiddleMillisecond(),
+                theme);
+        domainMarker.add(marker);
+    }
+
+
+    protected void doSectorAverageOut(
+            FLYSArtifact artifact,
+            Object       data,
+            String       desc,
+            Document     theme,
+            boolean      visible)
+    {
+        logger.debug("doSectorAverageOut(): description = " + desc);
+
+        QWDDateRange qwd = (QWDDateRange) data;
+        TimeSeriesCollection tsc = new TimeSeriesCollection();
+        TimeSeries        series = new StyledTimeSeries(desc, theme);
+
+        if (qwd == null || qwd.qwd == null || qwd.dateRange == null) {
+            return;
+        }
+        RegularTimePeriod rtp = new Day(qwd.qwd.getDate());
+        double value = qwd.qwd.getDeltaW();
+
+        // Draw a line spanning the analysis time.
+        series.add(rtp, value);
+        rtp = new Day(qwd.dateRange.getFrom());
+        series.addOrUpdate(rtp, value);
+        rtp = new Day(qwd.dateRange.getTo());
+        series.addOrUpdate(rtp, value);
+
+        tsc.addSeries(series);
+
+        addAxisDataset(tsc, 0, visible);
+
+        if (visible && ThemeUtil.parseShowLineLabel(theme)) {
+            List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>();
+            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
+                    "\u0394 W(t) [cm] " + (float)Math.round(qwd.qwd.getDeltaW() * 10000) / 10000,
+                    tsc.getXValue(0, 0),
+                    qwd.qwd.getDeltaW());
+            textAnnos.add(anno);
+
+            FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, theme);
+            flysAnno.setTextAnnotations(textAnnos);
+            addAnnotations(flysAnno);
+        }
+    }
+
+
+    protected void doAnalysisEventsOut(
+            FLYSArtifact artifact,
+            Object       data,
+            String       desc,
+            Document     theme,
+            boolean      visible
+            ) {
+        logger.debug("doAnalysisEventsOut: desc = " + desc);
+
+        QWD qwd = (QWD) data;
+        doQWDEventsOut(qwd, desc, theme, visible);
+    }
+
+
+    protected void doQWDEventsOut(QWD qwd, String desc, Document theme, boolean visible)
+    {
+        TimeSeriesCollection tsc = new TimeSeriesCollection();
+
+        TimeSeries   series = new StyledTimeSeries(desc, theme);
+        TimeSeries interpol = new StyledTimeSeries(desc + "interpol", theme);
+
+        if (qwd == null) {
+            logger.debug("doQWDEventsOut: qwd == null");
+            return;
+        }
+
+        Map<Integer, int[]> annoIdxMap = new HashMap<Integer, int[]>();
+
+        int idxInterpol = 0;
+        int idxRegular = 0;
+        RegularTimePeriod rtp = new Day(qwd.getDate());
+        double value =  qwd.getDeltaW();
+        boolean interpolate = qwd.getInterpolated();
+        if (interpolate) {
+            if(interpol.addOrUpdate(rtp, value) == null) {
+                annoIdxMap.put(
+                        0,
+                        new int[]{1, idxInterpol});
+                idxInterpol++;
+            }
+        }
+        else {
+            if(series.addOrUpdate(rtp, value) == null) {
+                annoIdxMap.put(
+                        0,
+                        new int[]{0, idxRegular});
+                idxRegular++;
+            }
+        }
+
+        tsc.addSeries(series);
+        tsc.addSeries(interpol);
+        addAxisDataset(tsc, 0, visible);
+        addAttribute(desc + "interpol", "interpolate");
+        addAttribute(desc, "outline");
+
+        doQWDTextAnnotations(annoIdxMap, tsc, qwd, theme, visible);
+    }
+
+
+    /**
+     * @param annoIdxMap map of index in qwds to series/data item indices in tsc.
+     */
+    protected void doQWDTextAnnotations(Map<Integer, int[]> annoIdxMap,
+            TimeSeriesCollection tsc, QWD qwd, Document theme,
+            boolean visible) {
+        logger.debug("doQWDTextAnnotation()");
+
+        if (!visible || !ThemeUtil.parseShowPointLabel(theme)) {
+            logger.debug("doQWDTextAnnotation: annotation not visible");
+            return;
+        }
+
+        Locale locale = Resources.getLocale(context.getMeta());
+        NumberFormat nf = NumberFormat.getInstance(locale);
+
+        List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>();
+        Set<Map.Entry<Integer, int[]>> entries = annoIdxMap.entrySet();
+
+        for(Map.Entry<Integer, int[]> entry : entries) {
+            int[] idxs = entry.getValue();
+            double x = tsc.getXValue(idxs[0], idxs[1]);
+
+            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
+                    nf.format(qwd.getQ()) + " m\u00B3/s",
+                    x,
+                    qwd.getDeltaW());
+            textAnnos.add(anno);
+        }
+
+        FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, theme);
+        flysAnno.setTextAnnotations(textAnnos);
+        addAnnotations(flysAnno);
+    }
+
+
+    protected void doReferenceEventsOut(
+            FLYSArtifact artifact,
+            Object       data,
+            String       desc,
+            Document     theme,
+            boolean      visible
+            ) {
+        logger.debug("doReferenceEventsOut: desc = " + desc);
+
+        QWD qwd = (QWD) data;
+        doQWDEventsOut(qwd, desc, theme, visible);
+    }
+
+
+    protected void doDeviationOut(
+            FLYSArtifact artifact,
+            Object       data,
+            String       desc,
+            Document     theme,
+            boolean      visible
+            ) {
+        logger.debug("doDeviationOut: desc = " + desc);
+
+        if (data == null || !visible) {
+            logger.debug("no standard deviation");
+            return;
+        }
+        double[] value = (double[]) data;
+        StyledDomainMarker lower = new StyledDomainMarker((value[0] * -1), 0, theme);
+        StyledDomainMarker upper = new StyledDomainMarker(0, value[0], theme);
+
+        valueMarker.add(lower);
+        valueMarker.add(upper);
+    }
+
+
+    protected void doAnalysisPeriodsOut(
+            FLYSArtifact artifact,
+            Object       data,
+            String       desc,
+            Document     theme,
+            boolean      visible)
+    {
+        DateRange[] ranges = (DateRange[]) data;
+        if (ranges == null || !visible) {
+            return;
+        }
+        for (int i = 0; i < ranges.length; i++) {
+            logger.debug("creating domain marker");
+            RegularTimePeriod start = new Day(ranges[i].getFrom());
+            RegularTimePeriod end = new Day(ranges[i].getTo());
+            StyledDomainMarker marker =
+                    new StyledDomainMarker(start.getMiddleMillisecond(),
+                            end.getMiddleMillisecond(), theme);
+            marker.useSecondColor(i % 2 == 0);
+            domainMarker.add(marker);
+        }
+        logger.debug("domainmarkers: " + domainMarker.size());
+    }
+
+
+    @Override
+    public void init(Document request, OutputStream out, CallContext context) {
+        super.init(request, out, context);
+
+        Double currentKm = FixChartGenerator.getCurrentKmFromRequest(request);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("currentKm = " + currentKm);
+        }
+
+        context.putContextValue("currentKm", currentKm);
+
+        StyledValueMarker marker = new StyledValueMarker(0, request);
+        valueMarker.add(marker);
+    }
+}
+// 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/exports/fixings/FixDeltaWtInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,11 @@
+package de.intevation.flys.exports.fixings;
+
+import de.intevation.flys.exports.ChartInfoGenerator;
+
+public class FixDeltaWtInfoGenerator extends ChartInfoGenerator {
+
+    public FixDeltaWtInfoGenerator() {
+        super(new FixDeltaWtGenerator());
+    }
+}
+// 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/exports/fixings/FixDerivedCurveGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,138 @@
+package de.intevation.flys.exports.fixings;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.fixings.FixDerivateFacet;
+import de.intevation.flys.artifacts.model.fixings.FixFunction;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.exports.ChartGenerator;
+import de.intevation.flys.jfree.JFreeUtil;
+import de.intevation.flys.jfree.StyledXYSeries;
+
+/**
+ * Generator for fixation derived function curve.
+ *
+ * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a>
+ */
+public class FixDerivedCurveGenerator
+extends FixChartGenerator
+implements FacetTypes
+{
+    /** Private logger. */
+    private static Logger logger =
+            Logger.getLogger(FixDerivedCurveGenerator.class);
+
+    public static final String I18N_CHART_TITLE =
+            "chart.fixings.derivedcurve.title";
+
+    public static final String I18N_CHART_SUBTITLE =
+            "chart.fixings.derivedcurve.subtitle";
+
+    public static final String I18N_XAXIS_LABEL =
+            "chart.fixings.derivedcurve.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL =
+            "chart.fixings.derivedcurve.yaxis.label";
+
+    public static final String I18N_CHART_TITLE_DEFAULT =
+            "Ableitungskurve";
+
+    public static final String I18N_XAXIS_LABEL_DEFAULT =
+            "Q [m\u00B3/s]";
+
+    public static final String I18N_YAXIS_LABEL_DEFAULT =
+            "W [NN + m]";
+
+    public static enum YAXIS {
+        W(0),
+        Q(1);
+        public int idx;
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+
+    @Override
+    public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doOut");
+
+        if (FacetTypes.IS.MANUALPOINTS(aaf.getFacetName())) {
+            doPoints(aaf.getData(context),
+                    aaf,
+                    doc, visible, YAXIS.W.idx);
+        }
+        else {
+            FixDerivateFacet facet = (FixDerivateFacet)aaf.getFacet();
+            FixFunction func = (FixFunction)facet.getData(
+                    aaf.getArtifact(), context);
+
+            if (func == null) {
+                logger.warn("doOut: Facet does not contain FixFunction");
+                return;
+            }
+
+            double maxQ = func.getMaxQ();
+
+            if (maxQ > 0) {
+                StyledXYSeries series = JFreeUtil.sampleFunction2D(
+                        func.getFunction(),
+                        doc,
+                        aaf.getFacetDescription(),
+                        500,   // number of samples
+                        0.0 ,  // start
+                        maxQ); // end
+                addAxisSeries(series, 0, visible);
+            }
+        }
+    }
+
+
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+
+    @Override
+    protected String getChartTitle() {
+        return Resources.format(
+                context.getMeta(),
+                I18N_CHART_TITLE,
+                I18N_CHART_TITLE_DEFAULT,
+                context.getContextValue(CURRENT_KM));
+    }
+
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+
+    @Override
+    protected String getDefaultYAxisLabel(int pos) {
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+    }
+
+
+    @Override
+    protected ChartGenerator.YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+}
+// 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/exports/fixings/FixDerivedCurveInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,11 @@
+package de.intevation.flys.exports.fixings;
+
+import de.intevation.flys.exports.ChartInfoGenerator;
+
+public class FixDerivedCurveInfoGenerator extends ChartInfoGenerator {
+
+    public FixDerivedCurveInfoGenerator() {
+        super(new FixDerivedCurveGenerator());
+    }
+}
+// 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/exports/fixings/FixLongitudinalSectionGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,315 @@
+package de.intevation.flys.exports.fixings;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.plot.Marker;
+import org.jfree.chart.plot.ValueMarker;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.fixings.AnalysisPeriod;
+import de.intevation.flys.artifacts.model.fixings.QWD;
+import de.intevation.flys.exports.ChartGenerator;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledAreaSeriesCollection;
+import de.intevation.flys.jfree.StyledXYSeries;
+import de.intevation.flys.utils.KMIndex;
+
+public class FixLongitudinalSectionGenerator
+extends FixChartGenerator
+implements FacetTypes
+{
+    private static Logger logger =
+            Logger.getLogger(FixLongitudinalSectionGenerator.class);
+
+    public static final String I18N_CHART_TITLE =
+            "chart.fixings.longitudinalsection.title";
+
+    public static final String I18N_CHART_SUBTITLE =
+            "chart.fixings.longitudinalsection.subtitle";
+
+    public static final String I18N_XAXIS_LABEL =
+            "chart.fixings.longitudinalsection.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL =
+            "chart.fixings.longitudinalsection.yaxis.label";
+
+    public static final String I18N_CHART_TITLE_DEFAULT  =
+            "Fixierungsanalyse";
+
+    public static final String I18N_XAXIS_LABEL_DEFAULT  =
+            "[km]";
+
+    public static final String I18N_YAXIS_LABEL_DEFAULT  =
+            "delta W [cm]";
+
+    public static enum YAXIS {
+        dW(0);
+        public int idx;
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+    @Override
+    public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        String name = aaf.getFacetName();
+        logger.debug("FixLongitudinalSectionGenerator: doOut: " + name);
+
+        if (name.contains(FIX_SECTOR_AVERAGE_LS_DEVIATION)) {
+            doSectorAverageDeviationOut(aaf, doc, visible);
+        }
+        else if (name.contains(FIX_SECTOR_AVERAGE_LS)) {
+            doSectorAverageOut(aaf, doc, visible);
+        }
+        else if (name.equals(FIX_REFERENCE_EVENTS_LS)) {
+            doReferenceEventsOut(aaf, doc, visible);
+        }
+        else if (name.equals(FIX_ANALYSIS_EVENTS_LS)) {
+            doAnalysisEventsOut(aaf, doc, visible);
+        }
+        else if (name.equals(FIX_DEVIATION_LS)) {
+            doReferenceDeviationOut(aaf, doc, visible);
+        }
+        else if (name.equals(LONGITUDINAL_ANNOTATION)) {
+            doAnnotations(
+                    (FLYSAnnotation) aaf.getData(context),
+                    aaf,
+                    doc,
+                    visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints (aaf.getData(context),
+                    aaf,
+                    doc, visible, YAXIS.dW.idx);
+        }
+        else {
+            logger.warn("Unknown facet name " + name);
+            return;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected void doSectorAverageOut(
+            ArtifactAndFacet aaf,
+            Document doc,
+            boolean visible)
+    {
+        logger.debug("doSectorAverageOut" + aaf.getFacet().getIndex());
+
+        int index = aaf.getFacet().getIndex();
+        int sectorNdx = index & 3;
+
+        KMIndex<AnalysisPeriod> kms =
+                (KMIndex<AnalysisPeriod>)aaf.getData(context);
+
+        if(kms == null) {
+            return;
+        }
+
+        XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc);
+
+        for (KMIndex.Entry<AnalysisPeriod> entry: kms) {
+            double km = entry.getKm();
+            AnalysisPeriod ap = entry.getValue();
+            QWD qwd = ap.getQSectorAverages()[sectorNdx];
+            if (qwd == null) {
+                continue;
+            }
+            double deltaW = qwd.getDeltaW();
+            series.add(km, deltaW);
+        }
+
+        addAxisSeries(series, 0, visible);
+
+    }
+
+
+    @SuppressWarnings("unchecked")
+    protected void doSectorAverageDeviationOut(
+            ArtifactAndFacet aaf,
+            Document doc,
+            boolean visible)
+    {
+        logger.debug("doSectorAverageOut" + aaf.getFacet().getIndex());
+
+        int index = aaf.getFacet().getIndex();
+        int sectorNdx = index & 3;
+
+        KMIndex<AnalysisPeriod> kms =
+                (KMIndex<AnalysisPeriod>)aaf.getData(context);
+
+        if(kms == null) {
+            return;
+        }
+
+        StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc);
+        XYSeries upper =
+                new StyledXYSeries(aaf.getFacetDescription(), false, doc);
+        XYSeries lower =
+                new StyledXYSeries(aaf.getFacetDescription() + " ", false, doc);
+
+        for (KMIndex.Entry<AnalysisPeriod> entry: kms) {
+            double km = entry.getKm();
+            AnalysisPeriod ap = entry.getValue();
+            QWD qwd = ap.getQSectorAverages()[sectorNdx];
+            double dev = ap.getQSectorStdDev(sectorNdx);
+            logger.debug("std-dev: " + dev);
+            if (qwd == null) {
+                continue;
+            }
+            double deltaW = qwd.getDeltaW();
+            double up = deltaW + dev;
+            double lo = deltaW - dev;
+            upper.add(km, up);
+            lower.add(km, lo);
+        }
+        area.addSeries(upper);
+        area.addSeries(lower);
+
+        addAreaSeries(area, 0, visible);
+    }
+
+
+    @SuppressWarnings("unchecked")
+    protected void doReferenceDeviationOut(
+            ArtifactAndFacet aaf,
+            Document doc,
+            boolean visible)
+    {
+        logger.debug("doReferenceOut");
+
+        KMIndex<double[]> kms =
+                (KMIndex<double[]>)aaf.getData(context);
+
+        if(kms == null) {
+            return;
+        }
+
+        StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc);
+        XYSeries upper =
+                new StyledXYSeries(aaf.getFacetDescription(), false, doc);
+        XYSeries lower =
+                new StyledXYSeries(aaf.getFacetDescription() + " ", false, doc);
+
+
+        for (KMIndex.Entry<double[]> entry: kms) {
+            double km = entry.getKm();
+            double[] devArray = entry.getValue();
+            if (devArray == null) {
+                continue;
+            }
+            double dev = devArray[0];
+            double up = dev;
+            double lo = -dev;
+            upper.add(km, up, false);
+            lower.add(km, lo, false);
+        }
+        area.addSeries(upper);
+        area.addSeries(lower);
+
+        Marker marker = new ValueMarker(0);
+        marker.setStroke(new BasicStroke(2));
+        marker.setPaint(Color.BLACK);
+        addValueMarker(marker);
+        addAreaSeries(area, 0, visible);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected void doAnalysisEventsOut(
+            ArtifactAndFacet aaf,
+            Document doc,
+            boolean visible)
+    {
+        logger.debug("doAnalysisEventsOut");
+
+        KMIndex<QWD> kms =
+                (KMIndex<QWD>)aaf.getData(context);
+
+        if(kms == null) {
+            return;
+        }
+
+        XYSeriesCollection col = new XYSeriesCollection();
+
+        StyledXYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, doc);
+
+        for (KMIndex.Entry<QWD> entry: kms) {
+            double km = entry.getKm();
+            QWD qwd = entry.getValue();
+
+            series.add(km, qwd.getDeltaW());
+        }
+        col.addSeries(series);
+
+        addAxisDataset(col, 0, visible);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected void doReferenceEventsOut(
+            ArtifactAndFacet aaf,
+            Document doc,
+            boolean visible)
+    {
+        logger.debug("doReferenceEventOut");
+
+        KMIndex<QWD> kms =
+                (KMIndex<QWD>)aaf.getData(context);
+
+        if(kms == null) {
+            return;
+        }
+
+        XYSeriesCollection col = new XYSeriesCollection();
+
+        StyledXYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, doc);
+
+        for (KMIndex.Entry<QWD> entry: kms) {
+            double km = entry.getKm();
+            QWD qwd = entry.getValue();
+
+            series.add(km, qwd.getDeltaW());
+        }
+        col.addSeries(series);
+
+        addAxisDataset(col, 0, visible);
+    }
+
+
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultYAxisLabel(int pos) {
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected ChartGenerator.YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+}
+// 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/exports/fixings/FixLongitudinalSectionInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,11 @@
+package de.intevation.flys.exports.fixings;
+
+import de.intevation.flys.exports.ChartInfoGenerator;
+
+public class FixLongitudinalSectionInfoGenerator extends ChartInfoGenerator {
+
+    public FixLongitudinalSectionInfoGenerator() {
+        super(new FixLongitudinalSectionGenerator());
+    }
+}
+// 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/exports/fixings/FixWQCurveGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,571 @@
+package de.intevation.flys.exports.fixings;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.chart.plot.Marker;
+import org.jfree.chart.plot.ValueMarker;
+import org.jfree.chart.title.TextTitle;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.ui.RectangleAnchor;
+import org.jfree.ui.RectangleInsets;
+import org.jfree.ui.TextAnchor;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.StaticWKmsArtifact;
+import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.access.FixAnalysisAccess;
+import de.intevation.flys.artifacts.model.DateRange;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.NamedDouble;
+import de.intevation.flys.artifacts.model.QWDDateRange;
+import de.intevation.flys.artifacts.model.WKms;
+import de.intevation.flys.artifacts.model.WQKms;
+import de.intevation.flys.artifacts.model.fixings.FixFunction;
+import de.intevation.flys.artifacts.model.fixings.FixWQCurveFacet;
+import de.intevation.flys.artifacts.model.fixings.QWD;
+import de.intevation.flys.artifacts.model.fixings.QWI;
+import de.intevation.flys.artifacts.resources.Resources;
+import de.intevation.flys.exports.ChartGenerator;
+import de.intevation.flys.exports.StyledSeriesBuilder;
+import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.JFreeUtil;
+import de.intevation.flys.jfree.StickyAxisAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.River;
+import de.intevation.flys.utils.FLYSUtils;
+import de.intevation.flys.utils.ThemeUtil;
+
+/**
+ * Generator for WQ fixing charts.
+ * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a>
+ */
+public class FixWQCurveGenerator
+extends      FixChartGenerator
+implements   FacetTypes
+{
+    private static Logger logger =
+            Logger.getLogger(FixWQCurveGenerator.class);
+
+    public static final String I18N_CHART_TITLE =
+            "chart.fixings.wq.title";
+
+    public static final String I18N_CHART_SUBTITLE =
+            "chart.fixings.wq.subtitle";
+
+    public static final String I18N_CHART_SUBTITLE1 =
+            "chart.fixings.wq.subtitle1";
+
+    public static final String I18N_XAXIS_LABEL =
+            "chart.fixings.wq.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL =
+            "chart.fixings.wq.yaxis.label";
+
+    public static final String I18N_CHART_TITLE_DEFAULT  =
+            "Fixierungsanalyse";
+
+    public static final String I18N_XAXIS_LABEL_DEFAULT  =
+            "Q [m\u00B3/s]";
+
+    public static final String I18N_YAXIS_LABEL_DEFAULT  =
+            "W [NN + m]";
+
+    public static enum YAXIS {
+        W(0),
+        Q(1);
+        public int idx;
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+
+    private FLYSArtifact artifact;
+
+
+    @Override
+    public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        String name = aaf.getFacetName();
+        logger.debug("doOut: " + name);
+
+        this.artifact = (FLYSArtifact)aaf.getArtifact();
+
+        if(name.startsWith(FIX_SECTOR_AVERAGE_WQ)) {
+            doSectorAverageOut(aaf, doc, visible);
+        }
+        else if(FIX_ANALYSIS_EVENTS_WQ.equals(name)) {
+            doAnalysisEventsOut(aaf, doc, visible);
+        }
+        else if(FIX_REFERENCE_EVENTS_WQ.equals(name)) {
+            doReferenceEventsOut(aaf, doc, visible);
+        }
+        else if(FIX_WQ_CURVE.equals(name)) {
+            doWQCurveOut(aaf, doc, visible);
+        }
+        else if(FIX_OUTLIER.equals(name)) {
+            doOutlierOut(aaf, doc, visible);
+        }
+        else if(QSECTOR.equals(name)) {
+            doQSectorOut(aaf, doc, visible);
+        }
+        else if(STATIC_WKMS_INTERPOL.equals(name) ||
+                STATIC_WKMS.equals(name) ||
+                HEIGHTMARKS_POINTS.equals(name) ) {
+            doWAnnotations(
+                    aaf.getData(context),
+                    aaf,
+                    doc,
+                    visible);
+        }
+        else if (LONGITUDINAL_W.equals(name) || STATIC_WQ.equals(name)) {
+            doWQOut(aaf.getData(context), aaf, doc, visible);
+        }
+        else if (name.equals(DISCHARGE_CURVE)) {
+            doDischargeOut(
+                    (WINFOArtifact) aaf.getArtifact(),
+                    aaf.getData(context),
+                    aaf.getFacetDescription(),
+                    doc,
+                    visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(aaf.getFacetName())) {
+            doPoints(aaf.getData(context),
+                    aaf,
+                    doc, visible, YAXIS.W.idx);
+        }
+        else {
+            logger.warn("Unknown facet name " + name);
+            return;
+        }
+    }
+
+    /** Add sector average points to chart */
+    protected void doSectorAverageOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doSectorAverageOut");
+
+        QWDDateRange qwdd = (QWDDateRange) aaf.getData(context);
+        QWD qwd = qwdd != null ? qwdd.getQWD() : null;
+
+        if(qwd != null) {
+            addQWSeries(new QWD[] { qwd }, aaf, doc, visible);
+        }
+        else {
+            logger.debug("doSectorAverageOut: qwd == null");
+        }
+    }
+
+    /** Add analysis event points to chart */
+    protected void doAnalysisEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doAnalysisEventsOut");
+
+        QWD qwd = (QWD)aaf.getData(context);
+        if(qwd != null) {
+            XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc);
+            List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>();
+
+            DateFormat dateFormat = DateFormat.getDateInstance(
+                    DateFormat.SHORT);
+
+            series.add(qwd.getQ(), qwd.getW());
+
+            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
+                    dateFormat.format(qwd.getDate()),
+                    qwd.getQ(),
+                    qwd.getW());
+            textAnnos.add(anno);
+
+            addAxisSeries(series, 0, visible);
+            if(visible && ThemeUtil.parseShowPointLabel(doc)) {
+                FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, doc);
+                flysAnno.setTextAnnotations(textAnnos);
+                addAnnotations(flysAnno);
+            }
+        }
+        else {
+            logger.debug("doAnalysisEventsOut: qwds == null");
+        }
+    }
+
+    /** Add reference event points to chart */
+    protected void doReferenceEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doReferenceEventsOut");
+
+        QWI qwd = (QWI)aaf.getData(context);
+        if(qwd != null) {
+            XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc);
+            List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>();
+
+            DateFormat dateFormat = DateFormat.getDateInstance(
+                    DateFormat.SHORT);
+
+            series.add(qwd.getQ(), qwd.getW());
+
+            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
+                    dateFormat.format(qwd.getDate()),
+                    qwd.getQ(),
+                    qwd.getW());
+            textAnnos.add(anno);
+
+            addAxisSeries(series, 0, visible);
+            if(visible && ThemeUtil.parseShowPointLabel(doc)) {
+                FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, doc);
+                flysAnno.setTextAnnotations(textAnnos);
+                addAnnotations(flysAnno);
+            }
+        }
+        else {
+            logger.debug("doAnalysisEventsOut: qwds == null");
+        }
+    }
+
+    protected void doWQCurveOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doWQCurveOut");
+
+        FixWQCurveFacet facet = (FixWQCurveFacet)aaf.getFacet();
+        FixFunction func = (FixFunction)facet.getData(
+                aaf.getArtifact(), context);
+
+        if (func == null) {
+            logger.warn("doWQCurveOut: Facet does not contain FixFunction");
+            return;
+        }
+
+        double maxQ = func.getMaxQ();
+
+        if (maxQ > 0) {
+            StyledXYSeries series = JFreeUtil.sampleFunction2D(
+                    func.getFunction(),
+                    doc,
+                    aaf.getFacetDescription(),
+                    500,   // number of samples
+                    0.0 ,  // start
+                    maxQ); // end
+
+            addAxisSeries(series, 0, visible);
+        }
+        else {
+            logger.warn("doWQCurveOut: maxQ <= 0");
+        }
+    }
+
+    protected void doOutlierOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doOutlierOut");
+
+        QWI[] qws = (QWI[])aaf.getData(context);
+        addQWSeries(qws, aaf, doc, visible);
+    }
+
+
+    /** Add markers for q sectors. */
+    protected void doQSectorOut(ArtifactAndFacet aaf, Document theme, boolean visible) {
+        logger.debug("doQSectorOut");
+        if (!visible) {
+            return;
+        }
+
+        Object qsectorsObj = aaf.getData(context);
+        if (qsectorsObj == null || !(qsectorsObj instanceof List)) {
+            logger.warn("No QSectors coming from data.");
+            return;
+        }
+
+        List<?> qsectorsList = (List<?>) qsectorsObj;
+        if (qsectorsList.size() == 0 || !(qsectorsList.get(0) instanceof NamedDouble)) {
+            logger.warn("No QSectors coming from data.");
+            return;
+        }
+
+        @SuppressWarnings("unchecked")
+        List<NamedDouble> qsectors = (List<NamedDouble>) qsectorsList;
+
+        for (NamedDouble qsector : qsectors) {
+            if (Double.isNaN(qsector.getValue())) {
+                continue;
+            }
+            Marker m = new ValueMarker(qsector.getValue());
+            m.setPaint(Color.black);
+
+            float[] dashes = ThemeUtil.parseLineStyle(theme);
+            int size       = ThemeUtil.parseLineWidth(theme);
+            BasicStroke stroke;
+            if (dashes.length <= 1) {
+                stroke = new BasicStroke(size);
+            }
+            else {
+                stroke = new BasicStroke(size,
+                        BasicStroke.CAP_BUTT,
+                        BasicStroke.JOIN_ROUND,
+                        1.0f,
+                        dashes,
+                        0.0f);
+            }
+            m.setStroke(stroke);
+
+            if (ThemeUtil.parseShowLineLabel(theme)) {
+                m.setLabel(qsector.getName());
+                m.setPaint(ThemeUtil.parseTextColor(theme));
+                m.setLabelFont(ThemeUtil.parseTextFont(theme));
+            }
+            Color paint = ThemeUtil.parseLineColorField(theme);
+            if (paint != null) {
+                m.setPaint(paint);
+            }
+            m.setLabelAnchor(RectangleAnchor.TOP_LEFT);
+            m.setLabelTextAnchor(TextAnchor.TOP_LEFT);
+            m.setLabelOffset(new RectangleInsets(5, 5, 10, 10));
+            addDomainMarker(m);
+        }
+    }
+
+
+    /**
+     * Add W-Annotations to plot.
+     * @param wqkms actual data (double[][]).
+     * @param theme theme to use.
+     */
+    protected void doWAnnotations(
+            Object   wqkms,
+            ArtifactAndFacet aandf,
+            Document theme,
+            boolean  visible
+            ) {
+        Facet facet = aandf.getFacet();
+
+        List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>();
+        if (wqkms instanceof double[][]) {
+            logger.debug("Got double[][]");
+            double [][] data = (double [][]) wqkms;
+            for (int i = 0; i< data[0].length; i++) {
+                xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
+                        (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS));
+            }
+
+            doAnnotations(new FLYSAnnotation(facet.getDescription(), xy),
+                    aandf, theme, visible);
+        }
+        else {
+            // Assume its WKms.
+            logger.debug("Got WKms");
+            WKms data = (WKms) wqkms;
+
+            Double ckm = (Double) context.getContextValue(CURRENT_KM);
+            double location = (ckm != null)
+                    ? ckm.doubleValue()
+                            : getRange()[0];
+                    double w = StaticWKmsArtifact.getWAtKmLin(data, location);
+                    xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
+                            (float) w, StickyAxisAnnotation.SimpleAxis.Y_AXIS));
+
+                    doAnnotations(new FLYSAnnotation(facet.getDescription(), xy),
+                            aandf, theme, visible);
+        }
+    }
+
+
+    /**
+     * Add series with discharge curve to diagram.
+     */
+    protected void doDischargeOut(
+            WINFOArtifact artifact,
+            Object        o,
+            String        description,
+            Document      theme,
+            boolean       visible)
+    {
+        WQKms wqkms = (WQKms) o;
+
+        String gaugeName = wqkms.getName();
+
+        River river = FLYSUtils.getRiver(artifact);
+
+        if (river == null) {
+            logger.debug("no river found");
+            return;
+        }
+
+        Gauge gauge = river.determineGaugeByName(gaugeName);
+
+        if (gauge == null) {
+            logger.debug("no gauge found");
+            return;
+        }
+
+        XYSeries series = new StyledXYSeries(description, theme);
+        StyledSeriesBuilder.addPointsQW(series, wqkms);
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+
+    /**
+     * Add WQ Data to plot.
+     * @param wqkms data as double[][]
+     */
+    protected void doWQOut(
+            Object           wqkms,
+            ArtifactAndFacet aaf,
+            Document         theme,
+            boolean          visible
+            ) {
+        logger.debug("FixWQCurveGenerator: doWQOut");
+        if (wqkms instanceof WQKms) {
+            WQKms data = (WQKms) wqkms;
+
+            XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+            StyledSeriesBuilder.addPointsQW(series, data);
+
+            addAxisSeries(series, YAXIS.W.idx, visible);
+        }
+        else {
+            double [][] data = (double [][]) wqkms;
+
+            XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+            StyledSeriesBuilder.addPoints(series, data, true);
+
+            addAxisSeries(series, YAXIS.W.idx, visible);
+        }
+    }
+
+
+    protected void addQWSeries(
+            QWI []           qws,
+            ArtifactAndFacet aaf,
+            Document         theme,
+            boolean          visible
+            ) {
+        if (qws == null) {
+            return;
+        }
+
+        XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+        List<XYTextAnnotation> textAnnos =
+                new ArrayList<XYTextAnnotation>(qws.length);
+
+        DateFormat dateFormat = DateFormat.getDateInstance(
+                DateFormat.SHORT);
+
+        for (QWI qw: qws) {
+            series.add(qw.getQ(), qw.getW());
+
+            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
+                    dateFormat.format(qw.getDate()),
+                    qw.getQ(),
+                    qw.getW());
+            textAnnos.add(anno);
+        }
+
+        addAxisSeries(series, 0, visible);
+        if (visible && ThemeUtil.parseShowPointLabel(theme)) {
+            FLYSAnnotation flysAnno =
+                    new FLYSAnnotation(null, null, null, theme);
+            flysAnno.setTextAnnotations(textAnnos);
+            addAnnotations(flysAnno);
+        }
+    }
+
+    @Override
+    protected String getChartTitle() {
+        return Resources.format(
+                context.getMeta(),
+                I18N_CHART_TITLE,
+                I18N_CHART_TITLE_DEFAULT,
+                context.getContextValue(CURRENT_KM));
+    }
+
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultChartSubtitle() {
+        FixAnalysisAccess access = new FixAnalysisAccess(artifact);
+        DateRange dateRange = access.getDateRange();
+        DateRange refRange  = access.getReferencePeriod();
+
+        if (dateRange != null && refRange != null) {
+            return Resources.format(
+                    context.getMeta(),
+                    I18N_CHART_SUBTITLE,
+                    "",
+                    access.getRiver(),
+                    dateRange.getFrom(),
+                    dateRange.getTo(),
+                    refRange.getFrom(),
+                    refRange.getTo());
+        }
+
+        return null;
+    }
+
+    @Override
+    protected void addSubtitles(JFreeChart chart) {
+        String defaultSubtitle = getDefaultChartSubtitle();
+
+        if (defaultSubtitle == null || defaultSubtitle.length() == 0) {
+            return;
+        }
+
+        chart.addSubtitle(new TextTitle(defaultSubtitle));
+
+        StringBuilder buf = new StringBuilder();
+
+        // Add analysis periods as additional subtitle
+        FixAnalysisAccess access = new FixAnalysisAccess(artifact);
+        DateRange[] aperiods = access.getAnalysisPeriods();
+        buf.append(msg("fix.analysis.periods"));
+        buf.append(": ");
+        for(int n = 0; n < aperiods.length; n++) {
+            buf.append(
+                    Resources.format(
+                            context.getMeta(),
+                            I18N_CHART_SUBTITLE1,
+                            "",
+                            aperiods[n].getFrom(),
+                            aperiods[n].getTo()));
+            if(n + 1 < aperiods.length) {
+                buf.append("; ");
+            }
+        }
+
+        chart.addSubtitle(new TextTitle(buf.toString()));
+    }
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultYAxisLabel(int pos) {
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected ChartGenerator.YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+}
+// 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/exports/fixings/FixWQCurveInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.exports.fixings;
+
+import de.intevation.flys.exports.ChartInfoGenerator;
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific fixing
+ * analysis W/Q curves.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixWQCurveInfoGenerator extends ChartInfoGenerator {
+
+    public FixWQCurveInfoGenerator() {
+        super(new FixWQCurveGenerator());
+    }
+}
+// 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/exports/fixings/ParametersExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,115 @@
+package de.intevation.flys.exports.fixings;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.artifacts.model.fixings.FixAnalysisResult;
+
+import de.intevation.flys.artifacts.resources.Resources;
+
+import de.intevation.flys.exports.AbstractExporter;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.text.NumberFormat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+public class ParametersExporter
+extends      AbstractExporter
+{
+    private static Logger log = Logger.getLogger(ParametersExporter.class);
+
+    protected List<Parameters> parametersList;
+
+    @Override
+    public void init(Document request, OutputStream out, CallContext context) {
+        log.debug("ParametersExporter.init");
+        super.init(request, out, context);
+        parametersList = new ArrayList<Parameters>();
+    }
+
+    @Override
+    protected void addData(Object d) {
+        log.debug("ParametersExporter.addData");
+        if (!(d instanceof CalculationResult)) {
+            log.warn("Invalid data type");
+            return;
+        }
+
+        Object data = ((CalculationResult)d).getData();
+        if (!(data instanceof FixAnalysisResult)) {
+            log.warn("Invalid data stored in result.");
+            return;
+        }
+
+        FixAnalysisResult result = (FixAnalysisResult)data;
+        parametersList.add(result.getParameters());
+    }
+
+    @Override
+    public void generate()
+    throws IOException
+    {
+        log.debug("ParametersExporter.generate");
+
+        if (facet == null) {
+            throw new IOException("invalid (null) facet for exporter");
+        }
+
+        if (facet.equals(FIX_PARAMETERS)) {
+            generateCSV();
+        }
+        else {
+            throw new IOException(
+                "invalid facet for exporter: '" + facet + "'");
+        }
+    }
+
+    @Override
+    protected void writeCSVData(final CSVWriter writer) throws IOException {
+
+        if (parametersList.isEmpty()) {
+            return;
+        }
+
+        Parameters parameters = parametersList.get(0);
+        writer.writeNext(parameters.getColumnNames());
+
+        final int numColumns = parameters.getNumberColumns();
+
+        parameters.visit(new Parameters.Visitor() {
+
+            String [] row = new String[numColumns];
+
+            NumberFormat format = NumberFormat.getInstance(
+                Resources.getLocale(context.getMeta()));
+
+            @Override
+            public void visit(double [] data) {
+                for (int i = 0; i < data.length; ++i) {
+                    row[i] = format.format(data[i]);
+                }
+                writer.writeNext(row);
+            }
+        }, new double[numColumns]);
+
+        writer.flush();
+    }
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        // TODO: Implement me!
+    }
+}
+// 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/exports/minfo/BedDiffEpochInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,12 @@
+package de.intevation.flys.exports.minfo;
+
+import de.intevation.flys.exports.ChartInfoGenerator;
+
+
+public class BedDiffEpochInfoGenerator
+extends ChartInfoGenerator
+{
+   public BedDiffEpochInfoGenerator() {
+        super(new BedDifferenceEpochGenerator());
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedDiffHeightYearGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,113 @@
+package de.intevation.flys.exports.minfo;
+
+import org.apache.log4j.Logger;
+import org.jfree.data.xy.XYSeries;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.minfo.BedDiffYearResult;
+import de.intevation.flys.exports.StyledSeriesBuilder;
+import de.intevation.flys.exports.XYChartGenerator;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+
+
+public class BedDiffHeightYearGenerator
+extends XYChartGenerator
+implements FacetTypes
+{
+    public enum YAXIS {
+        D(0);
+
+        protected int idx;
+
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+    /** The logger that is used in this generator. */
+    private static Logger logger = Logger.getLogger(BedDiffHeightYearGenerator.class);
+
+    public static final String I18N_CHART_TITLE = "chart.beddifference.height.title";
+    public static final String I18N_XAXIS_LABEL = "chart.beddifference.height.xaxis.label";
+    public static final String I18N_YAXIS_LABEL = "chart.beddifference.height.yaxis.label";
+
+    public static final String I18N_CHART_TITLE_DEFAULT = "Sohlenhöhen Differenz";
+    public static final String I18N_XAXIS_LABEL_DEFAULT = "Fluss-Km";
+    public static final String I18N_YAXIS_LABEL_DEFAULT = "delta S [cm / Jahr]";
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+    @Override
+    public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) {
+        String name = bundle.getFacetName();
+
+        logger.debug("doOut: " + name);
+
+        if (name == null) {
+            logger.error("No facet name for doOut(). No output generated!");
+            return;
+        }
+
+        Facet facet = bundle.getFacet();
+
+        if (facet == null) {
+            return;
+        }
+
+        if (name.equals(BED_DIFFERENCE_HEIGHT_YEAR)) {
+            doBedDifferenceYearOut(
+                (BedDiffYearResult) bundle.getData(context),
+                bundle, attr, visible);
+        }
+        else if (name.equals(LONGITUDINAL_ANNOTATION)) {
+            doAnnotations(
+                (FLYSAnnotation) bundle.getData(context),
+                 bundle,
+                 attr,
+                 visible);
+        }
+    }
+
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultYAxisLabel(int pos) {
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+    }
+
+    protected void doBedDifferenceYearOut(BedDiffYearResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+        StyledSeriesBuilder.addPoints(series, data.getHeightPerYearData(), true);
+
+        addAxisSeries(series, YAXIS.D.idx, visible);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedDiffHeightYearInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,12 @@
+package de.intevation.flys.exports.minfo;
+
+import de.intevation.flys.exports.ChartInfoGenerator;
+
+
+public class BedDiffHeightYearInfoGenerator
+extends ChartInfoGenerator
+{
+    public BedDiffHeightYearInfoGenerator() {
+        super (new BedDiffHeightYearGenerator());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedDiffYearInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,12 @@
+package de.intevation.flys.exports.minfo;
+
+import de.intevation.flys.exports.ChartInfoGenerator;
+
+
+public class BedDiffYearInfoGenerator
+extends ChartInfoGenerator
+{
+    public BedDiffYearInfoGenerator() {
+        super(new BedDifferenceYearGenerator());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedDifferenceEpochGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,151 @@
+package de.intevation.flys.exports.minfo;
+
+import org.apache.log4j.Logger;
+import org.jfree.data.xy.XYSeries;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.minfo.BedDiffEpochResult;
+import de.intevation.flys.exports.StyledSeriesBuilder;
+import de.intevation.flys.exports.XYChartGenerator;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+
+
+public class BedDifferenceEpochGenerator
+extends XYChartGenerator
+implements FacetTypes
+{
+    public enum YAXIS {
+        D(0), H(1);
+
+        protected int idx;
+
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+    /** The logger that is used in this generator. */
+    private static Logger logger = Logger.getLogger(BedQualityGenerator.class);
+
+    public static final String I18N_CHART_TITLE = "chart.beddifference.epoch.title";
+    public static final String I18N_XAXIS_LABEL = "chart.beddifference.xaxis.label";
+    public static final String I18N_YAXIS_LABEL = "chart.beddifference.yaxis.label.diff";
+    public static final String I18N_SECOND_YAXIS_LABEL = "chart.beddifference.yaxis.label.height";
+
+    public static final String I18N_CHART_TITLE_DEFAULT = "Sohlenhöhen Differenz";
+    public static final String I18N_XAXIS_LABEL_DEFAULT = "Fluss-Km";
+    public static final String I18N_YAXIS_LABEL_DEFAULT = "delta S [m]";
+    public static final String I18N_SECOND_YAXIS_LABEL_DEFAULT = "Höhe [m]";
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+    @Override
+    public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) {
+        String name = bundle.getFacetName();
+
+        logger.debug("doOut: " + name);
+
+        if (name == null) {
+            logger.error("No facet name for doOut(). No output generated!");
+            return;
+        }
+
+        Facet facet = bundle.getFacet();
+
+        if (facet == null) {
+            return;
+        }
+
+        if (name.equals(BED_DIFFERENCE_EPOCH)) {
+            doBedDifferenceEpochOut(
+                (BedDiffEpochResult) bundle.getData(context),
+                bundle, attr, visible);
+        }
+        else if (name.equals(BED_DIFFERENCE_EPOCH_HEIGHT1)) {
+            doBedDifferenceHeightsOut((BedDiffEpochResult)bundle.getData(context),
+                bundle, attr, visible, 0);
+        }
+        else if (name.equals(BED_DIFFERENCE_EPOCH_HEIGHT2)) {
+            doBedDifferenceHeightsOut((BedDiffEpochResult)bundle.getData(context),
+                bundle, attr, visible, 1);
+        }
+        else if (name.equals(LONGITUDINAL_ANNOTATION)) {
+            doAnnotations(
+                (FLYSAnnotation) bundle.getData(context),
+                 bundle,
+                 attr,
+                 visible);
+        }
+    }
+
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultYAxisLabel(int pos) {
+        String label = "default";
+        if (pos == YAXIS.D.idx) {
+            label = msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+        }
+        else if (pos == YAXIS.H.idx) {
+            label = msg(I18N_SECOND_YAXIS_LABEL, I18N_SECOND_YAXIS_LABEL_DEFAULT);
+        }
+
+        return label;
+    }
+
+    protected void doBedDifferenceEpochOut(BedDiffEpochResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+        StyledSeriesBuilder.addPoints(series, data.getDifferencesData(), true);
+
+        addAxisSeries(series, YAXIS.D.idx, visible);
+    }
+
+    private void doBedDifferenceHeightsOut(
+        BedDiffEpochResult data,
+        ArtifactAndFacet bundle,
+        Document attr,
+        boolean visible,
+        int idx) {
+         logger.debug("doBedDifferenceHeightOut()");
+
+        XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), attr);
+        if (idx == 0) {
+            StyledSeriesBuilder.addPoints(series, data.getHeights1Data(), true);
+        }
+        else {
+            StyledSeriesBuilder.addPoints(series, data.getHeights2Data(), true);
+        }
+
+        addAxisSeries(series, YAXIS.H.idx, visible);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedDifferenceYearGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,173 @@
+package de.intevation.flys.exports.minfo;
+
+import org.apache.log4j.Logger;
+import org.jfree.data.xy.XYSeries;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.minfo.BedDiffYearResult;
+import de.intevation.flys.exports.StyledSeriesBuilder;
+import de.intevation.flys.exports.XYChartGenerator;
+import de.intevation.flys.jfree.FLYSAnnotation;
+import de.intevation.flys.jfree.StyledXYSeries;
+
+
+public class BedDifferenceYearGenerator
+extends XYChartGenerator
+implements FacetTypes
+{
+    public enum YAXIS {
+        D(0), M(1), H(2);
+
+        protected int idx;
+
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+    /** The logger that is used in this generator. */
+    private static Logger logger = Logger.getLogger(BedDifferenceYearGenerator.class);
+
+    public static final String I18N_CHART_TITLE = "chart.beddifference.year.title";
+    public static final String I18N_XAXIS_LABEL = "chart.beddifference.xaxis.label";
+    public static final String I18N_YAXIS_LABEL = "chart.beddifference.yaxis.label.diff";
+    public static final String I18N_SECOND_YAXIS_LABEL = "chart.beddifference.yaxis.label.morph";
+    public static final String I18N_THIRD_YAXIS_LABEL = "chart.beddifference.yaxis.label.heights";
+
+    public static final String I18N_CHART_TITLE_DEFAULT = "Sohlenhöhen Differenz";
+    public static final String I18N_XAXIS_LABEL_DEFAULT = "Fluss-Km";
+    public static final String I18N_YAXIS_LABEL_DEFAULT = "delta S [m]";
+    public static final String I18N_SECOND_YAXIS_LABEL_DEFAULT = "Morph. Breite [m]";
+    public static final String I18N_THIRD_YAXIS_LABEL_DEFAULT = "Höhe [m]";
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+    @Override
+    public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) {
+        String name = bundle.getFacetName();
+
+        logger.debug("doOut: " + name);
+
+        if (name == null) {
+            logger.error("No facet name for doOut(). No output generated!");
+            return;
+        }
+
+        Facet facet = bundle.getFacet();
+
+        if (facet == null) {
+            return;
+        }
+
+        if (name.equals(BED_DIFFERENCE_YEAR)) {
+            doBedDifferenceYearOut(
+                (BedDiffYearResult) bundle.getData(context),
+                bundle, attr, visible);
+        }
+        else if (name.equals(BED_DIFFERENCE_MORPH_WIDTH)) {
+            doBedDifferenceMorphWidthOut(
+                (BedDiffYearResult) bundle.getData(context),
+                bundle, attr, visible);
+        }
+        else if (name.equals(BED_DIFFERENCE_YEAR_HEIGHT1)) {
+            doBedDifferenceHeightsOut(
+                (BedDiffYearResult)bundle.getData(context),
+                bundle, attr, visible, 0);
+        }
+        else if (name.equals(BED_DIFFERENCE_YEAR_HEIGHT2)) {
+            doBedDifferenceHeightsOut(
+                (BedDiffYearResult)bundle.getData(context),
+                bundle, attr, visible, 1);
+        }
+        else if (name.equals(LONGITUDINAL_ANNOTATION)) {
+            doAnnotations(
+                (FLYSAnnotation) bundle.getData(context),
+                 bundle,
+                 attr,
+                 visible);
+        }
+    }
+
+    private void doBedDifferenceHeightsOut(
+        BedDiffYearResult data,
+        ArtifactAndFacet bundle,
+        Document attr,
+        boolean visible,
+        int idx) {
+         logger.debug("doBedDifferenceYearOut()");
+
+        XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), attr);
+        if (idx == 0) {
+            StyledSeriesBuilder.addPoints(series, data.getHeights1Data(), true);
+        }
+        else {
+            StyledSeriesBuilder.addPoints(series, data.getHeights2Data(), true);
+        }
+
+        addAxisSeries(series, YAXIS.H.idx, visible);
+    }
+
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultYAxisLabel(int pos) {
+        String label = "default";
+        if (pos == YAXIS.D.idx) {
+            label = msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+        }
+        else if (pos == YAXIS.M.idx) {
+            label = msg(I18N_SECOND_YAXIS_LABEL, I18N_SECOND_YAXIS_LABEL_DEFAULT);
+        }
+        else if (pos == YAXIS.H.idx) {
+            label = msg(I18N_THIRD_YAXIS_LABEL, I18N_THIRD_YAXIS_LABEL_DEFAULT);
+        }
+
+        return label;
+    }
+
+    protected void doBedDifferenceYearOut(BedDiffYearResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+        logger.debug("doBedDifferenceYearOut()");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+        StyledSeriesBuilder.addPoints(series, data.getDifferencesData(), true);
+
+        addAxisSeries(series, YAXIS.D.idx, visible);
+    }
+
+    protected void doBedDifferenceMorphWidthOut(BedDiffYearResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+        logger.debug("doBedDifferencesMorphWidthOut()");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+        StyledSeriesBuilder.addPoints(series, data.getMorphWidthData(), true);
+
+        addAxisSeries(series, YAXIS.M.idx, visible);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedQualityExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,216 @@
+package de.intevation.flys.exports.minfo;
+
+import gnu.trove.TDoubleArrayList;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+
+import au.com.bytecode.opencsv.CSVWriter;
+import de.intevation.artifacts.CallContext;
+import de.intevation.flys.artifacts.model.CalculationResult;
+import de.intevation.flys.artifacts.model.minfo.BedDiameterResult;
+import de.intevation.flys.artifacts.model.minfo.BedParametersResult;
+import de.intevation.flys.artifacts.model.minfo.BedQualityResult;
+import de.intevation.flys.artifacts.model.minfo.BedloadDiameterResult;
+import de.intevation.flys.exports.AbstractExporter;
+import de.intevation.flys.utils.Formatter;
+
+
+public class BedQualityExporter
+extends AbstractExporter
+{
+    /** Private logger. */
+    private static Logger logger = Logger.getLogger(BedQualityExporter.class);
+
+    private static final String CSV_HEADER_KM = "export.minfo.bedquality.km";
+    private static final String CSV_HEADER_DENSITY_CAP =
+        "export.minfo.bedquality.density_cap";
+    private static final String CSV_HEADER_DENSITY_SUB =
+        "export.minfo.bedquality.density_sub";
+    private static final String CSV_HEADER_POROSITY_CAP =
+        "export.minfo.bedquality.porosity_cap";
+    private static final String CSV_HEADER_POROSITY_SUB =
+        "export.minfo.bedquality.porosity_sub";
+    private static final String CSV_HEADER_BEDLOAD =
+        "export.minfo.bedquality.bedload";
+    private static final String CSV_HEADER_BED_CAP =
+        "export.minfo.bedquality.bed_cap";
+    private static final String CSV_HEADER_BED_SUB =
+        "export.minfo.bedquality.bed_sub";
+
+    private BedQualityResult[] results;
+
+    @Override
+    public void init(Document request, OutputStream out, CallContext context) {
+        logger.debug("BedQualityExporter.init");
+        super.init(request, out, context);
+        results = new BedQualityResult[0];
+    }
+
+    @Override
+    protected void writeCSVData(CSVWriter writer) throws IOException {
+        // TODO Auto-generated method stub
+        writeCSVHeader(writer);
+
+        NumberFormat kmf = Formatter.getCalculationKm(context.getMeta());
+
+        TDoubleArrayList kms = new TDoubleArrayList();
+        int cols = 1;
+        for (int i = 0; i < results.length; i++) {
+            BedDiameterResult[] beds = results[i].getBedResults();
+            for (int j = 0; j < beds.length; j++) {
+                TDoubleArrayList bkms = beds[j].getKms();
+                for (int k = 0; k < bkms.size(); k++) {
+                    if (!kms.contains(bkms.get(k))) {
+                        kms.add(bkms.get(k));
+                    }
+                }
+            }
+            BedloadDiameterResult[] loads = results[i].getBedloadResults();
+            for (int j = 0; j < loads.length; j++) {
+                TDoubleArrayList lkms = loads[i].getKms();
+                for (int k = 0; k < lkms.size(); k++) {
+                    if (!kms.contains(lkms.get(k))) {
+                        kms.add(lkms.get(k));
+                    }
+                }
+            }
+            cols += beds.length * 2;
+            cols += loads.length;
+            if (beds.length > 0) {
+                cols += 4;
+            }
+        }
+
+        kms.sort();
+        List<double[]> rows = new LinkedList<double[]>();
+        for (int i = 0; i < kms.size(); i++) {
+            double[] row = new double[cols];
+            double km = kms.get(i);
+            row[0] = km;
+            for (int j = 0; j < results.length; j++) {
+                BedloadDiameterResult[] loads = results[j].getBedloadResults();
+
+                for(int k = 0; k < loads.length; k++) {
+                    // k + 1: shift km column.
+                    // j* loads.length: shift periods.
+                    row[(k + 1) + (j * loads.length)] =
+                        loads[k].getDiameter(km);
+                }
+                BedDiameterResult[] beds = results[j].getBedResults();
+                for (int k = 0; k < beds.length; k++) {
+                    // k + 1: shift km column.
+                    // j * beds.length: shift periods.
+                    // loads.length * results.length: shift bed load columns.
+                    int ndx = (k + 1) + (j * beds.length) + (loads.length * results.length);
+                    row[ndx] = beds[k].getDiameterCap(km);
+                    row[ndx + 1] = beds[k].getDiameterSub(km);
+                }
+                BedParametersResult[] params = results[j].getParameters();
+                for(int k = 0; k < params.length; k++) {
+                    // loads.length + (beds.lenght * 2) * (j + 1): shift bed and bedload columns.
+                    int ndx = 1 + (loads.length + (beds.length * 2) * (j + 1));
+                    row[ndx] = params[k].getLoadDensityCap(km);
+                    row[ndx + 1] = params[k].getLoadDensitySub(km);
+                    row[ndx + 2] = params[k].getPorosityCap(km);
+                    row[ndx + 3] = params[k].getPorositySub(km);
+                }
+            }
+            rows.add(row);
+        }
+        for (double[] d : rows) {
+            logger.debug(Arrays.toString(d));
+            List<String> cells = new LinkedList<String>();
+            for (int i = 0; i < d.length; i++) {
+                if (!Double.isNaN(d[i])) {
+                    NumberFormat nf = Formatter.getFormatter(context, 1, 3);
+                    cells.add(nf.format(d[i]));
+                }
+                else {
+                    cells.add("");
+                }
+            }
+            writer.writeNext(cells.toArray(new String[cells.size()]));
+        }
+    }
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    protected void addData(Object data) {
+        // TODO Auto-generated method stub
+        logger.debug("addData()");
+        if (!(data instanceof CalculationResult)) {
+            logger.warn("Invalid data type.");
+            return;
+        }
+        Object[] d = (Object[])((CalculationResult)data).getData();
+
+        if (!(d instanceof BedQualityResult[])) {
+            logger.warn("Invalid result object.");
+            return;
+        }
+        results = (BedQualityResult[])d;
+    }
+
+    protected void writeCSVHeader(CSVWriter writer) {
+        logger.debug("writeCSVHeader()");
+
+        List<String> header = new LinkedList<String>();
+        if (results != null)  {
+            header.add(msg(CSV_HEADER_KM, "km"));
+            for (int i = 0; i < results.length; i++) {
+                DateFormat df = Formatter.getDateFormatter(context.getMeta(), "dd.MM.yyyy");
+                String d1 = df.format(results[i].getDateRange().getFrom());
+                String d2 = df.format(results[i].getDateRange().getTo());
+                BedloadDiameterResult[] loads = results[i].getBedloadResults();
+                BedDiameterResult[] beds = results[i].getBedResults();
+                BedParametersResult[] params = results[i].getParameters();
+                for (int j = 0; j < loads.length; j++) {
+                    header.add(msg(CSV_HEADER_BEDLOAD, CSV_HEADER_BEDLOAD) +
+                        " - " +
+                        msg(loads[j].getType().toString(),
+                            loads[j].getType().toString()) + " - " +
+                        d1 + "-" + d2);
+                }
+                for (int j = 0; j < beds.length; j++) {
+                    header.add(msg(CSV_HEADER_BED_CAP, CSV_HEADER_BED_CAP) + " - " +
+                        msg(beds[j].getType().toString(),
+                            beds[j].getType().toString()) + " - " +
+                        d1 + "-" + d2);
+                    header.add(msg(CSV_HEADER_BED_SUB, CSV_HEADER_BED_SUB) + " - " +
+                        msg(beds[j].getType().toString(),
+                            beds[j].getType().toString()) + " - " +
+                        d1 + "-" + d2);
+                }
+                if (params.length > 0) {
+                    header.add(
+                        msg(CSV_HEADER_DENSITY_CAP, CSV_HEADER_DENSITY_CAP) +
+                        " - " + d1 + "-" + d2);
+                    header.add(
+                        msg(CSV_HEADER_DENSITY_SUB, CSV_HEADER_DENSITY_SUB) +
+                        " - " + d1 + "-" + d2);
+                    header.add(
+                        msg(CSV_HEADER_POROSITY_CAP, CSV_HEADER_POROSITY_CAP) +
+                        " - " + d1 + "-" + d2);
+                    header.add(
+                        msg(CSV_HEADER_POROSITY_SUB, CSV_HEADER_POROSITY_SUB) +
+                        " - " + d1 + "-" + d2);
+                }
+            }
+        }
+        writer.writeNext(header.toArray(new String[header.size()]));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/exports/minfo/BedQualityGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,273 @@
+package de.intevation.flys.exports.minfo;
+
+import org.apache.log4j.Logger;
+import org.jfree.data.xy.XYSeries;
+import org.w3c.dom.Document;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+import de.intevation.flys.artifacts.model.FacetTypes;
+import de.intevation.flys.artifacts.model.minfo.BedDiameterResult;
+import de.intevation.flys.artifacts.model.minfo.BedParametersResult;
+import de.intevation.flys.artifacts.model.minfo.BedloadDiameterResult;
+import de.intevation.flys.exports.StyledSeriesBuilder;
+import de.intevation.flys.exports.XYChartGenerator;
+import de.intevation.flys.jfree.StyledXYSeries;
+
+
+/**
+ * An OutGenerator that generates bed quality charts.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class BedQualityGenerator extends XYChartGenerator implements FacetTypes {
+
+    public enum YAXIS {
+        W(0), P(1), D(2);
+
+        protected int idx;
+
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+    /** The logger that is used in this generator. */
+    private static Logger logger = Logger.getLogger(BedQualityGenerator.class);
+
+    public static final String I18N_CHART_TITLE = "chart.bedquality.title";
+    public static final String I18N_XAXIS_LABEL = "chart.bedquality.xaxis.label";
+    public static final String I18N_YAXIS_LABEL = "chart.bedquality.yaxis.label";
+    public static final String I18N_SECOND_YAXIS_LABEL = "chart.bedquality.yaxis.label.porosity";
+    public static final String I18N_THIRD_YAXIS_LABEL = "chart.bedquality.yaxis.label.diameter";
+
+    public static final String I18N_CHART_TITLE_DEFAULT = "Sohlen Längsschnitt";
+    public static final String I18N_XAXIS_LABEL_DEFAULT = "Fluss-Km";
+    public static final String I18N_YAXIS_LABEL_DEFAULT = "Durchmesser [m]";
+    public static final String I18N_SECOND_YAXIS_LABEL_DEFAULT = "Porosität [%]";
+    public static final String I18N_THIRD_YAXIS_LABEL_DEFAULT = "Dichte [t/m^3]";
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+    /**
+     * Returns the default title for this chart.
+     *
+     * @return the default title for this chart.
+     */
+    @Override
+    public String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+    /**
+     * Get internationalized label for the x axis.
+     */
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultYAxisLabel(int index) {
+        String label = "default";
+
+        if (index == YAXIS.W.idx) {
+            label = getWAxisLabel();
+        }
+        else if (index == YAXIS.P.idx) {
+            label = getPAxisLabel();
+        }
+        else if (index == YAXIS.D.idx) {
+            label = getDAxisLabel();
+        }
+
+        return label;
+    }
+
+    /**
+     * Get internationalized label for the y axis displaying the diameter.
+     */
+    protected String getWAxisLabel() {
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+    }
+
+    /**
+     * Get internationalized label for the y axis displaying the porosity.
+     */
+    protected String getPAxisLabel() {
+        return msg(I18N_SECOND_YAXIS_LABEL, I18N_SECOND_YAXIS_LABEL_DEFAULT);
+    }
+
+    /**
+     * Get internationalized label for the y axis displaying the density.
+     */
+    protected String getDAxisLabel() {
+        return msg(I18N_THIRD_YAXIS_LABEL, I18N_THIRD_YAXIS_LABEL_DEFAULT);
+    }
+
+    /**
+     * Produce output.
+     *
+     * @param artifactAndFacet
+     *            current facet.
+     * @param attr
+     *            theme for facet
+     */
+    public void doOut(ArtifactAndFacet artifactAndFacet, Document attr,
+        boolean visible) {
+        String name = artifactAndFacet.getFacetName();
+
+        logger.debug("BedQualityGenerator.doOut: " + name);
+
+        if (name == null) {
+            logger.error("No facet name for doOut(). No output generated!");
+            return;
+        }
+
+        Facet facet = artifactAndFacet.getFacet();
+
+        if (facet == null) {
+            return;
+        }
+
+        // TODO BED_QUALITY_BED_DIAMETER_TOPLAYER
+        if (name.equals(BED_QUALITY_BED_DIAMETER_TOPLAYER)) {
+            doBedDiameterTopLayerOut(
+                (BedDiameterResult) artifactAndFacet.getData(context),
+                artifactAndFacet, attr, visible);
+        }
+        else if (name.equals(BED_QUALITY_BED_DIAMETER_SUBLAYER)) {
+            doBedDiameterSubLayerOut(
+                (BedDiameterResult) artifactAndFacet.getData(context),
+                artifactAndFacet, attr, visible);
+        }
+        // TODO BED_QUALITY_BED_DIAMETER_SUBLAYER
+        else if (name.equals(BED_QUALITY_BEDLOAD_DIAMETER)) {
+            doBedLoadDiameterOut(
+                (BedloadDiameterResult) artifactAndFacet.getData(context),
+                artifactAndFacet, attr, visible);
+        }
+        else if (name.equals(BED_QUALITY_POROSITY_TOPLAYER)) {
+            doPorosityTopLayerOut(
+                (BedParametersResult) artifactAndFacet.getData(context),
+                artifactAndFacet, attr, visible);
+        }
+        else if (name.equals(BED_QUALITY_POROSITY_SUBLAYER)) {
+            doPorositySubLayerOut(
+                (BedParametersResult) artifactAndFacet.getData(context),
+                artifactAndFacet, attr, visible);
+        }
+        else if (name.equals(BED_QUALITY_SEDIMENT_DENSITY_TOPLAYER)) {
+            doDensityTopLayerOut(
+                (BedParametersResult) artifactAndFacet.getData(context),
+                artifactAndFacet, attr, visible);
+        }
+        else if (name.equals(BED_QUALITY_SEDIMENT_DENSITY_SUBLAYER)) {
+            doDensitySubLayerOut(
+                (BedParametersResult) artifactAndFacet.getData(context),
+                artifactAndFacet, attr, visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(name)) {
+            doPoints(artifactAndFacet.getData(context), artifactAndFacet, attr,
+                visible, YAXIS.W.idx);
+        }
+        else {
+            logger.warn("Unknown facet name: " + name);
+            return;
+        }
+    }
+
+    protected void doBedDiameterTopLayerOut(BedDiameterResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+        logger.debug("BedQuality.doBedDiameterTopLayerOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+        StyledSeriesBuilder.addPoints(series, data.getDiameterCapData(), true);
+
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+    protected void doBedDiameterSubLayerOut(BedDiameterResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+        logger.debug("BedQuality.doBedDiameterSubLayerOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+        StyledSeriesBuilder.addPoints(series, data.getDiameterSubData(), true);
+
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+    protected void doBedLoadDiameterOut(BedloadDiameterResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+        logger.debug("BedQuality.doBedLoadDiameterOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+        StyledSeriesBuilder.addPoints(series, data.getDiameterData(), true);
+
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+    protected void doPorosityTopLayerOut(BedParametersResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+        logger.debug("BedQuality.doPorosityTopLayerOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        StyledSeriesBuilder.addPoints(series, data.getPorosityCapData(),
+            true);
+
+        addAxisSeries(series, YAXIS.P.idx, visible);
+    }
+
+    protected void doPorositySubLayerOut(BedParametersResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+        logger.debug("BedQuality.doPorositySubLayerOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        StyledSeriesBuilder.addPoints(series, data.getPorositySubData(),
+            true);
+
+        addAxisSeries(series, YAXIS.P.idx, visible);
+    }
+
+    protected void doDensityTopLayerOut(BedParametersResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+        logger.debug("BedQuality.doDensityOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        StyledSeriesBuilder.addPoints(series, data.getDensityCapData(),
+            true);
+
+        addAxisSeries(series, YAXIS.D.idx, visible);
+    }
+
+    protected void doDensitySubLayerOut(BedParametersResult data,
+        ArtifactAndFacet aandf, Document theme, boolean visible) {
+        logger.debug("BedQuality.doDensityOut");
+
+        XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme);
+
+        StyledSeriesBuilder.addPoints(series, data.getDensitySubData(),
+            true);
+
+        addAxisSeries(series, YAXIS.D.idx, visible);
+    }
+}
+// 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/exports/minfo/BedQualityInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,18 @@
+package de.intevation.flys.exports.minfo;
+
+import de.intevation.flys.exports.ChartInfoGenerator;
+
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific computed
+ * bed quality curves.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class BedQualityInfoGenerator extends ChartInfoGenerator {
+
+    public BedQualityInfoGenerator() {
+        super(new BedQualityGenerator());
+    }
+}
+// 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/exports/sq/SQOverviewGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,238 @@
+package de.intevation.flys.exports.sq;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.imageio.ImageIO;
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.ChartRenderingInfo;
+import org.jfree.chart.JFreeChart;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Settings;
+import de.intevation.artifacts.Artifact;
+import de.intevation.artifacts.ArtifactDatabaseException;
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.flys.artifacts.context.FLYSContext;
+import de.intevation.flys.collections.FLYSArtifactCollection;
+import de.intevation.flys.exports.ChartGenerator;
+import de.intevation.flys.exports.OutGenerator;
+import de.intevation.flys.exports.OutputHelper;
+
+public class SQOverviewGenerator
+implements OutGenerator
+{
+    private static Logger logger = Logger.getLogger(SQOverviewGenerator.class);
+
+    public static final String XPATH_CHART_SIZE =
+        "/art:action/art:attributes/art:size";
+
+    protected FLYSArtifactCollection collection;
+
+    protected Artifact master;
+
+    protected Settings settings;
+
+    protected Document request;
+
+    protected OutputStream out;
+
+    protected CallContext context;
+
+    protected List<JFreeChart> charts;
+
+    /**
+     * Produce output.
+     * @param artifactAndFacet current facet and artifact.
+     * @param attr  theme for facet
+     */
+    @Override
+    public void doOut(
+        ArtifactAndFacet artifactAndFacet,
+        Document         attr,
+        boolean          visible
+    ) {
+        logger.debug("doOut()");
+
+        String name = artifactAndFacet.getData(context).toString();
+        if(name != null) {
+            logger.debug("name: " + name);
+            ChartGenerator g =
+                (ChartGenerator)FLYSContext.getOutGenerator(
+                    context,
+                    name,
+                    null);
+
+            if (g == null) {
+                logger.debug("generator is null.");
+                return;
+            }
+
+            OutputHelper helper = new OutputHelper(master.identifier());
+            Document collectionAttribute = collection.getAttribute();
+
+            try {
+                Document cAttr = getAttribute(context, collectionAttribute, name);
+                g.init(request, out, context);
+
+                helper.doOut(g, name, name, cAttr, context);
+                JFreeChart chart = g.generateChart();
+                chart.removeLegend();
+                charts.add(chart);
+            }
+            catch (IOException e) {
+                logger.warn(e);
+            }
+            catch (ArtifactDatabaseException e) {
+                logger.warn(e);
+            }
+        }
+    }
+
+    @Override
+    public void init(Document request, OutputStream out, CallContext context) {
+        this.request = request;
+        this.out = out;
+        this.context = context;
+        charts = new ArrayList<JFreeChart>();
+    }
+
+    @Override
+    public void setMasterArtifact(Artifact master) {
+        this.master = master;
+    }
+
+    @Override
+    public void setCollection(FLYSArtifactCollection collection) {
+        this.collection = collection;
+    }
+
+    @Override
+    public void generate() throws IOException {
+        logger.debug("SQOverviewGenerator.generate");
+
+        int[] size = getSize();
+
+        if (size == null) {
+            size = new int[] {400, 600};
+        }
+        BufferedImage result =
+            new BufferedImage(size[0], size[1], BufferedImage.TYPE_INT_RGB);
+        for (int i = 0; i < charts.size(); i++) {
+            logger.debug("index: " + i);
+            JFreeChart chart = charts.get(i);
+            ChartRenderingInfo info = new ChartRenderingInfo();
+            BufferedImage img =
+                chart.createBufferedImage(size[0]/2, size[1]/3, info);
+            int horPos = 0;
+            int vertPos = 0;
+            if (i % 2 == 1) {
+                horPos = size[0]/2;
+            }
+            if (i > 1) {
+                vertPos = (size[1] / 3) * (i / 2);
+            }
+            result.createGraphics().drawImage(img, horPos, vertPos, null);
+        }
+        ImageIO.write(result, "png", out);
+    }
+
+    @Override
+    public void setSettings(Settings settings) {
+        this.settings = settings;
+    }
+
+    @Override
+    public Settings getSettings() {
+        return this.settings;
+    }
+
+
+    /**
+     * Returns the "attribute" (part of description document) for a specific
+     * output type.
+     *
+     * @param context The CallContext object.
+     * @param attr The xml attribute saved at the collection.
+     * @param output The name of the desired output type.
+     *
+     * @return the attribute for the desired output type.
+     */
+    protected Document getAttribute(
+        CallContext context,
+        Document    attr,
+        String      output)
+    throws    ArtifactDatabaseException
+    {
+        logger.debug("find specific XML node for Output: " + output);
+
+        Map<String, String> vars = new HashMap<String, String>();
+        vars.put("output", output);
+
+        Node out = (Node) XMLUtils.xpath(
+            attr,
+            "art:attribute/art:outputs/art:output[@name=$output]",
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE,
+            vars);
+
+        if (out != null) {
+            Document o = XMLUtils.newDocument();
+            o.appendChild(o.importNode(out, true));
+
+            return o;
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Returns the size of a chart export as array which has been specified by
+     * the incoming request document.
+     *
+     * @return the size of a chart as [width, height] or null if no width or
+     * height are given in the request document.
+     */
+    protected int[] getSize() {
+        int[] size = new int[2];
+
+        Element sizeEl = (Element)XMLUtils.xpath(
+            request,
+            XPATH_CHART_SIZE,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (sizeEl != null) {
+            String uri = ArtifactNamespaceContext.NAMESPACE_URI;
+
+            String w = sizeEl.getAttributeNS(uri, "width");
+            String h = sizeEl.getAttributeNS(uri, "height");
+
+            if (w.length() > 0 && h.length() > 0) {
+                try {
+                    size[0] = Integer.parseInt(w);
+                    size[1] = Integer.parseInt(h);
+                }
+                catch (NumberFormatException nfe) {
+                    logger.warn("Wrong values for chart width/height.");
+                }
+            }
+        }
+
+        return size[0] > 0 && size[1] > 0 ? size : null;
+    }
+}
+// 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/exports/sq/SQRelationExporter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,162 @@
+package de.intevation.flys.exports.sq;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Document;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+import de.intevation.artifacts.CallContext;
+
+import de.intevation.flys.artifacts.model.CalculationResult;
+
+import de.intevation.flys.artifacts.model.sq.SQFractionResult;
+import de.intevation.flys.artifacts.model.sq.SQResult;
+import de.intevation.flys.artifacts.model.Parameters;
+
+import de.intevation.flys.exports.AbstractExporter;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class SQRelationExporter extends AbstractExporter {
+
+    /** Private logger. */
+    private static final Logger logger =
+        Logger.getLogger(SQRelationExporter.class);
+
+
+    public static final String CSV_PARAMETER =
+        "export.sqrelation.csv.header.parameter";
+
+    public static final String CSV_STATION =
+        "export.sqrelation.csv.header.station";
+
+    public static final String CSV_KM =
+        "export.sqrelation.csv.header.km";
+
+    public static final String CSV_FUNCTION =
+        "export.sqrelation.csv.header.function";
+
+    public static final String CSV_GAUGE =
+        "export.sqrelation.csv.header.gauge";
+
+    public static final String CSV_COEFF_A =
+        "export.sqrelation.csv.header.coeff.a";
+
+    public static final String CSV_COEFF_B =
+        "export.sqrelation.csv.header.coeff.b";
+
+    public static final String CSV_COEFF_Q =
+        "export.sqrelation.csv.header.coeff.q";
+
+    public static final String CSV_COEFF_R =
+        "export.sqrelation.csv.header.coeff.r";
+
+    public static final String CSV_N_TOTAL =
+        "export.sqrelation.csv.header.n.total";
+
+    public static final String CSV_N_OUTLIERS =
+        "export.sqrelation.csv.header.n.outliers";
+
+    public static final String CSV_C_DUAN =
+        "export.sqrelation.csv.header.c.duan";
+
+    public static final String CSV_C_FERGUSON =
+        "export.sqrelation.csv.header.c.ferguson";
+
+    public static final String CSV_VARIANCE =
+        "export.sqrelation.csv.header.variance";
+
+
+    protected List<SQResult []> data;
+
+
+    public void init(Document request, OutputStream out, CallContext cc) {
+        super.init(request, out, cc);
+        data = new ArrayList<SQResult []>();
+    }
+
+
+    @Override
+    protected void addData(Object d) {
+        if (d instanceof CalculationResult) {
+            d = ((CalculationResult)d).getData();
+            if (d instanceof SQResult []) {
+                data.add((SQResult [])d);
+            }
+        }
+    }
+
+    protected void writeCSVHeader(CSVWriter writer) {
+        writer.writeNext(new String[] {
+            msg(CSV_KM        , CSV_KM),
+            msg(CSV_PARAMETER,  CSV_PARAMETER),
+            msg(CSV_COEFF_A   , CSV_COEFF_A),
+            msg(CSV_COEFF_B   , CSV_COEFF_B),
+            msg(CSV_N_TOTAL   , CSV_N_TOTAL),
+            msg(CSV_N_OUTLIERS, CSV_N_OUTLIERS),
+            msg(CSV_VARIANCE  , CSV_VARIANCE)
+        });
+    }
+
+    @Override
+    protected void writeCSVData(CSVWriter writer) {
+        logger.debug("writeCSVData");
+
+        writeCSVHeader(writer);
+
+        for (SQResult [] results: data) {
+            for (SQResult result: results) {
+                data2CSV(writer, result);
+            }
+        }
+    }
+
+    protected void data2CSV(CSVWriter writer, SQResult result) {
+        logger.debug("data2CSV");
+
+        // TODO: i18n
+        String km = String.valueOf(result.getKm());
+
+        for (int i = 0; i < SQResult.NUMBER_FRACTIONS; ++i) {
+            SQFractionResult fraction = result.getFraction(i);
+
+            String name = result.getFractionName(i);
+
+            Parameters parameters = fraction.getParameters();
+
+            if (parameters == null) {
+                continue;
+            }
+
+            double a  = parameters.getValue(0, "a");
+            double b  = parameters.getValue(0, "b");
+            double sd = Math.sqrt(parameters.getValue(0, "std_dev"));
+            int    o  = fraction.totalNumOutliers();
+            int    t  = fraction.numMeasurements() + o;
+
+            writer.writeNext(new String[] {
+                km,
+                name,
+                String.valueOf(a),
+                String.valueOf(b),
+                String.valueOf(t),
+                String.valueOf(o),
+                String.valueOf(sd)
+            });
+        }
+    }
+
+
+    @Override
+    protected void writePDF(OutputStream out) {
+        logger.debug("writePDF");
+        logger.error("NOT IMPLEMENTED: writePDF");
+    }
+}
+// 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/exports/sq/SQRelationGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,203 @@
+package de.intevation.flys.exports.sq;
+
+import de.intevation.artifactdatabase.state.ArtifactAndFacet;
+import de.intevation.artifactdatabase.state.Facet;
+
+import de.intevation.flys.artifacts.model.FacetTypes;
+
+import de.intevation.flys.artifacts.model.sq.SQ;
+import de.intevation.flys.artifacts.model.sq.SQFunction;
+
+import de.intevation.flys.exports.XYChartGenerator;
+
+import de.intevation.flys.jfree.JFreeUtil;
+import de.intevation.flys.jfree.StyledXYSeries;
+
+import org.apache.log4j.Logger;
+
+import org.jfree.chart.axis.LogarithmicAxis;
+import org.jfree.chart.axis.NumberAxis;
+
+import org.jfree.data.xy.XYSeries;
+
+import org.w3c.dom.Document;
+
+/**
+ * An OutGenerator that generates charts for MINFO sq relation.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class SQRelationGenerator
+extends      XYChartGenerator
+implements   FacetTypes
+{
+    public enum YAXIS {
+        S(0);
+        protected int idx;
+        private YAXIS(int c) {
+           idx = c;
+        }
+    }
+
+
+    public static final String I18N_XAXIS_LABEL =
+        "chart.sq_relation.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL =
+        "chart.sq_relation.yaxis.label";
+
+
+    /** The logger that is used in this generator. */
+    private static Logger logger = Logger.getLogger(SQRelationGenerator.class);
+
+
+    @Override
+    protected YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+
+
+    @Override
+    public String getDefaultChartTitle() {
+        return "TODO: CHART TITLE";
+    }
+
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL);
+    }
+
+
+    @Override
+    protected String getDefaultYAxisLabel(int index) {
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL);
+    }
+
+
+    @Override
+    protected NumberAxis createXAxis(String label) {
+        return new LogarithmicAxis(label);
+    }
+
+
+    @Override
+    protected NumberAxis createYAxis(int index) {
+        return new LogarithmicAxis(getDefaultYAxisLabel(index));
+    }
+
+
+    @Override
+    public void doOut(
+        ArtifactAndFacet artifactAndFacet,
+        Document         attr,
+        boolean          visible
+    ) {
+        logger.debug("doOut");
+
+        Facet  facet = artifactAndFacet.getFacet();
+        String name  = facet != null ? facet.getName() : null;
+
+        if (name == null || name.length() == 0) {
+            logger.warn("Invalid facet with no name given!");
+            return;
+        }
+
+        if (IS.SQ_CURVE(name)) {
+            doSQCurveOut(artifactAndFacet, attr, visible);
+        }
+        else if (IS.SQ_MEASUREMENT(name)) {
+            doSQOut(artifactAndFacet, attr, visible);
+        }
+        else if (IS.SQ_OUTLIER(name)) {
+            doSQOut(artifactAndFacet, attr, visible);
+        }
+    }
+
+
+    protected void doSQCurveOut(
+        ArtifactAndFacet artifactAndFacet,
+        Document         attr,
+        boolean          visible
+    ) {
+        String desc = artifactAndFacet.getFacetDescription();
+        logger.debug("doSQCurveOut: " + desc);
+
+        Facet      f    = artifactAndFacet.getFacet();
+        SQFunction func = (SQFunction) artifactAndFacet.getData(context);
+
+        if (func == null) {
+            return;
+        }
+
+        XYSeries series = JFreeUtil.sampleFunction2D(
+            func.getFunction(),
+            attr,
+            desc,
+            500,
+            Math.max(func.getMinQ(), 0.01),
+            Math.max(func.getMaxQ(), 0.02));
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Series '" + desc + "' has "
+                + series.getItemCount() + " items.");
+
+            logger.debug("   -> min x = " + series.getMinX());
+            logger.debug("   -> max x = " + series.getMaxX());
+            logger.debug("   -> min y = " + series.getMinY());
+            logger.debug("   -> max y = " + series.getMaxY());
+        }
+
+        addAxisSeries(series, YAXIS.S.idx, visible);
+    }
+
+
+    protected void doSQOut(
+        ArtifactAndFacet artifactAndFacet,
+        Document         attr,
+        boolean          visible
+    ) {
+        String desc = artifactAndFacet.getFacetDescription();
+        logger.debug("doSQOut: " + desc);
+
+        Facet    f      = artifactAndFacet.getFacet();
+        SQ[]     sqs    = (SQ[]) artifactAndFacet.getData(context);
+        if (sqs == null) {
+            logger.debug("No SQs found for facet");
+            return;
+        }
+        XYSeries series = new StyledXYSeries(desc, attr);
+
+        for (SQ sq: sqs) {
+            double q = sq.getQ();
+            double s = sq.getS();
+            if (s > 0d && q > 0d) {
+                series.add(q, s, false);
+            }
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Series '" + desc + "' has "
+                + series.getItemCount() + " items.");
+
+            logger.debug("   -> min x = " + series.getMinX());
+            logger.debug("   -> max x = " + series.getMaxX());
+            logger.debug("   -> min y = " + series.getMinY());
+            logger.debug("   -> max y = " + series.getMaxY());
+        }
+
+        addAxisSeries(series, YAXIS.S.idx, visible);
+    }
+}
+// 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/exports/sq/SQRelationGeneratorA.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.exports.sq;
+
+
+public class SQRelationGeneratorA extends SQRelationGenerator {
+
+    public static final String I18N_CHART_TITLE =
+        "chart.sq_relation_a.title";
+
+
+    @Override
+    public String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
+    }
+}
+// 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/exports/sq/SQRelationGeneratorB.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.exports.sq;
+
+
+public class SQRelationGeneratorB extends SQRelationGenerator {
+
+    public static final String I18N_CHART_TITLE =
+        "chart.sq_relation_b.title";
+
+
+    @Override
+    public String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
+    }
+}
+// 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/exports/sq/SQRelationGeneratorC.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.exports.sq;
+
+
+public class SQRelationGeneratorC extends SQRelationGenerator {
+
+    public static final String I18N_CHART_TITLE =
+        "chart.sq_relation_c.title";
+
+
+    @Override
+    public String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
+    }
+}
+// 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/exports/sq/SQRelationGeneratorD.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.exports.sq;
+
+
+public class SQRelationGeneratorD extends SQRelationGenerator {
+
+    public static final String I18N_CHART_TITLE =
+        "chart.sq_relation_d.title";
+
+
+    @Override
+    public String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
+    }
+}
+// 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/exports/sq/SQRelationGeneratorE.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.exports.sq;
+
+
+public class SQRelationGeneratorE extends SQRelationGenerator {
+
+    public static final String I18N_CHART_TITLE =
+        "chart.sq_relation_e.title";
+
+
+    @Override
+    public String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
+    }
+}
+// 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/exports/sq/SQRelationGeneratorF.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.exports.sq;
+
+
+public class SQRelationGeneratorF extends SQRelationGenerator {
+
+    public static final String I18N_CHART_TITLE =
+        "chart.sq_relation_f.title";
+
+
+    @Override
+    public String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE);
+    }
+}
+// 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/exports/sq/SQRelationInfoGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,19 @@
+package de.intevation.flys.exports.sq;
+
+import de.intevation.flys.exports.ChartInfoGenerator;
+
+
+/**
+ * A ChartInfoGenerator that generates meta information for specific
+ * sq relation charts.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class SQRelationInfoGenerator
+extends      ChartInfoGenerator
+{
+    public SQRelationInfoGenerator() {
+        super(new SQRelationGenerator());
+    }
+}
+// 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/java2d/ShapeUtils.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,83 @@
+package de.intevation.flys.java2d;
+
+import java.awt.Shape;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ShapeUtils
+{
+    // TODO: Use enum
+    public static final int MEASURED     = 0;
+    public static final int DIGITIZED    = 1;
+    public static final int INTERPOLATED = 2;
+
+    public static final boolean DIGITIZED_FILL    = false;
+    public static final boolean MEASURED_FILL     = true;
+    public static final boolean INTERPOLATED_FILL = false;
+
+   public static final Shape DIGITIZED_SHAPE =
+        createCross(4f);
+
+    public static final Shape MEASURED_SHAPE =
+        new Rectangle2D.Double(-2, -2, 4, 4);
+
+    public static final Shape INTERPOLATED_SHAPE =
+        new Ellipse2D.Double(-2, -2, 4, 4);
+
+    protected static Map<Long, Shape> scaledShapesCache =
+        new HashMap<Long, Shape>();
+
+    public static final Shape createCross(float size) {
+        float half = size * 0.5f;
+        GeneralPath p = new GeneralPath();
+        p.moveTo(-half, -half);
+        p.lineTo(half, half);
+        p.closePath();
+        p.moveTo(-half, half);
+        p.lineTo(half, -half);
+        p.closePath();
+        return p;
+    }
+
+    public static Shape scale(Shape shape, float factor) {
+        if (factor == 1f) {
+            return shape;
+        }
+        AffineTransform xform =
+            AffineTransform.getScaleInstance(factor, factor);
+
+        GeneralPath gp = new GeneralPath(shape);
+        return gp.createTransformedShape(xform);
+    }
+
+    public static synchronized Shape getScaledShape(int type, float size) {
+
+        Long hash = Long.valueOf(
+            (((long)type) << 32) | Float.floatToIntBits(size));
+
+        Shape shape = scaledShapesCache.get(hash);
+
+        if (shape == null) {
+            switch (type) {
+                case MEASURED:
+                    shape = MEASURED_SHAPE;
+                    break;
+                case DIGITIZED:
+                    shape = DIGITIZED_SHAPE;
+                    break;
+                default:
+                    shape = INTERPOLATED_SHAPE;
+            }
+            scaledShapesCache.put(hash, shape = scale(shape, size));
+        }
+
+        return shape;
+    }
+}
+// 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/jfree/Bounds.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,24 @@
+package de.intevation.flys.jfree;
+
+import java.io.Serializable;
+
+import org.jfree.chart.axis.ValueAxis;
+
+
+/**
+ * Somewhat better Ranges.
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public interface Bounds extends Serializable {
+
+    Number getLower();
+
+    Number getUpper();
+
+    void applyBounds(ValueAxis axis);
+
+    void applyBounds(ValueAxis axis, int percent);
+
+    Bounds combine(Bounds bounds);
+}
+// 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/jfree/CollisionFreeLineLabelEntity.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,21 @@
+package de.intevation.flys.jfree;
+
+import java.awt.Shape;
+
+import org.jfree.chart.entity.XYAnnotationEntity;
+
+/**
+ * Chart Entity for Line Labels that should not collide.
+ */
+public class CollisionFreeLineLabelEntity
+extends XYAnnotationEntity {
+    public CollisionFreeLineLabelEntity(
+        Shape hotspot,
+        int rendererIndex,
+        String toolTip,
+        String url
+    ) {
+        super(hotspot, rendererIndex, toolTip, url);
+    }
+}
+// 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/jfree/CollisionFreeXYTextAnnotation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,146 @@
+package de.intevation.flys.jfree;
+
+import org.apache.log4j.Logger;
+
+import java.awt.Shape;
+import java.awt.geom.Rectangle2D;
+
+import org.jfree.chart.entity.EntityCollection;
+import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.entity.XYAnnotationEntity;
+import org.jfree.chart.plot.PlotRenderingInfo;
+import org.jfree.chart.plot.Plot;
+
+import org.jfree.text.TextUtilities;
+
+import org.jfree.ui.RectangleEdge;
+
+/**
+ * Custom Annotations class that is drawn only if no collisions with other
+ * already drawn CustomAnnotations in current plot are found.
+ */
+public class CollisionFreeXYTextAnnotation extends XYTextAnnotation {
+
+    /** Logger for this class. */
+    private static Logger logger =
+        Logger.getLogger(CollisionFreeXYTextAnnotation.class);
+
+
+    public CollisionFreeXYTextAnnotation(String text, double x, double y) {
+        super(text, x, y);
+    }
+
+
+    /**
+     * Draw the Annotation only if it does not collide with other
+     * already drawn Annotations- texts.
+     *
+     * @param g2            the graphics device.
+     * @param plot          the plot.
+     * @param dataArea      the data area.
+     * @param domainAxis    the domain axis.
+     * @param rangeAxis     the range axis.
+     * @param rendererIndex the render index.
+     * @param info          state information, escpecially collects info about
+     *                      already drawn shapes (and thus annotations), used
+     *                      for collision detection.
+     */
+    @Override
+    public void draw(
+        java.awt.Graphics2D g2,
+        XYPlot plot,
+        java.awt.geom.Rectangle2D dataArea,
+        ValueAxis domainAxis,
+        ValueAxis rangeAxis,
+        int rendererIndex,
+        PlotRenderingInfo info
+    ) {
+        // From superclass, adjusted access only.
+        PlotOrientation orientation = plot.getOrientation();
+        RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
+                plot.getDomainAxisLocation(), orientation);
+        RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
+                plot.getRangeAxisLocation(), orientation);
+
+        float anchorX = (float) domainAxis.valueToJava2D(
+                this.getX(), dataArea, domainEdge);
+        float anchorY = (float) rangeAxis.valueToJava2D(
+                this.getY(), dataArea, rangeEdge);
+
+        if (orientation == PlotOrientation.HORIZONTAL) {
+            float tempAnchor = anchorX;
+            anchorX = anchorY;
+            anchorY = tempAnchor;
+        }
+
+        g2.setFont(getFont());
+        Shape hotspot = TextUtilities.calculateRotatedStringBounds(
+                getText(), g2, anchorX, anchorY, getTextAnchor(),
+                getRotationAngle(), getRotationAnchor());
+
+        // Deviation from superclass: prevent collision.
+        Rectangle2D hotspotBox = hotspot.getBounds2D();
+
+        if (JFreeUtil.collides(hotspot, info.getOwner().getEntityCollection(),
+            XYAnnotationEntity.class)) {
+            return;
+        }
+
+        if (this.getBackgroundPaint() != null) {
+            g2.setPaint(this.getBackgroundPaint());
+            g2.fill(hotspot);
+        }
+        g2.setPaint(getPaint());
+        TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY,
+                getTextAnchor(), getRotationAngle(), getRotationAnchor());
+        if (this.isOutlineVisible()) {
+            g2.setStroke(this.getOutlineStroke());
+            g2.setPaint(this.getOutlinePaint());
+            g2.draw(hotspot);
+        }
+
+        //String toolTip = getToolTipText();
+        //String url = getURL();
+        String toolTip = "CollisionFreeXYTextAnnotation";
+        String url     = toolTip;
+
+        if (toolTip != null || url != null) {
+            addEntity(info, hotspot, rendererIndex, toolTip, url);
+        }
+        else {
+            addEntity(info, hotspot, rendererIndex,
+                "CollisionFreeXYTextAnnotation",
+                "CollisionFreeXYTextAnnotation");
+        }
+    }
+
+    /**
+     * A utility method for adding an {@link CollisionFreeXYAnnotationEntity} to
+     * a {@link PlotRenderingInfo} instance.
+     *
+     * @param info  the plot rendering info (<code>null</code> permitted).
+     * @param hotspot  the hotspot area.
+     * @param rendererIndex  the renderer index.
+     * @param toolTipText  the tool tip text.
+     * @param urlText  the URL text.
+     */
+    protected void addEntity(PlotRenderingInfo info,
+                             Shape hotspot, int rendererIndex,
+                             String toolTipText, String urlText) {
+        if (info == null) {
+            return;
+        }
+        EntityCollection entities = info.getOwner().getEntityCollection();
+        if (entities == null) {
+            return;
+        }
+        CollisionFreeXYTextAnnotationEntity entity =
+            new CollisionFreeXYTextAnnotationEntity(hotspot,
+                rendererIndex, toolTipText, urlText);
+        entities.add(entity);
+    }
+}
+// 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/jfree/CollisionFreeXYTextAnnotationEntity.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,21 @@
+package de.intevation.flys.jfree;
+
+import java.awt.Shape;
+
+import org.jfree.chart.entity.XYAnnotationEntity;
+
+/**
+ * Chart Entity for XYTextAnnotations that should not collide.
+ */
+public class CollisionFreeXYTextAnnotationEntity
+extends XYAnnotationEntity {
+    public CollisionFreeXYTextAnnotationEntity(
+        Shape hotspot,
+        int rendererIndex,
+        String toolTip,
+        String url
+    ) {
+        super(hotspot, rendererIndex, toolTip, url);
+    }
+}
+// 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/jfree/DoubleBounds.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,79 @@
+package de.intevation.flys.jfree;
+
+
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.data.Range;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DoubleBounds implements Bounds {
+
+    protected double lower;
+    protected double upper;
+
+
+    /**
+     * Default constructor. <b>A DoubleBounds has always set lower &lt;
+     * upper!</b>
+     */
+    public DoubleBounds(double lower, double upper) {
+        this.lower = Math.min(lower, upper);
+        this.upper = Math.max(lower, upper);
+    }
+
+
+    @Override
+    public Number getLower() {
+        return Double.valueOf(lower);
+    }
+
+
+    @Override
+    public Number getUpper() {
+        return Double.valueOf(upper);
+    }
+
+
+    @Override
+    public void applyBounds(ValueAxis axis) {
+        axis.setRange(new Range(lower, upper));
+    }
+
+
+    /**
+     * Set extended range to ValueAxis.
+     * @param percent how many percent to extend (in each direction,
+     *        thus 10 percent on [0,100] -> [-10,110].
+     */
+    @Override
+    public void applyBounds(ValueAxis axis, int percent) {
+        double space = (upper - lower) / 100 * percent;
+        axis.setRange(new Range(lower-space, upper+space));
+    }
+
+
+    @Override
+    public Bounds combine(Bounds bounds) {
+        if (bounds == null) {
+            return this;
+        }
+
+        DoubleBounds other = (DoubleBounds) bounds;
+
+        double otherLower = other.getLower().doubleValue();
+        double otherUpper = other.getUpper().doubleValue();
+
+        return new DoubleBounds(
+            otherLower < lower ? otherLower : lower,
+            otherUpper > upper ? otherUpper : upper);
+    }
+
+
+    @Override
+    public String toString() {
+        return "DoubleBounds=[" + lower + " ; " + upper + "]";
+    }
+}
+// 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/jfree/EnhancedLineAndShapeRenderer.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,576 @@
+package de.intevation.flys.jfree;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.geom.Rectangle2D;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.entity.EntityCollection;
+import org.jfree.chart.plot.CrosshairState;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+import org.jfree.text.TextUtilities;
+import org.jfree.ui.RectangleEdge;
+import org.jfree.ui.TextAnchor;
+import org.jfree.util.BooleanList;
+import org.jfree.util.ShapeUtilities;
+
+/**
+ * Renderer with additional the additional functionality of renderering minima
+ * and/or maxima of dataseries contained in datasets.
+ */
+public class EnhancedLineAndShapeRenderer extends XYLineAndShapeRenderer {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /** Own logger. */
+    private static final Logger logger =
+        Logger.getLogger(EnhancedLineAndShapeRenderer.class);
+
+    protected BooleanList isMinimumShapeVisible;
+    protected BooleanList isMaximumShapeVisible;
+    protected BooleanList showLineLabel;
+
+    protected Map<Integer, Double> seriesMinimum;
+    protected Map<Integer, Double> seriesMinimumX;
+    protected Map<Integer, Double> seriesMaximum;
+
+    protected Map<Integer, Font> lineLabelFonts;
+    protected Map<Integer, Color> lineLabelTextColors;
+    protected BooleanList showLineLabelBG;
+    protected Map<Integer, Color> lineLabelBGColors;
+
+
+    public EnhancedLineAndShapeRenderer(boolean lines, boolean shapes) {
+        super(lines, shapes);
+        this.isMinimumShapeVisible = new BooleanList();
+        this.isMaximumShapeVisible = new BooleanList();
+        this.showLineLabel         = new BooleanList();
+        this.showLineLabelBG       = new BooleanList();
+        this.seriesMinimum         = new HashMap<Integer, Double>();
+        this.seriesMaximum         = new HashMap<Integer, Double>();
+        this.seriesMinimumX        = new HashMap<Integer, Double>();
+        this.lineLabelFonts        = new HashMap<Integer, Font>();
+        this.lineLabelTextColors   = new HashMap<Integer, Color>();
+        this.lineLabelBGColors     = new HashMap<Integer, Color>();
+    }
+
+
+    /**
+     * Draw a background-box of a text to render.
+     * @param g2 graphics device to use
+     * @param text text to draw
+     * @param textX x-position for text
+     * @param textY y-position for text
+     * @param bgColor color to fill box with.
+     */
+    public static void drawTextBox(Graphics2D g2,
+        String text, float textX, float textY, Color bgColor
+    ) {
+        Rectangle2D hotspotBox = g2.getFontMetrics().getStringBounds(text, g2);
+        float w = (float) hotspotBox.getWidth(), h = (float) hotspotBox.getHeight();
+        hotspotBox.setRect(textX, textY-h, w, h);
+        Color oldColor = g2.getColor();
+        g2.setColor(bgColor);
+        g2.fill(hotspotBox);
+        g2.setColor(oldColor);
+    }
+
+
+    /**
+     * Whether or not a specific item in a series (maybe the maxima) should
+     * be rendered with shape.
+     */
+    public boolean getItemShapeVisible(XYDataset dataset, int series, int item){
+        if (super.getItemShapeVisible(series, item)) {
+            return true;
+        }
+
+        if (isMinimumShapeVisible(series) && isMinimum(dataset, series, item)) {
+            return true;
+        }
+
+        if (isMaximumShapeVisible(series) && isMaximum(dataset, series, item)) {
+            return true;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Rectangle used to draw maximums shape.
+     */
+    public Shape getMaximumShape(int series, int column) {
+        return new Rectangle2D.Double(-5d, -5d, 10d, 10d);
+    }
+
+
+    /**
+     * Rectangle used to draw minimums shape.
+     */
+    public Shape getMinimumShape(int series, int column) {
+        return new Rectangle2D.Double(-5d, -5d, 10d, 10d);
+    }
+
+
+    /** Get fill paint for the maximum indicators. */
+    public Paint getMaximumFillPaint(int series, int column) {
+        Paint p = getItemPaint(series, column);
+
+        if (p instanceof Color) {
+            Color c = (Color) p;
+            Color b = c;
+
+            for (int i = 0; i < 2; i++) {
+                b = b.darker();
+            }
+
+            return b;
+        }
+
+        logger.warn("Item paint is no instance of Color!");
+        return p;
+    }
+
+
+    /** Get fill paint for the minimum indicators. */
+    public Paint getMinimumFillPaint(int series, int column) {
+        Paint p = getItemPaint(series, column);
+
+        if (p instanceof Color) {
+            Color c = (Color) p;
+            Color b = c;
+
+            for (int i = 0; i < 2; i++) {
+                b = b.darker();
+            }
+
+            return b;
+        }
+
+        logger.warn("Item paint is no instance of Color!");
+        return p;
+    }
+
+
+    /**
+     * Overrides XYLineAndShapeRenderer.drawSecondaryPass() to call an adapted
+     * method getItemShapeVisible() which now takes an XYDataset. So, 99% of
+     * code equal the code in XYLineAndShapeRenderer.
+     */
+    @Override
+    protected void drawSecondaryPass(
+        Graphics2D       g2,
+        XYPlot           plot,
+        XYDataset        dataset,
+        int              pass,
+        int              series,
+        int              item,
+        ValueAxis        domainAxis,
+        Rectangle2D      dataArea,
+        ValueAxis        rangeAxis,
+        CrosshairState   crosshairState,
+        EntityCollection entities
+    ) {
+        Shape entityArea = null;
+
+        // get the data point...
+        double x1 = dataset.getXValue(series, item);
+        double y1 = dataset.getYValue(series, item);
+        if (Double.isNaN(y1) || Double.isNaN(x1)) {
+            return;
+        }
+
+        PlotOrientation orientation = plot.getOrientation();
+        RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
+        RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
+        double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
+        double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation);
+
+        if (getItemShapeVisible(dataset, series, item)) {
+            Shape shape = null;
+
+            // OPTIMIZE: instead of calculating minimum and maximum for every
+            //           point, calculate it just once (assume that dataset
+            //           content does not change during rendering).
+            // NOTE:     Above OPTIMIZE might already be fulfilled to most extend.
+            boolean isMinimum = isMinimumShapeVisible(series)
+                && isMinimum(dataset, series, item);
+
+            boolean isMaximum = isMaximumShapeVisible(series)
+                && isMaximum(dataset, series, item);
+
+            if (isMinimum) {
+                logger.debug("Create a Minimum shape.");
+                shape = getMinimumShape(series, item);
+            }
+            else if (isMaximum) {
+                logger.debug("Create a Maximum shape.");
+                shape = getMaximumShape(series, item);
+            }
+            else {
+                shape = getItemShape(series, item);
+            }
+
+            if (orientation == PlotOrientation.HORIZONTAL) {
+                shape = ShapeUtilities.createTranslatedShape(shape, transY1,
+                        transX1);
+            }
+            else if (orientation == PlotOrientation.VERTICAL) {
+                shape = ShapeUtilities.createTranslatedShape(shape, transX1,
+                        transY1);
+            }
+            entityArea = shape;
+            if (shape.intersects(dataArea)) {
+                if (getItemShapeFilled(series, item)) {
+                    if (getUseFillPaint()) {
+                        g2.setPaint(getItemFillPaint(series, item));
+                    }
+                    else {
+                        g2.setPaint(getItemPaint(series, item));
+                    }
+                    g2.fill(shape);
+                }
+                if (getDrawOutlines()) {
+                    if (getUseOutlinePaint()) {
+                        g2.setPaint(getItemOutlinePaint(series, item));
+                    }
+                    else {
+                        g2.setPaint(getItemPaint(series, item));
+                    }
+                    g2.setStroke(getItemOutlineStroke(series, item));
+                    g2.draw(shape);
+                }
+
+                if (isMinimum) {
+                    g2.setPaint(getMinimumFillPaint(series, item));
+                    g2.fill(shape);
+                    g2.setPaint(getItemOutlinePaint(series, item));
+                    g2.setStroke(getItemOutlineStroke(series, item));
+                    g2.draw(shape);
+                }
+                else if (isMaximum) {
+                    g2.setPaint(getMaximumFillPaint(series, item));
+                    g2.fill(shape);
+                    g2.setPaint(getItemOutlinePaint(series, item));
+                    g2.setStroke(getItemOutlineStroke(series, item));
+                    g2.draw(shape);
+                }
+            }
+        } // if (getItemShapeVisible(dataset, series, item))
+
+        double xx = transX1;
+        double yy = transY1;
+        if (orientation == PlotOrientation.HORIZONTAL) {
+            xx = transY1;
+            yy = transX1;
+        }
+
+        // Draw the item label if there is one...
+        if (isItemLabelVisible(series, item)) {
+            drawItemLabel(g2, orientation, dataset, series, item, xx, yy,
+                    (y1 < 0.0));
+        }
+
+        // Draw label of line.
+        if (dataset instanceof XYSeriesCollection
+            && isShowLineLabel(series)
+            && isMinimumX (dataset, series, item)
+            ) {
+            XYSeries xYSeries = ((XYSeriesCollection) dataset).getSeries(series);
+            String waterlevelLabel = (xYSeries instanceof HasLabel)
+                ? ((HasLabel)xYSeries).getLabel()
+                : xYSeries.getKey().toString();
+            // TODO Force water of some German rivers to flow direction mountains.
+
+            Font oldFont = g2.getFont();
+
+            Color oldColor = g2.getColor();
+            g2.setFont(this.getLineLabelFont(series));
+            g2.setColor(this.getLineLabelTextColor(series));
+            g2.setBackground(Color.black);
+
+            // Try to always display label if the data is visible.
+            if (!isPointInRect(dataArea, xx, yy)) {
+                // Move into the data area.
+                xx = Math.max(xx, dataArea.getMinX());
+                xx = Math.min(xx, dataArea.getMaxX());
+                yy = Math.max(yy, dataArea.getMinY());
+                yy = Math.min(yy, dataArea.getMaxY());
+            }
+
+            // Move to right until no collisions exist anymore
+            Shape hotspot = TextUtilities.calculateRotatedStringBounds(
+                waterlevelLabel, g2, (float)xx, (float)yy-3f,
+                TextAnchor.CENTER_LEFT,
+                0f, TextAnchor.CENTER_LEFT);
+            while (JFreeUtil.collides(hotspot, entities,
+                                      CollisionFreeLineLabelEntity.class)) {
+                xx += 5f;
+                hotspot = TextUtilities.calculateRotatedStringBounds(
+                    waterlevelLabel, g2, (float)xx, (float)yy-3f, TextAnchor.CENTER_LEFT,
+                    0f, TextAnchor.CENTER_LEFT);
+            }
+
+            // Register to avoid collissions.
+            entities.add(new CollisionFreeLineLabelEntity(hotspot,
+                1, "", ""));
+
+            // Fill background.
+            if (isShowLineLabelBG(series)) {
+                drawTextBox(g2, waterlevelLabel, (float)xx, (float)yy-3f,
+                    getLineLabelBGColor(series));
+            }
+
+            g2.drawString(waterlevelLabel, (float)xx, (float)yy-3f);
+
+            g2.setFont(oldFont);
+            g2.setColor(oldColor);
+        }
+
+        int domainAxisIndex = plot.getDomainAxisIndex(domainAxis);
+        int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis);
+        updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex,
+                rangeAxisIndex, transX1, transY1, orientation);
+
+        // Add an entity for the item, but only if it falls within the data
+        // area...
+        if (entities != null && isPointInRect(dataArea, xx, yy)) {
+            addEntity(entities, entityArea, dataset, series, item, xx, yy);
+        }
+    }
+
+
+    /**
+     * Sets whether or not the minimum should be rendered with shape.
+     */
+    public void setIsMinimumShapeVisisble(int series, boolean isVisible) {
+        this.isMinimumShapeVisible.setBoolean(series, isVisible);
+    }
+
+
+    /**
+     * Whether or not the minimum should be rendered with shape.
+     */
+    public boolean isMinimumShapeVisible(int series) {
+        if (this.isMinimumShapeVisible.size() <= series) {
+            return false;
+        }
+
+        return isMinimumShapeVisible.getBoolean(series);
+    }
+
+
+    /**
+     * Sets whether or not the maximum should be rendered with shape.
+     */
+    public void setIsMaximumShapeVisible(int series, boolean isVisible) {
+        this.isMaximumShapeVisible.setBoolean(series, isVisible);
+    }
+
+
+    /**
+     * Whether or not the maximum should be rendered with shape.
+     */
+    public boolean isMaximumShapeVisible(int series) {
+        if (this.isMaximumShapeVisible.size() <= series) {
+            return false;
+        }
+
+        return isMaximumShapeVisible.getBoolean(series);
+    }
+
+    /** Whether or not a label should be shown for series. */
+    public boolean isShowLineLabel(int series) {
+        if (this.showLineLabel.size() <= series) {
+            return false;
+        }
+
+        return showLineLabel.getBoolean(series);
+    }
+
+
+    /** Sets whether or not a label should be shown for series. */
+    public void setShowLineLabel(boolean showLineLabel, int series) {
+        this.showLineLabel.setBoolean(series, showLineLabel);
+    }
+
+
+    /** Whether or not a label should be shown for series. */
+    public boolean isShowLineLabelBG(int series) {
+        if (this.showLineLabelBG.size() <= series) {
+            return false;
+        }
+
+        return showLineLabelBG.getBoolean(series);
+    }
+
+
+    public void setShowLineLabelBG(int series, boolean doShow) {
+        this.showLineLabelBG.setBoolean(series, doShow);
+    }
+
+    public Color getLineLabelBGColor(int series) {
+        if (this.lineLabelBGColors.size() <= series) {
+            return null;
+        }
+
+        return this.lineLabelBGColors.get(series);
+    }
+
+    public void setLineLabelBGColor(int series, Color color) {
+        this.lineLabelBGColors.put(series, color);
+    }
+
+    public Color getLineLabelTextColor(int series) {
+        if (this.lineLabelTextColors.size() <= series) {
+            return null;
+        }
+
+        return this.lineLabelTextColors.get(series);
+    }
+
+    public void setLineLabelTextColor(int series, Color color) {
+        this.lineLabelTextColors.put(series, color);
+    }
+
+    public void setLineLabelFont(Font font, int series) {
+        this.lineLabelFonts.put(series, font);
+    }
+
+    public Font getLineLabelFont(int series) {
+        return this.lineLabelFonts.get(series);
+    }
+
+
+    /**
+     * True if the given item of given dataset has the smallest
+     * X value within this set.
+     */
+    public boolean isMinimumX(XYDataset dataset, int series, int item) {
+        return dataset.getXValue(series, item) == getMinimumX(dataset, series);
+    }
+
+
+    /**
+     * Get Minimum X Value of a given series in a dataset.
+     * The value is stored for later use if queried the first time.
+     */
+    public double getMinimumX(XYDataset dataset, int series) {
+        Integer key = Integer.valueOf(series);
+        Double  old = seriesMinimumX.get(key);
+
+        if (old != null) {
+            return old.doubleValue();
+        }
+
+        logger.debug("Compute minimum of Series: " + series);
+
+        double min = Double.MAX_VALUE;
+
+        for (int i = 0, n = dataset.getItemCount(series); i < n; i++) {
+            double tmpValue = dataset.getXValue(series, i);
+
+            if (tmpValue < min) {
+                min = tmpValue;
+            }
+        }
+
+        seriesMinimumX.put(key, Double.valueOf(min));
+
+        return min;
+    }
+
+
+    /**
+     * True if the given item of given dataset has the smallest
+     * Y value within this set.
+     */
+    public boolean isMinimum(XYDataset dataset, int series, int item) {
+        return dataset.getYValue(series, item) == getMinimum(dataset, series);
+    }
+
+
+    /**
+     * Get Minimum Y Value of a given series in a dataset.
+     * The value is stored for later use if queried the first time.
+     */
+    public double getMinimum(XYDataset dataset, int series) {
+        Integer key = Integer.valueOf(series);
+        Double  old = seriesMinimum.get(key);
+
+        if (old != null) {
+            return old.doubleValue();
+        }
+
+        logger.debug("Compute minimum of Series: " + series);
+
+        double min = Double.MAX_VALUE;
+
+        for (int i = 0, n = dataset.getItemCount(series); i < n; i++) {
+            double tmpValue = dataset.getYValue(series, i);
+
+            if (tmpValue < min) {
+                min = tmpValue;
+            }
+        }
+
+        seriesMinimum.put(key, Double.valueOf(min));
+
+        return min;
+    }
+
+
+    /**
+     * True if the given item of given dataset has the biggest
+     * Y value within this set.
+     */
+    public boolean isMaximum(XYDataset dataset, int series, int item) {
+        return dataset.getYValue(series, item) == getMaximum(dataset, series);
+    }
+
+
+    /**
+     * Get maximum Y Value of a given series in a dataset.
+     * The value is stored for later use if queried the first time.
+     */
+    public double getMaximum(XYDataset dataset, int series) {
+        Integer key = Integer.valueOf(series);
+        Double  old = seriesMaximum.get(key);
+
+        if (old != null) {
+            return old.doubleValue();
+        }
+
+        logger.debug("Compute maximum of Series: " + series);
+
+        double max = -Double.MAX_VALUE;
+
+        for (int i = 0, n = dataset.getItemCount(series); i < n; i++) {
+            double tmpValue = dataset.getYValue(series, i);
+
+            if (tmpValue > max) {
+                max = tmpValue;
+            }
+        }
+
+        seriesMaximum.put(key, Double.valueOf(max));
+
+        return max;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/FLYSAnnotation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,28 +1,64 @@
 package de.intevation.flys.jfree;
 
+import java.util.Collections;
 import java.util.List;
 
 import org.w3c.dom.Document;
 
 import org.jfree.chart.annotations.XYTextAnnotation;
 
+import de.intevation.flys.artifacts.model.HYKFactory;
+
 /**
- * List of Annotations with name and theme.
+ * List of Text- Annotations with name and theme.
  */
 public class FLYSAnnotation {
 
-    protected List<XYTextAnnotation> annotations;
+    /* 'Other' Text Annotations. */
+    protected List<XYTextAnnotation> textAnnotations;
 
+    /** Annotations at axis. */
+    protected List<StickyAxisAnnotation> axisTextAnnotations;
+
+    /** Areas at axis. */
+    protected List<HYKFactory.Zone> boxes;
+
+    /** Styling information. */
     protected Document theme;
 
+    /** Chart-legend information. */
     protected String label;
 
 
-    public FLYSAnnotation(String label, List<XYTextAnnotation> annotations) {
-        this.label       = label;
-        this.annotations = annotations;
+    public FLYSAnnotation(String label, List<StickyAxisAnnotation> annotations) {
+        this(label, annotations, null, null);
     }
 
+
+    /** Create annotations, parameter might be null. */
+    public FLYSAnnotation(String label, List<StickyAxisAnnotation> annotations,
+        List<HYKFactory.Zone> bAnnotations
+    ) {
+        this(label, annotations, bAnnotations, null);
+    }
+
+
+    /** Create annotations, parameter might be null. */
+    public FLYSAnnotation(String label, List<StickyAxisAnnotation> annotations,
+        List<HYKFactory.Zone> bAnnotations, Document theme
+    ) {
+        this.label           = label;
+        this.axisTextAnnotations = (annotations != null)
+                               ? annotations
+                               : Collections.<StickyAxisAnnotation>emptyList();
+        this.boxes  = (bAnnotations != null)
+                               ? bAnnotations
+                               : Collections.<HYKFactory.Zone>emptyList();
+        this.textAnnotations = Collections.<XYTextAnnotation>emptyList();
+        this.setTheme(theme);
+    }
+
+
     public void setLabel(String label) {
         this.label = label;
     }
@@ -31,8 +67,21 @@
         return label;
     }
 
-    public List<XYTextAnnotation> getAnnotations() {
-        return annotations;
+    public List<StickyAxisAnnotation> getAxisTextAnnotations() {
+        return axisTextAnnotations;
+    }
+
+    public void setTextAnnotations(List<XYTextAnnotation> annotations) {
+        this.textAnnotations = annotations;
+    }
+
+    /** Set the "other" Text Annotations. */
+    public List<XYTextAnnotation> getTextAnnotations() {
+        return textAnnotations;
+    }
+
+    public List<HYKFactory.Zone> getBoxes() {
+        return boxes;
     }
 
     public void setTheme(Document theme) {
@@ -42,5 +91,17 @@
     public Document getTheme() {
         return theme;
     }
+
+    /**
+     * Set sticky axis of all axisTextAnnotations
+     * to the X axis if it is currently Y, and vice versa.
+     * @return this
+     */
+    public FLYSAnnotation flipStickyAxis() {
+        for (StickyAxisAnnotation saa: axisTextAnnotations) {
+            saa.flipStickyAxis();
+        }
+        return this;
+    }
 }
 // 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/jfree/HasLabel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,8 @@
+package de.intevation.flys.jfree;
+
+/** Interface to say something is labelled. */
+public interface HasLabel {
+    public String getLabel();
+    public void setLabel(String label);
+}
+// 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/jfree/JFreeUtil.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,120 @@
+package de.intevation.flys.jfree;
+
+import java.awt.Shape;
+import java.awt.geom.Rectangle2D;
+import java.util.Iterator;
+import java.util.Random;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.entity.ChartEntity;
+import org.jfree.chart.entity.EntityCollection;
+import org.w3c.dom.Document;
+
+import de.intevation.flys.artifacts.math.Function;
+
+public class JFreeUtil {
+
+    private static final Logger logger = Logger.getLogger(JFreeUtil.class);
+
+    /** Do not instantiate. */
+    private JFreeUtil() {
+    }
+
+
+    /**
+     * True if \param hotspot collides with a Entity in \param entities.
+     * @param hotspot Shape to compare against other shapes (bounds only).
+     * @param entities entities against which to compare shape.
+     * @param exclusiveEntityClass If not null, consider only entities of
+     *        given class.
+     * @return true if a collision (non-zero intersection) exists between
+     *        shapes.
+     */
+    public static boolean collides(Shape hotspot, EntityCollection entities,
+        Class exclusiveEntityClass) {
+        if (entities == null) return false;
+
+        Rectangle2D hotspotBox = hotspot.getBounds2D();
+
+        for (Iterator i = entities.iterator(); i.hasNext(); ) {
+            Object next = i.next();
+            ChartEntity entity = (ChartEntity) next;
+            if (exclusiveEntityClass == null
+                || exclusiveEntityClass.isInstance(entity))
+                {
+                if (entity.getArea().intersects(hotspotBox)) {
+                    // Found collision, early stop.
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * This function samples a randomized line that contains of x and y values
+     * between <i>startX</i>, <i>endX</i>, <i>startY</i> and <i>endY</i>. The
+     * number of points in the line is specified by <i>num</i>.
+     *
+     * @param num The number of points in the line.
+     * @param startX The min value of the x values.
+     * @param endX The max value of the x values.
+     * @param startY The min value of the y values.
+     * @param endY The max value of the y values.
+     * @return an array with [allX-values, allY-values].
+     * @throws IllegalArgumentException
+     */
+    public static double[][] randomizeLine(
+        int    num,
+        double startX,
+        double endX,
+        double startY,
+        double endY
+    ) throws IllegalArgumentException
+    {
+        if (num <= 0) {
+            throw new IllegalArgumentException("Parameter 'num' has to be > 0");
+        }
+
+        Random random = new Random();
+
+        double[] x = new double[num];
+        double[] y = new double[num];
+
+        for (int i = 0; i < num; i++) {
+            double xFac = random.nextDouble();
+            double yFac = random.nextDouble();
+
+            x[i] = startX + xFac * (endX - startX);
+            y[i] = startY + yFac * (endY - startY);
+
+            logger.debug("Created new point: " + x[i] + "|" + y[i]);
+        }
+
+        return new double[][] { x, y };
+    }
+
+
+    public static StyledXYSeries sampleFunction2D(
+        Function func,
+        Document theme,
+        String   seriesKey,
+        int      samples,
+        double   start,
+        double   end
+    ) {
+        StyledXYSeries series = new StyledXYSeries(seriesKey, theme);
+
+        double step = (end - start) / (samples - 1);
+
+        for (int i = 0; i < samples; i++) {
+            double x = start + (step * i);
+            series.add(x, func.value(x));
+        }
+
+        return series;
+    }
+}
+// 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/jfree/ShapeRenderer.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,357 @@
+package de.intevation.flys.jfree;
+
+/**
+ * Copyright (c) 2006, 2012 by Intevation GmbH
+ *
+ * @author Sascha L. Teichmann (teichmann@intevation.de)
+ *
+ * This program is free software under the LGPL (&gt;=v2.1)
+ * Read the file LGPL coming with FLYS for details.
+ */
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.jfree.chart.axis.ValueAxis;
+
+import org.jfree.chart.labels.ItemLabelPosition;
+import org.jfree.chart.labels.XYItemLabelGenerator;
+
+import org.jfree.chart.plot.CrosshairState;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.PlotRenderingInfo;
+import org.jfree.chart.plot.XYPlot;
+
+import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
+import org.jfree.chart.renderer.xy.XYItemRendererState;
+
+import org.jfree.data.xy.XYDataset;
+
+import org.jfree.text.TextUtilities;
+
+import org.jfree.ui.RectangleEdge;
+
+public class ShapeRenderer
+extends      StandardXYItemRenderer {
+
+    public static class Entry {
+        protected Shape   shape;
+        protected Shape   frame;
+        protected Paint   paint;
+        protected boolean filled;
+
+        public Entry(
+            Shape shape,
+            Paint paint,
+            boolean filled
+        ) {
+            this.shape = shape;
+            this.paint = paint;
+            this.filled = filled;
+        }
+
+        public Entry(
+            Shape   shape,
+            Shape   frame,
+            Paint   paint,
+            boolean filled
+        ) {
+            this.shape  = shape;
+            this.frame  = frame;
+            this.paint  = paint;
+            this.filled = filled;
+        }
+
+        public Shape getShape() {
+            return shape;
+        }
+
+        public void setShape(Shape shape) {
+            this.shape = shape;
+        }
+
+
+        public Paint getPaint() {
+            return paint;
+        }
+
+        public void setPaint(Paint paint) {
+            this.paint = paint;
+        }
+
+        public boolean getFilled() {
+            return filled;
+        }
+
+        public void setFilled(boolean filled) {
+            this.filled = filled;
+        }
+
+        public boolean equals(Object other) {
+            Entry entry = (Entry)other;
+            return filled == entry.filled
+                   &&   paint.equals(entry.paint)
+                   &&   shape.equals(entry.shape);
+        }
+
+        public int hashCode() {
+            return
+                shape.hashCode() ^
+                paint.hashCode() ^
+                (filled ? 1231 : 1237);
+        }
+    } // class Entry
+
+    public interface LabelGenerator {
+        String createLabel(Entry entry);
+    } // interface EntryLabelGenerator
+
+    protected Entry []  entries;
+
+    protected List<Rectangle2D> labelBoundingBoxes;
+
+    protected Rectangle2D area;
+
+    public ShapeRenderer() {
+        this(SHAPES);
+    }
+
+    public ShapeRenderer(int type) {
+        super(type);
+    }
+
+    public ShapeRenderer(Map<Entry, Integer> map) {
+        super(SHAPES);
+        setEntries(map);
+    }
+
+    public void setEntries(Entry [] entries) {
+        this.entries = entries;
+    }
+
+    public void setEntries(Map<Entry, Integer> map) {
+        Entry [] entries = new Entry[map.size()];
+
+        for (Map.Entry<Entry, Integer> entry: map.entrySet()) {
+            entries[entry.getValue()] = entry.getKey();
+        }
+
+        setEntries(entries);
+    }
+
+    @Override
+    public Shape getSeriesShape(int series) {
+        return entries[series].shape;
+    }
+
+    public Shape getSeriesFrame(int series) {
+        return entries[series].frame;
+    }
+
+    @Override
+    public Paint getSeriesPaint(int series) {
+        return entries[series].paint;
+    }
+
+    @Override
+    public boolean getItemShapeFilled(int series, int item) {
+        return entries[series].filled;
+    }
+
+    @Override
+    public XYItemRendererState initialise(
+        Graphics2D        g2,
+        Rectangle2D       dataArea,
+        XYPlot            plot,
+        XYDataset         data,
+        PlotRenderingInfo info
+    ) {
+        if (labelBoundingBoxes == null) {
+            labelBoundingBoxes = new ArrayList<Rectangle2D>(32);
+        }
+        else {
+            labelBoundingBoxes.clear();
+        }
+
+        area = dataArea;
+
+        return super.initialise(g2, dataArea, plot, data, info);
+    }
+
+    @Override
+    public void drawItem(
+        Graphics2D          g2,
+        XYItemRendererState state,
+        Rectangle2D         dataArea,
+        PlotRenderingInfo   info,
+        XYPlot              plot,
+        ValueAxis           domainAxis,
+        ValueAxis           rangeAxis,
+        XYDataset           dataset,
+        int                 series,
+        int                 item,
+        CrosshairState      crosshairState,
+        int                 pass
+    ) {
+        if (!getItemVisible(series, item)) {
+            return;
+        }
+
+        // get the data point...
+        double x1 = dataset.getXValue(series, item);
+        double y1 = dataset.getYValue(series, item);
+        if (Double.isNaN(x1) || Double.isNaN(y1)) {
+            return;
+        }
+
+        RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
+        RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
+        double x = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
+        double y = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation);
+
+        if (dataArea.contains(x, y))
+            super.drawItem(
+                g2,
+                state,
+                dataArea,
+                info,
+                plot,
+                domainAxis,
+                rangeAxis,
+                dataset,
+                series,
+                item,
+                crosshairState,
+                pass);
+    }
+
+    protected Point2D shiftBox(Rectangle2D box) {
+
+        double cx1 = area.getX();
+        double cy1 = area.getY();
+        double cx2 = cx1 + area.getWidth();
+        double cy2 = cy1 + area.getHeight();
+
+        double bx1 = box.getX();
+        double by1 = box.getY();
+        double bx2 = bx1 + box.getWidth();
+        double by2 = by1 + box.getHeight();
+
+        double dx;
+        double dy;
+
+        if (bx1 < cx1) {
+            dx = cx1 - bx1;
+        }
+        else if (bx2 > cx2) {
+            dx = cx2 - bx2;
+        }
+        else {
+            dx = 0d;
+        }
+
+        if (by1 < cy1) {
+            dy = cy1 - by1;
+        }
+        else if (by2 > cy2) {
+            dy = cy2 - by2;
+        }
+        else {
+            dy = 0d;
+        }
+
+        return new Point2D.Double(dx, dy);
+    }
+
+    @Override
+    protected void drawItemLabel(
+        Graphics2D      g2,
+        PlotOrientation orientation,
+        XYDataset       dataset,
+        int             series,
+        int             item,
+        double          x,
+        double          y,
+        boolean         negative
+    ) {
+        XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
+        if (generator == null) {
+            return;
+        }
+
+        Font labelFont = getItemLabelFont(series, item);
+
+        Paint paint = getItemLabelPaint(series, item);
+
+        g2.setFont(labelFont);
+        g2.setPaint(paint);
+
+        String label = generator.generateLabel(dataset, series, item);
+
+        ATTEMPS: for (int attempt = 0; attempt < 2; ++attempt) {
+            // get the label position..
+            ItemLabelPosition position = null;
+
+            boolean pos;
+            switch (attempt) {
+                case 0: pos = negative; break;
+                case 1: pos = !negative; break;
+                default: break ATTEMPS;
+            }
+
+            if (pos) {
+                position = getNegativeItemLabelPosition(series, item);
+            }
+            else {
+                position = getPositiveItemLabelPosition(series, item);
+            }
+
+            // work out the label anchor point...
+            Point2D anchorPoint = calculateLabelAnchorPoint(
+                position.getItemLabelAnchor(), x, y, orientation);
+
+            Shape labelShape = TextUtilities.calculateRotatedStringBounds(
+                label, g2,
+                (float)anchorPoint.getX(), (float)anchorPoint.getY(),
+                position.getTextAnchor(), position.getAngle(),
+                position.getRotationAnchor());
+
+            Rectangle2D bbox = labelShape.getBounds2D();
+
+            Point2D shift = shiftBox(bbox);
+
+            bbox = new Rectangle2D.Double(
+                bbox.getX() + shift.getX(),
+                bbox.getY() + shift.getY(),
+                bbox.getWidth(),
+                bbox.getHeight());
+
+            if (labelBoundingBoxes != null) {
+                for (Rectangle2D old: labelBoundingBoxes) {
+                    if (old.intersects(bbox)) {
+                        continue ATTEMPS;
+                    }
+                }
+                labelBoundingBoxes.add(bbox);
+            }
+
+            TextUtilities.drawRotatedString(
+                label, g2,
+                (float)(anchorPoint.getX() + shift.getX()),
+                (float)(anchorPoint.getY() + shift.getY()),
+                position.getTextAnchor(), position.getAngle(),
+                position.getRotationAnchor());
+            break;
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StableXYDifferenceRenderer.java	Fri Sep 28 12:15:52 2012 +0200
@@ -80,7 +80,9 @@
 import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Graphics2D;
+import java.awt.Font;
 import java.awt.Paint;
+import java.awt.geom.Point2D;
 import java.awt.Shape;
 import java.awt.Stroke;
 import java.awt.geom.GeneralPath;
@@ -121,6 +123,10 @@
 
 import de.intevation.flys.artifacts.math.Linear;
 
+import java.text.NumberFormat;
+
+import org.apache.log4j.Logger;
+
 /**
  * A renderer for an {@link XYPlot} that highlights the differences between two
  * series.  The example shown here is generated by the
@@ -133,6 +139,13 @@
 public class StableXYDifferenceRenderer extends AbstractXYItemRenderer
         implements XYItemRenderer, PublicCloneable {
 
+    private static Logger log = Logger.getLogger(StableXYDifferenceRenderer.class);
+
+    public static final int CALCULATE_POSITIVE_AREA = 1;
+    public static final int CALCULATE_NEGATIVE_AREA = 2;
+    public static final int CALCULATE_ALL_AREA =
+                            CALCULATE_POSITIVE_AREA | CALCULATE_NEGATIVE_AREA;
+
     /** For serialization. */
     private static final long serialVersionUID = -8447915602375584857L;
 
@@ -159,7 +172,37 @@
 
     protected boolean drawOriginalSeries;
 
-    //private XYDatasetToZeroMapper mapper;
+    /** The color of the label showing the calculated area. */
+    protected Color labelColor;
+
+    /** The background color of the label showing the calculated area. */
+    protected Color labelBGColor;
+
+    /** Font to draw label of calculated area with. */
+    protected Font labelFont;
+
+    /** Template to create i18ned label for area. */
+    protected String areaLabelTamplate;
+
+    /** NumberFormat to use for area. */
+    protected NumberFormat areaLabelNumberFormat;
+
+    protected int areaCalculationMode;
+
+    protected double positiveArea;
+    protected double negativeArea;
+
+    /** Whether or not to draw a label in the area. */
+    protected boolean labelArea = true;
+
+
+    /** Arithmetic centroid of drawn polygons. */
+    protected Point2D.Double centroid;
+
+
+    /** Number of points that contributed to the centroid. */
+    protected int centroidNPoints = 0;
+
 
     /**
      * This flag controls whether or not the x-coordinates (in Java2D space)
@@ -179,6 +222,11 @@
         this(Color.green, Color.red, false /*,  null */);
     }
 
+    public StableXYDifferenceRenderer(Paint positivePaint, Paint negativePaint,
+                                boolean shapes) {
+        this(positivePaint, negativePaint, shapes, CALCULATE_ALL_AREA);
+    }
+
     /**
      * Creates a new renderer.
      *
@@ -189,7 +237,7 @@
      * @param shapes  draw shapes?
      */
     public StableXYDifferenceRenderer(Paint positivePaint, Paint negativePaint,
-                                boolean shapes) {
+                                boolean shapes, int areaCalculationMode) {
         if (positivePaint == null) {
             throw new IllegalArgumentException(
                     "Null 'positivePaint' argument.");
@@ -207,8 +255,79 @@
         this.outlineStroke = new BasicStroke(1);
         this.outlinePaint  = Color.black;
         this.drawOriginalSeries = false;
+        this.areaCalculationMode = areaCalculationMode;
+        this.labelBGColor  = null;
+        this.centroid      = new Point2D.Double(0,0);
     }
 
+    public int getAreaCalculationMode() {
+        return areaCalculationMode;
+    }
+
+    public void setAreaCalculationMode(int areaCalculationMode) {
+        this.areaCalculationMode = areaCalculationMode;
+    }
+
+
+    /** Set template to use to create area label (e.g. 'Area=%dm2'). */
+    public void setAreaLabelTemplate(String areaTemplate) {
+        this.areaLabelTamplate = areaTemplate;
+    }
+
+
+    public void setAreaLabelNumberFormat(NumberFormat nf) {
+        this.areaLabelNumberFormat = nf;
+    }
+
+
+    public boolean isLabelArea() {
+        return this.labelArea;
+    }
+
+    public void setLabelArea(boolean label) {
+        this.labelArea = label;
+    }
+
+
+    /** Set font to paint label with. */
+    public void setLabelFont(Font font) {
+        this.labelFont = font;
+    }
+
+
+    /** Get font with which label is painted. */
+    public Font getLabelFont() {
+        return this.labelFont;
+    }
+
+
+    /** Set color with which to paint label. */
+    public void setLabelColor(Color color) {
+        this.labelColor = color;
+    }
+
+
+    /** Get color with which label is painted. */
+    public Color getLabelColor() {
+        return this.labelColor;
+    }
+
+
+    /** Set color with which to paint label bg. */
+    public void setLabelBGColor(Color color) {
+        this.labelBGColor = color;
+    }
+
+
+    /** Get color with which label is painted. */
+    public Color getLabelBGColor() {
+        return this.labelBGColor;
+    }
+
+
+    public double getCalculatedArea() {
+        return positiveArea + negativeArea;
+    }
 
     /**
      * Sets color that is used if drawOutline is true.
@@ -403,7 +522,7 @@
      * The renderer can do nothing if it chooses.
      *
      * @param g2  the graphics device.
-     * @param dataArea  the area inside the axes.
+     * @param dataArea  the (visible) area inside the axes.
      * @param plot  the plot.
      * @param data  the data.
      * @param info  an optional info collection object to return data back to
@@ -433,6 +552,10 @@
         return 2;
     }
 
+
+    /**
+     * Adds x/y data to series.
+     */
     private static final void addSeries(
         DefaultXYDataset ds,
         Comparable       key,
@@ -487,13 +610,15 @@
             xs.add(x);
             return true;
         }
-        System.err.println("pushed smaller");
+        log.debug("pushed smaller");
         return false;
     }
 
     protected static List<XYDataset> splitByNaNsTwoSeries(
         XYDataset dataset
     ) {
+        boolean debug = log.isDebugEnabled();
+
         List<XYDataset> datasets = new ArrayList<XYDataset>();
 
         int N = dataset.getItemCount(0);
@@ -532,11 +657,11 @@
             for (; nj < M &&  Double.isNaN(dataset.getXValue(1, nj)); ++nj);
 
             if (ni == N && nj == M) { // no more splits
-                System.err.println("no more splits ....");
+                log.debug("no more splits ....");
                 for (; i < ni; ++i) {
                     double x = dataset.getXValue(0, i);
                     double y = dataset.getYValue(0, i);
-                    if (!Double.isNaN(x) 
+                    if (!Double.isNaN(x)
                     &&  !Double.isNaN(y)
                     &&  add(six, x)) {
                         siy.add(y);
@@ -560,8 +685,10 @@
                 break;
             }
 
-            System.err.println("ni: " + ni + " " + N);
-            System.err.println("nj: " + nj + " " + M);
+            if (debug) {
+                log.debug("ni: " + ni + " " + N);
+                log.debug("nj: " + nj + " " + M);
+            }
 
             double xni = ni < N
                 ? dataset.getXValue(0, ni)
@@ -597,15 +724,19 @@
                     pushxi = x; pushyi = y;
                 }
                 else { // x > xns: intersection
-                    System.err.println("xns: " + xns);
-                    System.err.println("x/y: " + x + " / " + y);
+                    if (debug) {
+                        log.debug("xns: " + xns);
+                        log.debug("x/y: " + x + " / " + y);
+                    }
                     int SIX = six.size();
                     if (SIX > 0) { // should always be true
                         double yns = Linear.linear(
                             xns,
-                            six.getQuick(SIX-1), x, 
+                            six.getQuick(SIX-1), x,
                             siy.getQuick(SIX-1), y);
-                        System.err.println("intersection at: " + yns);
+                        if (debug) {
+                            log.debug("intersection at: " + yns);
+                        }
                         if (add(six, xns)) {
                             siy.add(yns);
                         }
@@ -641,7 +772,9 @@
                             xns,
                             sjx.getQuick(SJX-1), x,
                             sjy.getQuick(SJX-1), y);
-                        System.err.println("intersection at: " + yns);
+                        if (debug) {
+                            log.debug("intersection at: " + yns);
+                        }
                         if (add(sjx, xns)) {
                             sjy.add(yns);
                         }
@@ -677,7 +810,7 @@
         for (; i < N; ++i) {
             double x = dataset.getXValue(0, i);
             double y = dataset.getXValue(0, i);
-            if (!Double.isNaN(x) 
+            if (!Double.isNaN(x)
             &&  !Double.isNaN(y)
             &&  add(six, x)) {
                 siy.add(y);
@@ -702,7 +835,9 @@
             datasets.add(ds);
         }
 
-        System.err.println("datasets after split: " + datasets.size());
+        if (debug) {
+            log.debug("datasets after split: " + datasets.size());
+        }
 
         return datasets;
     }
@@ -710,8 +845,8 @@
     public static List<XYDataset> splitByNaNs(XYDataset dataset)  {
 
         switch (dataset.getSeriesCount()) {
-            case 0: 
-                return Collections.emptyList();
+            case 0:
+                return Collections.<XYDataset>emptyList();
             case 1:
                 return splitByNaNsOneSeries(dataset);
             default: // two or more
@@ -719,6 +854,7 @@
         }
     }
 
+
     /**
      * Draws the visual representation of a single data item.
      *
@@ -752,7 +888,7 @@
         switch (pass) {
             case 0:
                 for (XYDataset ds: splitByNaNs(dataset)) {
-                    drawItemPass0(g2, dataArea, info, 
+                    drawItemPass0(g2, dataArea, info,
                         plot, domainAxis, rangeAxis,
                         ds, series, item, crosshairState);
                 }
@@ -762,6 +898,43 @@
                     plot, domainAxis, rangeAxis,
                     dataset, series, item, crosshairState);
         }
+
+        // Find geometric middle, calculate area and paint a string with it here.
+        if (pass == 1 && this.labelArea && areaLabelNumberFormat != null && areaLabelTamplate != null) {
+            double center_x = centroid.getX();
+            double center_y = centroid.getY();
+            center_x = domainAxis.valueToJava2D(center_x, dataArea,
+                plot.getDomainAxisEdge());
+            center_y = rangeAxis.valueToJava2D(center_y, dataArea,
+                plot.getRangeAxisEdge());
+
+            // Respect text-extend if text should appear really centered.
+
+            float area = 0f;
+            if (areaCalculationMode == CALCULATE_POSITIVE_AREA
+               || areaCalculationMode == CALCULATE_ALL_AREA) {
+                area += Math.abs(positiveArea);
+            }
+            if (areaCalculationMode == CALCULATE_NEGATIVE_AREA
+               || areaCalculationMode == CALCULATE_ALL_AREA) {
+                area += Math.abs(negativeArea);
+            }
+            if (area != 0f) {
+                Color oldColor = g2.getColor();
+                Font oldFont = g2.getFont();
+                g2.setFont(labelFont);
+                String labelText = String.format(this.areaLabelTamplate,
+                    areaLabelNumberFormat.format(area));
+                if (labelBGColor != null) {
+                    EnhancedLineAndShapeRenderer.drawTextBox(g2, labelText,
+                        (float)center_x, (float)center_y, labelBGColor);
+                }
+                g2.setColor(labelColor);
+                g2.drawString(labelText, (float)center_x, (float)center_y);
+                g2.setFont(oldFont);
+                g2.setColor(oldColor);
+            }
+        }
     }
 
     /**
@@ -1389,6 +1562,45 @@
                 || (l_subtrahendLast < l_minuendFirst));
     }
 
+
+    public void updateCentroid(Object [] xValues, Object [] yValues) {
+        double x = 0d, y = 0d;
+
+        for (int i = 0, N = xValues.length; i < N; ++i) {
+            x += ((Double)xValues[i]).doubleValue();
+            y += ((Double)yValues[i]).doubleValue();
+        }
+
+        x /= xValues.length;
+        y /= yValues.length;
+
+        centroidNPoints++;
+        double factorNew = 1d / centroidNPoints;
+        double factorOld = 1d - factorNew;
+
+        centroid = new Point2D.Double((factorNew * x + factorOld * centroid.x),
+            (factorNew * y + factorOld * centroid.y));
+    }
+
+
+    public static double calculateArea(Object [] xValues, Object [] yValues) {
+        double area = 0d;
+
+        for (int i = 0, N = xValues.length; i < N; ++i) {
+            int j = (i + 1) % N;
+            double xi = ((Double)xValues[i]).doubleValue();
+            double yi = ((Double)yValues[i]).doubleValue();
+            double xj = ((Double)xValues[j]).doubleValue();
+            double yj = ((Double)yValues[j]).doubleValue();
+
+            area += xi*yj;
+            area -= xj*yi;
+            // TODO centroid calculation here?
+        }
+
+        return 0.5d*area;
+    }
+
     /**
      * Draws the visual representation of a polygon
      *
@@ -1421,6 +1633,11 @@
         Object[] l_xValues = x_xValues.toArray();
         Object[] l_yValues = x_yValues.toArray();
 
+        double area = calculateArea(l_xValues, l_yValues)/2d;
+        if (x_positive) positiveArea += area;
+        else            negativeArea += area;
+        updateCentroid(l_xValues, l_yValues);
+
         GeneralPath l_path = new GeneralPath();
 
         if (PlotOrientation.VERTICAL == l_orientation) {
--- a/flys-artifacts/src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/jfree/StickyAxisAnnotation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,33 +2,6 @@
 
 import org.apache.log4j.Logger;
 
-import java.util.Iterator;
-
-import java.awt.Shape;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.Line2D;
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.BasicStroke;
-
-import org.jfree.chart.annotations.XYTextAnnotation;
-import org.jfree.chart.axis.ValueAxis;
-import org.jfree.chart.util.LineUtilities;
-import org.jfree.chart.plot.PlotOrientation;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.entity.XYAnnotationEntity;
-import org.jfree.chart.plot.PlotRenderingInfo;
-import org.jfree.chart.ChartRenderingInfo;
-import org.jfree.chart.plot.Plot;
-
-import org.jfree.data.Range;
-
-import org.jfree.text.TextUtilities;
-
-import org.jfree.ui.RectangleEdge;
-import org.jfree.ui.TextAnchor;
-
-import de.intevation.flys.utils.ThemeAccess;
 
 /**
  * Custom Annotations class that is drawn only if no collisions with other
@@ -36,55 +9,46 @@
  * the axis is shown in all cases, though.
  * Draws a given text and a line to it from either axis.
  */
-public class StickyAxisAnnotation extends XYTextAnnotation {
+public class StickyAxisAnnotation {
 
-    /** Logger for this class. */    
+    /** Logger for this class. */
     private static Logger logger =
         Logger.getLogger(StickyAxisAnnotation.class);
 
     /** Simplified view on axes. */
     public static enum SimpleAxis {
         X_AXIS, /** Usually "horizontal". */
-        Y_AXIS  /** Usually "vertical". */
+        Y_AXIS, /** Usually "vertical". */
+        Y_AXIS2
     }
 
+    /** The "symbolic" integer representing which axis to stick to. */
+    protected int axisSymbol;
+
     /** Which axis to stick to. */
     protected SimpleAxis stickyAxis = SimpleAxis.X_AXIS;
 
     /** The 1-dimensional position of this annotation. */
     protected float pos;
 
-    /** Theme attributes. */
-    protected Color textColor;
-    protected Color lineColor;
-    protected Font font;
-    protected int lineWidth;
-    protected String textOrientation = "vertical";
-    protected Color textBackground;
-    protected boolean showBackground;
-
-
     /**
-     * Trivial constructor.
-     *
-     * @param text Text to display.
-     * @param x    X-position in dataspace (typical horizontal, in km).
-     * @param y    Y-position in dataspace (typical vertical, in m).
-     * @deprecated
+     * Optional field used when from axis a line should be drawn that
+     * hits a curve or something similar (current scenario: duration curves).
+     * This value is in the "other" dimension than the pos - field.
      */
-    public StickyAxisAnnotation(String text, float x, float y) {
-        super(text, x, y);
-        setStickyAxis(SimpleAxis.X_AXIS);
-    }
+    protected float hitPoint;
+
+    /** The text to display at axis. */
+    String text;
 
 
     /**
      * Constructor with implicit sticky x-axis.
-     * @param text       the text to display.
-     * @param pos        the position at which to draw the text and mark.
+     * @param text the text to display.
+     * @param pos  the position at which to draw the text and mark.
      */
     public StickyAxisAnnotation(String text, float pos) {
-        this(text, pos, pos, SimpleAxis.X_AXIS);
+        this(text, pos, SimpleAxis.X_AXIS);
     }
 
 
@@ -92,25 +56,30 @@
      * Constructor with given explicit axis.
      * @param text       the text to display.
      * @param pos        the position at which to draw the text and mark.
-     * @param stickyAxis the axis at which to stick (and to which 'pos' is
+     * @param stickAxis the axis at which to stick (and to which 'pos' is
      *                   relative).
      */
-    public StickyAxisAnnotation(String text, float pos, SimpleAxis stickAxis) {
-        super(text, pos, pos);
-        setStickyAxis(stickAxis);
-        this.pos = pos;
+    public StickyAxisAnnotation(String text, float pos, SimpleAxis stickAxis
+    ) {
+        this(text, pos, stickAxis, 0);
     }
 
 
     /**
-     * Legacy-Constructor.
-     * @deprecated
+     * Constructor with given explicit axis and axisSymbol
+     * @param text       the text to display.
+     * @param pos        the position at which to draw the text and mark.
+     * @param stickAxis the axis at which to stick (and to which 'pos' is
+     *                   relative).
      */
-    public StickyAxisAnnotation(String text, float x, float y,
-            SimpleAxis stickAxis) {
-        super(text, x, y);
+    public StickyAxisAnnotation(String text, float pos, SimpleAxis stickAxis,
+            int axisSymbol
+    ) {
         setStickyAxis(stickAxis);
-        this.pos = x;
+        this.text   = text;
+        this.pos    = pos;
+        this.axisSymbol = axisSymbol;
+        this.hitPoint = Float.NaN;
     }
 
 
@@ -122,238 +91,50 @@
      */
     public void setStickyAxis(SimpleAxis stickyAxis) {
         this.stickyAxis = stickyAxis;
-        if (stickyAxis == SimpleAxis.X_AXIS){
-            float o = 270f;
-            if(textOrientation.equals("horizontal")) {
-                o = 0f;
-            }
-            this.setRotationAngle(o * (Math.PI / 180f));
-            this.setRotationAnchor(TextAnchor.CENTER_LEFT);
-            this.setTextAnchor(TextAnchor.CENTER_LEFT);
-        } else {
-            this.setRotationAngle(0f * (Math.PI / 180f));
-            this.setRotationAnchor(TextAnchor.CENTER_LEFT);
-            this.setTextAnchor(TextAnchor.CENTER_LEFT);
-        }
-    }
-
-
-    /**
-     * Draws a small line at axis where this annotation resides.
-     *
-     * @param g2          the graphics device.
-     * @param dataArea    the data area.
-     * @param domainAxis  the domain axis.
-     * @param rangeAxis   the range axis.
-     * @param domainEdge  the domain edge.
-     * @param rangeEdge   the range edge.
-     * @param orientation the plot orientation.
-     */
-    protected void drawAxisMark(
-            java.awt.Graphics2D g2,
-            java.awt.geom.Rectangle2D dataArea,
-            ValueAxis domainAxis,
-            ValueAxis rangeAxis,
-            RectangleEdge domainEdge,
-            RectangleEdge rangeEdge,
-            PlotOrientation orientation) {
-        float j2DX1 = 0.0f;
-        float j2DX2 = 0.0f;
-        float j2DY1 = 0.0f;
-        float j2DY2 = 0.0f;
-        float x = (float) getX();
-        float y = (float) getY();
-        /* When dependent on X/Y-Axis and orientation, following
-           can be used as a base:
-        if (orientation == PlotOrientation.VERTICAL) {
-            j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea,
-                        domainEdge);
-            j2DY1 = (float) rangeAxis.valueToJava2D(y, dataArea,
-                        rangeEdge);
-            j2DX2 = (float) domainAxis.valueToJava2D(x, dataArea,
-                        domainEdge);
-            j2DY2 = (float) rangeAxis.valueToJava2D(y, dataArea,
-                        rangeEdge);
-            }
-        else if (orientation == PlotOrientation.HORIZONTAL) {
-            j2DY1 = (float) domainAxis.valueToJava2D(x, dataArea,
-                    domainEdge);
-            j2DX1 = (float) rangeAxis.valueToJava2D(y, dataArea,
-                    rangeEdge);
-            j2DY2 = (float) domainAxis.valueToJava2D(x, dataArea,
-                    domainEdge);
-            j2DX2 = (float) rangeAxis.valueToJava2D(y, dataArea,
-                    rangeEdge);
-        }
-
-        g2.setPaint(this.paint);
-        g2.setStroke(this.stroke);
-        */
-        if (this.stickyAxis == SimpleAxis.X_AXIS) {
-            j2DY1 = (float) RectangleEdge.coordinate(dataArea, domainEdge);
-            double rangeLow = rangeAxis.getRange().getLowerBound();
-            // Line ends at 1.5% of full distance.
-            j2DY2 = (float) rangeAxis.valueToJava2D(
-                      (1f - 0.015f) * rangeLow + 0.015f * 
-                      rangeAxis.getRange().getUpperBound(),
-                     dataArea, rangeEdge);
-            j2DX1 = (float) domainAxis.valueToJava2D(x, dataArea, domainEdge);
-            j2DX2 = j2DX1;
-        } else {
-            j2DX1 = (float) RectangleEdge.coordinate(dataArea, rangeEdge);
-            Range domainRange = domainAxis.getRange();
-            double rangeLow = domainRange.getLowerBound();
-            // Line ends at 1.5% of full distance.
-            j2DX2 = (float) domainAxis.valueToJava2D(
-                      (1f - 0.015f) * rangeLow + 0.015f * 
-                      domainRange.getUpperBound(),
-                     dataArea, domainEdge);
-            j2DY1 = (float) rangeAxis.valueToJava2D(pos, dataArea, rangeEdge);
-            j2DY2 = j2DY1;
-        }
-
-        Line2D line = new Line2D.Float(j2DX1, j2DY1, j2DX2, j2DY2);
-
-        // line is clipped to avoid JRE bug 6574155, for more info
-        // see JFreeChart bug 2221495
-        boolean visible = LineUtilities.clipLine(line, dataArea);
-        if (visible) {
-            setOutlineStroke(new BasicStroke((float) lineWidth));
-            g2.setStroke(getOutlineStroke());
-            g2.setPaint(lineColor);
-            g2.draw(line);
-        }
     }
 
 
-    /**
-     * Draw the Annotation; the text only if it does not collide with other
-     * already drawn Annotations- texts.
-     *
-     * @param g2            the graphics device.
-     * @param plot          the plot.
-     * @param dataArea      the data area.
-     * @param domainAxis    the domain axis.
-     * @param rangeAxis     the range axis.
-     * @param rendererIndex the render index.
-     * @param info          state information, escpecially collects info about
-     *                      already drawn shapes (and thus annotations), used
-     *                      for collision detection.
-     */
-    @Override
-    public void draw(
-       java.awt.Graphics2D g2,
-       XYPlot plot,
-       java.awt.geom.Rectangle2D dataArea,
-       ValueAxis domainAxis,
-       ValueAxis rangeAxis,
-       int rendererIndex,
-       PlotRenderingInfo info) {
-
-        if (info == null)
-            return;
-
-        if (domainAxis == null || rangeAxis == null
-                || domainAxis.getRange()    == null
-                || rangeAxis.getRange()     == null
-                ) {
-            logger.error("Annotation cannot be drawn (missing axis).");
-            return;
-        }
-
-        // Calculate the bounding box.
-        ChartRenderingInfo chartInfo = info.getOwner();
-
-        PlotOrientation orientation = plot.getOrientation();
-        RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
-            plot.getDomainAxisLocation(), orientation);
-        RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
-            plot.getRangeAxisLocation(), orientation);
-        float anchorX = 0f;
-        float anchorY = 0.0f;
-        if (this.stickyAxis == SimpleAxis.X_AXIS) {
-            // Text starts at 2% of full distance.
-            float rangeLow = (float) rangeAxis.getRange().getLowerBound();
-            float y = rangeLow + 0.02f * ((float)
-                rangeAxis.getRange().getUpperBound() - rangeLow);
-            setY(y);
+    public float getPos() {
+        return this.pos;
+    }
 
-            anchorX = (float) domainAxis.valueToJava2D(
-                getX(), dataArea, domainEdge);
-            anchorY = (float) rangeAxis.valueToJava2D(
-                getY(), dataArea, rangeEdge);
-        } else {
-            float rangeLow = (float) domainAxis.getRange().getLowerBound();
-            float x = rangeLow + 0.02f * ((float)
-                domainAxis.getRange().getUpperBound() - rangeLow);
-            setX(x);
-            anchorX = (float) domainAxis.valueToJava2D(
-                getX(), dataArea, domainEdge);
-            anchorY = (float) rangeAxis.valueToJava2D(
-                getY(), dataArea, rangeEdge);
-        }
-        if (orientation == PlotOrientation.HORIZONTAL) {
-            float tempAnchor = anchorX;
-            anchorX = anchorY;
-            anchorY = tempAnchor;
-        }
-
-        //Call to apply orientation.
-        setStickyAxis(stickyAxis);
-
-        // Always draw the small line at axis.
-        drawAxisMark(g2, dataArea, domainAxis, rangeAxis, domainEdge,
-            rangeEdge, orientation);
+    public SimpleAxis getStickyAxis() {
+        return this.stickyAxis;
+    }
 
-        Shape hotspot = TextUtilities.calculateRotatedStringBounds(
-            getText(), g2, anchorX, anchorY, getTextAnchor(),
-            getRotationAngle(), getRotationAnchor());
-        Rectangle2D hotspotBox = hotspot.getBounds2D();
-        // Check for collisions with other XYAnnotations.
-        for (Iterator i = chartInfo.getEntityCollection().iterator();
-                i.hasNext(); ) {
-            Object next = i.next();
-            // Collision with other stuff than XYAnnotations are okay.
-            if (next instanceof XYAnnotationEntity) {
-                XYAnnotationEntity drawnShape = (XYAnnotationEntity) next;
-                if (drawnShape.getArea().intersects(hotspotBox)) {
-                    // Found collision, early stop.
-                    return;
-                }
-            }
-        }
+    public boolean atX() {
+        return this.getStickyAxis() == SimpleAxis.X_AXIS;
+    }
 
-        // Draw the background.
-        if (showBackground) {
-            g2.setStroke(new BasicStroke ((float) 1));
-            g2.setBackground(textBackground);
-            g2.setPaint(textBackground);
-            hotspot = TextUtilities.calculateRotatedStringBounds(
-                getText(), g2, anchorX, anchorY, getTextAnchor(),
-                getRotationAngle(), getRotationAnchor());
-            g2.fill(hotspot);
-            g2.draw(hotspot);
-        }
-
-        // Draw the text.
-        g2.setPaint(textColor);
-        g2.setFont(font);
-        TextUtilities.drawRotatedString(getText(), g2, anchorX, anchorY,
-            getTextAnchor(), getRotationAngle(), getRotationAnchor());
-
-        // Add info that we have drawn this Annotation.
-        addEntity(info, hotspot, rendererIndex, getToolTipText(), getURL());
+    /** Get text to be displayed at axis. */
+    public String getText() {
+        return this.text;
     }
 
 
-    public void applyTheme(ThemeAccess ta) {
-        lineWidth       = ta.parseLineWidth();
-        lineColor       = ta.parseLineColorField();
-        textColor       = ta.parseTextColor();
-        font            = ta.parseTextFont();
-        textOrientation = ta.parseTextOrientation();
-        textBackground  = ta.parseTextBackground();
-        showBackground  = ta.parseShowTextBackground();
+    public int getAxisSymbol() {
+        return this.axisSymbol;
+    }
+
+
+    /** Set where to hit a curve (if any). */
+    public void setHitPoint(float pos) {
+        this.hitPoint = pos;
+    }
+
+    /** Get where to hit a curve (if any). */
+    public float getHitPoint() {
+        return this.hitPoint;
+    }
+
+    /** Set sticky axis to the X axis if it is currently Y, and vice versa. */
+    public void flipStickyAxis() {
+        if (this.getStickyAxis() == SimpleAxis.X_AXIS) {
+            this.setStickyAxis(SimpleAxis.Y_AXIS);
+        }
+        else {
+            this.setStickyAxis(SimpleAxis.X_AXIS);
+        }
     }
 }
 // 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/jfree/Style.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.jfree;
+
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public interface Style {
+
+    XYLineAndShapeRenderer applyTheme(XYLineAndShapeRenderer r, int idx);
+
+    XYLineAndShapeRenderer getRenderer();
+}
+// 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/jfree/StyledAreaSeriesCollection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,162 @@
+package de.intevation.flys.jfree;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Stroke;
+
+import org.jfree.data.xy.XYSeriesCollection;
+import org.w3c.dom.Document;
+
+import de.intevation.flys.themes.ThemeAccess;
+import de.intevation.flys.utils.ThemeUtil;
+
+
+/**
+ * One or more dataseries to draw a polygon (either "open up/downwards", or
+ * the area between two curves), a theme-document and further display options.
+ * The theme-document will later "style" the graphical representation.
+ * The display options can be used to control the z-order and the axis of the
+ * dataset.
+ */
+public class StyledAreaSeriesCollection extends XYSeriesCollection {
+    private static final long serialVersionUID = 5274940965666948237L;
+
+    /** Mode, how to draw/which areas to fill. */
+    public enum FILL_MODE {UNDER, ABOVE, BETWEEN};
+
+    /** MODE in use. */
+    protected FILL_MODE mode;
+
+    /** The theme-document with attributes about actual visual representation. */
+    protected Document theme;
+
+
+    /**
+     * @param theme the theme-document.
+     */
+    public StyledAreaSeriesCollection(Document theme) {
+        this.theme = theme;
+        this.mode = FILL_MODE.BETWEEN;
+   }
+
+
+    /** Gets the Fill mode. */
+    public FILL_MODE getMode() {
+        return this.mode;
+    }
+
+
+    /** Sets the Fill mode. */
+    public void setMode(FILL_MODE fMode) {
+        this.mode = fMode;
+    }
+
+
+    /**
+     * Applies line color, size and type attributes to renderer, also
+     * whether to draw lines and/or points.
+     * @param renderer Renderer to apply theme to.
+     * @return \param renderer
+     */
+    public StableXYDifferenceRenderer applyTheme(
+        StableXYDifferenceRenderer renderer
+    ) {
+        applyFillColor(renderer);
+        applyShowShape(renderer);
+        applyOutlineColor(renderer);
+        applyOutlineStyle(renderer);
+        applyShowArea(renderer);
+        if (mode == FILL_MODE.UNDER) {
+            renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_NEGATIVE_AREA);
+        }
+        else if (mode == FILL_MODE.ABOVE) {
+            renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_POSITIVE_AREA);
+        }
+        else {
+            renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_ALL_AREA);
+        }
+
+        // Apply text style.
+        new ThemeAccess(theme).parseTextStyle().apply(renderer);
+        return renderer;
+    }
+
+
+    protected void applyFillColor(StableXYDifferenceRenderer renderer) {
+        Color paint = ThemeUtil.parseColor(
+                ThemeUtil.getBackgroundColorString(theme));
+
+        int transparency = ThemeUtil.parseTransparency(theme);
+        if (transparency > 0) {
+            paint = new Color(
+                        paint.getRed(),
+                        paint.getGreen(),
+                        paint.getBlue(),
+                        (int)((100 - transparency) * 2.55f));
+        }
+
+        if (paint != null && this.getMode() == FILL_MODE.ABOVE) {
+            renderer.setPositivePaint(paint);
+            renderer.setNegativePaint(new Color(0,0,0,0));
+        }
+        else if (paint != null && this.getMode() == FILL_MODE.UNDER) {
+            renderer.setNegativePaint(paint);
+            renderer.setPositivePaint(new Color(0,0,0,0));
+        }
+        else {
+            if (paint == null)
+                paint = new Color(177, 117, 102);
+            renderer.setPositivePaint(paint);
+            renderer.setNegativePaint(paint);
+        }
+    }
+
+
+    protected void applyShowShape(StableXYDifferenceRenderer renderer) {
+        boolean show = ThemeUtil.parseShowBorder(theme);
+        renderer.setDrawOutline(show);
+    }
+
+
+    protected void applyShowLine(StableXYDifferenceRenderer renderer) {
+        boolean show = ThemeUtil.parseShowLine(theme);
+        renderer.setShapesVisible(show);
+    }
+
+
+    protected void applyOutlineColor(StableXYDifferenceRenderer renderer) {
+        Color c = ThemeUtil.parseLineColorField(theme);
+        renderer.setOutlinePaint(c);
+    }
+
+    protected void applyOutlineWidth(StableXYDifferenceRenderer renderer) {
+        int size = ThemeUtil.parseLineWidth(theme);
+    }
+
+    /** Inform renderer whether it should draw a label. */
+    protected void applyShowArea(StableXYDifferenceRenderer renderer) {
+        renderer.setLabelArea(ThemeUtil.parseShowArea(theme));
+    }
+
+    protected void applyOutlineStyle(StableXYDifferenceRenderer renderer) {
+        float[] dashes = ThemeUtil.parseLineStyle(theme);
+        int size       = ThemeUtil.parseLineWidth(theme);
+
+        Stroke stroke = null;
+
+        if (dashes.length <= 1) {
+            stroke = new BasicStroke(Integer.valueOf(size));
+        }
+        else {
+            stroke = new BasicStroke(Integer.valueOf(size),
+                BasicStroke.CAP_BUTT,
+                BasicStroke.JOIN_ROUND,
+                1.0f,
+                dashes,
+                0.0f);
+        }
+
+        renderer.setOutlineStroke(stroke);
+    }
+}
+// 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/jfree/StyledDomainMarker.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,51 @@
+package de.intevation.flys.jfree;
+
+import java.awt.Color;
+
+import org.jfree.chart.plot.IntervalMarker;
+import org.w3c.dom.Document;
+
+import de.intevation.flys.utils.ThemeUtil;
+
+/**
+ * Marker that represents a highlighted interval.
+ *
+ * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a>
+ */
+public class StyledDomainMarker extends IntervalMarker {
+
+    private static final long serialVersionUID = -4369417661339512342L;
+
+    private final Color fillColor, backgroundColor;
+
+    public StyledDomainMarker(double start, double end, Document theme) {
+        super(start, end);
+
+        backgroundColor = ThemeUtil.parseColor(
+                ThemeUtil.getBackgroundColorString(theme));
+        fillColor = ThemeUtil.parseColor(
+                ThemeUtil.getFillColorString(theme));
+        useSecondColor(false);
+
+        int alpha = 100 - ThemeUtil.parseInteger(
+                ThemeUtil.getTransparencyString(theme), 50);
+        setAlpha(alpha / 100.0f);
+    }
+
+    /**
+     * To properly differentiate several styled domain markers side by side,
+     * we can use this switch to toggle between two colors.
+     * @param secondColor
+     */
+    public void useSecondColor(boolean secondColor) {
+        if(secondColor) {
+            if(backgroundColor != null)
+                setPaint(backgroundColor);
+        }
+        else {
+            if(fillColor != null)
+                setPaint(fillColor);
+        }
+    }
+}
+// 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/jfree/StyledSeries.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,13 @@
+package de.intevation.flys.jfree;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public interface StyledSeries {
+
+    void setStyle(Style style);
+
+    Style getStyle();
+}
+// 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/jfree/StyledTimeSeries.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,39 @@
+package de.intevation.flys.jfree;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+import org.jfree.data.time.TimeSeries;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class StyledTimeSeries extends TimeSeries implements StyledSeries {
+
+    private static final Logger logger =
+        Logger.getLogger(StyledTimeSeries.class);
+
+
+    protected Style style;
+
+
+    public StyledTimeSeries(String key, Document theme) {
+        super(key);
+        setStyle(new XYStyle(theme));
+    }
+
+
+    @Override
+    public void setStyle(Style style) {
+        this.style = style;
+    }
+
+
+    @Override
+    public Style getStyle() {
+        return style;
+    }
+}
+// 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/jfree/StyledValueMarker.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,32 @@
+package de.intevation.flys.jfree;
+
+import de.intevation.flys.utils.ThemeUtil;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+
+import org.jfree.chart.plot.ValueMarker;
+import org.w3c.dom.Document;
+
+/**
+ * Marker that represents a single value.
+ * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a>
+ */
+public class StyledValueMarker extends ValueMarker {
+
+    private static final long serialVersionUID = -3607777705307785140L;
+
+    public StyledValueMarker(double value, Document theme) {
+        super(value);
+
+        Color color = ThemeUtil.parsePointColor(theme);
+        if(color == null) {
+            color = Color.BLACK;
+        }
+        this.setPaint(color);
+
+        int size = ThemeUtil.parsePointWidth(theme);
+        setStroke(new BasicStroke(size));
+    }
+}
+// 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/jfree/StyledXYSeries.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,82 @@
+package de.intevation.flys.jfree;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+
+import org.jfree.data.xy.XYDataItem;
+import org.jfree.data.xy.XYSeries;
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class StyledXYSeries extends XYSeries implements StyledSeries, HasLabel {
+
+    private static final Logger logger = Logger.getLogger(StyledXYSeries.class);
+
+    protected Style style;
+
+    /** If this Series is to be labelled, use this String as label. */
+    protected String label;
+
+
+    public StyledXYSeries(String key, Document theme) {
+        this(key, true, theme);
+        this.label = key.toString();
+    }
+
+
+    public StyledXYSeries(String key, Document theme, XYSeries unstyledSeries) {
+        this(key, theme);
+        add(unstyledSeries);
+    }
+
+
+    /**
+     * @param sorted whether or not to sort the points. Sorting will move NANs
+     *               to one extrema which can cause problems in certain
+     *               algorithms.
+     */
+    public StyledXYSeries(String key, boolean sorted, Document theme) {
+        super(key, sorted);
+        setStyle(new XYStyle(theme));
+        this.label = key.toString();
+    }
+
+
+    @Override
+    public void setStyle(Style style) {
+        this.style = style;
+    }
+
+
+    @Override
+    public Style getStyle() {
+        return style;
+    }
+
+
+    @Override
+    public String getLabel() {
+        return label;
+    }
+
+    @Override
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    protected void add(XYSeries series) {
+        List<XYDataItem> items = series.getItems();
+        add(items);
+    }
+
+    protected void add(List<XYDataItem> items) {
+        for(XYDataItem item : items) {
+            add(item.getXValue(), item.getYValue());
+        }
+    }
+}
+// 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/jfree/TimeBounds.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,88 @@
+package de.intevation.flys.jfree;
+
+import java.util.Date;
+
+import org.jfree.chart.axis.DateAxis;
+import org.jfree.chart.axis.ValueAxis;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class TimeBounds implements Bounds {
+
+    protected long lower;
+    protected long upper;
+
+
+    public TimeBounds(long lower, long upper) {
+        this.lower = lower;
+        this.upper = upper;
+    }
+
+
+    @Override
+    public Number getLower() {
+        return Long.valueOf(lower);
+    }
+
+
+    public Date getLowerAsDate() {
+        return new Date(lower);
+    }
+
+
+    @Override
+    public Number getUpper() {
+        return Long.valueOf(upper);
+    }
+
+
+    public Date getUpperAsDate() {
+        return new Date(upper);
+    }
+
+
+    @Override
+    public void applyBounds(ValueAxis axis) {
+        DateAxis dateAxis = (DateAxis) axis;
+
+        dateAxis.setMinimumDate(new Date(lower));
+        dateAxis.setMaximumDate(new Date(upper));
+    }
+
+
+    @Override
+    public void applyBounds(ValueAxis axis, int percent) {
+        DateAxis dateAxis = (DateAxis) axis;
+
+        long space = (upper - lower) / 100 * percent;
+
+        dateAxis.setMinimumDate(new Date(lower-space));
+        dateAxis.setMaximumDate(new Date(upper+space));
+    }
+
+
+    @Override
+    public Bounds combine(Bounds bounds) {
+        if (bounds == null) {
+            return this;
+        }
+
+        TimeBounds other = (TimeBounds) bounds;
+
+        long otherLower = other.getLower().longValue();
+        long otherUpper = other.getUpper().longValue();
+
+        return new TimeBounds(
+            otherLower < lower ? otherLower : lower,
+            otherUpper > upper ? otherUpper : upper);
+    }
+
+
+    @Override
+    public String toString() {
+        return "TimeBounds=["+ getLowerAsDate() + " ; " + getUpperAsDate() +"]";
+    }
+}
+// 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/jfree/XYStyle.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,229 @@
+package de.intevation.flys.jfree;
+
+import de.intevation.flys.utils.ThemeUtil;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.geom.Ellipse2D;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.w3c.dom.Document;
+
+
+/**
+ * Utility to apply theme-settings to a renderer.
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class XYStyle implements Style {
+
+    private static Logger logger = Logger.getLogger(XYStyle.class);
+
+    protected Document theme;
+
+    protected XYLineAndShapeRenderer renderer;
+
+
+    public XYStyle(Document theme) {
+        this.theme = theme;
+        this.renderer = null;
+    }
+
+
+    /**
+     * Applies line color, size and type attributes to renderer, also
+     * whether to draw lines and/or points.
+     */
+    @Override
+    public XYLineAndShapeRenderer applyTheme(XYLineAndShapeRenderer r, int idx){
+        this.renderer = r;
+        applyLineColor(r, idx);
+        applyLineSize(r, idx);
+        applyLineType(r, idx);
+        applyShowLine(r, idx);
+        applyShowPoints(r, idx);
+        applyPointSize(r, idx);
+        applyPointColor(r, idx);
+        applyShowMinimum(r, idx);
+        applyShowMaximum(r, idx);
+
+        // Line label styles
+        applyShowLineLabel(r, idx);
+        applyShowLineLabelBG(r, idx);
+        applyLineLabelFont(r, idx);
+        applyLineLabelColor(r, idx);
+        applyLineLabelBGColor(r, idx);
+
+        // Point label styles
+        // TODO: Currently point label are annotations and are not drawn this way
+        /*
+        applyShowPointLabelBG(r, idx);
+        applyLinePointFont(r, idx);
+        applyLinePointColor(r, idx);
+        applyLinePointBGColor(r, idx);*/
+
+        return r;
+    }
+
+
+    /** Set line color to renderer. */
+    protected void applyLineColor(XYLineAndShapeRenderer r, int idx) {
+        Color c = ThemeUtil.parseLineColorField(theme);
+        if(c != null) {
+            logger.debug("applyLineColor " + c.toString());
+            r.setSeriesPaint(idx, c);
+        }
+        else {
+            logger.warn("applyLineColor: color is null - malformed linecolor field?");
+        }
+    }
+
+
+    /** Tells the renderer whether or not to add a label to a line. */
+    protected void applyShowLineLabel(XYLineAndShapeRenderer r, int idx) {
+        if (!(r instanceof EnhancedLineAndShapeRenderer)) {
+            return;
+        }
+        boolean showLabelLine = ThemeUtil.parseShowLineLabel(theme);
+        boolean anyLabel = showLabelLine || ThemeUtil.parseShowWidth(theme) ||
+                           ThemeUtil.parseShowLevel(theme) ||
+                           ThemeUtil.parseShowMiddleHeight(theme);
+        ((EnhancedLineAndShapeRenderer)r).setShowLineLabel(anyLabel, idx);
+    }
+
+
+    /** Tells the renderer whether or not to fill the bg of a lines label. */
+    protected void applyShowLineLabelBG(XYLineAndShapeRenderer r, int idx) {
+        if (!(r instanceof EnhancedLineAndShapeRenderer)) {
+            return;
+        }
+        boolean showLabelLine = ThemeUtil.parseLabelShowBackground(theme);
+        ((EnhancedLineAndShapeRenderer)r).setShowLineLabelBG(idx, showLabelLine);
+    }
+
+    /** Tell the renderer which font (and -size and -style) to use for
+     * linelabels. */
+    protected void applyLineLabelFont(XYLineAndShapeRenderer r, int idx) {
+        if (!(r instanceof EnhancedLineAndShapeRenderer)) {
+            return;
+        }
+        ((EnhancedLineAndShapeRenderer)r).setLineLabelFont(
+                ThemeUtil.parseTextFont(theme), idx);
+    }
+
+    /** Tell the renderer which color to use for
+     * linelabels. */
+    protected void applyLineLabelColor(XYLineAndShapeRenderer r, int idx) {
+        if (!(r instanceof EnhancedLineAndShapeRenderer)) {
+            return;
+        }
+        ((EnhancedLineAndShapeRenderer)r).setLineLabelTextColor(
+                idx, ThemeUtil.parseTextColor(theme));
+    }
+
+    /** Tell the renderer which color to use for bg of
+     * linelabels. */
+    protected void applyLineLabelBGColor(XYLineAndShapeRenderer r, int idx) {
+        if (!(r instanceof EnhancedLineAndShapeRenderer)) {
+            return;
+        }
+        ((EnhancedLineAndShapeRenderer)r).setLineLabelBGColor(idx,
+            ThemeUtil.parseTextBackground(theme));
+    }
+
+    /** Set stroke of series. */
+    protected void applyLineSize(XYLineAndShapeRenderer r, int idx) {
+        int size = ThemeUtil.parseLineWidth(theme);
+        r.setSeriesStroke(
+            idx,
+            new BasicStroke(size));
+    }
+
+
+    /** Set stroke strength of series. */
+    protected void applyLineType(XYLineAndShapeRenderer r, int idx) {
+        int size = ThemeUtil.parseLineWidth(theme);
+        float[] dashes = ThemeUtil.parseLineStyle(theme);
+
+        // Do not apply the dashed style.
+        if (dashes.length <= 1) {
+            return;
+        }
+
+        r.setSeriesStroke(
+            idx,
+            new BasicStroke(size,
+                            BasicStroke.CAP_BUTT,
+                            BasicStroke.JOIN_ROUND,
+                            1.0f,
+                            dashes,
+                            0.0f));
+    }
+
+
+    protected void applyPointSize(XYLineAndShapeRenderer r, int idx) {
+        int size = ThemeUtil.parsePointWidth(theme);
+        int dim  = 2 * size;
+
+        r.setSeriesShape(idx, new Ellipse2D.Double(-size, -size, dim, dim));
+    }
+
+
+    protected void applyPointColor(XYLineAndShapeRenderer r, int idx) {
+        Color c = ThemeUtil.parsePointColor(theme);
+
+        if (c != null) {
+            r.setSeriesFillPaint(idx, c);
+            r.setUseFillPaint(true);
+            r.setDrawOutlines(false);
+        }
+    }
+
+
+    /**
+     * Sets form and visibility of points.
+     */
+    protected void applyShowPoints(XYLineAndShapeRenderer r, int idx) {
+        boolean show = ThemeUtil.parseShowPoints(theme);
+
+        r.setSeriesShapesVisible(idx, show);
+        r.setDrawOutlines(true);
+    }
+
+
+    protected void applyShowLine(XYLineAndShapeRenderer r, int idx) {
+        boolean show = ThemeUtil.parseShowLine(theme);
+        r.setSeriesLinesVisible(idx, show);
+    }
+
+
+    protected void applyShowMinimum(XYLineAndShapeRenderer r, int idx) {
+        if (!(r instanceof EnhancedLineAndShapeRenderer)) {
+            return;
+        }
+
+        boolean visible = ThemeUtil.parseShowMinimum(theme);
+
+        EnhancedLineAndShapeRenderer er = (EnhancedLineAndShapeRenderer) r;
+        er.setIsMinimumShapeVisisble(idx, visible);
+    }
+
+
+    protected void applyShowMaximum(XYLineAndShapeRenderer r, int idx) {
+        if (!(r instanceof EnhancedLineAndShapeRenderer)) {
+            return;
+        }
+
+        boolean visible = ThemeUtil.parseShowMaximum(theme);
+
+        EnhancedLineAndShapeRenderer er = (EnhancedLineAndShapeRenderer) r;
+        er.setIsMaximumShapeVisible(idx, visible);
+    }
+
+
+    @Override
+    public XYLineAndShapeRenderer getRenderer() {
+        return this.renderer;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/themes/DefaultTheme.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/DefaultTheme.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,7 +1,6 @@
 package de.intevation.flys.themes;
 
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 
 import org.w3c.dom.Document;
@@ -154,17 +153,14 @@
      * @param theme The document root element.
      */
     protected void appendAttributes(ElementCreator cr, Element theme) {
-        Iterator<String> iter = attr.keySet().iterator();
 
-        while (iter.hasNext()) {
-            String key = iter.next();
-            String val = getAttribute(key);
+        for (Map.Entry<String, String> entry: attr.entrySet()) {
+            String key = entry.getKey();
+            String val = entry.getValue();
 
-            if (key == null || val == null) {
-                continue;
+            if (key != null && val != null) {
+                cr.addAttr(theme, key, val);
             }
-
-            cr.addAttr(theme, key, val);
         }
     }
 
@@ -176,12 +172,10 @@
      * @param theme The document root element.
      */
     protected void appendFields(ElementCreator cr, Element theme) {
-        Iterator<String> iter = fields.keySet().iterator();
 
-        while (iter.hasNext()) {
-            String name = iter.next();
-
-            ThemeField field = getField(name);
+        for (Map.Entry<String, ThemeField> entry: fields.entrySet()) {
+            String     name  = entry.getKey();
+            ThemeField field = entry.getValue();
 
             Document doc = field.toXML();
             Node    root = doc.getFirstChild();
--- a/flys-artifacts/src/main/java/de/intevation/flys/themes/DefaultThemeField.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/DefaultThemeField.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,7 +1,6 @@
 package de.intevation.flys.themes;
 
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 
 import org.w3c.dom.Document;
@@ -68,13 +67,8 @@
 
         Element field = cr.create("field");
 
-        Iterator<String> iter = attr.keySet().iterator();
-
-        while (iter.hasNext()) {
-            String name  = iter.next();
-            String value = (String) getAttribute(name);
-
-            cr.addAttr(field, name, value);
+        for (Map.Entry<String, Object> entry: attr.entrySet()) {
+            cr.addAttr(field, entry.getKey(), (String)entry.getValue());
         }
 
         doc.appendChild(field);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/LineStyle.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,21 @@
+package de.intevation.flys.themes;
+
+import java.awt.Color;
+
+public class LineStyle {
+    protected Color lineColor;
+    protected int   lineWidth;
+
+    public LineStyle(Color color, int width) {
+        this.lineColor = color;
+        this.lineWidth = width;
+    }
+
+    public int getWidth() {
+        return lineWidth;
+    }
+
+    public Color getColor() {
+        return lineColor;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/PointStyle.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,5 @@
+package de.intevation.flys.themes;
+
+public class PointStyle {
+    // TODO tbd
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/TextStyle.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,52 @@
+package de.intevation.flys.themes;
+
+import de.intevation.flys.jfree.StableXYDifferenceRenderer;
+
+import java.awt.Color;
+import java.awt.Font;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.annotations.XYTextAnnotation;
+
+public class TextStyle {
+    @SuppressWarnings("unused")
+    private static Logger log = Logger.getLogger(TextStyle.class);
+
+    protected Color   textColor;
+    protected Font    font;
+    protected Color   bgColor;
+    protected boolean showBg;
+    protected boolean isVertical;
+
+    public TextStyle(Color fgColor, Font font, Color bgColor,
+        boolean showBg, boolean isVertical
+    ) {
+        this.textColor  = fgColor;
+        this.font       = font;
+        this.bgColor    = bgColor;
+        this.showBg     = showBg;
+        this.isVertical = isVertical;
+    }
+
+    public void apply(XYTextAnnotation ta) {
+        ta.setPaint(textColor);
+        ta.setFont(font);
+        if (this.showBg) {
+            ta.setBackgroundPaint(bgColor);
+        }
+        if (this.isVertical) {
+            ta.setRotationAngle(270f*Math.PI/180f);
+        }
+        else {
+            ta.setRotationAngle(0);
+        }
+    }
+
+    public void apply(StableXYDifferenceRenderer renderer) {
+        renderer.setLabelColor(textColor);
+        renderer.setLabelFont(font);
+        if (this.showBg) {
+            renderer.setLabelBGColor(bgColor);
+        }
+    }
+}
\ No newline at end of file
--- a/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeAccess.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeAccess.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,4 +1,6 @@
-package de.intevation.flys.utils;
+package de.intevation.flys.themes;
+
+import de.intevation.flys.utils.ThemeUtil;
 
 import java.awt.Color;
 import java.awt.Font;
@@ -18,11 +20,14 @@
     protected String  textOrientation;
     protected Color   textBackground;
     protected Boolean showTextBackground;
+    protected Color   pointColor;
+
 
     public ThemeAccess(Document theme) {
         this.theme = theme;
     }
 
+
     public int parseLineWidth() {
         if (lineWidth == null) {
             lineWidth = ThemeUtil.parseLineWidth(theme);
@@ -30,6 +35,7 @@
         return lineWidth;
     }
 
+
     public Color parseLineColorField() {
         if (lineColor == null) {
             lineColor = ThemeUtil.parseLineColorField(theme);
@@ -40,6 +46,7 @@
         return lineColor;
     }
 
+
     public Color parseTextColor() {
         if (textColor == null) {
             textColor = ThemeUtil.parseTextColor(theme);
@@ -50,6 +57,7 @@
         return textColor;
     }
 
+
     public Font parseTextFont() {
         if (font == null) {
             font = ThemeUtil.parseTextFont(theme);
@@ -60,12 +68,10 @@
         return font;
     }
 
+
     public String parseTextOrientation() {
         if (textOrientation == null) {
             textOrientation = ThemeUtil.parseTextOrientation(theme);
-            if (textOrientation == null) {
-                textOrientation = "horizontal";
-            }
         }
         return textOrientation;
     }
@@ -81,16 +87,38 @@
         return textBackground;
     }
 
-    public boolean parseShowTextBackground() {
+    public boolean parseLabelShowBackground() {
         if (showTextBackground == null) {
-            showTextBackground = ThemeUtil.parseShowTextBackground(theme);
+            showTextBackground = ThemeUtil.parseLabelShowBackground(theme);
         }
         return showTextBackground;
     }
 
-    /**
-    more of this
-    */
 
+    public Color parsePointColor() {
+        if (pointColor == null) {
+            pointColor = ThemeUtil.parsePointColor(theme);
+
+            if (pointColor == null) {
+                return parseLineColorField();
+            }
+        }
+
+        return pointColor;
+    }
+
+
+    public LineStyle parseLineStyle() {
+        return new LineStyle(parseLineColorField(), Integer.valueOf(parseLineWidth()));
+    }
+
+    public TextStyle parseTextStyle() {
+        return new TextStyle(
+            parseTextColor(),
+            parseTextFont(),
+            parseTextBackground(),
+            parseLabelShowBackground(),
+            !parseTextOrientation().equals("horizontal"));
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,22 +1,23 @@
 package de.intevation.flys.themes;
 
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.context.FLYSContext;
+
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import javax.xml.xpath.XPathConstants;
 
 import org.apache.log4j.Logger;
-
 import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.flys.artifacts.context.FLYSContext;
-import de.intevation.flys.artifacts.FLYSArtifact;
-
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  *
@@ -70,9 +71,13 @@
         FLYSContext c,
         String name,
         String pattern,
-        String output)
+        String output,
+        String groupName)
     {
-        logger.debug("Search theme for: " + name + " - pattern: " + pattern);
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "Search theme for: " + name + " - pattern: " + pattern);
+        }
 
         if (c == null || name == null) {
             logger.warn("Cannot search for theme.");
@@ -80,15 +85,32 @@
         }
 
         // Fetch mapping and themes.
+        @SuppressWarnings("unchecked")
         Map<String, List<ThemeMapping>> map = (Map<String, List<ThemeMapping>>)
             c.get(FLYSContext.THEME_MAPPING);
 
-        Map<String, Theme> t = (Map<String, Theme>)
+        @SuppressWarnings("unchecked")
+        List<ThemeGroup> tgs = (List<ThemeGroup>)
             c.get(FLYSContext.THEMES);
 
+        ThemeGroup group = null;
+        for (ThemeGroup tg: tgs) {
+            if (tg.getName().equals(groupName)) {
+                group = tg;
+                break;
+            }
+        }
+
+        if (group == null) {
+            logger.warn("No theme group found: '" + groupName + "'");
+            return null;
+        }
+
+        Map<String, Theme> t = group.getThemes();
+
         FLYSArtifact artifact = (FLYSArtifact) c.get(FLYSContext.ARTIFACT_KEY);
 
-        if (map == null || map.size() == 0 || t == null || t.size() == 0) {
+        if (map == null || map.isEmpty() || t == null || t.isEmpty()) {
             logger.warn("No mappings or themes found. Cannot retrieve theme!");
             return null;
         }
@@ -107,7 +129,10 @@
                 && tm.masterAttrMatches(artifact)
                 && tm.outputMatches(output))
             {
-                return t.get(tm.getTo());
+                String target = tm.getTo();
+
+                logger.debug("Found theme '" + target + "'");
+                return t.get(target);
             }
         }
 
@@ -121,23 +146,54 @@
     }
 
 
+    @SuppressWarnings("unchecked")
+    public static List<ThemeGroup> getThemeGroups(FLYSContext c) {
+        List<ThemeGroup> tgs = (List<ThemeGroup>)
+            c.get(FLYSContext.THEMES);
+        return tgs;
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static List<Theme> getThemes (FLYSContext c, String name) {
+        List<ThemeGroup> tgs = (List<ThemeGroup>)
+            c.get(FLYSContext.THEMES);
+        if (tgs == null) {
+            return null;
+        }
+
+        List<Theme> themes = new ArrayList<Theme>();
+        for (ThemeGroup tg: tgs) {
+            themes.add(tg.getThemeByName(name));
+        }
+        return themes;
+    }
+
     protected static String getName(Node config) {
-        return (String) XMLUtils.xpath(config, "@name", XPathConstants.STRING);
+        return ((Element)config).getAttribute("name");
     }
 
 
     protected static String getDescription(Node config) {
-        return (String) XMLUtils.xpath(config, "@desc", XPathConstants.STRING);
+        return ((Element)config).getAttribute("desc");
     }
 
 
     protected static void parseInherits(Document themeCfg, Node cfg, Theme t) {
+        parseInherits(themeCfg, cfg, t, null);
+    }
+
+    protected static void parseInherits(
+        Document themeCfg,
+        Node     cfg,
+        Theme    t,
+        Map<String, Node> themes
+    ) {
         logger.debug("ThemeFactory.parseInherits");
 
-        NodeList inherits = (NodeList) XMLUtils.xpath(
-            cfg, "inherits/inherit", XPathConstants.NODESET);
+        NodeList inherits = ((Element)cfg).getElementsByTagName("inherit");
 
-        int num = inherits != null ? inherits.getLength() : 0;
+        int num = inherits.getLength();
 
         if (num == 0) {
             logger.debug("Theme does not inherit from other themes.");
@@ -146,30 +202,36 @@
 
         logger.debug("Theme inherits from " + num + " other themes.");
 
+        if (themes == null) {
+            themes = buildThemeMap(themeCfg);
+        }
+
         for (int i = 0; i < num; i++) {
             Node inherit = inherits.item(i);
-            String from  = (String) XMLUtils.xpath(
-                inherit, "@from", XPathConstants.STRING);
+            String from = ((Element)inherit).getAttribute("from");
 
-            Node tmp = getThemeNode(themeCfg, from);
+            Node tmp = themes.get(from);
 
-            parseInherits(themeCfg, tmp, t);
+            parseInherits(themeCfg, tmp, t, themes);
             parseFields(tmp, t);
         }
     }
 
+    protected static Map<String, Node> buildThemeMap(Document themeCfg) {
+        Map<String, Node> map = new HashMap<String, Node>();
+        String xpath = "/themes/themegroup/theme";
 
-    protected static Node getThemeNode(Document themeCfg, String name) {
-        if (name == null) {
-            logger.warn("Cannot search theme config without name!");
-            return null;
+        NodeList nodes = (NodeList)XMLUtils.xpath(
+            themeCfg, xpath, XPathConstants.NODESET);
+
+        if (nodes != null) {
+            for (int i = 0, N = nodes.getLength(); i < N; ++i) {
+                Node node = nodes.item(i);
+                String name = ((Element)node).getAttribute("name");
+                map.put(name, node);
+            }
         }
-
-        logger.debug("Search for theme: " + name);
-
-        String xpath = "/themes/theme[@name='" + name + "']";
-
-        return (Node) XMLUtils.xpath(themeCfg, xpath, XPathConstants.NODE);
+        return map;
     }
 
 
@@ -179,10 +241,9 @@
             return;
         }
 
-        NodeList fields = (NodeList) XMLUtils.xpath(
-            config, "fields/field", XPathConstants.NODESET);
+        NodeList fields = ((Element)config).getElementsByTagName("field");
 
-        int num = fields != null ? fields.getLength() : 0;
+        int num = fields.getLength();
 
         logger.debug("Found " + num + " own fields in this theme.");
 
@@ -200,10 +261,9 @@
 
 
     protected static void addField(Theme theme, Node field) {
-        String name = (String) XMLUtils.xpath(
-            field, "@name", XPathConstants.STRING);
+        String name = ((Element)field).getAttribute("name");
 
-        logger.debug("Add field: " + name);
+        logger.debug("Add field " + name + " to theme " + theme.getName());
 
         NamedNodeMap attrs = field.getAttributes();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeGroup.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,32 @@
+package de.intevation.flys.themes;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class ThemeGroup {
+
+    protected String name;
+
+    protected Map<String, Theme> themes;
+
+
+    public ThemeGroup(String name, Map<String, Theme> themes) {
+        this.name = name;
+        this.themes = themes;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public Map<String, Theme> getThemes() {
+        return this.themes;
+    }
+
+    public Theme getThemeByName(String name) {
+        return themes.get(name);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeMapping.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/themes/ThemeMapping.java	Fri Sep 28 12:15:52 2012 +0200
@@ -84,11 +84,20 @@
      * @return true if pattern matches text or pattern is empty.
      */
     public boolean applyPattern(String text) {
-        if (patternStr == null || patternStr.equals("")) {
+        if (patternStr == null || patternStr.length() == 0) {
             return true;
         }
         Matcher m = pattern.matcher(text);
-        return m.matches();
+
+       if (m.matches()) {
+           logger.debug("Pattern matches: " + text);
+           return true;
+       }
+       else {
+           logger.debug(
+               "Pattern '"+ text + "' does not match: " + this.patternStr);
+           return false;
+       }
     }
 
 
@@ -103,7 +112,7 @@
      * @return true if no condition is specified or condition is met.
      */
     public boolean masterAttrMatches(FLYSArtifact artifact) {
-        if (masterAttr == null || masterAttr.equals("")) {
+        if (masterAttr == null || masterAttr.length() == 0) {
            return true;
         }
 
@@ -116,7 +125,14 @@
         }
 
         // Test.
-        return artifact.getDataAsString(parts[0]).equals(parts[1]);
+        if (artifact.getDataAsString(parts[0]).equals(parts[1])) {
+            logger.debug("Matches master Attribute.");
+            return true;
+        }
+        else {
+            logger.debug("Does not match master Attribute.");
+            return false;
+        }
     }
 
 
@@ -125,11 +141,18 @@
      * in parameter output.
      */
     public boolean outputMatches(String output) {
-        if (this.output == null || this.output.equals("")) {
+        if (this.output == null || this.output.length() == 0) {
             return true;
         }
 
-        return this.output.equals(output);
+        if (this.output.equals(output)) {
+            logger.debug("Output matches this mapping: " + output);
+            return true;
+        }
+        else {
+            logger.debug("Output '"+ output +"' does not match: "+ this.output);
+            return false;
+        }
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/utils/DataUtil.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/DataUtil.java	Fri Sep 28 12:15:52 2012 +0200
@@ -13,13 +13,13 @@
     public static boolean guessWaterIncreasing(TDoubleArrayList data, float factor) {
         int N = data.size();
         if (N < 2) return false;
-    
+
         int samples = (int)(factor*N) + 1;
-    
+
         int up = 0;
-    
+
         Random rand = new Random();
-    
+
         for (int i = 0; i < samples; ++i) {
             int    pos2 = rand.nextInt(N-1) + 1;
             int    pos1 = rand.nextInt(pos2);
@@ -27,7 +27,7 @@
             double w2   = data.getQuick(pos2);
             if (w2 > w1) ++up;
         }
-    
+
         return up > samples/2;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/DateAverager.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,36 @@
+package de.intevation.flys.utils;
+
+import gnu.trove.TLongArrayList;
+
+import java.util.Date;
+
+public class DateAverager
+{
+   protected TLongArrayList dates;
+
+    public DateAverager() {
+        dates = new TLongArrayList();
+    }
+
+    public void add(Date date) {
+        dates.add(date.getTime());
+    }
+
+    public Date getAverage() {
+        int N = dates.size();
+        if (N == 0) {
+            return null;
+        }
+        long min = dates.min();
+        long sum = 0L;
+        for (int i = 0; i < N; ++i) {
+            sum += dates.getQuick(i) - min;
+        }
+        return new Date(min + (long)Math.round(sum/(double)N));
+    }
+
+    public void clear() {
+        dates.resetQuick();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/utils/DoubleUtil.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/DoubleUtil.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,12 +1,17 @@
 package de.intevation.flys.utils;
 
+import de.intevation.flys.artifacts.math.Linear;
+
+import gnu.trove.TDoubleArrayList;
+
 import java.util.Arrays;
 
-import de.intevation.flys.artifacts.math.Linear;
-
+import org.apache.log4j.Logger;
 
 public class DoubleUtil
 {
+    private static Logger log = Logger.getLogger(DoubleUtil.class);
+
     public static final double DEFAULT_STEP_PRECISION = 1e6;
 
     private DoubleUtil() {
@@ -132,5 +137,56 @@
 
         return out;
     }
+
+    public static final double [] fill(int N, double value) {
+        double [] result = new double[N];
+        Arrays.fill(result, value);
+        return result;
+    }
+
+    public interface SegmentCallback {
+        void newSegment(double from, double to, double [] values);
+    }
+
+    public static final void parseSegments(
+        String          input,
+        SegmentCallback callback
+    ) {
+        TDoubleArrayList vs = new TDoubleArrayList();
+
+        for (String segmentStr: input.split(":")) {
+            String [] parts = segmentStr.split(";");
+            if (parts.length < 3) {
+                log.warn("invalid segment: '" + segmentStr + "'");
+                continue;
+            }
+            try {
+                double from = Double.parseDouble(parts[0].trim());
+                double to   = Double.parseDouble(parts[1].trim());
+
+                vs.resetQuick();
+
+                for (String valueStr: parts[2].split(",")) {
+                    vs.add(round(Double.parseDouble(valueStr.trim())));
+                }
+
+                callback.newSegment(from, to, vs.toNativeArray());
+            }
+            catch (NumberFormatException nfe) {
+                log.warn("invalid segment: '" + segmentStr + "'");
+            }
+        }
+    }
+
+    public static final boolean isValid(double [][] data) {
+        for (double [] ds: data) {
+            for (double d: ds) {
+                if (Double.isNaN(d)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/utils/FLYSUtils.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/FLYSUtils.java	Fri Sep 28 12:15:52 2012 +0200
@@ -17,6 +17,8 @@
 import org.hibernate.impl.SessionFactoryImpl;
 
 import gnu.trove.TDoubleArrayList;
+import gnu.trove.TIntArrayList;
+import gnu.trove.TLongArrayList;
 
 import de.intevation.artifacts.Artifact;
 import de.intevation.artifacts.CallContext;
@@ -29,13 +31,22 @@
 import de.intevation.flys.artifacts.context.FLYSContext;
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.WINFOArtifact;
+import de.intevation.flys.artifacts.StaticWKmsArtifact;
 import de.intevation.flys.artifacts.model.RiverFactory;
 import de.intevation.flys.artifacts.model.LocationProvider;
 import de.intevation.flys.artifacts.model.WQ;
+import de.intevation.flys.artifacts.model.WKms;
+import de.intevation.flys.artifacts.model.WQKms;
+
+import de.intevation.artifactdatabase.state.State;
+import de.intevation.flys.artifacts.states.WaterlevelSelectState;
+import de.intevation.flys.artifacts.states.WDifferencesState;
 import de.intevation.flys.model.Gauge;
 import de.intevation.flys.model.MainValue;
 import de.intevation.flys.model.River;
 
+
+/** static helper methods to e.g. access FLYSArtifacts data. */
 public class FLYSUtils {
 
     /** The logger that is used in this utility. */
@@ -49,6 +60,12 @@
      */
     public static enum WQ_MODE { QFREE, QGAUGE, WFREE, WGAUGE, NONE };
 
+    /**
+     * An enum that represents the 4 possible WQ input modes in FLYS. The 4
+     * values are
+     * <i>ADAPTED</i> <i>SINGLE</i> <i>RANGE</i> and <i>NONE</i>.
+     */
+    public static enum WQ_INPUT { ADAPTED, SINGLE, RANGE, NONE };
 
     public static final Pattern NUMBERS_PATTERN =
         Pattern.compile("\\D*(\\d++.\\d*)\\D*");
@@ -149,7 +166,7 @@
 
     /**
      * This method returns an WQ_MODE enum which is based on the parameters
-     * stored in <i>flys</i> Artifact. If there is no <i>wq_mode</i> parameter
+     * stored in <i>flys</i> Artifact. If there is no <i>wq_isq</i> parameter
      * existing, WQ_MODE.NONE is returned.
      *
      * @param flys The FLYSArtifact that stores wq mode relevant parameters.
@@ -157,14 +174,24 @@
      * @return an enum WQ_MODE.
      */
     public static WQ_MODE getWQMode(FLYSArtifact flys) {
-        String  mode = flys.getDataAsString("wq_mode");
-        boolean free = flys.getDataAsBoolean("wq_free");
+        if (flys == null) {
+            return WQ_MODE.NONE;
+        }
 
-        if (mode != null && mode.equals("Q")) {
-            return free ? WQ_MODE.QFREE : WQ_MODE.QGAUGE;
+        String values = flys.getDataAsString("wq_values");
+        Boolean isQ   = flys.getDataAsBoolean("wq_isq");
+
+        if (values != null) {
+            return isQ ? WQ_MODE.QGAUGE : WQ_MODE.WGAUGE;
         }
-        else if (mode != null && mode.equals("W")) {
-            return free ? WQ_MODE.WFREE : WQ_MODE.WGAUGE;
+
+        Boolean isFree = flys.getDataAsBoolean("wq_isfree");
+
+        if (isQ) {
+            return isFree ? WQ_MODE.QFREE : WQ_MODE.QGAUGE;
+        }
+        else if (!isQ) {
+            return isFree ? WQ_MODE.WFREE : WQ_MODE.WGAUGE;
         }
         else {
             return WQ_MODE.NONE;
@@ -172,6 +199,26 @@
     }
 
 
+    public static WQ_INPUT getWQInputMode(FLYSArtifact flys) {
+        if (flys == null) {
+            return WQ_INPUT.NONE;
+        }
+
+        Boolean selection = flys.getDataAsBoolean("wq_isrange");
+        String adapted = flys.getDataAsString("wq_values");
+
+        if(adapted != null && adapted.length() > 0) {
+            return WQ_INPUT.ADAPTED;
+        }
+
+        if (selection != null && selection) {
+            return WQ_INPUT.RANGE;
+        }
+        else {
+            return WQ_INPUT.SINGLE;
+        }
+    }
+
     public static KM_MODE getKmRangeMode(FLYSArtifact flys) {
         String mode = flys.getDataAsString("ld_mode");
 
@@ -219,10 +266,44 @@
     }
 
 
+    /**
+     * Get bounds for river of artifact.
+     * @param flysArtifact artifact which has a "river" data.
+     * @return double array. min is at[0], max at[1]. null if given artifact is null
+     */
+    public static double[] getRiverMinMax(FLYSArtifact flysArtifact) {
+        if (flysArtifact == null) {
+            return null;
+        }
+
+        String riverName = flysArtifact.getDataAsString("river");
+
+        if (riverName == null) {
+            riverName = "";
+        }
+
+        logger.debug("Search for the min/max distances of '" + riverName + "'");
+
+        River river = RiverFactory.getRiver(riverName);
+
+        return river != null
+            ? river.determineMinMaxDistance()
+            : null;
+    }
+
+
     public static double[] getKmFromTo(FLYSArtifact flys) {
         String strFrom = flys.getDataAsString("ld_from");
         String strTo   = flys.getDataAsString("ld_to");
 
+        if (strFrom == null) {
+            strFrom = flys.getDataAsString("from");
+        }
+
+        if (strTo == null) {
+            strTo = flys.getDataAsString("to");
+        }
+
         if (strFrom == null || strTo == null) {
             return null;
         }
@@ -246,6 +327,16 @@
         String locationStr = flys.getDataAsString("ld_locations");
 
         if (locationStr == null || locationStr.length() == 0) {
+            if (flys instanceof WINFOArtifact) {
+                WINFOArtifact winfo = (WINFOArtifact) flys;
+                if (winfo.getReferenceStartKm() != null) {
+                    return new double[]
+                        {
+                            winfo.getReferenceStartKm().doubleValue(),
+                            winfo.getReferenceEndKms()[0]
+                        };
+                }
+            }
             return null;
         }
 
@@ -275,11 +366,9 @@
      * @return the Qs.
      */
     public static double[] getQs(FLYSArtifact flys) {
-        double[] kmRange = getKmRange(flys);
-
         // XXX this is not nice!
         if (flys instanceof WINFOArtifact) {
-            return ((WINFOArtifact) flys).getQs(kmRange);
+            return ((WINFOArtifact) flys).getQs();
         }
 
         logger.warn("This method currently supports WINFOArtifact only!");
@@ -297,11 +386,9 @@
      * @return the Ws.
      */
     public static double[] getWs(FLYSArtifact flys) {
-        double[] kmRange = getKmRange(flys);
-
         // XXX this is not nice!
         if (flys instanceof WINFOArtifact) {
-            return ((WINFOArtifact) flys).getWs(kmRange);
+            return ((WINFOArtifact) flys).getWs();
         }
 
         logger.warn("This method currently supports WINFOArtifact only!");
@@ -372,6 +459,12 @@
     }
 
 
+    /**
+     * Return the (first) Gauge corresponding to the given location(s) of
+     * the artifact.
+     * @param flys the artifact in question.
+     * @return (First) gauge of locations of river of artifact.
+     */
     public static Gauge getGauge(FLYSArtifact flys) {
         River river = getRiver(flys);
 
@@ -409,6 +502,24 @@
     }
 
 
+    public static Gauge getReferenceGauge(FLYSArtifact flys) {
+        Long officialNumber = flys.getDataAsLong("reference_gauge");
+
+        return officialNumber != null
+            ? Gauge.getGaugeByOfficialNumber(officialNumber)
+            : null;
+    }
+
+
+    public static String getReferenceGaugeName(FLYSArtifact flys) {
+        Gauge refGauge = getReferenceGauge(flys);
+
+        return refGauge != null
+            ? refGauge.getName()
+            : "-- not found --";
+    }
+
+
     public static Double getValueFromWQ(WQ wq) {
         if (wq == null) {
             return null;
@@ -581,7 +692,7 @@
      */
     public static String getUserWMSUrl(String artifactId) {
         String url = getXPathString(XPATH_MAPSERVER_URL);
-        url = url + "user-wms";
+        url = url.endsWith("/") ? url + "user-wms" : url + "/" + "user-wms";
 
         return url;
     }
@@ -606,5 +717,214 @@
 
         return LocationProvider.getLocation(river, km);
     }
+
+
+    /**
+     * This method returns the differences for a w-differences calculation.
+     *
+     * @param winfo The WINFOArtifact.
+     * @param context The context.
+     *
+     * @return The differences as string separated by semicolon and linebreak.
+     */
+    public static String getWDifferences(
+        WINFOArtifact winfo,
+        CallContext context)
+    {
+        State state = winfo.getCurrentState(context);
+        if(state instanceof WDifferencesState) {
+            String diffids = winfo.getDataAsString("diffids");
+            String datas[] = diffids.split("#");
+
+            // Validate the Data-Strings.
+            for (String s: datas) {
+                if (!WaterlevelSelectState.isValueValid(winfo.getDataAsString("diffids"))) {
+                    return "";
+                }
+            }
+
+            if (datas.length < 2) {
+                return "";
+            }
+
+            String diffs = "";
+            for(int i = 0; i < datas.length; i+=2) {
+                // e.g.:
+                // 42537f1e-3522-42ef-8968-635b03d8e9c6;longitudinal_section.w;1
+                WKms minuendWKms = getWKms(StringUtil.unbracket(datas[i+0]),
+                    context);
+                WKms subtrahendWKms = getWKms(StringUtil.unbracket(datas[i+1]),
+                    context);
+                if (minuendWKms != null && subtrahendWKms != null) {
+                    diffs += StringUtil.wWrap(minuendWKms.getName())
+                        + " - " + StringUtil.wWrap(subtrahendWKms.getName());
+                }
+                diffs += ";\n";
+            }
+            return diffs;
+        }
+        else {
+            logger.warn("Not a valid state for differences.");
+            return "";
+        }
+    }
+
+
+    protected static WKms getWKms(String mingle, CallContext context) {
+        String[] def  = mingle.split(";");
+        String   uuid = def[0];
+        String   name = def[1];
+        int      idx  = Integer.parseInt(def[2]);
+
+        if (name.startsWith("staticwkms")) {
+            StaticWKmsArtifact staticWKms =
+                (StaticWKmsArtifact) FLYSUtils.getArtifact(
+                    uuid,
+                    context);
+            WKms wkms = staticWKms.getWKms(idx);
+            if (wkms == null)
+                logger.error("No WKms from artifact.");
+            return wkms;
+        }
+
+        WINFOArtifact flys = (WINFOArtifact) FLYSUtils.getArtifact(
+            uuid,
+            context);
+
+        if (flys == null) {
+            logger.warn("One of the artifacts (1) for diff calculation could not be loaded");
+            return null;
+        }
+        else{
+            WQKms[] wqkms = (WQKms[]) flys.getWaterlevelData().
+                                              getData();
+            if (wqkms == null)
+            logger.warn("not  waterlevels in artifact");
+            else if (wqkms.length < idx)
+            logger.warn("not enough waterlevels in artifact");
+            return wqkms[idx];
+        }
+    }
+
+
+    /**
+     * This method transform a string into an int array. Therefore, the string
+     * <i>raw</i> must consist of int values separated by a <i>';'</i>.
+     *
+     * @param raw The raw integer array as string separated by a ';'.
+     *
+     * @return an array of int values.
+     */
+    public static int[] intArrayFromString(String raw) {
+        String[] splitted = raw != null ? raw.split(";") : null;
+
+        if (splitted == null || splitted.length == 0) {
+            logger.warn("No integer values found in '" + raw + "'");
+            return new int[0];
+        }
+
+        TIntArrayList integers = new TIntArrayList(splitted.length);
+
+        for (String value: splitted) {
+            try {
+                integers.add(Integer.parseInt(value));
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("Parsing integer failed: " + nfe);
+            }
+        }
+
+        return integers.toNativeArray();
+    }
+
+
+    /**
+     * This method transform a string into a long array. Therefore, the string
+     * <i>raw</i> must consist of int values separated by a <i>';'</i>.
+     *
+     * @param raw The raw long array as string separated by a ';'.
+     *
+     * @return an array of int values.
+     */
+    public static long[] longArrayFromString(String raw) {
+        String[] splitted = raw != null ? raw.split(";") : null;
+
+        if (splitted == null || splitted.length == 0) {
+            logger.warn("No long values found in '" + raw + "'");
+            return new long[0];
+        }
+
+        TLongArrayList longs = new TLongArrayList(splitted.length);
+
+        for (String value: splitted) {
+            try {
+                longs.add(Long.valueOf(value));
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("Parsing long failed: " + nfe);
+            }
+        }
+
+        return longs.toNativeArray();
+    }
+
+
+    /**
+     * This method transform a string into an double array. Therefore, the
+     * string <i>raw</i> must consist of double values separated by a
+     * <i>';'</i>.
+     *
+     * @param raw The raw double array as string separated by a ';'.
+     *
+     * @return an array of double values.
+     */
+    public static double[] doubleArrayFromString(String raw) {
+        String[] splitted = raw != null ? raw.split(";") : null;
+
+        if (splitted == null || splitted.length == 0) {
+            logger.warn("No double values found in '" + raw + "'");
+            return new double[0];
+        }
+
+        TDoubleArrayList doubles = new TDoubleArrayList(splitted.length);
+
+        for (String value: splitted) {
+            try {
+                doubles.add(Double.valueOf(value));
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("Parsing double failed: " + nfe);
+            }
+        }
+
+        return doubles.toNativeArray();
+    }
+
+
+    /**
+     * Returns the gauges that match the selected kilometer range.
+     *
+     * @param flys the flys artifact.
+     *
+     * @return the gauges based on the selected kilometer range (null if
+     *         none/no range set).
+     */
+    public static List<Gauge> getGauges(FLYSArtifact flys) {
+
+        River river = getRiver(flys);
+        if (river == null) {
+            logger.debug("getGauges: no river!");
+            return null;
+        }
+
+        double [] dist = getKmRange(flys);
+        if (dist == null) {
+            logger.debug("getGauges: no dist!");
+            return null;
+        }
+        logger.debug("getGauges: " + dist[0] + " - " + dist[1]);
+
+        return river.determineGauges(dist[0], dist[1]);
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/utils/Formatter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/Formatter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,15 +1,21 @@
 package de.intevation.flys.utils;
 
+import java.text.DateFormat;
 import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
 import java.util.Locale;
 
 import de.intevation.artifacts.CallContext;
-
+import de.intevation.artifacts.CallMeta;
 import de.intevation.flys.artifacts.resources.Resources;
 
 
 public final class Formatter {
 
+    // KMS IN ERROR REPORTS.
+    public static final int CALCULATION_REPORT_KM_MIN_DIGITS = 1;
+    public static final int CALCULATION_REPORT_KM_MAX_DIGITS = 3;
+
     // WATERLEVEL FORMATTER CONSTANTS
     public static final int WATERLEVEL_KM_MIN_DIGITS = 3;
     public static final int WATERLEVEL_KM_MAX_DIGITS = 3;
@@ -26,6 +32,13 @@
     public static final int COMPUTED_DISCHARGE_Q_MAX_DIGITS  = 2;
 
 
+    // HISTORICAL DISCHARGE CURVE FORMATTER CONSTANTS
+    public static final int HISTORICAL_DISCHARGE_W_MIN_DIGITS = 0;
+    public static final int HISTORICAL_DISCHARGE_W_MAX_DIGITS = 2;
+    public static final int HISTORICAL_DISCHARGE_Q_MIN_DIGITS = 0;
+    public static final int HISTORICAL_DISCHARGE_Q_MAX_DIGITS = 2;
+
+
     // DURATION CURVE FORMATTER CONSTANTS
     public static final int DURATION_W_MIN_DIGITS = 0;
     public static final int DURATION_W_MAX_DIGITS = 2;
@@ -35,8 +48,46 @@
     public static final int DURATION_D_MAX_DIGITS = 0;
 
 
-    public static NumberFormat getFormatter(CallContext c, int min, int max){
-        Locale       locale = Resources.getLocale(c.getMeta());
+    // FLOW VELOCITY FORMATTER CONSTANTS
+    public static final int FLOW_VELOCITY_KM_MIN_DIGITS     = 3;
+    public static final int FLOW_VELOCITY_KM_MAX_DIGITS     = 3;
+    public static final int FLOW_VELOCITY_VALUES_MIN_DIGITS = 2;
+    public static final int FLOW_VELOCITY_VALUES_MAX_DIGITS = 2;
+    public static final int FLOW_VELOCITY_Q_MIN_DIGITS      = 0;
+    public static final int FLOW_VELOCITY_Q_MAX_DIGITS      = 2;
+
+
+    // MIDDLE BED HEIGHT FORMATTER CONSTANTS
+    public static final int MIDDLE_BED_HEIGHT_KM_MIN_DIGITS             = 3;
+    public static final int MIDDLE_BED_HEIGHT_KM_MAX_DIGITS             = 3;
+    public static final int MIDDLE_BED_HEIGHT_HEIGHT_MIN_DIGITS         = 3;
+    public static final int MIDDLE_BED_HEIGHT_HEIGHT_MAX_DIGITS         = 3;
+    public static final int MIDDLE_BED_HEIGHT_UNCERT_MIN_DIGITS         = 3;
+    public static final int MIDDLE_BED_HEIGHT_UNCERT_MAX_DIGITS         = 3;
+    public static final int MIDDLE_BED_HEIGHT_DATAGAP_MIN_DIGITS        = 2;
+    public static final int MIDDLE_BED_HEIGHT_DATAGAP_MAX_DIGITS        = 2;
+    public static final int MIDDLE_BED_HEIGHT_SOUNDING_WIDTH_MIN_DIGITS = 0;
+    public static final int MIDDLE_BED_HEIGHT_SOUNDING_WIDTH_MAX_DIGITS = 0;
+    public static final int MIDDLE_BED_HEIGHT_WIDTH_MIN_DIGITS          = 3;
+    public static final int MIDDLE_BED_HEIGHT_WIDTH_MAX_DIGITS          = 3;
+
+    public static final int FIX_DELTA_W_KM_MIN_DIGITS = 3;
+    public static final int FIX_DELTA_W_KM_MAX_DIGITS = 3;
+    public static final int FIX_DELTA_W_DELTA_W_MIN_DIGITS = 3;
+    public static final int FIX_DELTA_W_DELTA_W_MAX_DIGITS = 3;
+    public static final int FIX_DELTA_W_DELTA_Q_MIN_DIGITS  = 0;
+    public static final int FIX_DELTA_W_DELTA_Q_MAX_DIGITS  = 2;
+
+    /**
+     * Creates a localized NumberFormatter with given range of decimal digits.
+     * @param m CallMeta to find the locale.
+     * @param min minimum number of decimal ("fraction") digits.
+     * @param max maximum number of decimal ("fraction") digits.
+     * @return A NumberFormat. Use #format(NUMBER) to get String representation
+     *         of NUMBER.
+     */
+    public static NumberFormat getFormatter(CallMeta m, int min, int max){
+        Locale       locale = Resources.getLocale(m);
         NumberFormat nf     = NumberFormat.getInstance(locale);
 
         nf.setMaximumFractionDigits(max);
@@ -45,6 +96,41 @@
         return nf;
     }
 
+    public static NumberFormat getFormatter(CallContext c, int min, int max){
+        return getFormatter(c.getMeta(), min, max);
+    }
+
+
+    /**
+     * Returns a number formatter with no max or min digits set.
+     *
+     * @param c The CallContext.
+     *
+     * @return a number formatter.
+     */
+    public static NumberFormat getRawFormatter(CallContext c) {
+        Locale locale = Resources.getLocale(c.getMeta());
+        return NumberFormat.getInstance(locale);
+    }
+
+
+    /**
+     * Returns a date formatter with SHORT style.
+     */
+    public static DateFormat getShortDateFormat(CallContext cc) {
+        Locale locale = Resources.getLocale(cc.getMeta());
+        return DateFormat.getDateInstance(DateFormat.SHORT, locale);
+    }
+
+
+    /**
+     * Returns a date formatter with MEDIUM style.
+     */
+    public static DateFormat getMediumDateFormat(CallContext cc) {
+        Locale locale = Resources.getLocale(cc.getMeta());
+        return DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
+    }
+
 
     /**
      * Returns the number formatter for kilometer values in waterlevel exports.
@@ -53,11 +139,17 @@
      */
     public static NumberFormat getWaterlevelKM(CallContext context) {
         return getFormatter(
-            context,
-            WATERLEVEL_KM_MIN_DIGITS,
-            WATERLEVEL_KM_MAX_DIGITS);
+                context,
+                WATERLEVEL_KM_MIN_DIGITS,
+                WATERLEVEL_KM_MAX_DIGITS);
     }
 
+    public static NumberFormat getWaterlevelW(CallMeta meta) {
+        return getFormatter(
+                meta,
+                WATERLEVEL_W_MIN_DIGITS,
+                WATERLEVEL_W_MAX_DIGITS);
+    }
 
     /**
      * Returns the number formatter for W values in waterlevel exports.
@@ -66,9 +158,9 @@
      */
     public static NumberFormat getWaterlevelW(CallContext context) {
         return getFormatter(
-            context,
-            WATERLEVEL_W_MIN_DIGITS,
-            WATERLEVEL_W_MAX_DIGITS);
+                context,
+                WATERLEVEL_W_MIN_DIGITS,
+                WATERLEVEL_W_MAX_DIGITS);
     }
 
 
@@ -79,11 +171,17 @@
      */
     public static NumberFormat getWaterlevelQ(CallContext context) {
         return getFormatter(
-            context,
-            WATERLEVEL_Q_MIN_DIGITS,
-            WATERLEVEL_Q_MAX_DIGITS);
+                context,
+                WATERLEVEL_Q_MIN_DIGITS,
+                WATERLEVEL_Q_MAX_DIGITS);
     }
 
+    public static NumberFormat getWaterlevelQ(CallMeta meta) {
+        return getFormatter(
+                meta,
+                WATERLEVEL_Q_MIN_DIGITS,
+                WATERLEVEL_Q_MAX_DIGITS);
+    }
 
     /**
      * Returns the number formatter for W values in exports of computed
@@ -93,9 +191,9 @@
      */
     public static NumberFormat getComputedDischargeW(CallContext context) {
         return getFormatter(
-            context,
-            COMPUTED_DISCHARGE_W_MIN_DIGITS,
-            COMPUTED_DISCHARGE_W_MAX_DIGITS);
+                context,
+                COMPUTED_DISCHARGE_W_MIN_DIGITS,
+                COMPUTED_DISCHARGE_W_MAX_DIGITS);
     }
 
 
@@ -107,9 +205,37 @@
      */
     public static NumberFormat getComputedDischargeQ(CallContext context) {
         return getFormatter(
-            context,
-            COMPUTED_DISCHARGE_Q_MIN_DIGITS,
-            COMPUTED_DISCHARGE_Q_MAX_DIGITS);
+                context,
+                COMPUTED_DISCHARGE_Q_MIN_DIGITS,
+                COMPUTED_DISCHARGE_Q_MAX_DIGITS);
+    }
+
+
+    /**
+     * Returns the number formatter for W values in exports of historical
+     * discharge curves.
+     *
+     * @return the number formatter for W values.
+     */
+    public static NumberFormat getHistoricalDischargeW(CallContext context) {
+        return getFormatter(
+                context,
+                HISTORICAL_DISCHARGE_W_MIN_DIGITS,
+                HISTORICAL_DISCHARGE_W_MAX_DIGITS);
+    }
+
+
+    /**
+     * Returns the number formatter for Q values in exports of historical
+     * discharge curves.
+     *
+     * @return the number formatter for Q values.
+     */
+    public static NumberFormat getHistoricalDischargeQ(CallContext context) {
+        return getFormatter(
+                context,
+                HISTORICAL_DISCHARGE_Q_MIN_DIGITS,
+                HISTORICAL_DISCHARGE_Q_MAX_DIGITS);
     }
 
 
@@ -120,9 +246,9 @@
      */
     public static NumberFormat getDurationW(CallContext context) {
         return getFormatter(
-            context,
-            DURATION_W_MIN_DIGITS,
-            DURATION_W_MAX_DIGITS);
+                context,
+                DURATION_W_MIN_DIGITS,
+                DURATION_W_MAX_DIGITS);
     }
 
 
@@ -133,9 +259,9 @@
      */
     public static NumberFormat getDurationQ(CallContext context) {
         return getFormatter(
-            context,
-            DURATION_Q_MIN_DIGITS,
-            DURATION_Q_MAX_DIGITS);
+                context,
+                DURATION_Q_MIN_DIGITS,
+                DURATION_Q_MAX_DIGITS);
     }
 
 
@@ -146,9 +272,129 @@
      */
     public static NumberFormat getDurationD(CallContext context) {
         return getFormatter(
-            context,
-            DURATION_D_MIN_DIGITS,
-            DURATION_D_MAX_DIGITS);
+                context,
+                DURATION_D_MIN_DIGITS,
+                DURATION_D_MAX_DIGITS);
+    }
+
+    public static NumberFormat getCalculationKm(CallMeta meta) {
+        return getFormatter(
+                meta,
+                CALCULATION_REPORT_KM_MIN_DIGITS,
+                CALCULATION_REPORT_KM_MAX_DIGITS);
+    }
+
+
+    public static NumberFormat getFlowVelocityKM(CallContext context) {
+        return getFormatter(
+                context,
+                FLOW_VELOCITY_KM_MIN_DIGITS,
+                FLOW_VELOCITY_KM_MAX_DIGITS);
+    }
+
+
+    public static NumberFormat getFlowVelocityValues(CallContext context) {
+        return getFormatter(
+                context,
+                FLOW_VELOCITY_VALUES_MIN_DIGITS,
+                FLOW_VELOCITY_VALUES_MAX_DIGITS);
+    }
+
+
+    public static NumberFormat getFlowVelocityQ(CallContext context) {
+        return getFormatter(
+                context,
+                FLOW_VELOCITY_Q_MIN_DIGITS,
+                FLOW_VELOCITY_Q_MAX_DIGITS);
+    }
+
+
+    public static NumberFormat getMiddleBedHeightKM(CallContext context) {
+        return getFormatter(
+                context,
+                MIDDLE_BED_HEIGHT_KM_MIN_DIGITS,
+                MIDDLE_BED_HEIGHT_KM_MAX_DIGITS);
+    }
+
+
+    public static NumberFormat getMiddleBedHeightHeight(CallContext context) {
+        return getFormatter(
+                context,
+                MIDDLE_BED_HEIGHT_HEIGHT_MIN_DIGITS,
+                MIDDLE_BED_HEIGHT_HEIGHT_MAX_DIGITS);
+    }
+
+
+    public static NumberFormat getMiddleBedHeightUncert(CallContext context) {
+        return getFormatter(
+                context,
+                MIDDLE_BED_HEIGHT_UNCERT_MIN_DIGITS,
+                MIDDLE_BED_HEIGHT_UNCERT_MAX_DIGITS);
+    }
+
+
+    public static NumberFormat getMiddleBedHeightDataGap(CallContext context) {
+        return getFormatter(
+                context,
+                MIDDLE_BED_HEIGHT_DATAGAP_MIN_DIGITS,
+                MIDDLE_BED_HEIGHT_DATAGAP_MAX_DIGITS);
+    }
+
+
+    public static NumberFormat getMiddleBedHeightSounding(CallContext context) {
+        return getFormatter(
+                context,
+                MIDDLE_BED_HEIGHT_SOUNDING_WIDTH_MIN_DIGITS,
+                MIDDLE_BED_HEIGHT_SOUNDING_WIDTH_MAX_DIGITS);
+    }
+
+
+    public static NumberFormat getMiddleBedHeightWidth(CallContext context) {
+        return getFormatter(
+                context,
+                MIDDLE_BED_HEIGHT_WIDTH_MIN_DIGITS,
+                MIDDLE_BED_HEIGHT_WIDTH_MAX_DIGITS);
+    }
+
+    public static NumberFormat getFixDeltaWKM(CallContext context) {
+        return getFormatter(
+                context,
+                FIX_DELTA_W_KM_MIN_DIGITS,
+                FIX_DELTA_W_KM_MAX_DIGITS);
+    }
+
+    public static NumberFormat getFixDeltaWDeltaW(CallContext context) {
+        return getFormatter(
+                context,
+                FIX_DELTA_W_DELTA_W_MIN_DIGITS,
+                FIX_DELTA_W_DELTA_W_MAX_DIGITS);
+    }
+
+    public static NumberFormat getFixDeltaWQ(CallContext context) {
+        return getFormatter(
+                context,
+                FIX_DELTA_W_DELTA_Q_MIN_DIGITS,
+                FIX_DELTA_W_DELTA_Q_MAX_DIGITS);
+    }
+
+    public static NumberFormat getFixDeltaWW(CallContext context) {
+        return getFormatter(
+                context,
+                FIX_DELTA_W_DELTA_W_MIN_DIGITS,
+                FIX_DELTA_W_DELTA_W_MAX_DIGITS);
+    }
+
+    public static NumberFormat getMeterFormat(CallContext context) {
+        return getFormatter(
+                context,
+                0,
+                2);
+
+    }
+
+    public static DateFormat getDateFormatter(CallMeta m, String pattern) {
+        Locale locale = Resources.getLocale(m);
+        return new SimpleDateFormat(pattern, locale);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/utils/GeometryUtils.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/GeometryUtils.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,7 +1,13 @@
 package de.intevation.flys.utils;
 
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+import com.vividsolutions.jts.geom.Geometry;
+
+import de.intevation.flys.model.RiverAxis;
+
+import java.io.File;
 import java.io.IOException;
-import java.io.File;
 import java.io.Serializable;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
@@ -10,81 +16,89 @@
 import java.util.Map;
 
 import org.apache.log4j.Logger;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Envelope;
-import com.vividsolutions.jts.geom.Geometry;
-
+import org.geotools.data.DataStoreFactorySpi;
+import org.geotools.data.DefaultTransaction;
+import org.geotools.data.FeatureWriter;
+import org.geotools.data.Transaction;
+import org.geotools.data.shapefile.ShapefileDataStore;
+import org.geotools.data.shapefile.ShapefileDataStoreFactory;
+import org.geotools.data.simple.SimpleFeatureIterator;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureIterator;
+import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
+import org.geotools.geojson.feature.FeatureJSON;
+import org.geotools.geometry.jts.JTS;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.referencing.CRS;
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
 import org.opengis.referencing.FactoryException;
 import org.opengis.referencing.NoSuchAuthorityCodeException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import org.geotools.data.DataStoreFactorySpi;
-import org.geotools.data.FeatureStore;
-import org.geotools.data.DefaultTransaction;
-import org.geotools.data.Transaction;
-import org.geotools.data.shapefile.ShapefileDataStore;
-import org.geotools.data.shapefile.ShapefileDataStoreFactory;
-import org.geotools.feature.FeatureIterator;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
-import org.geotools.geojson.feature.FeatureJSON;
-import org.geotools.referencing.CRS;
-
-import de.intevation.flys.model.RiverAxis;
-
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
 
 public class GeometryUtils {
 
     private static final Logger logger = Logger.getLogger(GeometryUtils.class);
 
+    public static final String PREFIX_EPSG  = "EPSG:";
+
+    public static final String DEFAULT_EPSG = "EPSG:31467";
 
     private GeometryUtils() {
     }
 
-
     public static Envelope getRiverBoundary(String rivername) {
-        RiverAxis axis = RiverAxis.getRiverAxis(rivername);
-        if (axis != null) {
-            // TODO Take the correct EPSG into account. Maybe, we need to
-            // reproject the geometry.
-            return axis.getGeom().getEnvelopeInternal();
+        List<RiverAxis> axes = RiverAxis.getRiverAxis(rivername);
+        if (axes != null && axes.size() > 0) {
+            Envelope max = null;
+
+            for (RiverAxis axis: axes) {
+                // TODO Take the correct EPSG into account. Maybe, we need to
+                // reproject the geometry.
+                Envelope env = axis.getGeom().getEnvelopeInternal();
+
+                if (max == null) {
+                    max = env;
+                }
+                else {
+                    max.expandToInclude(env);
+                }
+            }
+
+            return max;
         }
 
         return null;
     }
 
-
     public static String getRiverBounds(String rivername) {
         Envelope env = getRiverBoundary(rivername);
 
-        if (env == null) {
+        if (env != null) {
             return jtsBoundsToOLBounds(env);
         }
 
         return null;
     }
 
-
     /**
-     * Returns the boundary of Envelope <i>env</i> in OpenLayers
-     * representation.
+     * Returns the boundary of Envelope <i>env</i> in OpenLayers representation.
      *
      * @param env The envelope of a geometry.
      *
      * @return the OpenLayers boundary of <i>env</i>.
      */
     public static String jtsBoundsToOLBounds(Envelope env) {
-        return "" +
-            env.getMinX() + " " +
-            env.getMinY() + " " +
-            env.getMaxX() + " " +
-            env.getMaxY();
+        StringBuilder buf = new StringBuilder();
+        buf.append(env.getMinX()); buf.append(' ');
+        buf.append(env.getMinY()); buf.append(' ');
+        buf.append(env.getMaxX()); buf.append(' ');
+        buf.append(env.getMaxY());
+        return buf.toString();
     }
 
-
     public static String createOLBounds(Geometry a, Geometry b) {
         Coordinate[] ca = a.getCoordinates();
         Coordinate[] cb = b.getCoordinates();
@@ -113,29 +127,26 @@
         return "" + lowerX + " " + lowerY + " " + upperX + " " + upperY;
     }
 
-
     public static SimpleFeatureType buildFeatureType(
-        String name, String srs, Class geometryType)
+        String name, String srs, Class<?> geometryType)
     {
         return buildFeatureType(name, srs, geometryType, null);
     }
 
-
     /**
      * Creates a new SimpleFeatureType using a SimpleFeatureTypeBuilder.
      *
      * @param name The name of the FeatureType.
      * @param srs The SRS (e.g. "EPSG:31466").
      * @param geometryType The geometry type's class (e.g. Polygon.class).
-     * @param attrs Optional. An object with attribute-name/attribute-class
-     * pairs where index 0 specifies the name as string and index 1 the type
-     * as class.
+     * @param attrs Optional. An object with attribute-name/attribute-class pairs
+     * where index 0 specifies the name as string and index 1 the
+     * ype as class.
      *
      * @return a new SimpleFeatureType.
      */
-    public static SimpleFeatureType buildFeatureType(
-        String name, String srs, Class geometryType, Object[][] attrs)
-    {
+    public static SimpleFeatureType buildFeatureType(String name, String srs,
+        Class<?> geometryType, Object[][] attrs) {
         try {
             SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
             CoordinateReferenceSystem crs    = CRS.decode(srs);
@@ -149,7 +160,7 @@
 
             if (attrs != null) {
                 for (Object[] attr: attrs) {
-                    builder.add((String) attr[0], (Class) attr[1]);
+                    builder.add((String) attr[0], (Class<?>) attr[1]);
                 }
             }
 
@@ -163,7 +174,6 @@
         return null;
     }
 
-
     public static List<SimpleFeature> parseGeoJSON(
         String geojson, SimpleFeatureType ft
     ) {
@@ -188,19 +198,112 @@
     }
 
 
-    public static boolean writeShapefile(
-        File              shape,
-        SimpleFeatureType featureType,
-        FeatureCollection collection
+    /**
+     * This method returns the {@link CoordinateReferenceSystem} by the
+     * {@link String} <i>epsg</i>.
+     *
+     * @param epsg An EPSG code like <b>EPSG:31466</b>
+     *
+     * @return the {@link CoordinateReferenceSystem} specified by <i>epsg</i>.
+     */
+    public static CoordinateReferenceSystem getCoordinateReferenceSystem(
+        String epsg
     ) {
+        if (epsg == null) {
+            logger.warn("cannot create CoordinateReferenceSystem with null");
+            return null;
+        }
+
+        if (!epsg.startsWith(PREFIX_EPSG)) {
+            epsg = PREFIX_EPSG + epsg;
+        }
+
+        try {
+            return CRS.decode(epsg);
+        }
+        catch (FactoryException fe) {
+            logger.error(
+                "unable to get CoordinateReferenceSystem for: " + epsg,
+                fe);
+        }
+
+        return null;
+    }
+
+
+    public static Envelope transform(Envelope orig, String targetSrs) {
+        return transform(orig, targetSrs, DEFAULT_EPSG);
+    }
+
+
+    public static Envelope transform(
+        Envelope orig,
+        String   targetSrs,
+        String   origSrs
+    ) {
+        if (targetSrs == null || orig == null || origSrs == null) {
+            logger.warn("unable to transform envelope: empty parameters");
+            return orig;
+        }
+
+        logger.debug("Transform envlope to '" + targetSrs + "'");
+        try {
+            CoordinateReferenceSystem sourceCRS =
+                getCoordinateReferenceSystem(origSrs);
+
+            CoordinateReferenceSystem targetCRS =
+                getCoordinateReferenceSystem(targetSrs);
+
+            if (sourceCRS != null && targetCRS != null) {
+                ReferencedEnvelope tmpEnv =
+                    new ReferencedEnvelope(orig, CRS.decode(origSrs));
+
+                Envelope target = tmpEnv.transform(targetCRS, false);
+
+                if (logger.isDebugEnabled()) {
+                    logger.debug("   orig envelope       : " + orig);
+                    logger.debug("   transformed envelope: " + target);
+                }
+
+                return target;
+            }
+        }
+        catch (NoSuchAuthorityCodeException nsae) {
+            logger.error("Cannot get CoordinateReferenceSystem!", nsae);
+        }
+        catch (FactoryException fe) {
+            logger.error("Cannot get CoordinateReferenceSystem!", fe);
+        }
+        catch (TransformException te) {
+            logger.error("Cannot transform envelope from source "
+                + origSrs + " to target srs " + targetSrs);
+        }
+
+        return null;
+    }
+
+
+    public static boolean writeShapefile(File shape,
+        SimpleFeatureType featureType, FeatureCollection<?, ?> collection) {
+        return writeShapefile(shape, featureType, collection,
+            featureType.getCoordinateReferenceSystem());
+    }
+
+
+    public static boolean writeShapefile(File shape,
+        SimpleFeatureType featureType, FeatureCollection<?, ?> collection,
+        CoordinateReferenceSystem crs) {
         if (collection.isEmpty()) {
             logger.warn("Shapefile is not written - no features given!");
             return false;
         }
 
-        Transaction transaction = null;
+        Transaction   transaction = null;
 
         try {
+            MathTransform transform = CRS.findMathTransform(
+                CRS.decode(DEFAULT_EPSG), crs);
+
             Map<String, Serializable> params =
                 new HashMap<String, Serializable>();
 
@@ -218,13 +321,24 @@
 
             String typeName = newDataStore.getTypeNames()[0];
 
-            FeatureStore<SimpleFeatureType, SimpleFeature> featureStore =
-                (FeatureStore<SimpleFeatureType, SimpleFeature>)
-                    newDataStore.getFeatureSource(typeName);
+            FeatureWriter<SimpleFeatureType, SimpleFeature> writer =
+                newDataStore.getFeatureWriter(typeName, transaction);
 
-            featureStore.setTransaction(transaction);
+            SimpleFeatureIterator iterator = (SimpleFeatureIterator) collection.features();
 
-            featureStore.addFeatures(collection);
+            while (iterator.hasNext()){
+                SimpleFeature feature = iterator.next();
+                SimpleFeature copy    = writer.next();
+
+                copy.setAttributes(feature.getAttributes());
+
+                Geometry orig        = (Geometry) feature.getDefaultGeometry();
+                Geometry reprojected = JTS.transform(orig, transform);
+
+                copy.setDefaultGeometry(reprojected);
+                writer.write();
+            }
+
             transaction.commit();
 
             return true;
@@ -235,10 +349,20 @@
         catch (IOException ioe) {
             logger.error("Unable to write shapefile: " + ioe.getMessage());
         }
+        catch (NoSuchAuthorityCodeException nsae) {
+            logger.error("Cannot get CoordinateReferenceSystem for '"
+                + DEFAULT_EPSG + "'");
+        }
+        catch (FactoryException fe) {
+            logger.error("Cannot get CoordinateReferenceSystem for '"
+                + DEFAULT_EPSG + "'");
+        }
+        catch (TransformException te) {
+            logger.error("Was not able to transform geometry!", te);
+        }
         finally {
             if (transaction != null) {
                 try {
-                    logger.debug("XXX CLOSE TRANSACTION!");
                     transaction.close();
                 }
                 catch (IOException ioe) { /* do nothing */ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/IdGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,18 @@
+package de.intevation.flys.utils;
+
+public class IdGenerator {
+
+    protected int id;
+
+    public IdGenerator() {
+    }
+
+    public IdGenerator(int id) {
+        this.id = id;
+    }
+
+    public int next() {
+        return id++;
+    }
+}
+// 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/utils/KMIndex.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,92 @@
+package de.intevation.flys.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Iterator;
+
+import java.io.Serializable;
+
+public class KMIndex<A>
+implements   Serializable, Iterable<KMIndex.Entry<A>>
+{
+    public static final double EPSILON = 1e-4;
+
+    public static class Entry<A>
+    implements          Serializable, Comparable<Entry<A>>
+    {
+        protected double km;
+        protected A      value;
+
+        public Entry(double km) {
+            this.km = km;
+        }
+
+        public Entry(double km, A value) {
+            this.km    = km;
+            this.value = value;
+        }
+
+        public double getKm() {
+            return km;
+        }
+
+        public A getValue() {
+            return value;
+        }
+
+        public void setValue(A value) {
+            this.value = value;
+        }
+
+        @Override
+        public int compareTo(Entry<A> other) {
+            double diff = km - other.km;
+            if (diff < -EPSILON) return -1;
+            if (diff > +EPSILON) return +1;
+            return 0;
+        }
+
+        public boolean epsilonEquals(double km) {
+            return Math.abs(this.km - km) < EPSILON;
+        }
+    } // class Entry
+
+
+    protected List<Entry<A>> entries;
+
+    public KMIndex() {
+        this(10);
+    }
+
+    public KMIndex(int capacity) {
+        entries = new ArrayList<Entry<A>>(capacity);
+    }
+
+    public void add(double km, A value) {
+        entries.add(new Entry<A>(km, value));
+    }
+
+    public void sort() {
+        Collections.sort(entries);
+    }
+
+    public Entry<A> search(double km) {
+        for (Entry<A> entry: entries) {
+            if (entry.epsilonEquals(km)) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
+    public Entry<A> binarySearch(double km) {
+        int index = Collections.binarySearch(entries, new Entry<A>(km));
+        return index >= 0 ? entries.get(index) : null;
+    }
+
+    public Iterator<Entry<A>> iterator() {
+        return entries.iterator();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/utils/MapfileGenerator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/MapfileGenerator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,28 +1,31 @@
 package de.intevation.flys.utils;
 
+import de.intevation.artifacts.CallContext;
+import de.intevation.artifacts.common.utils.Config;
+import de.intevation.flys.artifacts.FLYSArtifact;
+import de.intevation.flys.artifacts.model.LayerInfo;
+import de.intevation.flys.artifacts.model.map.WMSDBLayerFacet;
+import de.intevation.flys.artifacts.model.map.WMSLayerFacet;
+import de.intevation.flys.artifacts.model.map.WSPLGENLayerFacet;
+import de.intevation.flys.artifacts.resources.Resources;
+
 import java.io.File;
-import java.io.FilenameFilter;
 import java.io.FileNotFoundException;
 import java.io.FileWriter;
+import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.Writer;
-
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
 import org.apache.log4j.Logger;
-
 import org.apache.velocity.Template;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
-
-import de.intevation.artifacts.common.utils.Config;
-
-import de.intevation.flys.artifacts.FLYSArtifact;
-import de.intevation.flys.artifacts.model.LayerInfo;
-import de.intevation.flys.artifacts.model.WMSLayerFacet;
-import de.intevation.flys.artifacts.model.WMSDBLayerFacet;
+import org.geotools.data.shapefile.ShpFiles;
+import org.geotools.data.shapefile.shp.ShapefileHeader;
+import org.geotools.data.shapefile.shp.ShapefileReader;
 
 /**
  * This class iterates over a bunch of directories, searches for meta
@@ -37,15 +40,18 @@
     public static final String WSPLGEN_RESULT_SHAPE   = "wsplgen.shp";
     public static final String WSPLGEN_LINES_SHAPE    = "barrier_lines.shp";
     public static final String WSPLGEN_POLYGONS_SHAPE = "barrier_polygons.shp";
+    public static final String WSPLGEN_USER_SHAPE     = "user-rgd.shp";
 
+    public static final String WSPLGEN_LAYER_TEMPLATE = "wsplgen_layer.vm";
     public static final String SHP_LAYER_TEMPLATE = "shapefile_layer.vm";
     public static final String DB_LAYER_TEMPLATE  = "db_layer.vm";
 
-    public static final String MS_WSPLGEN_PREFIX  = "wsplgen-";
-    public static final String MS_BARRIERS_PREFIX = "barriers-";
-    public static final String MS_LINE_PREFIX     = "lines-";
-    public static final String MS_POLYGONS_PREFIX = "polygons-";
-    public static final String MS_LAYER_PREFIX    = "ms_layer-";
+    public static final String MS_WSPLGEN_PREFIX   = "wsplgen-";
+    public static final String MS_BARRIERS_PREFIX  = "barriers-";
+    public static final String MS_LINE_PREFIX      = "lines-";
+    public static final String MS_POLYGONS_PREFIX  = "polygons-";
+    public static final String MS_LAYER_PREFIX     = "ms_layer-";
+    public static final String MS_USERSHAPE_PREFIX = "user-";
 
     protected static final long SLEEPTIME = 10 * 1000L; // 10 seconds
 
@@ -61,7 +67,7 @@
     private String velocityLogfile;
 
     private VelocityEngine velocityEngine;
-    private boolean lock[];
+    private final boolean lock[];
 
 
 
@@ -296,7 +302,7 @@
      * configured.
      */
     public File getShapefileBaseDir()
-    throws    FileNotFoundException, IOException
+            throws FileNotFoundException, IOException
     {
         if (shapefileDirectory == null) {
             String path = FLYSUtils.getXPathString(
@@ -311,7 +317,7 @@
             }
 
             if (!shapefileDirectory.exists()) {
-                shapefileDirectory.createNewFile();
+                shapefileDirectory.mkdirs();
             }
         }
 
@@ -320,7 +326,7 @@
 
 
     protected File[] getUserDirs()
-    throws    FileNotFoundException, IOException
+            throws FileNotFoundException, IOException
     {
         File   baseDir      = getShapefileBaseDir();
         File[] artifactDirs = baseDir.listFiles();
@@ -364,8 +370,12 @@
      * @param flys The FLYSArtifact that owns <i>wms</i>.
      * @param wms The WMSLayerFacet that contains information for the layer.
      */
-    public void createUeskLayer(FLYSArtifact flys, WMSLayerFacet wms)
-    throws FileNotFoundException, IOException
+    public void createUeskLayer(
+        FLYSArtifact  flys,
+        WSPLGENLayerFacet wms,
+        String        style,
+        CallContext context
+    ) throws FileNotFoundException, IOException
     {
         logger.debug("createUeskLayer");
 
@@ -374,13 +384,17 @@
         layerinfo.setType("POLYGON");
         layerinfo.setDirectory(flys.identifier());
         layerinfo.setData(WSPLGEN_RESULT_SHAPE);
-        layerinfo.setTitle("I18N_WSPLGEN_RESULT");
+        layerinfo.setTitle(Resources.getMsg(Resources.getLocale(context.getMeta()),
+                                            "floodmap.uesk",
+                                            "Floodmap"));
+        layerinfo.setStyle(style);
+        layerinfo.setSrid(wms.getSrid());
 
         String name = MS_LAYER_PREFIX + wms.getName();
 
-        Template template = getTemplateByName(SHP_LAYER_TEMPLATE);
+        Template template = getTemplateByName(WSPLGEN_LAYER_TEMPLATE);
         if (template == null) {
-            logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found.");
+            logger.warn("Template '" + WSPLGEN_LAYER_TEMPLATE + "' found.");
             return;
         }
 
@@ -407,8 +421,8 @@
     {
         logger.debug("createBarriersLayer");
 
-        String uuid = flys.identifier();
-        File   dir  = new File(getShapefileBaseDir(), uuid);
+        //String uuid = flys.identifier();
+        //File   dir  = new File(getShapefileBaseDir(), uuid);
 
         createBarriersLineLayer(flys, wms);
         createBarriersPolygonLayer(flys, wms);
@@ -441,6 +455,7 @@
         lineInfo.setTitle("I18N_LINE_SHAPE");
         lineInfo.setGroup(group);
         lineInfo.setGroupTitle(groupTitle);
+        lineInfo.setSrid(wms.getSrid());
 
         String nameLines = MS_LAYER_PREFIX + wms.getName() + "-lines";
 
@@ -486,6 +501,7 @@
         polygonInfo.setTitle("I18N_POLYGON_SHAPE");
         polygonInfo.setGroup(group);
         polygonInfo.setGroupTitle(groupTitle);
+        polygonInfo.setSrid(wms.getSrid());
 
         String namePolygons = MS_LAYER_PREFIX + wms.getName() + "-polygons";
 
@@ -506,6 +522,72 @@
 
 
     /**
+     * Creates a layer file used for Mapserver's mapfile which represents the
+     * shape files uploaded by the user.
+     *
+     * @param flys The FLYSArtifact that owns <i>wms</i>.
+     * @param wms The WMSLayerFacet that contains information for the layer.
+     */
+    public void createUserShapeLayer(FLYSArtifact flys, WMSLayerFacet wms)
+    throws FileNotFoundException, IOException
+    {
+        logger.debug("createUserShapeLayer");
+
+        String uuid = flys.identifier();
+        File   dir  = new File(getShapefileBaseDir(), uuid);
+        File   test = new File(dir, WSPLGEN_USER_SHAPE);
+
+        if (!test.exists() || !test.canRead()) {
+            logger.debug("No user layer existing.");
+            return;
+        }
+
+        File userShape = new File(dir, WSPLGEN_USER_SHAPE);
+        ShpFiles sf = new ShpFiles(userShape);
+        ShapefileReader sfr = new ShapefileReader(sf, true, false, null);
+        ShapefileHeader sfh = sfr.getHeader();
+
+        String group      = uuid + MS_USERSHAPE_PREFIX;
+        String groupTitle = "I18N_USER_SHAPE_TITLE";
+
+        LayerInfo info = new LayerInfo();
+        info.setName(MS_USERSHAPE_PREFIX + uuid);
+        if (sfh.getShapeType().isLineType()) {
+            info.setType("LINE");
+        }
+        else if (sfh.getShapeType().isPolygonType()) {
+            info.setType("POLYGON");
+        }
+        else {
+            return;
+        }
+        info.setDirectory(uuid);
+        info.setData(WSPLGEN_USER_SHAPE);
+        info.setTitle("I18N_USER_SHAPE");
+        info.setGroup(group);
+        info.setGroupTitle(groupTitle);
+        info.setSrid(wms.getSrid());
+
+        String nameUser = MS_LAYER_PREFIX + wms.getName();
+
+        Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE);
+        if (tpl == null) {
+            logger.warn("Template '" + SHP_LAYER_TEMPLATE + "' found.");
+            return;
+        }
+
+        try {
+            writeLayer(info, dir, nameUser, tpl);
+        }
+        catch (FileNotFoundException fnfe) {
+            logger.error(fnfe, fnfe);
+            logger.warn("Unable to write layer: " + nameUser);
+        }
+
+    }
+
+
+    /**
      * Creates a layer file used for Mapserver's mapfile which represents
      * geometries from database.
      *
@@ -528,10 +610,13 @@
         layerinfo.setData(wms.getData());
         layerinfo.setTitle(wms.getDescription());
         layerinfo.setStyle(style);
-        layerinfo.setExtent(GeometryUtils.jtsBoundsToOLBounds(wms.getExtent()));
+        if(wms.getExtent() != null) {
+            layerinfo.setExtent(GeometryUtils.jtsBoundsToOLBounds(wms.getExtent()));
+        }
         layerinfo.setConnection(wms.getConnection());
         layerinfo.setConnectionType(wms.getConnectionType());
         layerinfo.setLabelItem(wms.getLabelItem());
+        layerinfo.setSrid(wms.getSrid());
 
         String name = MS_LAYER_PREFIX + wms.getName();
 
--- a/flys-artifacts/src/main/java/de/intevation/flys/utils/ThemeUtil.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/ThemeUtil.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,18 +1,21 @@
 package de.intevation.flys.utils;
 
-import org.apache.log4j.Logger;
-
 import java.awt.Color;
 import java.awt.Font;
 
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
 import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
 
 import de.intevation.artifacts.common.utils.XMLUtils;
-
 import de.intevation.flys.artifacts.model.MapserverStyle;
 import de.intevation.flys.artifacts.model.MapserverStyle.Clazz;
+import de.intevation.flys.artifacts.model.MapserverStyle.Expression;
+import de.intevation.flys.artifacts.model.MapserverStyle.Label;
 import de.intevation.flys.artifacts.model.MapserverStyle.Style;
-import de.intevation.flys.artifacts.model.MapserverStyle.Label;
 
 
 /**
@@ -20,56 +23,103 @@
  */
 public class ThemeUtil {
 
+    /** Private logger. */
     private static Logger logger =
-        Logger.getLogger(ThemeUtil.class);
+            Logger.getLogger(ThemeUtil.class);
 
     public final static String XPATH_FILL_COLOR =
-        "/theme/field[@name='fillcolor']/@default";
+            "/theme/field[@name='fillcolor']/@default";
 
     public final static String XPATH_LINE_COLOR =
-        "/theme/field[@name='linecolor']/@default";
+            "/theme/field[@name='linecolor']/@default";
 
     public static final String XPATH_LINE_SIZE =
-        "/theme/field[@name='linesize']/@default";
+            "/theme/field[@name='linesize']/@default";
 
     public static final String XPATH_LINE_STYLE =
-        "/theme/field[@name='linetype']/@default";
+            "/theme/field[@name='linetype']/@default";
+
+    public static final String XPATH_POINT_SIZE =
+            "/theme/field[@name='pointsize']/@default";
+
+    public static final String XPATH_POINT_COLOR =
+            "/theme/field[@name='pointcolor']/@default";
 
     public final static String XPATH_SHOW_BORDER =
-        "/theme/field[@name='showborder']/@default";
+            "/theme/field[@name='showborder']/@default";
 
     public final static String XPATH_SHOW_POINTS =
-        "/theme/field[@name='showpoints']/@default";
+            "/theme/field[@name='showpoints']/@default";
 
     public final static String XPATH_SHOW_LINE =
-        "/theme/field[@name='showlines']/@default";
+            "/theme/field[@name='showlines']/@default";
+
+    public final static String XPATH_SHOW_VERTICAL_LINE =
+            "/theme/field[@name='showverticalline']/@default";
+
+    public final static String XPATH_SHOW_HORIZONTAL_LINE =
+            "/theme/field[@name='showhorizontalline']/@default";
+
+    public final static String XPATH_SHOW_LINE_LABEL =
+            "/theme/field[@name='showlinelabel']/@default";
+
+    public final static String XPATH_SHOW_POINT_LABEL =
+            "/theme/field[@name='showpointlabel']/@default";
+
+    public final static String XPATH_SHOW_WIDTH =
+            "/theme/field[@name='showwidth']/@default";
+
+    public final static String XPATH_SHOW_LEVEL =
+            "/theme/field[@name='showlevel']/@default";
 
     public final static String XPATH_TRANSPARENCY =
-        "/theme/field[@name='transparent']/@default";
-
-    public final static String XPATH_TEXT_COLOR =
-        "/theme/field[@name='textcolor']/@default";
+            "/theme/field[@name='transparency']/@default";
 
-    public final static String XPATH_TEXT_SIZE =
-        "/theme/field[@name='textsize']/@default";
+    public final static String XPATH_SHOW_AREA =
+            "/theme/field[@name='showarea']/@default";
 
-    public final static String XPATH_TEXT_FONT =
-        "/theme/field[@name='font']/@default";
+    public final static String XPATH_SHOW_MIDDLE_HEIGHT =
+            "/theme/field[@name='showmiddleheight']/@default";
 
-    public final static String XPATH_TEXT_STYLE =
-        "/theme/field[@name='textstyle']/@default";
+    public final static String XPATH_LABEL_FONT_COLOR =
+            "/theme/field[@name='labelfontcolor']/@default";
+
+    public final static String XPATH_LABEL_FONT_SIZE =
+            "/theme/field[@name='labelfontsize']/@default";
+
+    public final static String XPATH_LABEL_FONT_FACE =
+            "/theme/field[@name='labelfontface']/@default";
+
+    public final static String XPATH_LABEL_FONT_STYLE =
+            "/theme/field[@name='labelfontstyle']/@default";
 
     public final static String XPATH_TEXT_ORIENTATION =
-        "/theme/field[@name='textorientation']/@default";
+            "/theme/field[@name='textorientation']/@default";
 
-    public final static String XPATH_TEXT_BACKGROUND =
-        "/theme/field[@name='backgroundcolor']/@default";
+    public final static String XPATH_LABEL_BGCOLOR =
+            "/theme/field[@name='labelbgcolor']/@default";
 
-    public final static String XPATH_SHOW_BACKGROUND =
-        "/theme/field[@name='showbackground']/@default";
+    public final static String XPATH_LABEL_SHOW_BACKGROUND =
+            "/theme/field[@name='labelshowbg']/@default";
+
+    public final static String XPATH_BACKGROUND_COLOR =
+            "/theme/field[@name='backgroundcolor']/@default";
 
     public final static String XPATH_SYMBOL =
-        "/theme/field[@name='symbol']/@default";
+            "/theme/field[@name='symbol']/@default";
+
+    public final static String XPATH_SHOW_MINIMUM =
+            "/theme/field[@name='showminimum']/@default";
+
+    public final static String XPATH_SHOW_MAXIMUM =
+            "/theme/field[@name='showmaximum']/@default";
+
+    public final static String XPATH_WSPLGEN_FIELDS =
+            "/theme[@name='WSPLGEN']/field";
+
+    /** XPATH to bandwidth field. */
+    public final static String XPATH_BANDWIDTH =
+            "/theme/field[@name='bandwidth']/@default";
 
 
     /** Parse string to be boolean with default if empty or unrecognized. */
@@ -90,6 +140,52 @@
 
 
     /**
+     * Attempt converting \param value to an integer, in failing cases,
+     * return \param defaultsTo.
+     * @param value String to be converted to integer.
+     * @param defaultsTo Default to return if conversion failed.
+     * @return \param value as integer or defaultsto if conversion failed.
+     */
+    public static int parseInteger(String value, int defaultsTo) {
+        if (value == null || value.length() == 0) {
+            return defaultsTo;
+        }
+
+        try {
+            return Integer.parseInt(value);
+        }
+        catch (NumberFormatException nfe) {
+            // do nothing
+        }
+
+        return defaultsTo;
+    }
+
+
+    /**
+     * Attempt converting \param value to a double, in failing cases,
+     * return \param defaultsTo.
+     * @param value String to be converted to double.
+     * @param defaultsTo Default to return if conversion failed.
+     * @return \param value as integer or defaultsto if conversion failed.
+     */
+    public static double parseDouble(String value, double defaultsTo) {
+        if (value == null || value.length() == 0) {
+            return defaultsTo;
+        }
+
+        try {
+            return Double.parseDouble(value);
+        }
+        catch (NumberFormatException nfe) {
+            // do nothing
+        }
+
+        return defaultsTo;
+    }
+
+
+    /**
      * Parses line width, defaulting to 0.
      * @param theme the theme
      */
@@ -100,7 +196,7 @@
         }
 
         try {
-            return Integer.valueOf(size);
+            return Integer.parseInt(size);
         }
         catch (NumberFormatException nfe) {
             logger.warn("Unable to set line size from string: '" + size + "'");
@@ -110,6 +206,31 @@
 
 
     /**
+     * Parse band width, defaulting to 0.
+     * @param theme the theme.
+     */
+    public static double parseBandWidth(Document theme) {
+        String bandWidth = XMLUtils.xpathString(theme, XPATH_BANDWIDTH, null);
+
+        return parseDouble(bandWidth, 0);
+    }
+
+
+    public static int parsePointWidth(Document theme) {
+        String width = XMLUtils.xpathString(theme, XPATH_POINT_SIZE, null);
+
+        return parseInteger(width, 3);
+    }
+
+
+    public static Color parsePointColor(Document theme) {
+        String color = XMLUtils.xpathString(theme, XPATH_POINT_COLOR, null);
+        logger.debug("parsePointColor(): color = " + color);
+        return parseColor(color);
+    }
+
+
+    /**
      * Parses the line style, defaulting to '10'.
      * @param theme The theme.
      */
@@ -144,14 +265,14 @@
      * Parses text size, defaulting to 10.
      * @param theme The theme.
      */
-    public static int parseTextSize(Document theme) {
-        String size = XMLUtils.xpathString(theme, XPATH_TEXT_SIZE, null);
+    public static int parseTextSize(Document theme, String path) {
+        String size = XMLUtils.xpathString(theme, path, null);
         if (size == null || size.length() == 0) {
             return 10;
         }
 
         try {
-            return Integer.valueOf(size);
+            return Integer.parseInt(size);
         }
         catch (NumberFormatException nfe) {
         }
@@ -159,6 +280,11 @@
     }
 
 
+    public static int parseTextSize(Document theme) {
+        return parseTextSize(theme, XPATH_LABEL_FONT_SIZE);
+    }
+
+
     /**
      * Parses the attribute 'showpoints', defaults to false.
      * @param theme The theme.
@@ -168,6 +294,41 @@
         return parseBoolean(show, false);
     }
 
+    /**
+     * Parses the attribute 'showmiddleheight', defaults to false.
+     * @param theme The theme.
+     */
+    public static boolean parseShowMiddleHeight(Document theme) {
+        String show = XMLUtils.xpathString(theme, XPATH_SHOW_MIDDLE_HEIGHT, null);
+        return parseBoolean(show, false);
+    }
+
+    /**
+     * Parses the attribute 'showarea', defaults to false.
+     * @param theme The theme.
+     */
+    public static boolean parseShowArea(Document theme) {
+        String show = XMLUtils.xpathString(theme, XPATH_SHOW_AREA, null);
+        return parseBoolean(show, false);
+    }
+
+    /**
+     * Parses the attribute 'showverticalline', defaults to true.
+     * @param theme The theme.
+     */
+    public static boolean parseShowVerticalLine(Document theme) {
+        String show = XMLUtils.xpathString(theme, XPATH_SHOW_VERTICAL_LINE, null);
+        return parseBoolean(show, true);
+    }
+
+    /**
+     * Parses the attribute 'showhorizontalline', defaults to true.
+     * @param theme The theme.
+     */
+    public static boolean parseShowHorizontalLine(Document theme) {
+        String show = XMLUtils.xpathString(theme, XPATH_SHOW_HORIZONTAL_LINE, null);
+        return parseBoolean(show, true);
+    }
 
     /**
      * Parses the attribute 'showlines', defaults to true.
@@ -178,6 +339,19 @@
         return parseBoolean(show, true);
     }
 
+    /**
+     * Parses the attribute 'showlinelabel', defaults to true.
+     * @param theme The theme.
+     */
+    public static boolean parseShowLineLabel(Document theme) {
+        String show = XMLUtils.xpathString(theme, XPATH_SHOW_LINE_LABEL, null);
+        return parseBoolean(show, false);
+    }
+
+    public static boolean parseShowPointLabel(Document theme) {
+        String show = XMLUtils.xpathString(theme, XPATH_SHOW_POINT_LABEL, null);
+        return parseBoolean(show, false);
+    }
 
     /**
      * Parses text color.
@@ -193,7 +367,7 @@
      * @param theme The theme.
      */
     public static Font parseTextFont(Document theme) {
-        String font = XMLUtils.xpathString(theme, XPATH_TEXT_FONT, null);
+        String font = XMLUtils.xpathString(theme, XPATH_LABEL_FONT_FACE, null);
         if (font == null || font.length() == 0) {
             return null;
         }
@@ -209,8 +383,8 @@
      * Parses the text style, defaults to 'Font.PLAIN'.
      * @param theme The theme.
      */
-    public static int parseTextStyle(Document theme) {
-        String style = XMLUtils.xpathString(theme, XPATH_TEXT_STYLE, null);
+    public static int parseTextStyle(Document theme, String path) {
+        String style = XMLUtils.xpathString(theme, path, null);
         if (style == null || style.length() == 0) {
             return Font.PLAIN;
         }
@@ -227,16 +401,29 @@
     }
 
 
+    public static int parseTextStyle(Document theme) {
+        return parseTextStyle(theme, XPATH_LABEL_FONT_STYLE);
+    }
+
+
+    public static boolean parseShowWidth(Document theme) {
+        String show = XMLUtils.xpathString(theme, XPATH_SHOW_WIDTH, null);
+        return parseBoolean(show, false);
+    }
+
+
+    public static boolean parseShowLevel(Document theme) {
+        String show = XMLUtils.xpathString(theme, XPATH_SHOW_LEVEL, null);
+        return parseBoolean(show, false);
+    }
+
     /**
      * Parses the textorientation, defaults to 'vertical'.
      * @param theme The theme.
      */
     public static String parseTextOrientation(Document theme) {
         String o = XMLUtils.xpathString(theme, XPATH_TEXT_ORIENTATION, null);
-        if (o == null || o.length() == 0) {
-            return "vertical";
-        }
-        if(o.equals("true")) {
+        if ("true".equals(o)) {
             return "horizontal";
         }
         else {
@@ -250,7 +437,7 @@
      * @param theme The theme.
      */
     public static Color parseTextBackground(Document theme) {
-        String color = getBackgroundColorString(theme);
+        String color = getLabelBackgroundColorString(theme);
         if (color == null || color.length() == 0) {
             return Color.WHITE;
         }
@@ -263,12 +450,42 @@
      * false.
      * @param theme The theme.
      */
-    public static boolean parseShowTextBackground(Document theme) {
-        String show = XMLUtils.xpathString(theme, XPATH_SHOW_BACKGROUND, null);
+    public static boolean parseLabelShowBackground(Document theme) {
+        String show = XMLUtils.xpathString(theme, XPATH_LABEL_SHOW_BACKGROUND, null);
         return parseBoolean(show, false);
     }
 
 
+    public static Color parseColor(String colorString) {
+        if (colorString == null || colorString.length() == 0) {
+            return null;
+        }
+        else if (colorString.indexOf("#") == 0) {
+            return parseHexColor(colorString);
+        }
+        else if (colorString.indexOf(",") >= 0) {
+            return parseRGB(colorString);
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Parse a string like "#00CC22" and return the corresponding color.
+     *
+     * @param hex The hex color value.
+     *
+     * @return a Color or null, if <i>hex</i> is empty.
+     */
+    public static Color parseHexColor(String hex) {
+        if (hex == null) {
+            return null;
+        }
+
+        return Color.decode(hex);
+    }
+
     /**
      * Parse a string like "103, 100, 0" and return a corresping color.
      * @param rgbtext Color as string representation, e.g. "255,0,20".
@@ -282,9 +499,9 @@
         Color c = null;
         try {
             c = new Color(
-                    Integer.valueOf(rgb[0].trim()),
-                    Integer.valueOf(rgb[1].trim()),
-                    Integer.valueOf(rgb[2].trim()));
+                    Integer.parseInt(rgb[0].trim()),
+                    Integer.parseInt(rgb[1].trim()),
+                    Integer.parseInt(rgb[2].trim()));
         }
         catch (NumberFormatException nfe) {
             c = null;
@@ -297,23 +514,32 @@
         return XMLUtils.xpathString(theme, XPATH_LINE_COLOR, null);
     }
 
+
     /** Get show border as string. */
     public static String getShowBorderString(Document theme) {
         return XMLUtils.xpathString(theme, XPATH_SHOW_BORDER, null);
     }
 
+
     /** Get fill color as string. */
     public static String getFillColorString(Document theme) {
         return XMLUtils.xpathString(theme, XPATH_FILL_COLOR, null);
     }
 
+
+    public static String getLabelBackgroundColorString(Document theme) {
+        return XMLUtils.xpathString(theme, XPATH_LABEL_BGCOLOR, null);
+    }
+
+
     public static String getBackgroundColorString(Document theme) {
-        return XMLUtils.xpathString(theme, XPATH_TEXT_BACKGROUND, null);
+        return XMLUtils.xpathString(theme, XPATH_BACKGROUND_COLOR, null);
     }
 
 
     public static String getTextColorString(Document theme) {
-        return XMLUtils.xpathString(theme, XPATH_TEXT_COLOR, null);
+        String textColor = XMLUtils.xpathString(theme, XPATH_LABEL_FONT_COLOR, null);
+        return textColor;
     }
 
 
@@ -321,11 +547,22 @@
         return XMLUtils.xpathString(theme, XPATH_SYMBOL, null);
     }
 
+
     public static String getTransparencyString(Document theme) {
         return XMLUtils.xpathString(theme, XPATH_TRANSPARENCY, null);
     }
 
 
+    public static String getShowMinimum(Document theme) {
+        return XMLUtils.xpathString(theme, XPATH_SHOW_MINIMUM, null);
+    }
+
+
+    public static String getShowMaximum(Document theme) {
+        return XMLUtils.xpathString(theme, XPATH_SHOW_MAXIMUM, null);
+    }
+
+
     /**
      * Gets color from color field.
      * @param theme    the theme document.
@@ -335,27 +572,99 @@
         return parseRGB(getFillColorString(theme));
     }
 
+
     public static boolean parseShowBorder(Document theme) {
         return parseBoolean(getShowBorderString(theme), false);
     }
 
-    public static boolean parseTransparency(Document theme) {
-        return parseBoolean(getTransparencyString(theme), false);
+
+    public static int parseTransparency(Document theme) {
+        return parseInteger(getTransparencyString(theme), 50);
     }
 
+
     /**
      * Gets color from color field.
      * @param theme    the theme document.
      * @return color.
      */
     public static Color parseLineColorField(Document theme) {
-        return parseRGB(getLineColorString(theme));
+        String lineColorStr = getLineColorString(theme);
+        logger.debug("parseLineColorField: lineColorStr = " +
+                (lineColorStr == null ? "null" : lineColorStr));
+        return parseRGB(lineColorStr);
+    }
+
+
+    public static boolean parseShowMinimum(Document theme) {
+        return parseBoolean(getShowMinimum(theme), false);
+    }
+
+
+    public static boolean parseShowMaximum(Document theme) {
+        return parseBoolean(getShowMaximum(theme), false);
+    }
+
+
+    public static String createWSPLGENStyle(Document theme) {
+        NodeList categories = (NodeList) XMLUtils.xpath(
+                theme,
+                XPATH_WSPLGEN_FIELDS,
+                XPathConstants.NODESET);
+
+        return createWSPLGENStyle(categories).toString();
+    }
+
+    protected static MapserverStyle createWSPLGENStyle(NodeList categories) {
+        MapserverStyle ms = new MapserverStyle();
+
+        for (int i = 0, n = categories.getLength(); i < n; i++) {
+            Element  cat = (Element) categories.item(i);
+            String color = cat.getAttribute("default");
+            String name  = cat.getAttribute("name");
+
+            String expr;
+
+            try {
+                int length = name.length();
+                int idx    = Integer.parseInt(name.substring(length-1, length));
+
+                expr = createWSPLGENExpression(idx);
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("Error while parsing WSPLGEN category.", nfe);
+                continue;
+            }
+
+            Clazz      c = new Clazz(expr);
+            Style      s = new Style();
+            s.setColor(color.replace(",", ""));
+            s.setSize(5);
+
+            c.addItem(new Expression("(" + expr + ")"));
+            c.addItem(s);
+
+            ms.addClazz(c);
+        }
+
+        return ms;
+    }
+
+
+    protected static String createWSPLGENExpression(int idx) {
+        if (idx < 5) {
+            int lower = idx - 1;
+            return "[DIFF] >= " + lower + " AND  [DIFF] < " + idx;
+        }
+        else {
+            return "[DIFF] >= 4";
+        }
     }
 
 
     public static String createMapserverStyle(Document theme) {
         String symbol    = getSymbol(theme);
-        String backcolor = getBackgroundColorString(theme);
+        String backcolor = getLabelBackgroundColorString(theme);
         String linecolor = getLineColorString(theme);
 
         int linewidth = parseLineWidth(theme);
--- a/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/FacetCreator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/FacetCreator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,19 +3,19 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.log4j.Logger;
+
 import com.vividsolutions.jts.geom.Envelope;
 
-import de.intevation.artifacts.CallContext;
-
 import de.intevation.artifactdatabase.state.Facet;
-
-import de.intevation.flys.model.CrossSectionTrack;
-
+import de.intevation.artifacts.CallContext;
 import de.intevation.flys.artifacts.FLYSArtifact;
 import de.intevation.flys.artifacts.model.FacetTypes;
-import de.intevation.flys.artifacts.model.WMSLayerFacet;
+import de.intevation.flys.artifacts.model.map.WMSLayerFacet;
+import de.intevation.flys.artifacts.model.map.WSPLGENLayerFacet;
 import de.intevation.flys.artifacts.resources.Resources;
 import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
+import de.intevation.flys.model.CrossSectionTrack;
 import de.intevation.flys.utils.FLYSUtils;
 import de.intevation.flys.utils.GeometryUtils;
 import de.intevation.flys.utils.MapfileGenerator;
@@ -23,10 +23,12 @@
 
 public class FacetCreator implements FacetTypes {
 
-    public static final String I18N_WSPLGEN_RESULT   = "floodmap.uesk";
-    public static final String I18N_WSPLGEN_DEFAULT  = "floodmap.uesk";
-    public static final String I18N_BARRIERS         = "floodmap.barriers";
-    public static final String I18N_BARRIERS_DEFAULT = "floodmap.barriers";
+    public static final String I18N_WSPLGEN_RESULT    = "floodmap.uesk";
+    public static final String I18N_WSPLGEN_DEFAULT   = "floodmap.uesk";
+    public static final String I18N_BARRIERS          = "floodmap.barriers";
+    public static final String I18N_BARRIERS_DEFAULT  = "floodmap.barriers";
+    public static final String I18N_USERSHAPE         = "floodmap.usershape";
+    public static final String I18N_USERSHAPE_DEFAULT = "floodmap.usershape";
 
     protected FLYSArtifact artifact;
 
@@ -39,6 +41,10 @@
     protected String hash;
     protected String stateId;
 
+
+    private static Logger logger = Logger.getLogger(FacetCreator.class);
+
+
     public FacetCreator(
         FLYSArtifact artifact,
         CallContext  cc,
@@ -70,6 +76,10 @@
         String river = getRiver();
         double kms[] = FLYSUtils.getKmRange(artifact);
 
+        logger.debug("### getWSPLGENBounds");
+        logger.debug("###    from km: " + kms[0]);
+        logger.debug("###    to   km: " + kms[1]);
+
         CrossSectionTrack a =
             CrossSectionTrack.getCrossSectionTrack(river, kms[0]);
 
@@ -84,6 +94,9 @@
         Envelope envB = b.getGeom().getEnvelopeInternal();
 
         envA.expandToInclude(envB);
+        envA = GeometryUtils.transform(envA, getSrid());
+
+        logger.debug("###    => " + envA);
 
         return envA;
     }
@@ -97,7 +110,7 @@
     }
 
     public void createWSPLGENFacet() {
-        WMSLayerFacet wsplgen = new WMSLayerFacet(
+        WSPLGENLayerFacet wsplgen = new WSPLGENLayerFacet(
             0,
             FLOODMAP_WSPLGEN,
             Resources.getMsg(
@@ -118,6 +131,7 @@
         wsplgen.addLayer(
             MapfileGenerator.MS_WSPLGEN_PREFIX + artifact.identifier());
         wsplgen.setSrid(getSrid());
+        wsplgen.setOriginalExtent(bounds);
         wsplgen.setExtent(bounds);
 
         tmpFacets.add(wsplgen);
@@ -145,7 +159,30 @@
     }
 
 
+    public void createUserShapeFacet() {
+        WMSLayerFacet shape = new WMSLayerFacet(
+            1,
+            FLOODMAP_USERSHAPE,
+            Resources.getMsg(
+                cc.getMeta(),
+                I18N_USERSHAPE,
+                I18N_USERSHAPE_DEFAULT),
+            ComputeType.ADVANCE,
+            stateId,
+            hash,
+            getUrl());
+
+        shape.addLayer(
+            MapfileGenerator.MS_USERSHAPE_PREFIX + artifact.identifier());
+        shape.setSrid(getSrid());
+        shape.setExtent(getBounds());
+
+        tmpFacets.add(shape);
+    }
+
+
     public void finish() {
         facets.addAll(getFacets());
     }
-} // end of FacetCreator
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/JobObserver.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/JobObserver.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,16 +1,16 @@
 package de.intevation.flys.wsplgen;
 
 import java.io.BufferedReader;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.IOException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.log4j.Logger;
 
 import de.intevation.flys.artifacts.model.CalculationMessage;
-import de.intevation.flys.artifacts.model.WSPLGENJob;
+import de.intevation.flys.artifacts.model.map.WSPLGENJob;
 
 
 public class JobObserver extends Thread {
--- a/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/ProblemObserver.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/ProblemObserver.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,8 +5,8 @@
 
 import org.apache.log4j.Logger;
 
-import de.intevation.flys.artifacts.model.WSPLGENCalculation;
-import de.intevation.flys.artifacts.model.WSPLGENJob;
+import de.intevation.flys.artifacts.model.map.WSPLGENCalculation;
+import de.intevation.flys.artifacts.model.map.WSPLGENJob;
 
 
 public class ProblemObserver extends JobObserver {
--- a/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/Scheduler.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/Scheduler.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,8 +8,7 @@
 import org.apache.log4j.Logger;
 
 import de.intevation.artifacts.CallContext;
-
-import de.intevation.flys.artifacts.model.WSPLGENJob;
+import de.intevation.flys.artifacts.model.map.WSPLGENJob;
 
 
 /**
--- a/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/WSPLGENCallable.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/java/de/intevation/flys/wsplgen/WSPLGENCallable.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,14 +1,13 @@
 package de.intevation.flys.wsplgen;
 
+import java.io.File;
 import java.io.IOException;
-import java.io.File;
 import java.util.concurrent.Callable;
 
 import org.apache.log4j.Logger;
 
 import de.intevation.artifacts.CallContext;
-
-import de.intevation.flys.artifacts.model.WSPLGENJob;
+import de.intevation.flys.artifacts.model.map.WSPLGENJob;
 
 
 /**
Binary file flys-artifacts/src/main/resources/images/bfg_logo.gif has changed
Binary file flys-artifacts/src/main/resources/images/intevation.png has changed
--- a/flys-artifacts/src/main/resources/messages.properties	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/resources/messages.properties	Fri Sep 28 12:15:52 2012 +0200
@@ -1,3 +1,6 @@
+false=Nein
+true=Ja
+
 state.winfo.river = River
 state.winfo.calculation_mode = Calculation Mode
 state.winfo.location_distance = Location or distance selection
@@ -13,6 +16,48 @@
 state.winfo.uesk.differences = Differenzen between waterlevel and terrain
 state.winfo.uesk.scenario = Flood Plain / Scenario
 state.winfo.waterlevel_pair_select = Chosen differences
+state.winfo.historicalq.reference_gauge = Selection of Reference Gauge
+state.winfo.historicalq.timerange = Selection of Evaluation time
+state.winfo.historicalq.mode = Selecion of analyses
+state.winfo.reference.curve.input.start = Chosen Reference
+state.winfo.reference.curve.input.end = Chosen Evaluation
+state.fix.river = River
+state.fix.calculation.mode = Calculation Mode
+state.fix.location = Distance
+state.fix.period = Period
+state.fix.gaugerange = Gaugerange
+state.fix.eventselect = Event selection
+state.fix.analysis.referenceperiod = Reference period
+state.fix.analysis.analysisperiods = Analysis period
+state.fix.analysis.function = Function
+state.fix.analysis.preprocessing = Outliers
+state.fix.preprocess=preprocess
+state.fix.vollmer.function=Function
+state.fix.vollmer.preprocessing = Outliers
+state.fix.vollmer.qa = Input for W/Q data
+
+state.minfo.river = River
+state.minfo.calculation_mode = Calculation Mode
+state.minfo.distance_only = Range selection
+state.minfo.dischargestate = Selection of discharge state and channel
+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
+state.minfo.bed.location = Location/Distance
+state.minfo.bed.periods = Periods
+state.minfo.bed.char_diameter = Characteristic Diameter
+state.minfo.soundings = Choose Soundings
+
+year=Year
+epoch=Epoch
+soundings = Soundings / Epochs
+
+historical.mode.w = Waterlevel Analyse
+historical.mode.q = Discharge Analyse
 
 calc.surface.curve = Water Level/Surface Curve
 calc.flood.map = Flood Plain
@@ -20,22 +65,67 @@
 calc.duration.curve = Duration Curve
 calc.discharge.longitudinal.section = TODO (W bei...)
 calc.w.differences = Differences
+calc.historical.discharge.curve = Historical Discharge Curve
+calc.reference.curve = Reference Curve
+calc.fixation.default = Fixingg
+calc.fixation.vollmer = Generative Waterlevel
+calc.bed.middle = Middle Bed Height
+calc.bed.diff = Bed Height Difference
+calc.bed.quality = Bed Quality
+calc.sediment.load = Sediment Load
+calc.flow.velocity = Flow Velocity
+calc.sq.relation = Load Discharge Relation
+calc.bed.d90 = D90
+calc.bed.d84 = D84
+calc.bed.d80 = D80
+calc.bed.d75 = D75
+calc.bed.d70 = D70
+calc.bed.d60 = D60
+calc.bed.d50 = D50
+calc.bed.d40 = D40
+calc.bed.d30 = D30
+calc.bed.d25 = D25
+calc.bed.d20 = D20
+calc.bed.d16 = D16
+calc.bed.d10 = D10
+calc.bed.dmin = Dmin
+calc.bed.dmax = Dmax
+calc.bed.dmid = Dmid
 
-calc.reference.curve = Reference Curve
+calculation.analysis = Fixinganalysis
+calculation.vollmer = relocated Waterlevel Calculation
+
+state.chart.river = River
+state.chart.type = Charttype
+
+chart.new.durationcurve = Duration Curve
+chart.new.computeddischargecurve = Discharge Curve
+chart.new.longitudinal_section = Longitudinal Section
+chart.new.w_differences = Differences
+chart.new.crosssection = Cross Section
 
 cross_section = Cross Section
 
+reference_curve = Reference Curve
+reference_curve_normalized = Normalized Reference Curve
+
 scenario.current = Current
 scenario.potentiel = Potentiel
 scenario.scenario = Scenario
+
 floodplain.option = Use Floodplain?
+floodplain.active = Activ
+floodplain.inactive = Inactiv
 
 river = River
 calculation_mode = Calculation Mode
 ld_locations = Location(s)
+main_channel = Main channel
+total_channel = Total channel
 
 chart.longitudinal.section.title = W-Longitudinal Section
 chart.longitudinal.section.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###}
+chart.longitudinal.section.shortsubtitle = {0}
 chart.longitudinal.section.xaxis.label = {0}-km
 chart.longitudinal.section.yaxis.label = W [{0}]
 chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s]
@@ -55,21 +145,103 @@
 chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###}
 chart.computed.discharge.curve.yaxis.label = W [NN + m]
 chart.computed.discharge.curve.curve.label = Discharge Curve {0} km {1}
+chart.computed.discharge.curve.gauge = Discharge curve at gauge {0} (km {1})
 chart.duration.curve.title = Duration Curve
 chart.duration.curve.subtitle = {0}-km: {1,number,#.###}
 chart.duration.curve.xaxis.label = Duration of Non-Exceedence [Days]
 chart.duration.curve.yaxis.label = W [NN + m]
-chart.duration.curve.curve.w = Waterlevel duration curve for {0}
-chart.duration.curve.curve.q = Discharge duration curve for {0}
+chart.duration.curve.curve.w = Waterlevel duration curve for {0} (km: {1})
+chart.duration.curve.curve.q = Discharge duration curve for {0} (km: {1})
+chart.historical.discharge.title = Historical Discharge Curves
+chart.historical.discharge.subtitle = Gauge {0}
+chart.historical.discharge.xaxis.label = Time
+chart.historical.discharge.yaxis.label = Q [m\u00b3/s]
+chart.historical.discharge.yaxis.second.label = W [cm]
+
+chart.reference.curve.title = Reference Curve
+chart.reference.curve.subtitle = {0}
+
+chart.reference.curve.x.axis.in.cm = Reference Gauge(s) [cm]
+chart.reference.curve.x.axis.in.m = Reference Station [NN + m]
+chart.reference.curve.y.axis.in.cm = Target Gauge(s) [cm]
+chart.reference.curve.y.axis.in.m = Target Station(s) [NN + m] 
 
 chart.w_differences.title = Differences
 chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###}
 chart.w_differences.yaxis.label = m
 chart.w_differences.yaxis.second.label = W [NN + m]
 
+chart.normalized.reference.curve.title = Reduced Reference Curve
+
+chart.fixings.wq.title = Fixings Analysis at km {0}
+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.bedquality.title=Bed Longitudinal Section
+chart.bedquality.xaxis.label=River-Km
+chart.bedquality.yaxis.label=Diameter [m]
+chart.bedquality.yaxis.label.porosity=Porosity [%]
+chart.bedquality.yaxis.label.density=Density [t/m\u00b3]
+
+chart.bedheight_middle.section.title=Middle Bed Height
+chart.bedheight_middle.section.yaxis.label=middle Bed Height [mm a NN]
+
+chart.flow_velocity.section.title=Geschwindigkeit- und Schubspannung
+chart.flow_velocity.section.yaxis.label=Speed v [m/s]
+chart.flow_velocity.section.yaxis.second.label=Schubspannung Tau [N]
+
+chart.sq_relation.xaxis.label = Discharge [m\u00b3/s]
+chart.sq_relation.yaxis.label = Transport [kg/s]
+chart.sq_relation_a.title = Feinkornanteil
+chart.sq_relation_b.title = Sand (Suspensionstransport)
+chart.sq_relation_c.title = Sand (Geschiebetransport)
+chart.sq_relation_d.title = Fein- und Mittelkies
+chart.sq_relation_e.title = Grobkornanteil (> Mittelkies)
+chart.sq_relation_f.title = Geschiebetransport gesamt
+facet.sq_relation.curve = Potenziell (Geschiebedaten)
+facet.sq_relation.measurements = Geschiebedaten
+facet.sq_relation.outliers = Ausrei\u00dfer Durchgang {0}
+facet.sq_relation.outlier.curve = Potenziell Durchgang {0}
+facet.sq_relation.outlier.measurement = Geschiebedaten Durchgang {0}
+
 facet.longitudinal_section.annotations = POIs
 facet.discharge_curves.mainvalues.q = Q (main values)
 facet.discharge_curves.mainvalues.w = W (main values)
+facet.flow_velocity.mainchannel = v Mainchannel at {0}
+facet.flow_velocity.totalchannel = v Totalchannel at {0}
+facet.flow_velocity.tauchannel = TAU Mainchannel at {0}
+facet.bedheight_middle.single = Bed Height {0,number,####}
+facet.bedheight_middle.epoch = Bed Height Epoch {0,number,####} - {1,number,####}
+facet.bedquality.bed.porosity.toplayer = Porosity ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.porosity.sublayer = Porosity ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.density.toplayer = Density ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.density.sublayer = Density ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.diameter.toplayer = {0}_Bed ({1,date} - {2,date}) ({3})
+facet.bedquality.bed.diameter.sublayer = {0}_Bed ({1,date} - {2,date}) ({3})
+facet.bedquality.bedload.diameter = {0}_Bedload
+bedquality.toplayer = 0.0m - 0.3m
+bedquality.sublayer = 0.1m - 0.5m
+facet.bedheight.diff.year = Bedheight Difference {0}
+facet.bedheight.diff.morph = Morphologic Width {0}
+facet.bedheight.diff.height1 = Original Height Minuend {0}
+facet.bedheight.diff.height2 = Original Height Subtrahend {0}
+facet.bedheight.diff.absolute = Bedheight Difference/Year {0}
+facet.bedheight.diff.epoch = Bedheight Difference {0}
+
+chart.beddifference.height.title = Bedheight Difference
+chart.beddifference.height.xaxis.label = River-Km [km]
+chart.beddifference.height.yaxis.label = Difference [cm/year]
+chart.beddifference.epoch.title = Bedheight Difference
+chart.beddifference.xaxis.label = River-Km [km]
+chart.beddifference.yaxis.label.diff = Difference [m]
+chart.beddifference.yaxis.label.height = Absolute Height [m]
+chart.beddifference.year.title = Bedheight Difference
+chart.beddifference.xaxis.label = River-Km [km]
+chart.beddifference.yaxis.label.diff = Difference [m]
+chart.beddifference.yaxis.label.morph = Morphologic Width [m]
+chart.beddifference.yaxis.label.heights = Absolute Height [m]
+
 
 export.waterlevel.csv.header.km = River-Km
 export.waterlevel.csv.header.w = W [NN + m]
@@ -83,7 +255,7 @@
 export.waterlevel.csv.meta.river = # River: {0}
 export.waterlevel.csv.meta.range = # Location/Range (km): {0} - {1}
 export.waterlevel.csv.meta.gauge = # Gauge: {0}
-export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0} - {1}
+export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0}
 export.waterlevel.csv.meta.w = # W (NN + m): {0} - {1}
 export.waterlevel.csv.not.in.gauge.range = Outside selected gauge
 export.computed.discharge.curve.csv.header.w = W [NN + m]
@@ -96,6 +268,67 @@
 export.discharge.longitudinal.section.csv.header.cw = W corr.
 export.discharge.longitudinal.section.csv.header.q = Q [m\u00b3/s]
 export.discharge.curve.at.header = Computed Discharge Curve for {0} {0}-km: {1}
+export.historical.discharge.csv.header.timerange = Timerange
+export.historical.discharge.csv.header.waterlevel = Waterlevel
+export.historical.discharge.csv.header.discharge = Discharge
+export.historical.discharge.csv.header.diff = Difference
+export.historical.discharge.csv.header.gaugename = Gaugename
+export.reference_curve.csv.header.km = km
+export.reference_curve.csv.header.w.cm = W (cm at Gauge)
+export.reference_curve.csv.header.w.m = W (m + NHN)
+export.reference_curve.csv.header.w.q = equiv. Q (m\u00b3/s)
+
+export.waterlevel.pdf.mode = Waterlevel
+export.computed.discharge.pdf.mode = Computed Dischargecurve
+export.duration.pdf.mode = Durationcurve
+export.wdifferences.pdf.mode = W Differences
+export.historical.discharge.pdf.mode = Historical Discharge
+export.reference_curve.pdf.mode = Reference Curve
+export.computed.discharge.pdf.file = /jasper/computed-discharge_en.jasper
+export.duration.pdf.file = /jasper/duration_en.jasper
+export.waterlevel.pdf.file = /jasper/waterlevel_en.jasper
+export.wdifferences.pdf.file = /jasper/wdifferences_en.jasper
+export.historical.discharge.pdf.file = /jasper/historical-discharge_en.jasper
+export.reference_curve.pdf.file = /jasper/reference_en.jasper
+export.reference_curve.pdf.file.gauge = /jasper/reference_en_gauge.jasper
+export.reference_curve.pdf.file.gauge.end = /jasper/reference_en_gauge_end.jasper
+export.reference_curve.pdf.file.gauge.start.end = /jasper/reference_en_gauge_start_end.jasper
+export.flow_velocity.csv.header.km = River Km
+export.flow_velocity.csv.header.v_total = v Total Channel
+export.flow_velocity.csv.header.v_main = v Main Channel
+export.flow_velocity.csv.header.tau_main = TAU Main Channel
+export.flow_velocity.csv.header.q = Q [m\u00b3/s]
+export.flow_velocity.csv.header.locations = Location
+export.bedheight_middle.csv.header.km = River km
+export.bedheight_middle.csv.header.sounding = Sounding / Epoch
+export.bedheight_middle.csv.header.height = middle Bed Height
+export.bedheight_middle.csv.header.uncertainty = Uncertainty [m]
+export.bedheight_middle.csv.header.datagap = Data Gap
+export.bedheight_middle.csv.header.soundingwidth = Sounding Width [m]
+export.bedheight_middle.csv.header.width = morphological active width [m]
+export.bedheight_middle.csv.header.locations = Location
+export.sqrelation.csv.header.parameter = Parameter
+export.sqrelation.csv.header.station = Station
+export.sqrelation.csv.header.km = River-Km
+export.sqrelation.csv.header.function = Function
+export.sqrelation.csv.header.gauge = Gauge
+export.sqrelation.csv.header.coeff.a = a
+export.sqrelation.csv.header.coeff.b = b
+export.sqrelation.csv.header.coeff.q = Q
+export.sqrelation.csv.header.coeff.r = r^2
+export.sqrelation.csv.header.n.total = n total
+export.sqrelation.csv.header.n.outliers = n outliers
+export.sqrelation.csv.header.c.duan = C (DUAN)
+export.sqrelation.csv.header.c.ferguson = C (FERGUSON)
+export.sqrelation.csv.header.variance = Standard variance
+export.minfo.bedquality.km = km
+export.minfo.bedquality.density_cap = Density Toplayer
+export.minfo.bedquality.density_sub = Density Sublayer
+export.minfo.bedquality.porosity_cap = Porosity Toplayer
+export.minfo.bedquality.porosity_sub = Porosity Sublayer
+export.minfo.bedquality.bedload = Bedload Diameter
+export.minfo.bedquality.bed_cap = Bed Diameter Toplayer
+export.minfo.bedquality.bed_sub = Bed Diameter Sublayer
 
 floodmap.wmsbackground = Background Map
 floodmap.riveraxis = River Axis
@@ -109,6 +342,8 @@
 floodmap.lines = Lines
 floodmap.buildings = Buildings
 floodmap.fixpoints = Fixpoints
+floodmap.floodmaps = Floodmaps
+floodmap.usershape = User data
 
 wsplgen.job.queued = WSPLGEN job in queue.
 wsplgen.job.error = An unexpected error while starting WSPLGEN occured.
@@ -119,3 +354,149 @@
 Saar = Saar
 Elbe = Elbe
 
+state.map.river = River
+
+spline.interpolation.failed = Spline interpolation failed.
+cannot.find.w.for.q = Cannot find W for Q = {0,number,#.##}.
+cannot.find.q = Cannot find Q = {0,number,#.##}.
+no.ws.found = No Ws found.
+no.q.found.in.column = No Q found in {0,integer} column.
+spline.creation.failed = Spline creation failed.
+cannot.find.w.or.q = Cannot find W or Q.
+km.not.found = Cannot find km.
+cannot.create.wq.relation = Cannot create W/Q relation.
+cannot.create.index.q.relation = Cannot create index/Q relation.
+
+w.w.qkm1.failed = Calculating Q for WST index {0,number,#.##} failed.
+w.w.wkm1.failed = Calculating W for Q = {0,number,#.##} /  WST index {1,number,#.##} failed.
+w.w.qkm2.failed = Calculating Q for WST index {0,number,#.##} failed.
+w.w.wkm2.failed = Calculating W for Q = {0,number,#.##} /  WST index {1,number,#.##} failed.
+
+cannot.find.hist.q.for.w = Cannot find Q for W = {0,number,#.##} in timerange {1, date} - {2, date}
+cannot.find.hist.q.tables = Cannot find Discharge Tables for given timerange.
+cannot.find.hist.q.reftable = Cannot find reference Discharge Table for specified Gauge.
+
+more.than.one.q.for.w = Found more Qs for W = {0,number,#.##}.
+
+no.river.selected = No river selected.
+no.gauge.selected = No gauge selected.
+no.locations.selected = No locations selected.
+no.kms.selected = No KMs selected.
+converting.ws.to.qs.failed = Converting Ws to Qs failed.
+no.wst.for.river = No WST found for selected river.
+no.range.found = No range found.
+no.gauge.found.for.km = No gauge found for KM.
+cannot.create.segments = Cannot create segments.
+cannot.compute.discharge.curve = Cannot create discharge curve.
+cannot.find.ds = Cannot find Ds.
+no.segments.found = No segments found.
+no.values.given = No values given.
+cannot.interpolate.w.q = Cannot interpolate W/Q.
+manualpoints = Manual Points
+
+no.reference.start.km = No reference start station given.
+no.reference.end.kms = No reference end station(s) given.
+waterlevels = Waterlevels
+
+help.index=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe
+help.winfo=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO
+help.winfo.wsp.location_distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten
+help.winfo.wsp.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_W.2BAC8-Q_Daten
+help.winfo.discharge.longitudinal.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Berechnungsstrecke
+help.winfo.duration.locations=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten
+help.winfo.discharge.longitudinal.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_f.2BAPw-r_W.2BAC8-Q_Daten
+help.winfo.diff.diffs=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Zusammenstellen_der_Differenzen
+help.winfo.reference.curve.start=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Bezugsortes_.2BAC8_Bezugspegels
+help.winfo.reference.curve.end=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Zielortes_.2BAC8_Zielpegels
+help.winfo.uesk.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Berechnungsstrecke
+help.winfo.uesk.wsp=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Wasserspiegellage
+help.winfo.uesk.dem=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Digitalen_Gel.2BAOQ-ndemodells
+help.winfo.uesk.profiles=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Abstand_Interpolierte_Profile
+help.winfo.uesk.floodplain=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Laterale_Begrenzung
+help.winfo.uesk.differences=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Differenz_Wasserspiegellage_und_Gel.2BAOQ-nde
+help.winfo.uesk.scenario=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#A.2BANw-berschwemmungsfl.2BAOQ-che_.2BAC8_Szenario
+help.winfo.historical.discharge.reference_gauge=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Bezugspegels
+help.winfo.historical.discharge.timerange=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_des_Auswertezeitraumes
+help.winfo.historical.discharge.mode=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_der_Analyseart
+
+fix.reference.period=Reference period
+fix.reference.period.event=Reference event
+fix.reference.period.event.short=R
+fix.analysis.short=A
+fix.analysis.periods=Analysis periods
+fix.derivative=Derivative
+fix.outlier=Outlier
+fix.analysis=Analysis event
+fix.deviation=Standard deviation
+fix.reference.deviation=Reference deviation
+fix.vollmer.wq.curve=W/Q
+fix.vollmer.wq.outliers=Outliers
+fix.vollmer.wq.events=Events
+qsectors=Discharge Sectors
+
+chart.fix.deltawt.title=Difference from compensating curve at kilometer {0}
+chart.fix.deltawt.subtitle=Water: {0}; Period:  {1,date,short} to {2,date,short}; Reference period: {3,date,short} bis {4,date,short}
+chart.fix.deltawt.xaxis.label=Date
+chart.fix.deltawt.yaxis.label=\u0394 W(t) [cm]
+
+chart.fix.wq.subtitle=Water: {0}; Period: {1,date,short} to {2,date,short}
+chart.fixings.derivedcurve.title = Derived curve at km {0}
+chart.fixings.deltawt.title = Differences from fitted curve at km {0}
+
+chart.fixings.longitudinalsection.title=Longitudinal section
+
+export.fixings.deltawt.csv.header.km=km
+export.fixings.deltawt.csv.header.deltaw=\u0394 W [cm]
+export.fixings.deltawt.csv.header.q=Discharge [m\u00b3/s]
+export.fixings.deltawt.csv.header.w=Waterlevel [m]
+export.fixings.deltawt.csv.header.t=Date
+export.fixings.deltawt.csv.t.format=yyyy/MM/dd
+export.fixings.deltawt.csv.header.time.range=State
+export.fixings.deltawt.csv.reference=R
+export.fixings.deltawt.csv.analysis=A{0,number,integer}
+
+fix.missing.river=Missing river
+fix.missing.from=Missing start km
+fix.missing.to=Missing end km
+fix.missing.step="Missing step width
+fix.missing.function=Missing function type
+fix.missing.events=Missing list of events
+fix.missing.reference.period=Missing reference period
+fix.missing.analysis.periods=Missing analysis periods
+fix.missing.qstart.sector=Missing discharge start sector
+fix.missing.qend.sector=Missing discharge end sector
+fix.missing.prepocessing=Missing info about preprocessing
+fix.no.overview.available=No overview available
+fix.invalid.function.name=Name of function unknown
+fix.too.less.data.colums=Too less data columns for calculation
+fix.fitting.failed=Fitting failed
+fix.invalid.values=Invalid values
+fix.cannot.load.data=Cannot fetch data from database
+
+fix.km.chart.q.sector.border0=(MNQ + MQ)/2
+fix.km.chart.q.sector.border1=(MQ + MHQ)/2
+fix.km.chart.q.sector.border2=HQ5
+fix.km.chart.label.date=yyyy/MM/dd
+fix.km.chart.title=Fixings {0} km {1,number,#.###}
+fix.km.chart.q.axis=Q [m\u00b3/s]
+fix.km.chart.w.axis=W [NN + m]
+fix.km.chart.measured=measured
+fix.km.chart.interpolated=interpolated
+
+fix.export.at.header = Exported fixings discharge curve for {0} {0}-km: {1}
+sq.km.chart.label = Measuring Points
+sq.km.chart.title = Measuring Points
+sq.km.chart.km.axis = km
+sq.km.chart.date.axis = Date
+
+module.winfo = WINFO
+module.minfo = MINFO
+module.fixanalysis = Fix Analysis
+module.new_map = New Map
+module.new_chart = New Chart
+
+load_diameter = Bedload Diameter
+bed_diameter = Bed Diameter
+
+area.label.template = Area = %s m\u00b3
+
--- a/flys-artifacts/src/main/resources/messages_de.properties	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/resources/messages_de.properties	Fri Sep 28 12:15:52 2012 +0200
@@ -1,3 +1,6 @@
+false=Nein
+true=Ja
+
 state.winfo.river = Gew\u00e4sser
 state.winfo.calculation_mode = Berechnungsart
 state.winfo.location_distance = Wahl des Berechnungsortes/strecke
@@ -13,35 +16,121 @@
 state.winfo.uesk.differences = Differenzen zwischen Wasserspiegellage und Gel\u00e4nde
 state.winfo.uesk.scenario = \u00dcberschwemmungsfl\u00e4che / Szenario
 state.winfo.waterlevel_pair_select = Ausgew\u00e4hlte Differenzen
+state.winfo.historicalq.reference_gauge = Wahl des Bezugspegels
+state.winfo.historicalq.timerange = Wahl des Auswertezeitraums
+state.winfo.historicalq.mode = Wahl der Analyseart
+state.winfo.reference.curve.input.start = Bezugsort
+state.winfo.reference.curve.input.end = Zielort(e)
+state.fix.river = Gew\u00e4sser
+state.fix.calculation.mode = Berechnungsart
+state.fix.location = Strecke
+state.fix.period = Zeitraum
+state.fix.gaugerange = Abflussklassen
+state.fix.eventselect = Ereignisauswahl
+state.fix.analysis.referenceperiod = Bezugszeitraum
+state.fix.analysis.analysisperiods = Analysezeitr\u00e4ume
+state.fix.analysis.function = Funktion
+state.fix.analysis.preprocessing = Ausrei\u00DFer
+state.fix.preprocess=aufbereiten
+state.fix.vollmer.function=Funktion
+state.fix.vollmer.preprocessing = Ausrei\u00DFer
+state.fix.vollmer.qa = Eingabe f\u00e4r W/Q Daten
+
+state.minfo.river = Gew\u00e4sser
+state.minfo.calculation_mode = Berechnungsart
+state.minfo.distance_only = Wahl der Berechnungsstrecke
+state.minfo.dischargestate = Abflusszustand und Gerinne
+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
+state.minfo.bed.location = Ort(e)/Strecke
+state.minfo.bed.periods = Zeitraum/Zeitr\u00e4ume
+state.minfo.bed.char_diameter = Charakteristischer Durchmesser
+state.minfo.soundings = Wahl der Peilungen
+
+year=Jahr
+epoch=Epoche
+soundings = Peilungen / Epochen
+
+historical.mode.w = Wasserstandsanalyse
+historical.mode.q = Abflussanalyse
 
 calc.surface.curve = Wasserstand/Wasserspiegellage
 calc.flood.map = \u00dcberschwemmungsfl\u00e4che
-calc.discharge.curve = Abflusskurve/abflusstafel
+calc.discharge.curve = Abflusskurve/Abflusstafel
 calc.duration.curve = Dauerlinie
-calc.discharge.longitudinal.section = W bei ungleichwertigem Abflussl\u00e4ngsschnitt
+calc.discharge.longitudinal.section = W f\u00fcr ungleichwertigen Abflussl\u00e4ngsschnitt
 calc.w.differences = Differenzen
+calc.historical.discharge.curve = Hist. Abflusskurven
+calc.reference.curve = Bezugslinie
+calc.fixation.default = Fixierungsanalyse
+calc.fixation.vollmer = Ausgelagerte Wasserspiegellage
+calc.bed.middle = Mittlere Sohlh\u00f6he
+calc.bed.diff = Sohlh\u00f6hendifferenz
+calc.bed.quality = Sohlbeschaffenheit
+calc.sediment.load = Sedimentfracht
+calc.flow.velocity = Flie\u00dfgeschwindigkeit
+calc.sq.relation = Transport-Abfluss Beziehung
+calc.bed.d90 = D90
+calc.bed.d84 = D84
+calc.bed.d80 = D80
+calc.bed.d75 = D75
+calc.bed.d70 = D70
+calc.bed.d60 = D60
+calc.bed.d50 = D50
+calc.bed.d40 = D40
+calc.bed.d30 = D30
+calc.bed.d25 = D25
+calc.bed.d20 = D20
+calc.bed.d16 = D16
+calc.bed.d10 = D10
+calc.bed.dmin = Dmin
+calc.bed.dmax = Dmax
+calc.bed.dmid = Dmid
 
-calc.reference.curve = Bezugslinie
+calculation.analysis = Fixierungsanalyse
+calculation.vollmer = ausgelagerte Wasserspiegellage
+
+state.chart.river = Gew\u00e4sser
+state.chart.type = Diagrammtyp
+
+chart.new.durationcurve = Dauerlinie
+chart.new.computeddischargecurve = Abflusskurve
+chart.new.longitudinal_section = L\u00e4ngsschnitt
+chart.new.w_differences = Differenzen
+chart.new.crosssection = Querprofil
 
 cross_section = Querprofil
 
+reference_curve = Bezugslinie
+reference_curve_normalized = Reduzierte Bezugslinie
+
 scenario.current = Aktuell
-scenario.potentiel = Potentiell
+scenario.potentiel = Potenziell
 scenario.scenario = Szenario
 
 floodplain.option = Talaue verwenden?
+floodplain.active = Aktiv
+floodplain.inactive = Inaktiv
 
 river = Fluss
 calculation_mode = Berechnungsart
 ld_locations = Ort(e)
+main_channel = Hauptgerinne
+total_channel = Gesamtgerinne
 
-chart.cross_section.title = Querprofildiagram für Gew\u00e4sser {0}
+chart.cross_section.title = Querprofildiagramm f\u00fcr Gew\u00e4sser {0}
 chart.cross_section.subtitle = {0}-km: {1,number,#.###}
 chart.cross_section.xaxis.label = Abstand [m]
 chart.cross_section.yaxis.label = W [NN + m]
 
 chart.longitudinal.section.title = W-L\u00e4ngsschnitt
 chart.longitudinal.section.subtitle = Bereich: {0}-km {1,number,#.###} - {2,number,#.###}
+chart.longitudinal.section.shortsubtitle = {0}
 chart.longitudinal.section.xaxis.label = {0}-km
 chart.longitudinal.section.yaxis.label = W [{0}]
 chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s]
@@ -55,21 +144,103 @@
 chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###}
 chart.computed.discharge.curve.yaxis.label = W [NN + m]
 chart.computed.discharge.curve.curve.label = Abflusskurve {0} km {1}
+chart.computed.discharge.curve.gauge = Abflusskurve an Pegel {0} (km {1})
 chart.duration.curve.title = Dauerlinie
 chart.duration.curve.subtitle = {0}-km: {1,number,#.###}
 chart.duration.curve.xaxis.label = Unterschreitungsdauer [Tage]
 chart.duration.curve.yaxis.label = W [NN + m]
-chart.duration.curve.curve.w = Wasserstandsdauerline f\u00fcr {0}
-chart.duration.curve.curve.q = Abflussdauerline f\u00fcr {0}
+chart.duration.curve.curve.w = Wasserstandsdauerline f\u00fcr {0} (km:{1})
+chart.duration.curve.curve.q = Abflussdauerline f\u00fcr {0} (km:{1})
+chart.historical.discharge.title = Historische Abflusskurven
+chart.historical.discharge.subtitle = Pegel {0}
+chart.historical.discharge.xaxis.label = Zeit
+chart.historical.discharge.yaxis.label = Q [m\u00b3/s]
+chart.historical.discharge.yaxis.second.label = W [cm]
+
+chart.reference.curve.title = Bezugslinie
+chart.reference.curve.subtitle = {0}
+
+chart.fixings.derivedcurve.title = Ableitungskurve an Kilometer {0}
+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.reference.curve.x.axis.in.cm = Bezugspegel [cm]
+chart.reference.curve.x.axis.in.m = Bezugsort [NN + m]
+chart.reference.curve.y.axis.in.cm = Zielpegel [cm]
+chart.reference.curve.y.axis.in.m = Zielort(e) [NN + m] 
+
+chart.normalized.reference.curve.title = Reduzierte Bezugslinie
 
 chart.w_differences.title = Differenzen
 chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###}
 chart.w_differences.yaxis.label = m
 chart.w_differences.yaxis.second.label = W [NN + m]
 
+chart.bedquality.title=Sohlen L\u00e4ngsschnitt
+chart.bedquality.xaxis.label=Fluss-Km
+chart.bedquality.yaxis.label=Durchmesser [m]
+chart.bedquality.yaxis.label.porosity=Porosit\u00e4t [%]
+chart.bedquality.yaxis.label.density=Dichte [t/m\u00b3]
+
+chart.bedheight_middle.section.title=Mittlere Sohlh\u00f6he
+chart.bedheight_middle.section.yaxis.label=mittlere Sohlh\u00f6hen [mm\u00fcNN]
+
+chart.flow_velocity.section.title=Geschwindigkeit- und Schubspannung
+chart.flow_velocity.section.yaxis.label=Geschwindigkeit v [m/s]
+chart.flow_velocity.section.yaxis.second.label=Schubspannung Tau [N]
+
+chart.sq_relation.xaxis.label = Abfluss [m\u00b3/s]
+chart.sq_relation.yaxis.label = Transport [kg/s]
+chart.sq_relation_a.title = Feinkornanteil
+chart.sq_relation_b.title = Sand (Suspensionstransport)
+chart.sq_relation_c.title = Sand (Geschiebetransport)
+chart.sq_relation_d.title = Fein- und Mittelkies
+chart.sq_relation_e.title = Grobkornanteil (> Mittelkies)
+chart.sq_relation_f.title = Geschiebetransport gesamt
+facet.sq_relation.curve = Potenziell (Geschiebedaten)
+facet.sq_relation.measurements = Geschiebedaten
+facet.sq_relation.outliers = Ausrei\u00dfer Durchgang {0}
+facet.sq_relation.outlier.curve = Potenziell Durchgang {0}
+facet.sq_relation.outlier.measurement = Geschiebedaten Durchgang {0}
+
 facet.longitudinal_section.annotations = Streckenfavoriten
 facet.discharge_curves.mainvalues.q = Q (Haupt- und Extremwerte)
 facet.discharge_curves.mainvalues.w = W (Haupt- und Extremwerte)
+facet.flow_velocity.mainchannel = v Hauptgerinne bei {0}
+facet.flow_velocity.totalchannel = v Gesamtgerinne bei {0}
+facet.flow_velocity.tauchannel = TAU Hauptgerinne bei {0}
+facet.bedheight_middle.single = Sohlh\u00f6he {0,number,####}
+facet.bedheight_middle.epoch = Sohlh\u00f6he Epoche {0,number,####} - {1,number,####}
+facet.bedquality.bed.porosity.toplayer = Porosit\u00e4t ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.porosity.sublayer = Porosit\u00e4t ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.density.toplayer = Dichte ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.density.sublayer = Dichte ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.diameter.toplayer = {0}_Sohle ({1,date} - {2,date}) ({3})
+facet.bedquality.bed.diameter.sublayer = {0}_Sohle ({1,date} - {2,date}) ({3})
+facet.bedquality.bedload.diameter = {0}_Geschiebe
+bedquality.toplayer = 0,0m - 0,3m
+bedquality.sublayer = 0,1m - 0,5m
+facet.bedheight.diff.year = Sohlh\u00f6hendiffernez {0}
+facet.bedheight.diff.morph = Morphologische Breite {0}
+facet.bedheight.diff.height1 = H\u00f6he Minuend {0}
+facet.bedheight.diff.height2 = H\u00f6he Subtrahend {0}
+facet.bedheight.diff.absolute = Sohlh\u00f6hendifferenz/Jahr {0}
+facet.bedheight.diff.epoch = Sohlh\u00f6hendifferenz {0}
+
+chart.beddifference.height.title = Sohlh\u00f6hendifferenz
+chart.beddifference.height.xaxis.label = Fluss-Km [km]
+chart.beddifference.height.yaxis.label = Differenz [cm/Jahr]
+chart.beddifference.epoch.title = Sohlh\u00f6hendifferenz
+chart.beddifference.xaxis.label = Fluss-Km [km]
+chart.beddifference.yaxis.label.diff = Differenz [m]
+chart.beddifference.yaxis.label.height = Absolute H\u00f6he [m]
+chart.beddifference.year.title = Sohlh\u00f6hendifferenz
+chart.beddifference.xaxis.label = Fluss-Km [km]
+chart.beddifference.yaxis.label.diff = Differenz [m]
+chart.beddifference.yaxis.label.morph = Morphologische Breite [m]
+chart.beddifference.yaxis.label.heights = Absolute H\u00f6he [m]
 
 export.waterlevel.csv.header.km = Fluss-Km
 export.waterlevel.csv.header.w = W [NN + m]
@@ -83,7 +254,7 @@
 export.waterlevel.csv.meta.river = # Gew\u00e4sser: {0}
 export.waterlevel.csv.meta.range = # Ort/Bereich (km): {0} - {1}
 export.waterlevel.csv.meta.gauge = # Bezugspegel: {0}
-export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0} - {1}
+export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0}
 export.waterlevel.csv.meta.w = # W (NN + m): {0} - {1}
 export.waterlevel.csv.not.in.gauge.range = au\u00dferhalb gew\u00e4hlter Bezugspegels
 export.computed.discharge.curve.csv.header.w = W [NN + m]
@@ -96,6 +267,68 @@
 export.discharge.longitudinal.section.csv.header.cw = W korr.
 export.discharge.longitudinal.section.csv.header.q = Q [m\u00b3/s]
 export.discharge.curve.at.header = Berechnete Abflusskurve f\u00fcr {0} {0}-km: {1}
+export.historical.discharge.csv.header.timerange = Zeitraum
+export.historical.discharge.csv.header.waterlevel = Wasserstand
+export.historical.discharge.csv.header.discharge = Abfluss
+export.historical.discharge.csv.header.diff = Abflussdifferenz zur Bezugskurve
+export.historical.discharge.csv.header.gaugename = Pegelname
+export.reference_curve.csv.header.km = km
+export.reference_curve.csv.header.w.cm = W (cm am Pegel)
+export.reference_curve.csv.header.w.m = W (m + NHN)
+export.reference_curve.csv.header.w.q = gleichw. Q (m\u00b3/s)
+
+
+export.waterlevel.pdf.mode = Wasserstand
+export.computed.discharge.pdf.mode = Abflusskurve
+export.duration.pdf.mode = Dauerlinie
+export.wdifferences.pdf.mode = W Differenzen
+export.historical.discharge.pdf.mode = Historischer Abfluss
+export.reference_curve.pdf.mode = Bezugslinie
+export.computed.discharge.pdf.file = /jasper/computed-discharge.jasper
+export.duration.pdf.file = /jasper/duration.jasper
+export.waterlevel.pdf.file = /jasper/waterlevel.jasper
+export.wdifferences.pdf.file = /jasper/wdifferences.jasper
+export.historical.discharge.pdf.file = /jasper/historical-discharge.jasper
+export.reference_curve.pdf.file = /jasper/reference.jasper
+export.reference_curve.pdf.file.gauge = /jasper/reference_gauge.jasper
+export.reference_curve.pdf.file.gauge.end = /jasper/reference_gauge_end.jasper
+export.reference_curve.pdf.file.gauge.start.end = /jasper/reference_gauge_start_end.jasper
+export.flow_velocity.csv.header.km = Fluss-Km
+export.flow_velocity.csv.header.v_total = v Gesamtgerinne
+export.flow_velocity.csv.header.v_main = v Hauptgerinne
+export.flow_velocity.csv.header.tau_main = TAU Hauptgerinne
+export.flow_velocity.csv.header.q = Q [m\u00b3/s]
+export.flow_velocity.csv.header.locations = Streckendaten
+export.bedheight_middle.csv.header.km = Fluss-km
+export.bedheight_middle.csv.header.sounding = Peilung / Epoche
+export.bedheight_middle.csv.header.height = gemittelte Sohl\u00f6he
+export.bedheight_middle.csv.header.uncertainty = Unsicherheit [m]
+export.bedheight_middle.csv.header.datagap = Datenl\u00fccke
+export.bedheight_middle.csv.header.soundingwidth = Peilbreite [m]
+export.bedheight_middle.csv.header.width = morphologisch aktive Breite [m]
+export.bedheight_middle.csv.header.locations = Streckendaten
+export.sqrelation.csv.header.parameter = Parameter
+export.sqrelation.csv.header.station = Station
+export.sqrelation.csv.header.km = Fluss-Km
+export.sqrelation.csv.header.function = Funktion
+export.sqrelation.csv.header.gauge = Pegel
+export.sqrelation.csv.header.coeff.a = a
+export.sqrelation.csv.header.coeff.b = b
+export.sqrelation.csv.header.coeff.q = Q
+export.sqrelation.csv.header.coeff.r = r^2
+export.sqrelation.csv.header.n.total = n gesamt
+export.sqrelation.csv.header.n.outliers = n Ausrei\u00dfer
+export.sqrelation.csv.header.c.duan = C (DUAN)
+export.sqrelation.csv.header.c.ferguson = C (FERGUSON)
+export.sqrelation.csv.header.variance = Standardabweichung
+export.minfo.bedquality.km = km
+export.minfo.bedquality.density_cap = Sedimentdichte Deckschicht
+export.minfo.bedquality.density_sub = Sedimentdichte Unterschicht
+export.minfo.bedquality.porosity_cap = Porosit\u00e4t Deckschicht
+export.minfo.bedquality.porosity_sub = Porosit\u00e4t Unterschicht
+export.minfo.bedquality.bedload = Geschiebedurchmesser
+export.minfo.bedquality.bed_cap = Sohldurchmesser Deckschicht
+export.minfo.bedquality.bed_sub = Sohldurchmesser Unterschicht
 
 floodmap.wmsbackground = Hintergrundkarte
 floodmap.riveraxis = Flussachse
@@ -109,6 +342,8 @@
 floodmap.lines = Linien
 floodmap.buildings = Bauwerke
 floodmap.fixpoints = Festpunkte
+floodmap.floodmaps = \u00dcberschwemmungsfl\u00e4che
+floodmap.usershape = Benutzerdaten
 
 wsplgen.job.queued = WSPLGEN Berechnung befindet sich in Warteschlange.
 wsplgen.job.error = Ein unerwarteter Fehler beim Starten von WSPLGEN ist aufgetreten.
@@ -119,3 +354,151 @@
 Saar = Saar
 Elbe = Elbe
 
+state.map.river = Gew\u00e4sser
+
+spline.interpolation.failed = Spline interpolation fehlgeschlagen.
+cannot.find.w.for.q = W zu Q = {0,number,#.##} kann nicht ermittelt werden.
+cannot.find.q = Q = {0,number,#.##} konnte nicht gefunden werden.
+no.ws.found = Keine Ws gefunden.
+no.q.found.in.column = In Spalte {0,integer} wurde kein Q gefunden.
+spline.creation.failed = Spline creation failed.
+cannot.find.w.or.q = W oder Q konnten nicht ermittelt werden.
+km.not.found = Passender Kilometer konnte nicht gefunden werden.
+cannot.create.wq.relation = W/Q-Beziehung konnte nicht ermittelt werden.
+cannot.create.index.q.relation = Spaltenindex/Q-Beziehung konnte nicht erstellt werden.
+
+w.w.qkm1.failed = Berechnung von Q f\u00fcr WST-Index {0,number,#.##} fehlgeschlagen.
+w.w.wkm1.failed = Berechnung von W f\u00fcr Q = {0,number,#.##} / WST-Index {1,number,#.##} fehlgeschlagen.
+w.w.qkm2.failed = Berechnung von Q f\u00fcr WST-Index {0,number,#.##} fehlgeschlagen. 
+w.w.wkm2.failed = Berechnung von W f\u00fcr Q = {0,number,#.##} / WST-Index {1,number,#.##} fehlgeschlagen. 
+
+cannot.find.hist.q.for.w = Konnte zu W = {0,number,#.##} im Zeitraum ({1,date} - {2,date}) kein Abfluss ermitteln.
+cannot.find.hist.q.tables = Konnte f\u00fcr den angegebenen Zeitraum keine Abflusstafeln finden.
+cannot.find.hist.q.reftable = Konnte f\u00fcr den gew\u00e4hlten Pegel keine Bezugs-Abflusstafel ermitteln.
+
+more.than.one.q.for.w = Mehr als ein Q f\u00fcr W = {0,number,#.##} gefunden.
+
+no.river.selected = Kein Gew\u00e4sser ausgew\u00e4hlt.
+no.gauge.selected = Kein Pegel ausgew\u00e4hlt.
+no.locations.selected = Keine Orte angegeben.
+no.kms.selected = Keine Kilometerstationen angegeben.
+converting.ws.to.qs.failed = Konvertierung von Ws zu Qs fehlgeschlagen.
+no.wst.for.river = Keine zum Gew\u00e4sser passende WST gefunden.
+no.range.found = Kein passender Pegel gefunden.
+no.gauge.found.for.km = Zur gegebenen Kilometerstation existiert kein Pegel.
+cannot.create.segments = Flussabschnitte konnten nicht erzeugt werden.
+cannot.compute.discharge.curve = Die Abflusskurve konnte nicht berechnet werden..
+cannot.find.ds = Dauerzahlen konnten nicht gefunden werden.
+no.segments.found = Keine Flussabschnitte gefunden.
+no.values.given = Keine Werte angegeben.
+cannot.interpolate.w.q = W/Q-Wert konnte nicht interpoliert werden.
+
+manualpoints = Manuelle Punkte
+
+no.reference.start.km = Keine Startkilometerstation angegeben.
+no.reference.end.kms = Keine Endkilometerstation(en) angegeben.
+waterlevels = Wasserst\u00e4nde
+
+help.index=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe
+help.winfo=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO
+help.winfo.wsp.location_distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten
+help.winfo.wsp.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_W.2BAC8-Q_Daten
+help.winfo.discharge.longitudinal.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Berechnungsstrecke
+help.winfo.duration.locations=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten
+help.winfo.discharge.longitudinal.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_f.2BAPw-r_W.2BAC8-Q_Daten
+help.winfo.diff.diffs=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Zusammenstellen_der_Differenzen
+help.winfo.reference.curve.start=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Bezugsortes_.2BAC8_Bezugspegels
+help.winfo.reference.curve.end=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Zielortes_.2BAC8_Zielpegels
+help.winfo.uesk.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Berechnungsstrecke
+help.winfo.uesk.wsp=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Wasserspiegellage
+help.winfo.uesk.dem=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Digitalen_Gel.2BAOQ-ndemodells
+help.winfo.uesk.profiles=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Abstand_Interpolierte_Profile
+help.winfo.uesk.floodplain=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Laterale_Begrenzung
+help.winfo.uesk.differences=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Differenz_Wasserspiegellage_und_Gel.2BAOQ-nde
+help.winfo.uesk.scenario=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#A.2BANw-berschwemmungsfl.2BAOQ-che_.2BAC8_Szenario
+help.winfo.historical.discharge.reference_gauge=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Bezugspegels
+help.winfo.historical.discharge.timerange=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_des_Auswertezeitraumes
+help.winfo.historical.discharge.mode=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_der_Analyseart
+
+fix.reference.period=Bezugszeitraum
+fix.reference.period.event=Bezugsereignis
+fix.reference.period.event.short=B
+fix.analysis.short=A
+fix.analysis.periods=Analysezeitr\u00e4ume
+fix.derivative=Ableitung
+fix.outlier=Ausrei\u00dfer
+fix.analysis=Analyseereignis
+fix.deviation=Standardabweichung
+fix.reference.deviation=Abweichung im Bezugszeitraum
+fix.vollmer.wq.curve=W/Q
+fix.vollmer.wq.outliers=Ausrei\u00dfer
+fix.vollmer.wq.events=Ereignisse
+qsectors=Abfluss-Sektoren
+
+chart.fix.deltawt.title=Abweichungen von der Ausgleichskurve an Kilometer {0}
+chart.fix.deltawt.subtitle=Gew\u00e4sser: {0}; Darstellungszeitraum: {1,date,short} bis {2,date,short}; Bezugszeitraum: {3,date,short} bis {4,date,short}
+chart.fix.deltawt.xaxis.label=Datum
+chart.fix.deltawt.yaxis.label=\u0394 W(t) [cm]
+
+chart.fixings.wq.subtitle=Gew\u00e4sser: {0}; Darstellungszeitraum: {1,date,short} bis {2,date,short}; Bezugszeitraum: {3,date,short} bis {4,date,short}
+chart.fixings.wq.subtitle1={0,date,short} bis {1,date,short}
+
+chart.fixings.longitudinalsection.title=L\u00e4ngsschnitt
+
+export.fixings.deltawt.csv.header.km=km
+export.fixings.deltawt.csv.header.deltaw=\u0394 W [cm]
+export.fixings.deltawt.csv.header.q=Abfluss [m\u00b3/s]
+export.fixings.deltawt.csv.header.w=Wasserstand [m]
+export.fixings.deltawt.csv.header.t=Datum
+export.fixings.deltawt.csv.t.format=dd.MM.yyyy
+export.fixings.deltawt.csv.header.time.range=Status
+export.fixings.deltawt.csv.reference=B
+export.fixings.deltawt.csv.analysis=A{0,number,integer}
+
+chart.fix.wq.subtitle=Gew\u00e4sser: {0}; Zeitraum: {1,date,short} bis {2,date,short}
+
+fix.missing.river=Kein Gew\u00e4sser gew\u00e4hlt
+fix.missing.from=Kein Startkilometer gew\u00e4hlt
+fix.missing.to=Kein Endkilometer gew\u00e4hlt
+fix.missing.step=Keine Schrittweite angegeben
+fix.missing.function=Unbekannter Funktions-Typ
+fix.missing.events=Liste der Ereignisse fehlt
+fix.missing.reference.period=Kein Bezugszeitraum angegeben
+fix.missing.analysis.periods=Keine Analysezeitr\u00e4ume angegeben
+fix.missing.qstart.sector=Fehlender unterer Abflusssektor
+fix.missing.qend.sector=Fehlender oberer Abflusssektor
+fix.missing.prepocessing=Kein Information \u00fcber Aussrei\u00dfertests vorhanden
+fix.no.overview.available=Keine Daten\u00fcbersicht vorhanden
+fix.invalid.function.name=Unbekannter Funktionsname
+fix.too.less.data.colums=Zuwenig Daten f\u00fcr eine Kurvenanpassung
+fix.fitting.failed=Kurvenanpassung fehlgeschlagen
+fix.invalid.values=Ung\u00fcltige Werte
+fix.cannot.load.data=Daten konnten nicht aus der Datenbank geladen werden
+
+fix.km.chart.q.sector.border0=(MNQ + MQ)/2
+fix.km.chart.q.sector.border1=(MQ + MHQ)/2
+fix.km.chart.q.sector.border2=HQ5
+fix.km.chart.label.date=dd.MM.yyyy
+fix.km.chart.title=Fixierungen {0} km {1,number,#.###}
+fix.km.chart.q.axis=Q [m\u00b3/s]
+fix.km.chart.w.axis=W [NN + m]
+fix.km.chart.measured=gemessen
+fix.km.chart.interpolated=interpoliert
+
+fix.export.at.header =  Abflusskurve aus der Fixierungsanalyse f\u00fcr {0} {0}-km: {1}
+sq.km.chart.label = Messstellen
+sq.km.chart.title = Messstellen
+sq.km.chart.km.axis = km
+sq.km.chart.date.axis = Datum
+
+module.winfo = WINFO
+module.minfo = MINFO
+module.fixanalysis = Fixierungsanalyse
+module.new_map = Neue Karte
+module.new_chart = Neues Diagramm
+
+load_diameter = Geschiebedurchmesser
+bed_diameter = Sohldurchmesser
+
+area.label.template = Fl\u00e4che = %s m\u00b3
+
--- a/flys-artifacts/src/main/resources/messages_de_DE.properties	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/resources/messages_de_DE.properties	Fri Sep 28 12:15:52 2012 +0200
@@ -1,3 +1,6 @@
+false=Nein
+true=Ja
+
 state.winfo.river = Gew\u00e4sser
 state.winfo.calculation_mode = Berechnungsart
 state.winfo.location_distance = Wahl des Berechnungsortes/strecke
@@ -13,35 +16,121 @@
 state.winfo.uesk.differences = Differenzen zwischen Wasserspiegellage und Gel\u00e4nde
 state.winfo.uesk.scenario = \u00dcberschwemmungsfl\u00e4che / Szenario
 state.winfo.waterlevel_pair_select = Ausgew\u00e4hlte Differenzen
+state.winfo.historicalq.reference_gauge = Wahl des Bezugspegels
+state.winfo.historicalq.timerange = Wahl des Auswertezeitraums
+state.winfo.historicalq.mode = Wahl der Analyseart
+state.winfo.reference.curve.input.start = Bezugsort
+state.winfo.reference.curve.input.end = Zielort(e)
+state.fix.river = Gew\u00e4sser
+state.fix.calculation.mode = Berechnungsart
+state.fix.location = Strecke
+state.fix.period = Zeitraum
+state.fix.gaugerange = Abflussklassen
+state.fix.eventselect = Ereignisauswahl
+state.fix.analysis.referenceperiod = Bezugszeitraum
+state.fix.analysis.analysisperiods = Analysezeitr\u00e4ume
+state.fix.analysis.function = Funktion
+state.fix.analysis.preprocessing = Ausrei\u00DFer
+state.fix.preprocess=aufbereiten
+state.fix.vollmer.function=Funktion
+state.fix.vollmer.preprocessing = Ausrei\u00DFer
+state.fix.vollmer.qa = Eingabe f\u00e4r W/Q Daten
+
+state.minfo.river = Gew\u00e4sser
+state.minfo.calculation_mode = Berechnungsart
+state.minfo.distance_only = Wahl der Berechnungsstrecke
+state.minfo.dischargestate = Abflusszustand und Gerinne
+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
+state.minfo.bed.location = Ort(e)/Strecke
+state.minfo.bed.periods = Zeitraum/Zeitr\u00e4ume
+state.minfo.bed.char_diameter = Charakteristischer Durchmesser
+state.minfo.soundings = Wahl der Peilungen
+
+year=Jahr
+epoch=Epoche
+soundings = Peilungen / Epochen
+
+historical.mode.w = Wasserstandsanalyse
+historical.mode.q = Abflussanalyse
 
 calc.surface.curve = Wasserstand/Wasserspiegellage
 calc.flood.map = \u00dcberschwemmungsfl\u00e4che
 calc.discharge.curve = Abflusskurve/Abflusstafel
 calc.duration.curve = Dauerlinie
-calc.discharge.longitudinal.section = W bei ungleichwertigem Abflussl\u00e4ngsschnitt
+calc.discharge.longitudinal.section = W f\u00fcr ungleichwertigen Abflussl\u00e4ngsschnitt
 calc.w.differences = Differenzen
+calc.historical.discharge.curve = Hist. Abflusskurven
+calc.reference.curve = Bezugslinie
+calc.fixation.default = Fixierung
+calc.fixation.vollmer = Ausgelagerte Wasserspiegellage
+calc.bed.middle = Mittlere Sohlh\u00f6he
+calc.bed.diff = Sohlh\u00f6hendifferenz
+calc.bed.quality = Sohlbeschaffenheit
+calc.sediment.load = Sedimentfracht
+calc.flow.velocity = Flie\u00dfgeschwindigkeit
+calc.sq.relation = Transport-Abfluss Beziehung
+calc.bed.d90 = D90
+calc.bed.d84 = D84
+calc.bed.d80 = D80
+calc.bed.d75 = D75
+calc.bed.d70 = D70
+calc.bed.d60 = D60
+calc.bed.d50 = D50
+calc.bed.d40 = D40
+calc.bed.d30 = D30
+calc.bed.d25 = D25
+calc.bed.d20 = D20
+calc.bed.d16 = D16
+calc.bed.d10 = D10
+calc.bed.dmin = Dmin
+calc.bed.dmax = Dmax
+calc.bed.dmid = Dmid
 
-calc.reference.curve = Bezugslinie
+calculation.analysis = Fixierungsanalyse
+calculation.vollmer = ausgelagerte Wasserspiegellage
+
+state.chart.river = Gew\u00e4sser
+state.chart.type = Diagrammtyp
+
+chart.new.durationcurve = Dauerlinie
+chart.new.computeddischargecurve = Abflusskurve
+chart.new.longitudinal_section = L\u00e4ngsschnitt
+chart.new.w_differences = Differenzen
+chart.new.crosssection = Querprofil
 
 cross_section = Querprofil
 
+reference_curve = Bezugslinie
+reference_curve_normalized = Reduzierte Bezugslinie
+
 scenario.current = Aktuell
-scenario.potentiel = Potentiell
+scenario.potentiel = Potenziell
 scenario.scenario = Szenario
 
 floodplain.option = Talaue verwenden?
+floodplain.active = Aktiv
+floodplain.inactive = Inaktiv
 
 river = Fluss
 calculation_mode = Berechnungsart
 ld_locations = Ort(e)
+main_channel = Hauptgerinne
+total_channel = Gesamtgerinne
 
-chart.cross_section.title = Querprofildiagramm für Gew\u00e4sser {0}
+chart.cross_section.title = Querprofildiagramm f\u00fcr Gew\u00e4sser {0}
 chart.cross_section.subtitle = {0}-km: {1,number,#.###}
 chart.cross_section.xaxis.label = Abstand [m]
 chart.cross_section.yaxis.label = W [NN + m]
 
 chart.longitudinal.section.title = W-L\u00e4ngsschnitt
 chart.longitudinal.section.subtitle = Bereich: {0}-km {1,number,#.###} - {2,number,#.###}
+chart.longitudinal.section.shortsubtitle = {0}
 chart.longitudinal.section.xaxis.label = {0}-km
 chart.longitudinal.section.yaxis.label = W [{0}]
 chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s]
@@ -55,21 +144,101 @@
 chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###}
 chart.computed.discharge.curve.yaxis.label = W [NN + m]
 chart.computed.discharge.curve.curve.label = Abflusskurve {0} km {1}
+chart.computed.discharge.curve.gauge = Abflusskurve an Pegel {0} (km {1})
 chart.duration.curve.title = Dauerlinie
 chart.duration.curve.subtitle = {0}-km: {1,number,#.###}
 chart.duration.curve.xaxis.label = Unterschreitungsdauer [Tage]
 chart.duration.curve.yaxis.label = W [NN + m]
-chart.duration.curve.curve.w = Wasserstandsdauerline f\u00fcr {0}
-chart.duration.curve.curve.q = Abflussdauerline f\u00fcr {0}
+chart.duration.curve.curve.w = Wasserstandsdauerline f\u00fcr {0} (km:{1})
+chart.duration.curve.curve.q = Abflussdauerline f\u00fcr {0} (km:{1})
+chart.historical.discharge.title = Historische Abflusskurven
+chart.historical.discharge.subtitle = Pegel {0}
+chart.historical.discharge.xaxis.label = Zeit
+chart.historical.discharge.yaxis.label = Q [m\u00b3/s]
+chart.historical.discharge.yaxis.second.label = W [cm]
+
+chart.reference.curve.title = Bezugslinie
+chart.reference.curve.subtitle = {0}
+
+chart.reference.curve.x.axis.in.cm = Bezugspegel [cm]
+chart.reference.curve.x.axis.in.m = Bezugsort [NN + m]
+chart.reference.curve.y.axis.in.cm = Zielpegel [cm]
+chart.reference.curve.y.axis.in.m = Zielort(e) [NN + m] 
+
+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.normalized.reference.curve.title = Reduzierte Bezugslinie
 
 chart.w_differences.title = Differenzen
-chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###}
+chart.w_differences.subtitle = Strecke: {0}-km {1,number,#.###} - {2,number,#.###}
 chart.w_differences.yaxis.label = m
 chart.w_differences.yaxis.second.label = W [NN + m]
 
+chart.bedquality.title=Sohlen L\u00e4ngsschnitt
+chart.bedquality.xaxis.label=Fluss-Km
+chart.bedquality.yaxis.label=Durchmesser [m]
+chart.bedquality.yaxis.label.porosity=Porosit\u00e4t [%]
+chart.bedquality.yaxis.label.density=Dichte [t/m\u00b3]
+
+chart.bedheight_middle.section.title=Mittlere Sohlh\u00f6he
+chart.bedheight_middle.section.yaxis.label=mittlere Sohlh\u00f6hen [mm\u00fcNN]
+
+chart.flow_velocity.section.title=Geschwindigkeit- und Schubspannung
+chart.flow_velocity.section.yaxis.label=Geschwindigkeit v [m/s]
+chart.flow_velocity.section.yaxis.second.label=Schubspannung Tau [N]
+
+chart.sq_relation.xaxis.label = Abfluss [m\u00b3/s]
+chart.sq_relation.yaxis.label = Transport [kg/s]
+chart.sq_relation_a.title = Feinkornanteil
+chart.sq_relation_b.title = Sand (Suspensionstransport)
+chart.sq_relation_c.title = Sand (Geschiebetransport)
+chart.sq_relation_d.title = Fein- und Mittelkies
+chart.sq_relation_e.title = Grobkornanteil (> Mittelkies)
+chart.sq_relation_f.title = Geschiebetransport gesamt
+facet.sq_relation.curve = Potenziell (Geschiebedaten)
+facet.sq_relation.measurements = Geschiebedaten
+facet.sq_relation.outliers = Ausrei\u00dfer Durchgang {0}
+facet.sq_relation.outlier.curve = Potenziell Durchgang {0}
+facet.sq_relation.outlier.measurement = Geschiebedaten Durchgang {0}
+
 facet.longitudinal_section.annotations = Streckenfavoriten
 facet.discharge_curves.mainvalues.q = Q (Haupt- und Extremwerte)
 facet.discharge_curves.mainvalues.w = W (Haupt- und Extremwerte)
+facet.flow_velocity.mainchannel = v Hauptgerinne bei {0}
+facet.flow_velocity.totalchannel = v Gesamtgerinne bei {0}
+facet.flow_velocity.tauchannel = TAU Hauptgerinne bei {0}
+facet.bedheight_middle.single = Sohlh\u00f6he {0,number,####}
+facet.bedheight_middle.epoch = Sohlh\u00f6he Epoche {0,number,####} - {1,number,####}
+facet.bedquality.bed.porosity.toplayer = Porosit\u00e4t ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.porosity.sublayer = Porosit\u00e4t ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.density.toplayer = Dichte ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.density.sublayer = Dichte ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.diameter.toplayer = {0}_Sohle ({1,date} - {2,date}) ({3})
+facet.bedquality.bed.diameter.sublayer = {0}_Sohle ({1,date} - {2,date}) ({3})
+facet.bedquality.bedload.diameter = {0}_Geschiebe
+bedquality.toplayer = 0,0m - 0,3m
+bedquality.sublayer = 0,1m - 0,5m
+facet.bedheight.diff.year = Sohlh\u00f6hendiffernez {0}
+facet.bedheight.diff.morph = Morphologische Breite {0}
+facet.bedheight.diff.height1 = H\u00f6he Minuend {0}
+facet.bedheight.diff.height2 = H\u00f6he Subtrahend {0}
+facet.bedheight.diff.absolute = Sohlh\u00f6hendifferenz/Jahr {0}
+facet.bedheight.diff.epoch = Sohlh\u00f6hendifferenz {0}
+
+chart.beddifference.height.title = Sohlh\u00f6hendifferenz
+chart.beddifference.height.xaxis.label = Fluss-Km [km]
+chart.beddifference.height.yaxis.label = Differenz [cm/Jahr]
+chart.beddifference.epoch.title = Sohlh\u00f6hendifferenz
+chart.beddifference.xaxis.label = Fluss-Km [km]
+chart.beddifference.yaxis.label.diff = Differenz [m]
+chart.beddifference.yaxis.label.height = Absolute H\u00f6he [m]
+chart.beddifference.year.title = Sohlh\u00f6hendifferenz
+chart.beddifference.xaxis.label = Fluss-Km [km]
+chart.beddifference.yaxis.label.diff = Differenz [m]
+chart.beddifference.yaxis.label.morph = Morphologische Breite [m]
+chart.beddifference.yaxis.label.heights = Absolute H\u00f6he [m]
 
 export.waterlevel.csv.header.km = Fluss-Km
 export.waterlevel.csv.header.w = W [NN + m]
@@ -83,7 +252,7 @@
 export.waterlevel.csv.meta.river = # Gew\u00e4sser: {0}
 export.waterlevel.csv.meta.range = # Ort/Bereich (km): {0} - {1}
 export.waterlevel.csv.meta.gauge = # Bezugspegel: {0}
-export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0} - {1}
+export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0}
 export.waterlevel.csv.meta.w = # W (NN + m): {0} - {1}
 export.waterlevel.csv.not.in.gauge.range = au\u00dferhalb gew\u00e4hlter Bezugspegels
 export.computed.discharge.curve.csv.header.w = W [NN + m]
@@ -96,6 +265,67 @@
 export.discharge.longitudinal.section.csv.header.cw = W korr.
 export.discharge.longitudinal.section.csv.header.q = Q [m\u00b3/s]
 export.discharge.curve.at.header = Berechnete Abflusskurve f\u00fcr {0} {0}-km: {1}
+export.historical.discharge.csv.header.timerange = Zeitraum
+export.historical.discharge.csv.header.waterlevel = Wasserstand
+export.historical.discharge.csv.header.discharge = Abfluss
+export.historical.discharge.csv.header.diff = Abflussdifferenz zur Bezugskurve
+export.historical.discharge.csv.header.gaugename = Pegelname
+export.reference_curve.csv.header.km = km
+export.reference_curve.csv.header.w.cm = W (cm am Pegel)
+export.reference_curve.csv.header.w.m = W (m + NHN)
+export.reference_curve.csv.header.w.q = gleichw. Q (m\u00b3/s)
+
+export.waterlevel.pdf.mode = Wasserstand
+export.computed.discharge.pdf.mode = Abflusskurve
+export.duration.pdf.mode = Dauerline
+export.wdifferences.pdf.mode = W Differenzen
+export.historical.discharge.pdf.mode = Historischer Abfluss
+export.reference_curve.pdf.mode = Bezugslinie
+export.computed.discharge.pdf.file = /jasper/computed-discharge.jasper
+export.duration.pdf.file = /jasper/duration.jasper
+export.waterlevel.pdf.file = /jasper/waterlevel.jasper
+export.wdifferences.pdf.file = /jasper/wdifferences.jasper
+export.historical.discharge.pdf.file = /jasper/historical-discharge.jasper
+export.reference_curve.pdf.file = /jasper/reference.jasper
+export.reference_curve.pdf.file.gauge = /jasper/reference_gauge.jasper
+export.reference_curve.pdf.file.gauge.end = /jasper/reference_gauge_end.jasper
+export.reference_curve.pdf.file.gauge.start.end = /jasper/reference_gauge_start_end.jasper
+export.flow_velocity.csv.header.km = Fluss-Km
+export.flow_velocity.csv.header.v_total = v Gesamtgerinne
+export.flow_velocity.csv.header.v_main = v Hauptgerinne
+export.flow_velocity.csv.header.tau_main = TAU Hauptgerinne
+export.flow_velocity.csv.header.q = Q [m\u00b3/s]
+export.flow_velocity.csv.header.locations = Streckendaten
+export.bedheight_middle.csv.header.km = Fluss-km
+export.bedheight_middle.csv.header.sounding = Peilung / Epoche
+export.bedheight_middle.csv.header.height = gemittelte Sohl\u00f6he
+export.bedheight_middle.csv.header.uncertainty = Unsicherheit [m]
+export.bedheight_middle.csv.header.datagap = Datenl\u00fccke
+export.bedheight_middle.csv.header.soundingwidth = Peilbreite [m]
+export.bedheight_middle.csv.header.width = morphologisch aktive Breite [m]
+export.bedheight_middle.csv.header.locations = Streckendaten
+export.sqrelation.csv.header.parameter = Parameter
+export.sqrelation.csv.header.station = Station
+export.sqrelation.csv.header.km = Fluss-Km
+export.sqrelation.csv.header.function = Funktion
+export.sqrelation.csv.header.gauge = Pegel
+export.sqrelation.csv.header.coeff.a = a
+export.sqrelation.csv.header.coeff.b = b
+export.sqrelation.csv.header.coeff.q = Q
+export.sqrelation.csv.header.coeff.r = r^2
+export.sqrelation.csv.header.n.total = n gesamt
+export.sqrelation.csv.header.n.outliers = n Ausrei\u00dfer
+export.sqrelation.csv.header.c.duan = C (DUAN)
+export.sqrelation.csv.header.c.ferguson = C (FERGUSON)
+export.sqrelation.csv.header.variance = Standardabweichung
+export.minfo.bedquality.km = km
+export.minfo.bedquality.density_cap = Sedimentdichte Deckschicht
+export.minfo.bedquality.density_sub = Sedimentdichte Unterschicht
+export.minfo.bedquality.porosity_cap = Porosit\u00e4t Deckschicht
+export.minfo.bedquality.porosity_sub = Porosit\u00e4t Unterschicht
+export.minfo.bedquality.bedload = Geschiebedurchmesser
+export.minfo.bedquality.bed_cap = Sohldurchmesser Deckschicht
+export.minfo.bedquality.bed_sub = Sohldurchmesser Unterschicht
 
 floodmap.wmsbackground = Hintergrundkarte
 floodmap.riveraxis = Flussachse
@@ -109,6 +339,8 @@
 floodmap.lines = Linien
 floodmap.buildings = Bauwerke
 floodmap.fixpoints = Festpunkte
+floodmap.floodmaps = \u00dcberschwemmungsfl\u00e4che
+floodmap.usershape = Benutzerdaten
 
 wsplgen.job.queued = WSPLGEN Berechnung befindet sich in Warteschlange.
 wsplgen.job.error = Ein unerwarteter Fehler beim Starten von WSPLGEN ist aufgetreten.
@@ -118,3 +350,154 @@
 Mosel = Mosel
 Saar = Saar
 Elbe = Elbe
+
+state.map.river = Gew\u00e4sser
+
+spline.interpolation.failed = Spline interpolation fehlgeschlagen.
+cannot.find.w.for.q = W zu Q = {0,number,#.##} kann nicht ermittelt werden.
+cannot.find.q = Q = {0,number,#.##} konnte nicht gefunden werden.
+no.ws.found = Keine Ws gefunden.
+no.q.found.in.column = In Spalte {0,integer} wurde kein Q gefunden.
+spline.creation.failed = Spline creation failed.
+cannot.find.w.or.q = W oder Q konnten nicht ermittelt werden.
+km.not.found = Passender Kilometer konnte nicht gefunden werden.
+cannot.create.wq.relation = W/Q-Beziehung konnte nicht ermittelt werden.
+cannot.create.index.q.relation = Spaltenindex/Q-Beziehung konnte nicht erstellt werden.
+
+w.w.qkm1.failed = Berechnung von Q f\u00fcr WST-Index {0,number,#.##} fehlgeschlagen.
+w.w.wkm1.failed = Berechnung von W f\u00fcr Q = {0,number,#.##} / WST-Index {1,number,#.##} fehlgeschlagen.
+w.w.qkm2.failed = Berechnung von Q f\u00fcr WST-Index {0,number,#.##} fehlgeschlagen. 
+w.w.wkm2.failed = Berechnung von W f\u00fcr Q = {0,number,#.##} / WST-Index {1,number,#.##} fehlgeschlagen. 
+
+cannot.find.hist.q.for.w = Konnte zu W = {0,number,#.##} im Zeitraum ({1,date} - {2,date}) kein Abfluss ermitteln.
+cannot.find.hist.q.tables = Konnte f\u00fcr den angegebenen Zeitraum keine Abflusstafeln finden.
+cannot.find.hist.q.reftable = Konnte f\u00fcr den gew\u00e4hlten Pegel keine Bezugs-Abflusstafel ermitteln.
+
+more.than.one.q.for.w = Mehr als ein Q f\u00fcr W = {0,number,#.##} gefunden.
+
+no.river.selected = Kein Gew\u00e4sser ausgew\u00e4hlt.
+no.gauge.selected = Kein Pegel ausgew\u00e4hlt.
+no.locations.selected = Keine Orte angegeben.
+no.kms.selected = Keine Kilometerstationen angegeben.
+converting.ws.to.qs.failed = Konvertierung von Ws zu Qs fehlgeschlagen.
+no.wst.for.river = Keine zum Gew\u00e4sser passende WST gefunden.
+no.range.found = Kein passender Pegel gefunden.
+no.gauge.found.for.km = Zur gegebenen Kilometerstation existiert kein Pegel.
+cannot.create.segments = Flussabschnitte konnten nicht erzeugt werden.
+cannot.compute.discharge.curve = Die Abflusskurve konnte nicht berechnet werden..
+cannot.find.ds = Dauerzahlen konnten nicht gefunden werden.
+no.segments.found = Keine Flussabschnitte gefunden.
+no.values.given = Keine Werte angegeben.
+cannot.interpolate.w.q = W/Q-Wert konnte nicht interpoliert werden.
+
+manualpoints = Manuelle Punkte
+
+no.reference.start.km = Keine Startkilometerstation angegeben.
+no.reference.end.kms = Keine Endkilometerstation(en) angegeben.
+waterlevels = Wasserst\u00e4nde
+
+help.index=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe
+help.winfo=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO
+help.winfo.wsp.location_distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten
+help.winfo.wsp.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_W.2BAC8-Q_Daten
+help.winfo.discharge.longitudinal.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Berechnungsstrecke
+help.winfo.duration.locations=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten
+help.winfo.discharge.longitudinal.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_f.2BAPw-r_W.2BAC8-Q_Daten
+help.winfo.diff.diffs=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Zusammenstellen_der_Differenzen
+help.winfo.reference.curve.start=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Bezugsortes_.2BAC8_Bezugspegels
+help.winfo.reference.curve.end=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Zielortes_.2BAC8_Zielpegels
+help.winfo.uesk.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Berechnungsstrecke
+help.winfo.uesk.wsp=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Wasserspiegellage
+help.winfo.uesk.dem=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Digitalen_Gel.2BAOQ-ndemodells
+help.winfo.uesk.profiles=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Abstand_Interpolierte_Profile
+help.winfo.uesk.floodplain=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Laterale_Begrenzung
+help.winfo.uesk.differences=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Differenz_Wasserspiegellage_und_Gel.2BAOQ-nde
+help.winfo.uesk.scenario=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#A.2BANw-berschwemmungsfl.2BAOQ-che_.2BAC8_Szenario
+help.winfo.historical.discharge.reference_gauge=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Bezugspegels
+help.winfo.historical.discharge.timerange=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_des_Auswertezeitraumes
+help.winfo.historical.discharge.mode=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_der_Analyseart
+
+fix.reference.period=Bezugszeitraum
+fix.reference.period.event=Bezugsereignis
+fix.reference.period.event.short=B
+fix.analysis.short=A
+fix.analysis.periods=Analysezeitr\u00e4ume
+fix.derivative=Ableitung
+fix.outlier=Ausrei\u00dfer
+fix.analysis=Analyseereignis
+fix.deviation=Standardabweichung
+fix.reference.deviation=Abweichung im Bezugszeitraum
+fix.vollmer.wq.curve=W/Q
+fix.vollmer.wq.outliers=Ausrei\u00dfer
+fix.vollmer.wq.events=Ereignisse
+qsectors=Abfluss-Sektoren
+
+chart.fix.deltawt.title=Abweichungen von der Ausgleichskurve an Kilometer {0}
+chart.fix.deltawt.subtitle=Gew\u00e4sser: {0}; Darstellungszeitraum: {1,date,short} bis {2,date,short}; Bezugszeitraum: {3,date,short} bis {4,date,short}
+chart.fix.deltawt.xaxis.label=Datum
+chart.fix.deltawt.yaxis.label=\u0394 W(t) [cm]
+
+chart.fixings.wq.subtitle=Gew\u00e4sser: {0}; Darstellungszeitraum: {1,date,short} bis {2,date,short}; Bezugszeitraum: {3,date,short} bis {4,date,short}
+chart.fixings.wq.subtitle1={0,date,short} bis {1,date,short}
+
+chart.fix.wq.subtitle=Gew\u00e4sser: {0}; Zeitraum: {1,date,short} bis {2,date,short}
+
+chart.fixings.longitudinalsection.title=L\u00e4ngsschnitt
+
+chart.fixings.deltawt.title = Abweichungen von der Ausgleichskurve am Kilometer {0}
+
+export.fixings.deltawt.csv.header.km=km
+export.fixings.deltawt.csv.header.deltaw=\u0394 W [cm]
+export.fixings.deltawt.csv.header.q=Abfluss [m\u00b3/s]
+export.fixings.deltawt.csv.header.w=Wasserstand [m]
+export.fixings.deltawt.csv.header.t=Datum
+export.fixings.deltawt.csv.t.format=dd.MM.yyyy
+export.fixings.deltawt.csv.header.time.range=Status
+export.fixings.deltawt.csv.reference=B
+export.fixings.deltawt.csv.analysis=A{0,number,integer}
+
+fix.missing.river=Kein Gew\u00e4sser gew\u00e4hlt
+fix.missing.from=Kein Startkilometer gew\u00e4hlt
+fix.missing.to=Kein Endkilometer gew\u00e4hlt
+fix.missing.step=Keine Schrittweite angegeben
+fix.missing.function=Unbekannter Funktions-Typ
+fix.missing.events=Liste der Ereignisse fehlt
+fix.missing.reference.period=Kein Bezugszeitraum angegeben
+fix.missing.analysis.periods=Keine Analysezeitr\u00e4ume angegeben
+fix.missing.qstart.sector=Fehlender unterer Abflusssektor
+fix.missing.qend.sector=Fehlender oberer Abflusssektor
+fix.missing.prepocessing=Kein Information \u00fcber Aussrei\u00dfertests vorhanden
+fix.no.overview.available=Keine Daten\u00fcbersicht vorhanden
+fix.invalid.function.name=Unbekannter Funktionsname
+fix.too.less.data.colums=Zuwenig Daten f\u00fcr eine Kurvenanpassung
+fix.fitting.failed=Kurvenanpassung fehlgeschlagen
+fix.invalid.values=Ung\u00fcltige Werte
+fix.cannot.load.data=Daten konnten nicht aus der Datenbank geladen werden
+
+fix.km.chart.q.sector.border0=(MNQ + MQ)/2
+fix.km.chart.q.sector.border1=(MQ + MHQ)/2
+fix.km.chart.q.sector.border2=HQ5
+fix.km.chart.label.date=dd.MM.yyyy
+fix.km.chart.title=Fixierungen {0} km {1,number,#.###}
+fix.km.chart.q.axis=Q [m\u00b3/s]
+fix.km.chart.w.axis=W [NN + m]
+fix.km.chart.measured=gemessen
+fix.km.chart.interpolated=interpoliert
+
+fix.export.at.header =  Abflusskurve aus der Fixierungsanalyse f\u00fcr {0} {0}-km: {1}
+sq.km.chart.label = Messstellen
+sq.km.chart.title = Messstellen
+sq.km.chart.km.axis = km
+sq.km.chart.date.axis = Datum
+
+module.winfo = WINFO
+module.minfo = MINFO
+module.fixanalysis = Fixierungsanalyse
+module.new_map = Neue Karte
+module.new_chart = Neues Diagramm
+
+load_diameter = Geschiebedurchmesser
+bed_diameter = Sohldurchmesser
+
+area.label.template = Fl\u00e4che = %s m\u00b3
+
--- a/flys-artifacts/src/main/resources/messages_en.properties	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-artifacts/src/main/resources/messages_en.properties	Fri Sep 28 12:15:52 2012 +0200
@@ -1,3 +1,6 @@
+false=Nein
+true=Ja
+
 state.winfo.river = River
 state.winfo.calculation_mode = Calculation Mode
 state.winfo.location_distance = Location or distance selection
@@ -13,6 +16,48 @@
 state.winfo.uesk.differences = Differences between waterlevel and terrain
 state.winfo.uesk.scenario = Flood Plain / Scenario
 state.winfo.waterlevel_pair_select = Chosen Differences
+state.winfo.historicalq.reference_gauge = Selection of Reference Gauge
+state.winfo.historicalq.timerange = Selection of Evaluation time
+state.winfo.historicalq.mode = Selecion of analyses
+state.winfo.reference.curve.input.start = Chosen Reference
+state.winfo.reference.curve.input.end = Chosen Evaluation
+state.fix.river = River
+state.fix.calculation.mode = Calculation Mode
+state.fix.location = Distance
+state.fix.period = Period
+state.fix.gaugerange = Gaugerange
+state.fix.eventselect = Event selection
+state.fix.analysis.referenceperiod = Reference period
+state.fix.analysis.analysisperiods = Analysis period
+state.fix.analysis.function = Function
+state.fix.analysis.preprocessing = Outliers
+state.fix.preprocess=preprocess
+state.fix.vollmer.function=Function
+state.fix.vollmer.preprocessing = Outliers
+state.fix.vollmer.qa = Input for W/Q data
+
+state.minfo.river = River
+state.minfo.calculation_mode = Calculation Mode
+state.minfo.distance_only = Range selection
+state.minfo.dischargestate = Selection of discharge state and channel
+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
+state.minfo.bed.location = Location/Distance
+state.minfo.bed.periods = Periods
+state.minfo.bed.char_diameter = Characteristic Diameter
+state.minfo.soundings = Choose Soundings
+
+year=Year
+epoch=Epoch
+soundings = Soundings / Epochs
+
+historical.mode.w = Waterlevel Analyse
+historical.mode.q = Discharge Analyse
 
 calc.surface.curve = Water Level/Surface Curve
 calc.flood.map = Flood Plain
@@ -20,18 +65,63 @@
 calc.duration.curve = Duration Curve
 calc.discharge.longitudinal.section = TODO (W bei...)
 calc.w.differences = Differences
+calc.historical.discharge.curve = Historical Discharge Curve
+calc.reference.curve = Reference Curve
+calc.fixation.default = Fixation
+calc.fixation.vollmer = Balanced Waterlevel
+calc.bed.middle = Middle Bed Height
+calc.bed.diff = Bed Height Difference
+calc.bed.quality = Bed Quality
+calc.sediment.load = Sediment Load
+calc.flow.velocity = Flow Velocity
+calc.sq.relation = Load Discharge Relation
+calc.bed.d90 = D90
+calc.bed.d84 = D84
+calc.bed.d80 = D80
+calc.bed.d75 = D75
+calc.bed.d70 = D70
+calc.bed.d60 = D60
+calc.bed.d50 = D50
+calc.bed.d40 = D40
+calc.bed.d30 = D30
+calc.bed.d25 = D25
+calc.bed.d20 = D20
+calc.bed.d16 = D16
+calc.bed.d10 = D10
+calc.bed.dmin = Dmin
+calc.bed.dmax = Dmax
+calc.bed.dmid = Dmid
+
+calculation.analysis = Fixinganalysis
+calculation.vollmer = relocated Waterlevel Calculation
+
+state.chart.river = River
+state.chart.type = Charttype
+
+chart.new.durationcurve = Duration Curve
+chart.new.computeddischargecurve = Discharge Curve
+chart.new.longitudinal_section = Longitudinal Section
+chart.new.w_differences = Differences
+chart.new.crosssection = Cross Section
 
 cross_section = Cross Section
 
+reference_curve = Reference Curve
+reference_curve_normalized = Normalized Reference Curve
+
 scenario.current = Current
 scenario.potentiel = Potentiel
 scenario.scenario = Scenario
 
 floodplain.option = Use Floodplain?
+floodplain.active = Activ
+floodplain.inactive = Inactiv
 
 river = River
 calculation_mode = Calculation Mode
 ld_locations = Location(s)
+main_channel = Main channel
+total_channel = Total channel
 
 chart.cross_section.title = Cross Section for river {0}
 chart.cross_section.subtitle = {0}-km: {1,number,#.###}
@@ -40,10 +130,12 @@
 
 chart.longitudinal.section.title = W-Longitudinal Section
 chart.longitudinal.section.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###}
+chart.longitudinal.section.shortsubtitle = {0}
 chart.longitudinal.section.xaxis.label = {0}-km
 chart.longitudinal.section.yaxis.label = W [{0}]
 chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s]
 chart.longitudinal.annotations.label = {0}.km
+chart.computed.discharge.curve.gauge = Discharge curve at gauge {0} (km {1})
 chart.discharge.curve.title = Discharge Curve
 chart.discharge.curve.xaxis.label = Q [m\u00b3/s]
 chart.discharge.curve.yaxis.label = W [cm]
@@ -57,15 +149,100 @@
 chart.duration.curve.subtitle = {0}-km: {1,number,#.###}
 chart.duration.curve.xaxis.label = Duration of Non-Exceedence [Days]
 chart.duration.curve.yaxis.label = W [NN + m]
-chart.duration.curve.curve.w = Waterlevel duration curve for {0}
-chart.duration.curve.curve.q = Discharge duration curve for {0}
+chart.duration.curve.curve.w = Waterlevel duration curve for {0} (km: {1})
+chart.duration.curve.curve.q = Discharge duration curve for {0} (km: {1})
+chart.historical.discharge.title = Historical Discharge Curves for Gauge {0}
+chart.historical.discharge.subtitle = Gauge {0}
+chart.historical.discharge.xaxis.label = Time
+chart.historical.discharge.yaxis.label = Q [m\u00b3/s]
+chart.historical.discharge.yaxis.second.label = W [cm]
+
+chart.reference.curve.title = Reference Curve
+chart.reference.curve.subtitle = {0}
+
+chart.fixings.analysis.title = Longitudinal section at km {0}
+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.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.reference.curve.x.axis.in.cm = Reference Gauge(s) [cm]
+chart.reference.curve.x.axis.in.m = Reference Station [NN + m]
+chart.reference.curve.y.axis.in.cm = Target Gauge(s) [cm]
+chart.reference.curve.y.axis.in.m = Target Station(s) [NN + m] 
+
+chart.normalized.reference.curve.title = Reduced Reference Curve
 
 chart.w_differences.title = Differences
 chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###}
 chart.w_differences.yaxis.label = m
 chart.w_differences.yaxis.second.label = W [NN + m]
 
+chart.bedquality.title=Bed Longitudinal Section
+chart.bedquality.xaxis.label=River-Km
+chart.bedquality.yaxis.label=Diameter [m]
+chart.bedquality.yaxis.label.porosity=Porosity [%]
+chart.bedquality.yaxis.label.density=Density [t/m\u00b3]
+
+chart.bedheight_middle.section.title=Middle Bed Height
+chart.bedheight_middle.section.yaxis.label=middle Bed Height [mm a NN]
+
+chart.flow_velocity.section.title=Geschwindigkeit- und Schubspannung
+chart.flow_velocity.section.yaxis.label=Speed v [m/s]
+chart.flow_velocity.section.yaxis.second.label=Schubspannung Tau [N]
+
+chart.sq_relation.xaxis.label = Discharge [m\u00b3/s]
+chart.sq_relation.yaxis.label = Transport [kg/s]
+chart.sq_relation_a.title = Feinkornanteil
+chart.sq_relation_b.title = Sand (Suspensionstransport)
+chart.sq_relation_c.title = Sand (Geschiebetransport)
+chart.sq_relation_d.title = Fein- und Mittelkies
+chart.sq_relation_e.title = Grobkornanteil (> Mittelkies)
+chart.sq_relation_f.title = Geschiebetransport gesamt
+facet.sq_relation.curve = Potenziell (Geschiebedaten)
+facet.sq_relation.measurements = Geschiebedaten
+facet.sq_relation.outliers = Ausrei\u00dfer Durchgang {0}
+facet.sq_relation.outlier.curve = Potenziell Durchgang {0}
+facet.sq_relation.outlier.measurement = Geschiebedaten Durchgang {0}
+
 facet.longitudinal_section.annotations = POIs
+facet.discharge_curves.mainvalues.q = Q (main values)
+facet.discharge_curves.mainvalues.w = W (main values)
+facet.flow_velocity.mainchannel = v Mainchannel at {0}
+facet.flow_velocity.totalchannel = v Totalchannel at {0}
+facet.flow_velocity.tauchannel = TAU Mainchannel at {0}
+facet.bedheight_middle.single = Bed Height {0,number,####}
+facet.bedheight_middle.epoch = Bed Height Epoch {0,number,####} - {1,number,####}
+facet.bedquality.bed.porosity.toplayer = Porosity ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.porosity.sublayer = Porosity ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.density.toplayer = Density ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.density.sublayer = Density ({0,date} - {1,date}) ({2})
+facet.bedquality.bed.diameter.toplayer = {0}_Bed ({1,date} - {2,date}) ({3})
+facet.bedquality.bed.diameter.sublayer = {0}_Bed ({1,date} - {2,date}) ({3})
+facet.bedquality.bedload.diameter = {0}_Bedload
+bedquality.toplayer = 0.0m - 0.3m
+bedquality.sublayer = 0.1m - 0.5m
+facet.bedheight.diff.year = Bedheight Difference {0}
+facet.bedheight.diff.morph = Morphologic Width {0}
+facet.bedheight.diff.height1 = Original Height Minuend {0}
+facet.bedheight.diff.height2 = Original Height Subtrahend {0}
+facet.bedheight.diff.absolute = Bedheight Difference/Year {0}
+facet.bedheight.diff.epoch = Bedheight Difference {0}
+
+chart.beddifference.height.title = Bedheight Difference
+chart.beddifference.height.xaxis.label = River-Km [km]
+chart.beddifference.height.yaxis.label = Difference [cm/year]
+chart.beddifference.epoch.title = Bedheight Difference
+chart.beddifference.xaxis.label = River-Km [km]
+chart.beddifference.yaxis.label.diff = Difference [m]
+chart.beddifference.yaxis.label.height = Absolute Height [m]
+chart.beddifference.year.title = Bedheight Difference
+chart.beddifference.xaxis.label = River-Km [km]
+chart.beddifference.yaxis.label.diff = Difference [m]
+chart.beddifference.yaxis.label.morph = Morphologic Width [m]
+chart.beddifference.yaxis.label.heights = Absolute Height [m]
 
 export.waterlevel.csv.header.km = River-Km
 export.waterlevel.csv.header.w = W [NN + m]
@@ -79,7 +256,7 @@
 export.waterlevel.csv.meta.river = # River: {0}
 export.waterlevel.csv.meta.range = # Location/Range (km): {0} - {1}
 export.waterlevel.csv.meta.gauge = # Gauge: {0}
-export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0} - {1}
+export.waterlevel.csv.meta.q = # Q (m\u00b3/s): {0}
 export.waterlevel.csv.meta.w = # W (NN + m): {0} - {1}
 export.waterlevel.csv.not.in.gauge.range = Outside selected gauge
 export.computed.discharge.curve.csv.header.w = W [NN + m]
@@ -92,6 +269,67 @@
 export.discharge.longitudinal.section.csv.header.cw = W corr.
 export.discharge.longitudinal.section.csv.header.q = Q [m\u00b3/s]
 export.discharge.curve.at.header = Computed Discharge Curve for {0} {0}-km: {1}
+export.historical.discharge.csv.header.timerange = Timerange
+export.historical.discharge.csv.header.waterlevel = Waterlevel
+export.historical.discharge.csv.header.discharge = Discharge
+export.historical.discharge.csv.header.diff = Difference
+export.historical.discharge.csv.header.gaugename = Gaugename
+export.reference_curve.csv.header.km = km
+export.reference_curve.csv.header.w.cm = W (cm at Gauge)
+export.reference_curve.csv.header.w.m = W (m + NHN)
+export.reference_curve.csv.header.w.q = equiv. Q (m\u00b3/s)
+
+export.waterlevel.pdf.mode = Waterlevel
+export.computed.discharge.pdf.mode = Computed Dischargecurve
+export.duration.pdf.mode = Durationcurve
+export.wdifferences.pdf.mode = W Differences
+export.historical.discharge.pdf.mode = Historical Discharge
+export.reference_curve.pdf.mode = Reference Curve
+export.computed.discharge.pdf.file = /jasper/computed-discharge_en.jasper
+export.duration.pdf.file = /jasper/duration_en.jasper
+export.waterlevel.pdf.file = /jasper/waterlevel_en.jasper
+export.wdifferences.pdf.file = /jasper/wdifferences_en.jasper
+export.historical.discharge.pdf.file = /jasper/historical-discharge_en.jasper
+export.reference_curve.pdf.file = /jasper/reference_en.jasper
+export.reference_curve.pdf.file.gauge = /jasper/reference_en_gauge.jasper
+export.reference_curve.pdf.file.gauge.end = /jasper/reference_en_gauge_end.jasper
+export.reference_curve.pdf.file.gauge.start.end = /jasper/reference_en_gauge_start_end.jasper
+export.flow_velocity.csv.header.km = River Km
+export.flow_velocity.csv.header.v_total = v Total Channel
+export.flow_velocity.csv.header.v_main = v Main Channel
+export.flow_velocity.csv.header.tau_main = TAU Main Channel
+export.flow_velocity.csv.header.q = Q [m\u00b3/s]
+export.flow_velocity.csv.header.locations = Location
+export.bedheight_middle.csv.header.km = River km
+export.bedheight_middle.csv.header.sounding = Sounding / Epoch
+export.bedheight_middle.csv.header.height = middle Bed Height
+export.bedheight_middle.csv.header.uncertainty = Uncertainty [m]
+export.bedheight_middle.csv.header.datagap = Data Gap
+export.bedheight_middle.csv.header.soundingwidth = Sounding Width [m]
+export.bedheight_middle.csv.header.width = morphological active width [m]
+export.bedheight_middle.csv.header.locations = Location
+export.sqrelation.csv.header.parameter = Parameter
+export.sqrelation.csv.header.station = Station
+export.sqrelation.csv.header.km = River-Km
+export.sqrelation.csv.header.function = Function
+export.sqrelation.csv.header.gauge = Gauge
+export.sqrelation.csv.header.coeff.a = a
+export.sqrelation.csv.header.coeff.b = b
+export.sqrelation.csv.header.coeff.q = Q
+export.sqrelation.csv.header.coeff.r = r^2
+export.sqrelation.csv.header.n.total = n total
+export.sqrelation.csv.header.n.outliers = n outliers
+export.sqrelation.csv.header.c.duan = C (DUAN)
+export.sqrelation.csv.header.c.ferguson = C (FERGUSON)
+export.sqrelation.csv.header.variance = Standard variance
+export.minfo.bedquality.km = km
+export.minfo.bedquality.density_cap = Density Toplayer
+export.minfo.bedquality.density_sub = Density Sublayer
+export.minfo.bedquality.porosity_cap = Porosity Toplayer
+export.minfo.bedquality.porosity_sub = Porosity Sublayer
+export.minfo.bedquality.bedload = Bedload Diameter
+export.minfo.bedquality.bed_cap = Bed Diameter Toplayer
+export.minfo.bedquality.bed_sub = Bed Diameter Sublayer
 
 floodmap.wmsbackground = Background Map
 floodmap.riveraxis = River Axis
@@ -105,6 +343,8 @@
 floodmap.lines = Lines
 floodmap.buildings = Buildings
 floodmap.fixpoints = Fixpoints
+floodmap.floodmaps = Floodmaps
+floodmap.usershape = User data
 
 wsplgen.job.queued = WSPLGEN job in queue.
 wsplgen.job.error = An unexpected error while starting WSPLGEN occured.
@@ -115,3 +355,147 @@
 Saar = Saar
 Elbe = Elbe
 
+state.map.river = River
+
+spline.interpolation.failed = Spline interpolation failed.
+cannot.find.w.for.q = Cannot find W for Q = {0,number,#.##}.
+cannot.find.q = Cannot find Q = {0,number,#.##}.
+no.ws.found = No Ws found.
+no.q.found.in.column = No Q found in {0,integer} column.
+spline.creation.failed = Spline creation failed.
+cannot.find.w.or.q = Cannot find W or Q.
+km.not.found = Cannot find km.
+cannot.create.wq.relation = Cannot create W/Q relation.
+cannot.create.index.q.relation = Cannot create index/Q relation.
+
+w.w.qkm1.failed = Calculating Q for WST index {0,number,#.##} failed.
+w.w.wkm1.failed = Calculating W for Q = {0,number,#.##} /  WST index {1,number,#.##} failed.
+w.w.qkm2.failed = Calculating Q for WST index {0,number,#.##} failed.
+w.w.wkm2.failed = Calculating W for Q = {0,number,#.##} /  WST index {1,number,#.##} failed.
+
+cannot.find.hist.q.for.w = Cannot find Q for W = {0,number,#.##} in timerange {1, date} - {2, date}
+cannot.find.hist.q.tables = Cannot find Discharge Tables for given timerange.
+cannot.find.hist.q.reftable = Cannot find reference Discharge Table for specified Gauge.
+
+more.than.one.q.for.w = Found more Qs for W = {0,number,#.##}.
+
+no.river.selected = No river selected.
+no.gauge.selected = No gauge selected.
+no.locations.selected = No locations selected.
+no.kms.selected = No KMs selected.
+converting.ws.to.qs.failed = Converting Ws to Qs failed.
+no.wst.for.river = No WST found for selected river.
+no.range.found = No range found.
+no.gauge.found.for.km = No gauge found for KM.
+cannot.create.segments = Cannot create segments.
+cannot.compute.discharge.curve = Cannot create discharge curve.
+cannot.find.ds = Cannot find Ds.
+no.segments.found = No segments found.
+no.values.given = No values given.
+cannot.interpolate.w.q = Cannot interpolate W/Q.
+
+manualpoints = Manual Points
+
+no.reference.start.km = No reference start station given.
+no.reference.end.kms = No reference end station(s) given.
+waterlevels = Waterlevels
+
+help.index=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe
+help.winfo=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO
+help.winfo.wsp.location_distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten
+help.winfo.wsp.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_W.2BAC8-Q_Daten
+help.winfo.discharge.longitudinal.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Berechnungsstrecke
+help.winfo.duration.locations=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Streckendaten
+help.winfo.discharge.longitudinal.wq=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_f.2BAPw-r_W.2BAC8-Q_Daten
+help.winfo.diff.diffs=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Zusammenstellen_der_Differenzen
+help.winfo.reference.curve.start=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Bezugsortes_.2BAC8_Bezugspegels
+help.winfo.reference.curve.end=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_des_Zielortes_.2BAC8_Zielpegels
+help.winfo.uesk.distance=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Berechnungsstrecke
+help.winfo.uesk.wsp=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_der_Wasserspiegellage
+help.winfo.uesk.dem=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Digitalen_Gel.2BAOQ-ndemodells
+help.winfo.uesk.profiles=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Abstand_Interpolierte_Profile
+help.winfo.uesk.floodplain=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Laterale_Begrenzung
+help.winfo.uesk.differences=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Eingabe_Differenz_Wasserspiegellage_und_Gel.2BAOQ-nde
+help.winfo.uesk.scenario=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#A.2BANw-berschwemmungsfl.2BAOQ-che_.2BAC8_Szenario
+help.winfo.historical.discharge.reference_gauge=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Wahl_des_Bezugspegels
+help.winfo.historical.discharge.timerange=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_des_Auswertezeitraumes
+help.winfo.historical.discharge.mode=https://flys-intern.intevation.de/Flys-3.0/OnlineHilfe/WINFO#Auswahl_der_Analyseart
+
+fix.reference.period=Reference period
+fix.reference.period.event=Reference event
+fix.reference.period.event.short=R
+fix.analysis.short=A
+fix.analysis.periods=Analysis periods
+fix.derivative=Derivative
+fix.outlier=Outlier
+fix.analysis=Analysis event
+fix.deviation=Standard deviation
+fix.reference.deviation=Reference deviation
+fix.vollmer.wq.curve=W/Q
+fix.vollmer.wq.outliers=Outliers
+fix.vollmer.wq.events=Events
+qsectors=Discharge Sectors
+
+chart.fix.deltawt.title=Difference from compensating curve at kilometer {0}
+chart.fix.deltawt.subtitle=Water: {0}; Period:  {1,date,short} to {2,date,short}; Reference period: {3,date,short} bis {4,date,short}
+chart.fix.deltawt.xaxis.label=Date
+chart.fix.deltawt.yaxis.label=\u0394 W(t) [cm]
+
+chart.fix.wq.subtitle=Water: {0}; Period: {1,date,short} to {2,date,short}
+
+chart.fixings.longitudinalsection.title=Longitudinal section
+
+export.fixings.deltawt.csv.header.km=km
+export.fixings.deltawt.csv.header.deltaw=\u0394 W [cm]
+export.fixings.deltawt.csv.header.q=Discharge [m\u00b3/s]
+export.fixings.deltawt.csv.header.w=Waterlevel [m]
+export.fixings.deltawt.csv.header.t=Date
+export.fixings.deltawt.csv.t.format=yyyy/MM/dd
+export.fixings.deltawt.csv.header.time.range=State
+export.fixings.deltawt.csv.reference=R
+export.fixings.deltawt.csv.analysis=A{0,number,integer}
+
+fix.missing.river=Missing river
+fix.missing.from=Missing start km
+fix.missing.to=Missing end km
+fix.missing.step="Missing step width
+fix.missing.function=Missing function type
+fix.missing.events=Missing list of events
+fix.missing.reference.period=Missing reference period
+fix.missing.analysis.periods=Missing analysis periods
+fix.missing.qstart.sector=Missing discharge start sector
+fix.missing.qend.sector=Missing discharge end sector
+fix.missing.prepocessing=Missing info about preprocessing
+fix.no.overview.available=No overview available
+fix.invalid.function.name=Name of function unknown
+fix.too.less.data.colums=Too less data columns for calculation
+fix.fitting.failed=Fitting failed
+fix.invalid.values=Invalid values
+fix.cannot.load.data=Cannot fetch data from database
+
+fix.km.chart.q.sector.border0=(MNQ + MQ)/2
+fix.km.chart.q.sector.border1=(MQ + MHQ)/2
+fix.km.chart.q.sector.border2=HQ5
+fix.km.chart.label.date=yyyy/MM/dd
+fix.km.chart.title=Fixings {0} km {1,number,#.###}
+fix.km.chart.q.axis=Q [m\u00b3/s]
+fix.km.chart.w.axis=W [NN + m]
+fix.km.chart.measured=measured
+fix.km.chart.interpolated=interpolated
+
+fix.export.at.header = Exported fixings discharge curve for {0} {0}-km: {1}
+sq.km.chart.label = Measuring Points
+sq.km.chart.title = Measuring Points
+sq.km.chart.km.axis = km
+sq.km.chart.date.axis = Date
+
+module.winfo = WINFO
+module.minfo = MINFO
+module.fixanalysis = Fix Analysis
+module.new_map = New Map
+module.new_chart = New Chart
+
+load_diameter = Bedload Diameter
+bed_diameter = Bed Diameter
+
+area.label.template = Area = %s m\u00b3
--- a/flys-backend/ChangeLog	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/ChangeLog	Fri Sep 28 12:15:52 2012 +0200
@@ -1,3 +1,1641 @@
+2012-09-28  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/postgresql-spatial.sql,
+	  doc/schema/oracle-spatial.sql: Changed the type of date columns to
+	  VARCHAR. This is a quick fix to solve the concatination problem in
+	  Oracle and PostgreSQL. Both aren't able to concatinate null values.
+	  So, null values are not valid for those columns. Users can now decide
+	  to fill these columns with correct values or an empty string.
+
+	* src/main/java/de/intevation/flys/utils/DgmSqlConverter.java: Set
+	  year_from and year_to values to an empty string if no correct value is
+	  specified.
+
+2012-09-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	For issue862/1, fix parsing of year field of bed height csvs,
+	which sometimes contain non-year character.
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightParser.java:
+	  Extend RE to parse year field of Bed Height data csv.
+
+2012-09-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/RiverAxis.java:
+	  Added new method to query a special kind of river axes.
+
+2012-09-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Backend-part for fix of issue863.
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightEpochParser.java:
+	  Handle missing data points.
+
+2012-09-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeightEpoch.java:
+	  Doc.
+
+2012-09-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightSingleParser.java:
+	  Removed debug output.
+
+2012-09-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightSingleParser.java:
+	  Handle csv lines with just the km set ("gaps").
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightEpochParser.java:
+	  Added TODO, as more changes towards fix for issue863 are necessary.
+
+2012-09-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightParser.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightSingleValue.java:
+	  Cosmetics, docs.
+
+2012-09-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Towards fix for issue863 (data gaps in bed height single values).
+
+	* doc/schema/postgresql-minfo.sql,
+	  doc/schema/oracle-minfo.sql:
+	  Drop "NOT NULL" constraints on some single bed height value columns.
+
+2012-09-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/BedHeightSingle.java:
+	  Replaced labeled continue by a simple break.
+
+	* src/main/java/de/intevation/flys/utils/DgmSqlConverter.java,
+	  src/main/java/de/intevation/flys/importer/ImportElevationModel.java:
+	  Removed trailing whitespace.
+
+2012-09-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/postgresql-spatial.sql:
+
+	* doc/schema/import-dems.sql: Added more information to fullfil the schema
+	  for dems.
+
+	* src/main/java/de/intevation/flys/utils/DgmSqlConverter.java: New converter
+	  for CSV files with DGM information; results in a SQL file with INSERT
+	  statements.
+
+	* pom.xml: Added dependency to OpenCSV for reading CSV files.
+
+2012-09-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/importer.py: Fixed method name for ERROR log
+	  messages.
+
+	* doc/schema/postgresql-spatial.sql: Set geometry dim to '3' instead of
+	  '4'.
+
+2012-09-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeightEpoch.java,
+	  src/main/java/de/intevation/flys/importer/ImportElevationModel.java:
+	  Some minor bugfixes for MINFO import.
+
+2012-09-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/postgresql-spatial.sql: Adapted schema; added missing
+	  relations.
+
+	* doc/schema/postgresql-drop-spatial.sql: SQL statements to drop an
+	  existing FLYS postgresql schema.
+
+2012-09-21	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/River.java,
+	  src/main/java/de/intevation/flys/model/Gauge.java:
+	  Remove fetchInfoURL methods. The info url will be generated in the
+	  client.
+
+2012-09-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/schema/postgresql.sql, doc/schema/oracle.sql:
+	  Addes column 'official_number' to rivers table.
+	  This should contain the 'Bundeswasserstrassen Identnummer'.
+
+	* src/main/java/de/intevation/flys/model/River.java:
+	  Added new column to Hibernate model.
+
+2012-09-21	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/River.java,
+	  src/main/java/de/intevation/flys/model/Gauge.java:
+	  Rename getInfoURL methods to fetchInfoURL until the values are fetched
+	  from the db to statisfy hibernate.
+
+2012-09-21	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/River.java,
+	  src/main/java/de/intevation/flys/model/Gauge.java:
+	  Add new methods to return a HTTP URL for additional information about the
+	  river or gauge.
+
+2012-09-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportSedimentDensity.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevelDifference.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightSingle.java,
+	  src/main/java/de/intevation/flys/importer/ImportSedimentYield.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightEpoch.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevel.java,
+	  src/main/java/de/intevation/flys/importer/ImportFlowVelocityMeasurement.java,
+	  src/main/java/de/intevation/flys/importer/ImportMorphWidth.java,
+	  src/main/java/de/intevation/flys/importer/ImportFlowVelocityModel.java,
+	  src/main/java/de/intevation/flys/importer/ImportSQRelation.java: Store
+	  values into database only if its peer has been successfully stored,
+	  otherwise skip values.
+
+2012-09-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	 * src/main/java/de/intevation/flys/importer/ImportSedimentDensity.java,
+	   src/main/java/de/intevation/flys/importer/parsers/SedimentDensityParser.java:
+	   Removed trailing whitespace.
+
+2012-09-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/BedHeightType.java: Accept
+	  "Querprofil" as valid BedHeightType.
+
+	* src/main/java/de/intevation/flys/importer/parsers/SedimentYieldParser.java:
+	  Added missing GrainFraction.TOTAL type to parser.
+
+2012-09-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportSedimentDensity.java,
+	  src/main/java/de/intevation/flys/importer/parsers/BedHeightParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/SedimentDensityParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/WaterlevelDifferencesParser.java:
+	  Some litte logging improvements and be more tolerant with exceptions.
+
+2012-09-17  Ingo Weinzierl <ingo@intevation.de>
+
+	Taggd RELEASE 2.9.1
+
+2012-09-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/BedHeightEpoch.java:
+	  Corrected broken loop to find epochs for river and km range.
+
+	* src/main/java/de/intevation/flys/model/BedHeightSingle.java:
+	  Corrected broken loop to find singles for river and km range.
+
+2012-09-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightParser.java:
+	  Made code more robust.
+
+2012-09-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/Config.java:
+	  Add system property 'flys.backend.importer.skip.default'
+	  which enables the switching of the skipping default.
+	  Very useful if you want only some sub systems by
+	  setting this to 'true' and the sub systems to 'false'.
+
+2012-09-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/schema/postgresql.sql: Indices on cross sections
+	  were created too early (before the referenced tables
+	  were created).
+
+2012-09-12	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/River.java:
+	  Add new method determineMinMaxQ to fetch the mimimum and maximum q values
+	  from the database.
+
+2012-09-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* postgresql-minfo.sql: Added missing tables.
+	* oracle-minfo.sql: Fixed small typos.
+
+2012-09-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* pom.xml: Java 1.6 -> 1.6
+
+	* src/main/java/de/intevation/flys/utils/StringUtil.java:
+	  Replaced german comment (with an ill encoded Umlaut).
+
+2012-09-10	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Gauge.java:
+	  Remove obsolet method (#851).
+
+2012-09-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Gauge.java:
+	  We need min/max Q, too.
+
+2012-09-10	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/MinMaxWQ.java,
+	  src/main/java/de/intevation/flys/model/Gauge.java:
+	  Add method fetchMinMaxWQ to Gauge. This mehtod returns a new MinMaxWQ
+	  instance that contains the fetched values for the gauge overview info.
+
+2012-09-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Gauge.java:
+	  Moved some code over from flys-artifacts.
+
+2012-09-07  Ingo Weinzierl <ingo@intevation.de>
+
+	Tagged module as '2.9'.
+
+2012-09-07	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Gauge.java:
+	  Rename getDurationCurveData to fetchDurationCurveData to satisfy
+	  hibernate.
+
+2012-09-06	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Gauge.java:
+	  Move static getDurationCurveData method from flys-artifacts
+	  MainValuesFactory class to a instance method in Gauge class.
+
+2012-08-30  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Attempt fix for issue821 (cross sections just till +/-500m).
+
+	* src/main/java/de/intevation/flys/model/CrossSectionLine.java:
+	  Set max value for cross sections to 2500 instead of 500.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/run_geo.sh: New run script for the python based geo importer.
+
+	* contrib/run_hydr_morph.sh: New run script for the java based importer
+	  for hydrological and morphological data.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/overview.tex: Fixed typo.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-geodaesie.tex,
+	  doc/documentation/de/importer-hydr-morph.tex: Corrected name of run
+	  scripts.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-geodaesie.tex,
+	  doc/documentation/de/importer-hydr-morph.tex,
+	  doc/documentation/de/importer-manual.tex: Bugfixes and new geo error
+	  description.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/importer.py: Fixed broken method call.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/overview.tex: Hint to root permissions.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/importer.py: Set 'path' attribute for each feature.
+
+	* contrib/shpimporter/axis.py: Also accept shapes with 'achse' in its name.
+
+	* doc/schema/oracle-spatial.sql: Added 'path' attribute to each db
+	  relation.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-geodaesie.tex: Bugfixes and added hint.
+
+	* doc/documentation/de/importer-manual.tex: Set document revision and
+	  date.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-hydr-morph.tex: Added manual line breaks.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-hydr-morph.tex: Fixed bug during PDF
+	  creation.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-hydr-morph.tex: Bugfixes.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/overview.tex: Improved description of database
+	  schema creation. Describe command to unpack importer tarball.
+
+2012-08-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-geodaesie.tex: Added further error message
+	  if no connection to Oracle database could be established.
+
+2012-08-29  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-geodaesie.tex: Documented install steps
+	  for Oracle Instantclient and python and gdal.
+
+2012-08-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-hydr-morph.tex: Describe Log4J
+	  configuration; some smaller bugfixes.
+
+2012-08-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/overview.tex: Added comment to directory structure
+	  of a river.
+
+	* doc/documentation/de/importer-hydr-morph.tex: Describe import of
+	  morphological files.
+
+2012-08-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/title.tex,
+	  doc/documentation/de/overview.tex,
+	  doc/documentation/de/importer-hydr-morph.tex,
+	  doc/documentation/de/importer-manual.tex: Smaller fixed and structural
+	  changes.
+
+2012-08-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/documentation/de/importer-hydr-morph.tex: Added documentation from
+	  README.
+
+2012-08-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/README.txt: Documented which hydrological files are taken into account.
+
+2012-08-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/README.txt: Documented the classification of the annotations.
+
+2012-08-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/README.txt: Documented the db credentials.
+
+2012-08-24	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/README.txt: Completed the error messages (Puh!)
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeightSingle.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevelDifference.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightEpoch.java,
+	  src/main/java/de/intevation/flys/importer/parsers/BedHeightParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/BedHeightSingleParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/AnnotationsParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/MorphologicalWidthParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/SedimentYieldParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/AnnotationClassifier.java,
+	  src/main/java/de/intevation/flys/importer/parsers/WstParser.java,
+	  src/main/java/de/intevation/flys/importer/ImportSQRelation.java:
+	  Made error messages identifiable.
+
+2012-08-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/shapeimporter,
+	  doc/shapeimporter/documentation.txt: Removed. The documentation is now
+	  written in latex.
+
+	* doc/documentation,
+	  doc/documentation/de: New. The place where the german documentation is
+	  located.
+
+	* doc/documentation/de/title.tex,
+	  doc/documentation/de/importer-geodaesie.tex,
+	  doc/documentation/de/figures/bfg_logo.png,
+	  doc/documentation/de/figures/intevation-logo.pdf,
+	  doc/documentation/de/overview.tex,
+	  doc/documentation/de/importer-hydr-morph.tex,
+	  doc/documentation/de/importer-manual.tex: German documentation of the
+	  importer and shape importer.
+
+	* doc/documentation/de/Makefile: Makefile to generate the documentation.
+
+	* doc/documentation/de/README: Instructions to generate the documentation.
+
+2012-08-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/README.txt: Added warning messages. TODO: More warnings.
+
+	* src/main/java/de/intevation/flys/importer/parsers/PRFParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/StaFileParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/PegelGltParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/AtFileParser.java,
+	  src/main/java/de/intevation/flys/importer/ImportRiver.java:
+	  Made warnings identifiable.
+
+2012-08-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/README.txt: Added error messages.
+
+	* src/main/java/de/intevation/flys/importer/Importer.java,
+	  src/main/java/de/intevation/flys/importer/parsers/PRFParser.java
+	  src/main/java/de/intevation/flys/importer/parsers/HYKParser.java
+	  src/main/java/de/intevation/flys/importer/ImportRiver.java:
+	  Made errors identifiable.
+
+2012-08-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/README.txt: Documentation for the importer (german).
+	  TODO: db crendentials, warning & errors, annotation types.
+
+2012-08-22  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/run.sh: Moved 'SKIP_XXX' variables to the top of
+	  the script.
+
+2012-08-22  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/axis.py: Use log methods of shpimporter and
+	  removed print() calls.
+
+	* contrib/shpimporter/importer.py: Evaluate command line option 'dry_run'.
+	  Do not commit database transaction if it is activated.
+
+	* contrib/shpimporter/shpimporter.py: Added new command line option
+	  'dry_run' to supress database transactions.
+
+2012-08-22  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/shpimporter.py: Use OptionParse to read command line
+	  options. Now, it is no longer necessary to adjust user specific settings
+	  in python files. Users should adapt run.sh script for specific settings.
+
+	* contrib/shpimporter/catchments.py,
+	  contrib/shpimporter/boundaries.py,
+	  contrib/shpimporter/hws.py,
+	  contrib/shpimporter/importer.py,
+	  contrib/shpimporter/uesg.py,
+	  contrib/shpimporter/axis.py,
+	  contrib/shpimporter/km.py,
+	  contrib/shpimporter/floodplains.py,
+	  contrib/shpimporter/lines.py,
+	  contrib/shpimporter/gauges.py,
+	  contrib/shpimporter/buildings.py,
+	  contrib/shpimporter/fixpoints.py,
+	  contrib/shpimporter/crosssectiontracks.py: Added new method getName().
+
+	* contrib/shpimporter/utils.py: Use shpimporter functions to print debug
+	  messages.
+
+	* contrib/shpimporter/run.sh: New shell script to run the shape importer
+	  with a default configuration.
+
+2012-08-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FastAnnotations.java:
+	  Added toString() to Annotation.
+
+2012-07-27  Ingo Weinzierl <ingo@intevation.de>
+
+	Tagged module as '2.8.1'.
+
+2012-07-18	Felix Wolfsteller	<felix.wolfstellre@intevation.de>
+
+	* doc/schema/postgresql.sql, doc/schema/oracle.sql:
+	  Adjusted the official_lines views to include wst column pos.
+
+2012-07-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* Tagged module as '2.8'.
+
+2012-07-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Gauge.java,
+	  src/main/java/de/intevation/flys/backend/SpatialInfo.java:
+	  Removed same package imports.
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/hibernate/MapResultTransformer.java:
+	  Added static INSTANCE because its stateless.
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/hibernate/MapResultTransformer.java:
+	  Strategy to directly transform native SQL results into Maps.
+
+2012-07-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Fix for flys/issue359
+
+	* src/main/java/de/intevation/flys/importer/parsers/PRFParser.java:
+	  Removed extension from PRF descriptions.
+
+2012-07-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/schema/postgresql.sql, doc/schema/oracle.sql:
+	  Added indices for fasten access to cross section points.
+
+2012-07-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Partial fix for flys/issue697
+
+	* doc/schema/oracle.sql: Increased the decimal places of Ws, Qs and Kms to 5.
+
+2012-07-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Set correct connection provider class (its package has changed in the
+	  last commit).
+
+2012-07-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/utils/DBCPConnectionProvider.java:
+	  Fixed broken package declaration.
+
+2012-06-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/schema/postgresql.sql, doc/schema/oracle.sql:
+	  Added views to access the 'Amtlichen Linien'.
+
+2012-06-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/**/*.java: Removed trailing whitespace.
+
+2012-06-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	 Make access to SedDB configurable over conf.xml and provide
+	 access to sessions.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Moved FLYS specific stuff out into the concept of credential classes
+	  which provides the user, password, dialect, driver, url and the
+	  Hibernate classes to bind.
+
+	* src/main/java/de/intevation/flys/backend/Credentials.java: New.
+	  Abstact class to provide the data needed for the SessionFactoryProvider.
+
+	* src/main/java/de/intevation/flys/backend/FLYSCredentials.java: New.
+	  Extends Credentials to serve the FLYS specific stuff.
+
+	* src/main/java/de/intevation/flys/backend/SedDBCredentials.java: New.
+	  Extends Credentials to serve the SedDB specific stuff. The parameters
+	  are drawn from conf.xml in the form:
+
+	    <artifact-database>
+	      ...
+	      <seddb-database>
+	        <user>USER</user>
+	        <password>PASSWORD</password>
+	        <driver>DRIVER</driver>
+	        <url>URL</url>
+	        <dialect>DIALECT</dialect>
+	      </seddb-database>
+	      ...
+	    </artifact-database>
+
+	    If absent defaults are:
+	    - user:     seddb
+	    - password: seddb
+	    - driver:   org.postgresql.Driver
+	    - url:      jdbc:postgresql://localhost:5432/seddb
+	    - dialect:  org.hibernate.dialect.PostgreSQLDialect
+
+	   Defaults can be overwritten with system properties:
+	   - user:      flys.seddb.user
+	   - password:  flys.seddb.password
+	   - driver:    flys.seddb.driver
+	   - url:       flys.seddb.url
+	   - dialect:   flys.seddb.dialect
+
+	* src/main/java/de/intevation/flys/backend/SedDBSessionHolder.java: New.
+	  Use this if you want to establish a session to the SedDB!
+	  Works like the SessionHolder.
+
+	* src/main/java/de/intevation/flys/backend/SessionHolder.java:
+	  Add Override annotation. This holder gives you a session 
+	  to the FLYS database.
+
+	* src/main/java/de/intevation/flys/App.java: Adjusted.
+
+2012-06-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/seddb/model/*.java: Hibernate access to
+	  SedDB generated by Eclipse (ugly formatted, but compiles).
+
+2012-06-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/AnnotationsParser.java:
+	  Re-establish cross platform compatibilty again.
+
+2012-06-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/CrossSectionTrack.java: Added the
+	  missing 'name' property and added a function that returns all
+	  CrossSectionTracks of a specific river with a specific name.
+
+2012-06-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Added missing river_id column to
+	  sq_relation table and reordered the drop statements.
+
+	* src/main/java/de/intevation/flys/model/SQRelationValue.java,
+	  src/main/java/de/intevation/flys/model/SQRelation.java: Added missing
+	  constructors and fixed some minor bugs that occured during import test.
+
+	* src/main/java/de/intevation/flys/importer/ImportSQRelationValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportSQRelation.java:
+	  Implemented code to store sq relations and values into db.
+
+	* src/main/java/de/intevation/flys/importer/parsers/SQRelationParser.java:
+	  Override parse() to retrieve the filename.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Implemented
+	  code to store sq relations into db.
+
+2012-06-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportSQRelationValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportSQRelation.java:
+	  New classes used during the import process of MINFO sq relations.
+
+	* src/main/java/de/intevation/flys/importer/parsers/SQRelationParser.java:
+	  New line parser that reads MINFO specifc sq relation files.
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Added system
+	  property to skip parsing sq relations.
+
+	    "-Dflys.backend.importer.skip.sq.relation"
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Parse MINFO
+	  sq relations.
+
+2012-06-12  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Cleared some
+	  irritating debug statements.
+
+2012-06-12  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/annotation-types.xml: Added regex to match "Geschiebemesstellen" as
+	  "Messstelle" type.
+
+	* src/main/java/de/intevation/flys/importer/parsers/AnnotationsParser.java:
+	  Parse KM files in "../Morphologie/Streckendaten/". On Windows Systems,
+	  this won't work!
+
+2012-06-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FastAnnotations.java:
+	  Added Override annotation to new NameFilter.
+
+2012-06-11  Raimund Renkert  <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FastAnnotations.java:
+	  Added filter for annotation names.
+
+2012-06-08	Felix Wolfsteller	<felix.wolfstellre@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FastAnnotations.java:
+	  Fix comment.
+
+2012-06-08	Felix Wolfsteller	<felix.wolfstellre@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/SQRelationValue.java:
+	  Fix hibernaty annotation symptom (make it run again).
+
+2012-06-07  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Schema additions for MINFO s/q
+	  relation.
+
+	* src/main/java/de/intevation/flys/model/SQRelationValue.java,
+	  src/main/java/de/intevation/flys/model/SQRelation.java: New model
+	  classes for MINFO s/q relation.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered new model classes.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/GaugeLocation.java,
+	  src/main/java/de/intevation/flys/importer/ImportRiver.java:
+	  Removed superfluous imports.
+
+2012-05-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* Tagged module as '2.7'.
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/BedHeightEpoch.java,
+	  src/main/java/de/intevation/flys/model/BedHeightSingle.java: Added lower
+	  and upper km to function that returns all singles and epochs for a given
+	  river.
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/BedHeightSingleValue.java: Fixed
+	  a typo.
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/BedHeightSingleValue.java,
+	   src/main/java/de/intevation/flys/model/BedHeightEpochValue.java: Added
+	   functions to retrieve single and epoch values based on its owner and km
+	   range.
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/BedHeightEpoch.java,
+	  src/main/java/de/intevation/flys/model/BedHeightSingle.java: Added
+	  functions to get singles and epochs by river and by id.
+
+2012-05-15  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FlowVelocityModel.java,
+	  src/main/java/de/intevation/flys/model/FlowVelocityModelValue.java,
+	  src/main/java/de/intevation/flys/model/DischargeZone.java: Added static
+	  functions to retrieve data from database.
+
+2012-05-15  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/DischargeZone.java: Added a
+	  function getDischargeZones() that returns all DischargeZones for a given
+	  river.
+
+2012-05-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/gauges.py: Search for field 'MPNAAM' and use its
+	  value as name for the geometry.
+
+	* src/main/java/de/intevation/flys/model/GaugeLocation.java: New model
+	  class for storing locations of gauges.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered GaugeLocation class.
+
+2012-05-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/HydrBoundary.java,
+	  src/main/java/de/intevation/flys/model/HydrBoundaryPoly.java: New.
+	  Hydrological boundaries.
+
+	* src/main/java/de/intevation/flys/model/Line.java: Modified signature of
+	  Line.getLines(). It now also takes the name of a line to retrieve more
+	  specific lines.
+
+	* src/main/java/de/intevation/flys/model/Building.java: Modified signature
+	  of Building.getBuildings(). It now also takes the name of a building to
+	  retrieve more specific lines.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered HydrBoundary and HydrBoundaryPoly classes.
+
+2012-05-10  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/crosssectiontracks.py: Search for 'STATION' field in
+	  shapefile to extract the current km.
+
+2012-05-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Hws.java: The getHws() function
+	  got a further parameter 'name' to retrieve specific hws only.
+
+
+2012-05-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Catchment.java: The
+	  getCatchments() function got a further parameter 'name' to retrieve
+	  specific catchments only.
+
+2012-05-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-spatial_idx.sql: Set the geometry type of 'catchments'
+	  to 'multipolygon'.
+
+	* src/main/java/de/intevation/flys/model/Catchment.java: The geometry
+	  attribute in such instances is now from type 'Geometry'.
+
+2012-05-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/import-dems.sql: New. Insert statements to insert dems into
+	  database.
+
+2012-05-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-drop-spatial.sql,
+	  doc/schema/oracle-spatial.sql: New relation 'gauge_location' and some
+	  bugfixes in the drop schema.
+
+	* contrib/shpimporter/catchments.py,
+	  contrib/shpimporter/hws.py,
+	  contrib/shpimporter/gauges.py: New importers.
+
+	* contrib/shpimporter/importer.py: Added a debug statement to improve the
+	  visibility of the log output.
+
+	* contrib/shpimporter/shpimporter.py: Make use of the new importers.
+
+
+2012-05-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-drop-spatial.sql,
+	  doc/schema/oracle-spatial.sql: Added new relations for hydrological
+	  boundaries and appended a 'name' field to relations that had no such
+	  field yet.
+
+	* contrib/shpimporter/floodplains.py,
+	  contrib/shpimporter/boundaries.py: New importers for floodplain and
+	  hydrological boundaries.
+
+	* contrib/shpimporter/lines.py,
+	  contrib/shpimporter/buildings.py,
+	  contrib/shpimporter/uesg.py,
+	  contrib/shpimporter/fixpoints.py,
+	  contrib/shpimporter/axis.py,
+	  contrib/shpimporter/crosssectiontracks.py,
+	  contrib/shpimporter/km.py: Set the 'name' attribute for new features.
+
+	* contrib/shpimporter/importer.py: Some bugfixes and improvements:
+	  geometries are transformed into a destination coordinate system now.
+
+	* contrib/shpimporter/shpimporter.py: Use all importers and defined the
+	  destination srs.
+
+2012-05-02	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FastCrossSectionLine.java,
+	  src/main/java/de/intevation/flys/model/CrossSectionPoint.java,
+	  src/main/java/de/intevation/flys/model/CrossSectionLine.java,
+	  src/main/java/de/intevation/flys/importer/ImportCrossSectionLine.java,
+	  src/main/java/de/intevation/flys/importer/ImportRiver.java:
+	  Store meassure points of profiles as Doubles not as BigDecimal.
+	  This should save a lot of memory during the import.
+
+2012-04-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/FlowVelocityMeasurementParser.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevelDifferenceValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevelDifferenceColumn.java:
+	  Removed superfluous imports.
+
+2012-04-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/schema/postgresql-minfo.sql: Adjusted PostgreSQL port
+	  to match the Oracle schema.
+
+2012-04-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/annotation-types.xml: Adapted annotation typed based on BfG wishes.
+
+2012-04-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-drop.sql: New SQL file to drop WINFO specific db
+	  schema.
+
+2012-04-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle.sql: Made SQL instructions upper case.
+
+2012-04-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-drop-spatial.sql: New statements to drop the whole
+	  spatial schema.
+
+2012-04-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/lines.py,
+	  contrib/shpimporter/buildings.py,
+	  contrib/shpimporter/importer.py,
+	  contrib/shpimporter/fixpoints.py,
+	  contrib/shpimporter/axis.py,
+	  contrib/shpimporter/crosssectiontracks.py,
+	  contrib/shpimporter/km.py: New classes for importing specific
+	  shapefiles. Each of this imports defines its target db tablename and a
+	  directory path to the shapefiles it should import.
+
+	* contrib/shpimporter/uesg.py: Some modifications necessary to streamline
+	  the import process of shapefiles.
+
+	* contrib/shpimporter/shpimporter.py: Use all available imports for the
+	  import process.
+
+2012-04-26  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-spatial.sql: Repaired broken schema.
+
+2012-04-26  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Added a config
+	  option to skip parsing MINFO waterlevel differences:
+
+	    -Dflys.backend.importer.skip.waterlevel.differences=True
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Parse and
+	  store MINFO specific waterlevel differences.
+
+2012-04-26  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/WaterlevelDifferencesParser.java:
+	  New parser for MINFO specific waterlevel differences.
+
+	* src/main/java/de/intevation/flys/importer/ImportWaterlevelDifferenceValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevelDifference.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevelDifferenceColumn.java:
+	  New importer classes used during the import process of MINFO specific
+	  waterlevel differences.
+
+2012-04-26  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Added a missing constraint to
+	  'waterlevel_difference' relation. Remove that constraint in
+	  oracle-drop-minfo.sql.
+
+2012-04-25  Felix Wolfsteller <felix@intevation.de>
+
+	  * src/main/java/de/intevation/flys/model/WaterlevelDifferenceValue.java:
+	    (setValue, setValues): Change setter name to allow hibernate to recognize
+	    it.
+
+2012-04-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/WaterlevelDifferenceColumn.java,
+	  src/main/java/de/intevation/flys/model/WaterlevelDifference.java,
+	  src/main/java/de/intevation/flys/model/WaterlevelDifferenceValue.java:
+	  New model classes for MINFO specific waterlevel differences.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered new model classes.
+
+2012-04-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Improved the schema to store MINFO
+	  specific waterlevel differences.
+
+2012-04-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/WaterlevelValue.java: Renamed a
+	  property ('qRange' -> 'qrange') because there have been problem during the
+	  import.
+
+	* src/main/java/de/intevation/flys/importer/parsers/WaterlevelParser.java:
+	  Filled the stub with code.
+
+	* src/main/java/de/intevation/flys/importer/ImportWaterlevelValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevelQRange.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevel.java: Some
+	  adaptions and missing methods which are required during the import.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Use the
+	  correct directory to search for waterlevel files.
+
+2012-04-24  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql: Small type adaptions in the waterlevel_values
+	  relation.
+
+	* src/main/java/de/intevation/flys/importer/parsers/WaterlevelParser.java:
+	  First stub of a parser for MINFO specific waterlevel values.
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Added a new config
+	  option to skip parsing MINFO specifc waterlevel_values:
+
+	    -Dflys.backend.importer.skip.waterlevels=True
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Added code
+	  path to start parsing and storing MINFO specific waterlevel values.
+
+2012-04-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportWaterlevelValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevelQRange.java,
+	  src/main/java/de/intevation/flys/importer/ImportWaterlevel.java: New
+	  importer classes used for MINFO specific waterlevel import.
+
+2012-04-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/WaterlevelQRange.java,
+	  src/main/java/de/intevation/flys/model/WaterlevelValue.java,
+	  src/main/java/de/intevation/flys/model/Waterlevel.java: New model
+	  classes for MINFO specific waterlevel data.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered new model classes.
+
+2012-04-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Added relations for waterlevels
+	  specific to MINFO. Note: those waterlevel values are not stored in the
+	  WINFO specific relations!
+
+2012-04-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  src/main/java/de/intevation/flys/importer/ImportSedimentYield.java,
+	  src/main/java/de/intevation/flys/model/SedimentYield.java: Added a
+	  column 'description' to the sediment_yield relation.
+
+	* src/main/java/de/intevation/flys/importer/parsers/SedimentYieldParser.java:
+	  New parser for sediment yield data.
+
+	* src/main/java/de/intevation/flys/model/GrainFraction.java: Added constants
+	  that represent the names of the grain fraction types.
+
+	* src/main/java/de/intevation/flys/importer/ImportGrainFraction.java: New
+	  constructor that takes a name only.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Improved the
+	  process of parsing sediment yield files.
+
+2012-04-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Added new config
+	  option to skip parsing sediment yield data:
+
+	     -Dflys.backend.importer.skip.sediment.yield=true
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Prepared the
+	  importer to parse sediment yield data.
+
+	* src/main/java/de/intevation/flys/importer/ImportSedimentYield.java:
+	  storeDependencies() now throws SQLExceptions and
+	  ConstraintViolationExceptions.
+
+2012-04-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportGrainFraction.java,
+	  src/main/java/de/intevation/flys/importer/ImportSedimentYieldValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportSedimentYield.java: New
+	  importer classes for importing sediment yield data.
+
+2012-04-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/SedimentYield.java,
+	  src/main/java/de/intevation/flys/model/SedimentYieldValue.java,
+	  src/main/java/de/intevation/flys/model/GrainFraction.java: New model
+	  classes for sediment yield data.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered new model classes.
+
+2012-04-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Added missing river_id column to
+	  sediment_yield relation.
+
+2012-04-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Floodmaps.java,
+	  src/main/java/de/intevation/flys/importer/parsers/SedimentDensityParser.java,
+	  src/main/java/de/intevation/flys/importer/ImportDischargeZone.java:
+	  Removed superflous imports.
+
+2012-04-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Added relations for storing sediment
+	  yield values.
+
+2012-04-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: The discharge_zone relation has no
+	  longer a reference to a named main value but stores a lower and upper
+	  discharge as string.
+
+	* src/main/java/de/intevation/flys/model/DischargeZone.java,
+	  src/main/java/de/intevation/flys/importer/ImportDischargeZone.java:
+	  Adapted the code to the changes in the db schema.
+
+	* src/main/java/de/intevation/flys/importer/parsers/FlowVelocityModelParser.java:
+	  This parser now reads the meta information properly.
+
+	* src/main/java/de/intevation/flys/importer/ImportFlowVelocityModelValue.java:
+	  Repaired broken HQL statement.
+
+	* src/main/java/de/intevation/flys/importer/ImportFlowVelocityModel.java:
+	  Log the number of flow velocity model values that have been written into
+	  database.
+
+2012-04-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/FlowVelocityMeasurementParser.java:
+	  New parser for flow velocity measurements.
+
+	* src/main/java/de/intevation/flys/importer/ImportFlowVelocityMeasurementValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportFlowVelocityMeasurement.java,
+	  src/main/java/de/intevation/flys/importer/ImportFlowVelocityModelValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportFlowVelocityModel.java:
+	  Fixed broken HQL statements.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Store flow
+	  velocity measurements into database after parsing them.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered new model classes for flow velocity measurements.
+
+2012-04-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportFlowVelocityMeasurementValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportFlowVelocityMeasurement.java:
+	  New temp classes used during the import process of flow velocity
+	  measurements.
+
+2012-04-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FlowVelocityMeasurementValue.java,
+	  src/main/java/de/intevation/flys/model/FlowVelocityMeasurement.java: New
+	  model classes for storing flow velocity measurements.
+
+2012-04-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Added new relations for MINFO specific
+	  flow velocity measurements.
+
+2012-04-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/FlowVelocityModelParser.java:
+	  New. Parser for model files of MINFO specific flow velocity data.
+
+	* doc/schema/oracle-minfo.sql: Added a missing q column to
+	  flow_velocity_model_values relation.
+
+	* src/main/java/de/intevation/flys/importer/ImportFlowVelocityModelValue.java,
+	  src/main/java/de/intevation/flys/model/FlowVelocityModelValue.java:
+	  Added missing q column.
+
+	* src/main/java/de/intevation/flys/importer/ImportFlowVelocityModel.java:
+	  Added setter methods for meta data and an addValue() for adding new
+	  ImportFlowVelocityModelValues.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Use
+	  FlowVelocityModelParser for parsing model data of flow velocity files.
+
+2012-04-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportDischargeZone.java,
+	  src/main/java/de/intevation/flys/importer/ImportFlowVelocityModelValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportFlowVelocityModel.java:
+	  Temp classes used during the import process of flow velocity data.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Implemented
+	  the method that stores flow velocity model data.
+
+2012-04-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Prepared for
+	  parsing flow  velocity files.
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Added a config
+	  option to skip parsing flow velocity files:
+
+	    -Dflys.backend.importer.skip.flow.velocity=true
+
+2012-04-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FlowVelocityModel.java,
+	  src/main/java/de/intevation/flys/model/FlowVelocityModelValue.java,
+	  src/main/java/de/intevation/flys/model/DischargeZone.java: New model
+	  classes for MINFO specific database relations.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered the new model classes.
+
+2012-04-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Added new relations for MINFO specific
+	  flow velocity values.
+
+2012-02-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/schema/oracle-minfo.sql: Fixed column unit_id in table depths
+	  to match type of column id in table units.
+
+	* doc/schema/postgresql-minfo.sql: oracle-minfo.sql for a better DBMS.
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/MorphologicalWidth.java: Added
+	  annotation for values.
+
+	* src/main/java/de/intevation/flys/importer/ImportMorphWidthValue.java:
+	  Removed debug output in getPeer() and storeDependencies().
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/MorphologicalWidthParser.java:
+	  New parser for morphological widths files.
+
+	* src/main/java/de/intevation/flys/importer/ImportMorphWidth.java: Throw
+	  constraint violation exceptions.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Parse and
+	  store morphological widths.
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Added a config
+	  option to skip parsing morphological widths:
+
+	    -Dflys.backend.importer.skip.morphological.width=true
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql: Added a description field to morphological
+	  width values.
+
+	* src/main/java/de/intevation/flys/model/MorphologicalWidthValue.java:
+	  Added new instance variable for descriptions.
+
+	* src/main/java/de/intevation/flys/importer/ImportMorphWidthValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportMorphWidth.java: New
+	  temp classes used to store morphological width values during the import.
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Added new relations for MINFO specific
+	  morphological width.
+
+	* src/main/java/de/intevation/flys/model/MorphologicalWidth.java,
+	  src/main/java/de/intevation/flys/model/MorphologicalWidthValue.java: New
+	  model classes for morphological width.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered new model classes.
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql: Added a description field to table
+	  sediment_density.
+
+	* src/main/java/de/intevation/flys/model/SedimentDensityValue.java,
+	  src/main/java/de/intevation/flys/model/SedimentDensity.java: Some
+	  modifications based on the changes of the schema adaption in last commit.
+
+	* src/main/java/de/intevation/flys/importer/parsers/SedimentDensityParser.java:
+	  Override parse() of parent class to get the filename.
+
+	* src/main/java/de/intevation/flys/importer/ImportSedimentDensity.java,
+	  src/main/java/de/intevation/flys/importer/ImportDepth.java,
+	  src/main/java/de/intevation/flys/importer/ImportSedimentDensityValue.java:
+	  Implemented the methods storeDependencies() and getPeer() to save new
+	  instances into database.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Save all
+	  ImportSedimentDensity objects to database.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered the new model classes.
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Modified the db schema specific to
+	  MINFO; replaced some columns.
+
+	* src/main/java/de/intevation/flys/importer/parsers/SedimentDensityParser.java:
+	  Implemented the method stubs: parse meta data and data values.
+
+	* src/main/java/de/intevation/flys/importer/ImportSedimentDensityValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportSedimentDensity.java:
+	  Added and replaced some instance variables because the db schema has
+	  changed.
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/LineParser.java: New.
+	  An abstract parser that might be used to read a file and handle each
+	  line contained in the file seperatly.
+
+	* src/main/java/de/intevation/flys/importer/parsers/SedimentDensityParser.java:
+	  New. Subclasses LineParser. It is able to parse MINFO specific sediment
+	  density files. NOTE: currently just a stub.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Prepared to
+	  read MINFO specific sediment density files.
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Added a new
+	  config option to skip parsing MINFO sediment density values:
+
+	    -Dflys.backend.importer.skip.sediment.density=true
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/ImportSedimentDensity.java,
+	  src/main/java/de/intevation/flys/importer/ImportSedimentDensityValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportDepth.java: New importer
+	  classes used during MINFO sediment density import.
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Improved the MINFO schema to store
+	  sediment density values specific to a river and depth.
+
+	* src/main/java/de/intevation/flys/model/SedimentDensityValue.java,
+	  src/main/java/de/intevation/flys/model/SedimentDensity.java,
+	  src/main/java/de/intevation/flys/model/Depth.java: New model classes
+	  used to store sediment density values specific to a river and depth.
+
+2012-04-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightParser.java:
+	  New. An abstract super class for BedHeightSingleParser and
+	  BedHeightEpochParser. It implements methods for parsing meta data.
+	  Concrete subclasses need to implements the method for parsing data rows
+	  only.
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeight.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightValue.java: New.
+	  Interfaces that define some major methods which enables the BedHeightParser
+	  to parse both - single and epoch bed heights.
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightSingleParser.java:
+	  Moved the code for parsing meta data to BedHeightParser which is now the
+	  parent class.
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightEpochParser.java:
+	  New. A further subclass of BedHeightParser for parsing MINFO bed heights
+	  for epochs.
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeightSingleValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightEpochValue.java:
+	  Made them subclasses of ImportBedHeightValue.
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeightSingle.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightEpoch.java: Made
+	  them subclasses of ImportBedHeight.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Some
+	  adjustments to store ImportBedHeight and ImportBedHeightValue instances
+	  instead of concrete subclasses.
+
+2012-04-12  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql: Added a link to the river to bed_height_epoch
+	  table.
+
+	* src/main/java/de/intevation/flys/model/BedHeightEpochValue.java,
+	  src/main/java/de/intevation/flys/model/BedHeightEpoch.java: New model
+	  classes for MINFO bed height epochs.
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Splitted up the
+	  config option to skip parsing bed heights. Now, we are able to skip single
+	  and epoch bed heights using the following options:
+
+	    -Dflys.backend.importer.skip.bed.height.single=true  (skip singles)
+	    -Dflys.backend.importer.skip.bed.height.epoch=true   (skip epochs)
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeightEpoch.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightEpochValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportRiver.java: Implemented
+	  the whole stuff to parse those data.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered the new model classes.
+
+2012-04-12  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Schema adaptions specific to MINFO bed
+	  heights.
+
+	* src/main/java/de/intevation/flys/model/BedHeightSingleValue.java,
+	  src/main/java/de/intevation/flys/model/BedHeightType.java,
+	  src/main/java/de/intevation/flys/model/ElevationModel.java,
+	  src/main/java/de/intevation/flys/model/LocationSystem.java,
+	  src/main/java/de/intevation/flys/model/BedHeightSingle.java: New model
+	  classes for MINFO bed heights.
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightSingleParser.java:
+	  Some logging adjustments and a little bugfix: add BedHeightSingle objects
+	  after they were parsed; otherwise they are not saved to database.
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeightSingleValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightSingle.java,
+	  src/main/java/de/intevation/flys/importer/ImportElevationModel.java,
+	  src/main/java/de/intevation/flys/importer/ImportLocationSystem.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightType.java,
+	  src/main/java/de/intevation/flys/importer/ImportRiver.java: Implemented
+	  storeDependencies() and getPeer().
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered model classes.
+
+2012-04-11  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightSingleParser.java:
+	  Finished work on parsing meta information and data specific to single bed
+	  heights.
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeightSingleValue.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightSingle.java,
+	  src/main/java/de/intevation/flys/importer/ImportElevationModel.java,
+	  src/main/java/de/intevation/flys/importer/ImportLocationSystem.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightType.java: Some
+	  new and modified temp storages used during MINFO import.
+
+2012-04-11  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: Some schema adaptions specific to bed
+	  heights in MINFO.
+
+2012-04-11  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Added new command
+	  line option to skip parsing bed heights (german "Sohlhoehen").
+	  Set "-Dflys.backend.importer.skip.bed.height=true" to skip parsing this
+	  file type.
+
+	* src/main/java/de/intevation/flys/importer/parsers/BedHeightEpochParser.java,
+	  src/main/java/de/intevation/flys/importer/parsers/BedHeightSingleParser.java:
+	  Initial checkin of parsers for bed heights (single and epoch).
+
+	* src/main/java/de/intevation/flys/importer/ImportBedHeightSingle.java,
+	  src/main/java/de/intevation/flys/importer/ImportBedHeightEpoch.java: Temp
+	  storage for bed heights data used during the import.
+
+	* src/main/java/de/intevation/flys/importer/Importer.java: Added an INFO
+	  statement that signals the start of parsing rivers.
+
+	* src/main/java/de/intevation/flys/importer/ImportRiver.java: Collect and
+	  trigger parsing of bed heights files (placed in 'Morphologie/Sohlhoehen').
+
+2012-04-11  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-minfo.sql,
+	  doc/schema/oracle-drop-minfo.sql: MINFO specific DB schema and sql statements
+	  to drop MINFO specific stuff.
+
+2012-03-29  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/Config.java: Added a config
+	  option "flys.backend.importer.infogew.file" to set the path of an
+	  INFO.gew file.
+
+	* src/main/java/de/intevation/flys/importer/Importer.java: Read the path
+	  to the INFO.gew from the new config option and try to parse it.
+
+2012-03-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-spatial.sql: Set the type of 'lower' and 'upper' column
+	  of relation 'dem' to NUMBER(19,5).
+
+2012-03-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Floodmaps.java: Set geometry type
+	  to 'Geometry', because Oracle can save POLYGONS and MULTIPOLYGONS in the
+	  same relation; Hibernate seems unable to load both types.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered missing Floodmaps.
+
+2012-03-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* Tagged module as 'pre2.7-2012-03-16'.
+
+2012-03-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/oracle-spatial.sql: Repaired broken oracle db schema for
+	  relation 'floodmaps'.
+
+2012-03-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Floodmaps.java: New model class for
+	  'floodmaps'.
+
+	* src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java:
+	  Registered the Floodmaps model class.
+
+2012-03-07  Ingo Weinzierl <ingo@intevation.de>
+
+	* contrib/shpimporter/shpimporter.py,
+	  contrib/shpimporter/utils.py,
+	  contrib/shpimporter/uesg.py: A python based tool for importing
+	  shapefiles into a database. This tool is based on python because it
+	  makes use of GDAL OGR to read shapefiles and write features into
+	  database.
+
+2012-03-07  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/postgresql-spatial.sql: Adapted the PostgreSQL schema for
+	  floodmaps.
+
+2012-03-06  Ingo Weinzierl <ingo@intevation.de>
+
+	* doc/schema/postgresql-spatial.sql,
+	  doc/schema/oracle-spatial.sql: Added new relations for existing
+	  floodmaps (currently tested for PostgreSQL only!).
+
+2012-03-06  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Wst.java: Adapted method call of
+	  Log4J logger 'warning()' -> 'warn()'.
+
+2012-03-02  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Fix or workaround flys/issue632 .
+
+	* src/main/java/de/intevation/flys/model/Wst.java: Avoid NPE when
+	  trying to get min/max q values.
+
+2012-02-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/DischargeTable.java:
+	  The list of DischargeTableValue is now sorted by Q.
+
+2012-02-09  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Gauge.java: Added a method
+	  getMasterDischargeTable() to retrieve the discharge table with kind 0.
+
+2012-02-03  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/River.java
+	  (getGaugeDatumsKMs,queryGaugeDatumsKMs): renamed to avoid hibernate
+	  running into trouble finding db-mapping for type Map for
+	  what looks like a 'getter' of GaugeDatumsKMs.
+
+2012-02-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/River.java(getGaugeDatumsKMs):
+	  New method to build a map of gauge stattion km to 
+	  the datums (PNP) of the gauge.  Useful look if a km 
+	  is a gauge station.
+
+2012-01-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FastAnnotations.java:
+	  New. Fetches all informations of annotations in one go for
+	  a river. Useful to speed up annotation handling.
+
+2012-01-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/Gauge.java: Added a function that
+	  returns a Gauge based on its official number.
+
+2012-01-17	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/FastCrossSectionLine.java:
+	  New. Cacheable representation of the cross section line.
+
+	* src/main/java/de/intevation/flys/model/CrossSectionLine.java:
+	  Add a new isValid() method.
+
+	* src/main/java/de/intevation/flys/model/CrossSection.java:
+	  Added method getFastLines() to fetch the lines (FastCrossSectionLines)
+	  directly with a single SQL statement and without expensive
+	  intermediate representations.
+
+2012-01-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/CrossSection.java(getLines):
+	  Added method to fetch the lines of a cross section in a given interval.
+	  Useful to have chunked access to the lines.
+
+2012-01-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/CrossSectionLine.java
+	  (fetchCrossSectionLinesPoints): Simplified and prevent reallocations.
+
+2012-01-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/importer/parsers/StaFileParser.java:
+	  Introduced boolean system property 'flys.backend.sta.parse.gauge.numbers'
+	  default: false. If set the official number is parsed out of
+	  the first line of the STA files. This leads to problems with the
+	  data of the Elbe river.
+
+	* src/main/java/de/intevation/flys/backend/SpatialInfo.java: Removed
+	  superfluous import.
+
+2012-01-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/schema/postgresql-spatial.sql: Fixed table hws.
+
+2012-01-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/model/RiverAxis.java: The method
+	  getRiverAxis() now returns a list of RiverAxis objects. There is a
+	  modeling problem (see comment in the header of the class) which should
+	  be fixed!
+
+	* src/main/java/de/intevation/flys/backend/SpatialInfo.java: Adapted the
+	  code based on the modified signature in RiverAxis.
+
 2012-01-03  Ingo Weinzierl <ingo@intevation.de>
 
 	* src/main/java/de/intevation/flys/model/Wst.java: Added a method
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/run_geo.sh	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# Required
+RIVER_PATH="/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Saar"
+RIVER_ID=1
+TARGET_SRS=31467
+HOST=localhost
+USER=flys28
+PASS=flys28
+
+# Optional
+VERBOSE=1
+SKIP_AXIS=0
+SKIP_KMS=0
+SKIP_CROSSSECTIONS=0
+SKIP_LINES=0
+SKIP_FIXPOINTS=0
+SKIP_BUILDINGS=0
+SKIP_FLOODPLAINS=0
+SKIP_HYDR_BOUNDARIES=0
+SKIP_HWS=0
+SKIP_GAUGE_LOCATION=0
+SKIP_CATCHMENTS=0
+SKIP_UESG=0
+
+
+DIR=`dirname $0`
+DIR=`readlink -f "$DIR"`
+
+exec python $DIR/shpimporter/shpimporter.py \
+    --directory $RIVER_PATH \
+    --river_id $RIVER_ID \
+    --target_srs $TARGET_SRS \
+    --host $HOST \
+    --user $USER \
+    --password $PASS \
+    --verbose $VERBOSE \
+    --skip_axis $SKIP_AXIS \
+    --skip_kms $SKIP_KMS \
+    --skip_crosssections $SKIP_CROSSSECTIONS \
+    --skip_lines $SKIP_LINES \
+    --skip_fixpoints $SKIP_FIXPOINTS \
+    --skip_buildings $SKIP_BUILDINGS \
+    --skip_floodplains $SKIP_FLOODPLAINS \
+    --skip_hydr_boundaries $SKIP_HYDR_BOUNDARIES \
+    --skip_hws $SKIP_HWS \
+    --skip_gauge_locations $SKIP_GAUGE_LOCATION \
+    --skip_catchments $SKIP_CATCHMENTS \
+    --skip_uesgs $SKIP_UESG
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/run_hydr_morph.sh	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,103 @@
+#!/bin/bash
+
+######################### CONFIG OPTIONS ############################
+INFO_GEW="/vol1/projects/Geospatial/flys-3.0/testdaten/saar.gew"
+BACKEND_USER="flys28"
+BACKEND_PASS="flys28"
+BACKEND_HOST="czech-republic.atlas.intevation.de"
+BACKEND_PORT="1521"
+BACKEND_NAME="XE"
+LOG4J_CONFIG="conf/log4j.properties"
+#####################################################################
+
+
+########################## Oracle Settings ##########################
+BACKEND_DB_PREFIX="jdbc:oracle:thin:@"
+BACKEND_DB_DRIVER="oracle.jdbc.OracleDriver"
+BACKEND_DB_DIALECT="org.hibernate.dialect.OracleDialect"
+BACKEND_URL=$BACKEND_DB_PREFIX//$BACKEND_HOST:$BACKEND_PORT/$BACKEND_NAME
+#####################################################################
+
+
+######################## Custom Importer Settings ###################
+IMPORTER_DRY_RUN=false
+IMPORTER_MAINVALUE_TYPES=QWTD
+IMPORTER_ANNOTATION_TYPES="conf/annotation-types.xml"
+
+IMPORTER_SKIP_GAUGES=false
+IMPORTER_SKIP_ANNOTATIONS=false
+IMPORTER_SKIP_WST=false
+IMPORTER_SKIP_PRFS=false
+IMPORTER_SKIP_HYKS=false
+IMPORTER_SKIP_EXTRA_WST=false
+IMPORTER_SKIP_FIXATIONS=false
+IMPORTER_SKIP_OFFICIAL_LINES=false
+IMPORTER_SKIP_FLOOD_WATER=false
+IMPORTER_SKIP_FLOOD_PROTECTION=false
+
+IMPORTER_SKIP_BED_HEIGHT_SINGLE=false
+IMPORTER_SKIP_BED_HEIGHT_EPOCH=false
+IMPORTER_SKIP_SEDIMENT_DENSITY=false
+IMPORTER_SKIP_MORPHOLOGICAL_WIDTH=false
+IMPORTER_SKIP_FLOW_VELOCITY=false
+IMPORTER_SKIP_SEDIMENT_YIELD=false
+IMPORTER_SKIP_WATERLEVELS=false
+IMPORTER_SKIP_WATERLEVEL_DIFFERENCES=false
+IMPORTER_SKIP_SQ_RELATION=false
+#####################################################################
+
+#MIN_MEMORY="8192m"
+MIN_MEMORY="1024m"
+
+
+########################## Importer Settings ########################
+APP="de.intevation.flys.importer.Importer"
+DIR=`dirname $0`
+DIR=`readlink -f "$DIR/.."`
+#####################################################################
+
+
+########################## Collect required libraries ###############
+CLASSPATH=
+for l in `find "$DIR/lib" -name \*.jar -print`; do
+   CLASSPATH=$CLASSPATH:$l
+done
+
+export CLASSPATH
+#####################################################################
+
+
+######################### Run Importer ##############################
+exec java \
+    -Xmx$MIN_MEMORY \
+    -server \
+    -Dlog4j.configuration=file://`readlink -f $LOG4J_CONFIG` \
+    -Dflys.backend.importer.infogew.file=$INFO_GEW \
+    -Dflys.backend.main.value.types=$IMPORTER_MAINVALUE_TYPES \
+    -Dflys.backend.importer.annotation.types=$IMPORTER_ANNOTATION_TYPES \
+    -Dflys.backend.importer.dry.run=$IMPORTER_DRY_RUN \
+    -Dflys.backend.importer.skip.gauges=$IMPORTER_SKIP_GAUGES \
+    -Dflys.backend.importer.skip.annotations=$IMPORTER_SKIP_ANNOTATIONS \
+    -Dflys.backend.importer.skip.prfs=$IMPORTER_SKIP_PRFS \
+    -Dflys.backend.importer.skip.hyks=$IMPORTER_SKIP_HYKS \
+    -Dflys.backend.importer.skip.wst=$IMPORTER_SKIP_WST \
+    -Dflys.backend.importer.skip.extra.wsts=$IMPORTER_SKIP_EXTRA_WST \
+    -Dflys.backend.importer.skip.fixations=$IMPORTER_SKIP_FIXATIONS \
+    -Dflys.backend.importer.skip.official.lines=$IMPORTER_SKIP_OFFICIAL_LINES \
+    -Dflys.backend.importer.skip.flood.water=$IMPORTER_SKIP_FLOOD_WATER \
+    -Dflys.backend.importer.skip.flood.protection=$IMPORTER_SKIP_FLOOD_PROTECTION \
+    -Dflys.backend.importer.skip.bed.height.single=$IMPORTER_SKIP_BED_HEIGHT_SINGLE \
+    -Dflys.backend.importer.skip.bed.height.epoch=$IMPORTER_SKIP_BED_HEIGHT_EPOCH \
+    -Dflys.backend.importer.skip.sediment.density=$IMPORTER_SKIP_SEDIMENT_DENSITY \
+    -Dflys.backend.importer.skip.morphological.width=$IMPORTER_SKIP_MORPHOLOGICAL_WIDTH \
+    -Dflys.backend.importer.skip.flow.velocity=$IMPORTER_SKIP_FLOW_VELOCITY \
+    -Dflys.backend.importer.skip.sediment.yield=$IMPORTER_SKIP_SEDIMENT_YIELD \
+    -Dflys.backend.importer.skip.waterlevels=$IMPORTER_SKIP_WATERLEVELS \
+    -Dflys.backend.importer.skip.waterlevel.differences=$IMPORTER_SKIP_WATERLEVEL_DIFFERENCES \
+    -Dflys.backend.importer.skip.sq.relation=$IMPORTER_SKIP_SQ_RELATION \
+    -Dflys.backend.user=$BACKEND_USER \
+    -Dflys.backend.password=$BACKEND_PASS \
+    -Dflys.backend.url=$BACKEND_URL \
+    -Dflys.backend.driver=$BACKEND_DB_DRIVER \
+    -Dflys.backend.dialect=$BACKEND_DB_DIALECT \
+     $APP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/axis.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,52 @@
+import ogr
+
+from importer import Importer
+import shpimporter
+
+NAME="Axis"
+TABLE_NAME="river_axes"
+PATH="Geodaesie/Flussachse+km"
+
+
+class Axis(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 2
+
+
+    def isShapeRelevant(self, name, path):
+        return name == "achse" or name.find("achse") >= 0
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat = ogr.Feature(featureDef)
+        newFeat.SetGeometry(feat.GetGeometryRef())
+        newFeat.SetField("name", args['name'])
+
+        if self.IsFieldSet(feat, "river_id"):
+            riverId = feat.GetField("river_id")
+        else:
+            riverId = self.river_id
+
+        if self.IsFieldSet(feat, "kind"):
+            kind = feat.GetField("kind")
+        else:
+            kind = 0
+
+        newFeat.SetField("river_id", riverId)
+        newFeat.SetField("kind", kind)
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/boundaries.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,91 @@
+import ogr
+
+from importer import Importer
+
+TABLE_NAME="hydr_boundaries"
+TABLE_NAME_POLY="hydr_boundaries_poly"
+PATH="Hydrologie/Hydr.Grenzen/Linien"
+NAME="Hydr. Boundaries"
+
+
+class HydrBoundary(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 2
+
+
+    def isShapeRelevant(self, name, path):
+        return True
+
+
+    def getKind(self, path):
+        if path.find("BfG") > 0:
+            return 1
+        else:
+            return 2
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        kind  = self.getKind(args['path'])
+
+        newFeat  = ogr.Feature(featureDef)
+        geometry = feat.GetGeometryRef()
+        geometry.SetCoordinateDimension(2)
+
+        newFeat.SetGeometry(geometry)
+        newFeat.SetField("name", args['name'])
+        newFeat.SetField("kind", kind)
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        return newFeat
+
+
+
+class HydrBoundaryPoly(HydrBoundary):
+
+    def getTablename(self):
+        return TABLE_NAME_POLY
+
+
+    def getName(self):
+        return "%s (Polygons)" % NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 3 or geomType == 6
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        kind  = self.getKind(args['path'])
+
+        newFeat  = ogr.Feature(featureDef)
+        geometry = feat.GetGeometryRef()
+        geometry.SetCoordinateDimension(2)
+
+        newFeat.SetGeometry(geometry)
+        newFeat.SetField("name", args['name'])
+        newFeat.SetField("kind", kind)
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/buildings.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,47 @@
+import ogr
+
+from importer import Importer
+
+TABLE_NAME="buildings"
+PATH="Geodaesie/Bauwerke"
+NAME="Buildings"
+
+
+class Building(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 2
+
+
+    def isShapeRelevant(self, name, path):
+        return True
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat = ogr.Feature(featureDef)
+        newFeat.SetGeometry(feat.GetGeometryRef())
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        if self.IsFieldSet(feat, "Name"):
+            newFeat.SetField("name", feat.GetField("Name"))
+        elif self.IsFieldSet(feat, "KWNAAM"):
+            newFeat.SetField("name", feat.GetField("KWNAAM"))
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/catchments.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,53 @@
+import ogr
+
+from importer import Importer
+
+TABLE_NAME="catchment"
+PATH="Hydrologie/Einzugsgebiet"
+NAME="Catchments"
+
+
+class Catchment(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 3 or geomType == 6
+
+
+    def isShapeRelevant(self, name, path):
+        return True
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat  = ogr.Feature(featureDef)
+        geometry = feat.GetGeometryRef()
+        geometry.SetCoordinateDimension(2)
+
+        newFeat.SetGeometry(geometry)
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        if self.IsFieldSet(feat, "Name"):
+            newFeat.SetField("name", feat.GetField("name"))
+        else:
+            newFeat.SetField("name", args['name'])
+
+        if self.IsFieldSet(feat, "AREA"):
+            newFeat.SetField("area", feat.GetField("area"))
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/crosssectiontracks.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,57 @@
+import ogr
+
+from importer import Importer
+
+TABLE_NAME="cross_section_tracks"
+PATH="Geodaesie/Querprofile"
+NAME="Crosssections"
+
+
+class CrosssectionTrack(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 2
+
+
+    def isShapeRelevant(self, name, path):
+        return True
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat = ogr.Feature(featureDef)
+        newFeat.SetGeometry(feat.GetGeometryRef())
+        newFeat.SetField("name", args['name'])
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        if self.IsFieldSet(feat, "KILOMETER"):
+            newFeat.SetField("km", feat.GetFieldAsDouble("KILOMETER"))
+        elif self.IsFieldSet(feat, "KM"):
+            newFeat.SetField("km", feat.GetFieldAsDouble("KM"))
+        elif self.IsFieldSet(feat, "STATION"):
+            newFeat.SetField("km", feat.GetFieldAsDouble("STATION"))
+        else:
+            return None
+
+        if self.IsFieldSet(feat, "ELEVATION"):
+            newFeat.SetField("z", feat.GetFieldAsDouble("ELEVATION"))
+        else:
+            newFeat.SetField("z", 0)
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/fixpoints.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,61 @@
+import ogr, osr
+
+from importer import Importer
+
+TABLE_NAME="fixpoints"
+PATH="Geodaesie/Festpunkte"
+NAME="Fixpoints"
+
+
+class Fixpoint(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 1
+
+
+    def isShapeRelevant(self, name, path):
+        return True
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat  = ogr.Feature(featureDef)
+        geometry = feat.GetGeometryRef()
+
+        newFeat.SetGeometry(geometry)
+        newFeat.SetField("name", args['name'])
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        if self.IsFieldSet(feat, "KM"):
+            newFeat.SetField("km", feat.GetFieldAsDouble("KM"))
+        elif self.IsFieldSet(feat, "ELBE_KM"):
+            newFeat.SetField("km", feat.GetFieldAsDouble("ELBE_KM"))
+        else:
+            return None
+
+        if self.IsFieldSet(feat, "X"):
+            newFeat.SetField("x", feat.GetFieldAsDouble("X"))
+
+        if self.IsFieldSet(feat, "Y"):
+            newFeat.SetField("y", feat.GetFieldAsDouble("Y"))
+
+        if self.IsFieldSet(feat, "HPGP"):
+            newFeat.SetField("HPGP", feat.GetField("HPGP"))
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/floodplains.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,45 @@
+import ogr
+
+from importer import Importer
+
+TABLE_NAME="floodplain"
+PATH="Hydrologie/Hydr.Grenzen"
+NAME="Floodplains"
+
+
+class Floodplain(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 3 or geomType == 6
+
+
+    def isShapeRelevant(self, name, path):
+        return name.find("talaue") >= 0
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat  = ogr.Feature(featureDef)
+        geometry = feat.GetGeometryRef()
+
+        newFeat.SetGeometry(geometry)
+        newFeat.SetField("name", args['name'])
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/gauges.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,52 @@
+import ogr
+
+from importer import Importer
+
+TABLE_NAME="gauge_location"
+PATH="Hydrologie/Streckendaten"
+NAME="Gauge locations"
+
+
+class GaugeLocation(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 1
+
+
+    def isShapeRelevant(self, name, path):
+        return True
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat  = ogr.Feature(featureDef)
+        geometry = feat.GetGeometryRef()
+        geometry.SetCoordinateDimension(2)
+
+        newFeat.SetGeometry(geometry)
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        if self.IsFieldSet(feat, "Name"):
+            newFeat.SetField("name", feat.GetField("name"))
+        elif self.IsFieldSet(feat, "MPNAAM"):
+            newFeat.SetField("name", feat.GetField("MPNAAM"))
+        else:
+            newFeat.SetField("name", args['name'])
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/hws.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,56 @@
+import ogr
+
+from importer import Importer
+
+TABLE_NAME="hws"
+PATH="Hydrologie/HW-Schutzanlagen"
+NAME="HWS"
+
+
+class HWS(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 2
+
+
+    def isShapeRelevant(self, name, path):
+        return True
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat  = ogr.Feature(featureDef)
+        geometry = feat.GetGeometryRef()
+        geometry.SetCoordinateDimension(2)
+
+        newFeat.SetGeometry(geometry)
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        if self.IsFieldSet(feat, "TYP"):
+            newFeat.SetField("type", feat.GetField("TYP"))
+
+        if self.IsFieldSet(feat, "Bauart"):
+            newFeat.SetField("hws_facility", feat.GetField("Bauart"))
+
+        if self.IsFieldSet(feat, "Name"):
+            newFeat.SetField("name", feat.GetField("name"))
+        else:
+            newFeat.SetField("name", args['name'])
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/importer.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,147 @@
+import ogr, osr
+import shpimporter
+
+class Importer:
+
+    def __init__(self, config):
+        self.config = config
+        self.dbconn   = 'OCI:%s/%s@%s' % (config.user, config.password, config.host)
+        self.river_id = config.river_id
+        self.dest_srs = osr.SpatialReference()
+        self.dest_srs.ImportFromEPSG(config.target_srs)
+
+
+    def getKind(self, path):
+        raise NotImplementedError("Importer.getKind is abstract!")
+
+
+    def getPath(self, base):
+        raise NotImplementedError("Importer.getPath is abstract!")
+
+
+    def getTablename(self):
+        raise NotImplementedError("Importer.getTablename is abstract!")
+
+
+    def getName(self):
+        raise NotImplementedError("Importer.getTablename is abstract!")
+
+
+    def IsFieldSet(self, feat, name):
+        try:
+            isset = feat.GetField(name)
+            return isset is not None
+        except:
+            return False
+
+
+    def IsDoubleFieldSet(self, feat, name):
+        try:
+            isset = feat.GetFieldAsDouble(name)
+            return isset is not None
+        except:
+            return False
+
+
+    def isShapeRelevant(self, name, path):
+        return True
+
+
+    def walkOverShapes(self, shape):
+        (name, path) = shape
+        if not self.isShapeRelevant(name, path):
+            shpimporter.INFO("Skip shapefile '%s'" % path)
+            return
+
+        shp = ogr.Open(shape[1])
+        if shp is None:
+            shpimporter.ERROR("Shapefile '%s' could not be opened!" % path)
+            return
+
+        shpimporter.INFO("Processing shapefile '%s'" % path)
+        srcLayer = shp.GetLayerByName(name)
+
+        if srcLayer is None:
+            shpimporter.ERROR("Layer '%s' was not found!" % name)
+            return
+
+        return self.shape2Database(srcLayer, name, path)
+
+
+    def transform(self, feat):
+        geometry = feat.GetGeometryRef()
+        src_srs  = geometry.GetSpatialReference()
+
+        if src_srs is None:
+            shpimporter.ERROR("No source SRS given! No transformation possible!")
+            return feat
+
+        transformer = osr.CoordinateTransformation(src_srs, self.dest_srs)
+        geometry.Transform(transformer)
+
+        return feat
+
+
+    def shape2Database(self, srcLayer, name, path):
+        table     = ogr.Open(self.dbconn)
+        destLayer = table.GetLayerByName(self.getTablename())
+
+        if srcLayer is None:
+            shpimporter.ERROR("Shapefile is None!")
+            return -1
+
+        if destLayer is None:
+            shpimporter.ERROR("No destination layer given!")
+            return -1
+
+        count = srcLayer.GetFeatureCount()
+        shpimporter.DEBUG("Try to add %i features to database." % count)
+
+        srcLayer.ResetReading()
+
+        geomType    = -1
+        success     = 0
+        unsupported = 0
+        creationFailed = 0
+        featureDef  = destLayer.GetLayerDefn()
+
+        for feat in srcLayer:
+            geom     = feat.GetGeometryRef()
+
+            if geom is None:
+                continue
+
+            geomType = geom.GetGeometryType()
+
+            if self.isGeometryValid(geomType):
+                newFeat = self.createNewFeature(featureDef,
+                                                feat,
+                                                name=name,
+                                                path=path)
+
+                if newFeat is not None:
+		    newFeat.SetField("path", path)
+                    newFeat = self.transform(newFeat)
+                    res = destLayer.CreateFeature(newFeat)
+                    if res is None or res > 0:
+                        shpimporter.ERROR("Unable to insert feature: %r" % res)
+                    else:
+                        success = success + 1
+                else:
+                    creationFailed = creationFailed + 1
+            else:
+                unsupported = unsupported + 1
+
+        shpimporter.INFO("Inserted %i features" % success)
+        shpimporter.INFO("Failed to create %i features" % creationFailed)
+        shpimporter.INFO("Found %i unsupported features" % unsupported)
+
+        try:
+            if self.config.dry_run > 0:
+                return geomType
+            destLayer.CommitTransaction()
+        except e:
+            shpimporter.ERROR("Exception while committing transaction.")
+
+        return geomType
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/km.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,50 @@
+import ogr
+
+from importer import Importer
+
+TABLE_NAME="river_axes_km"
+PATH="Geodaesie/Flussachse+km"
+NAME="KMS"
+
+
+class KM(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 1
+
+
+    def isShapeRelevant(self, name, path):
+        return name == "km"
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat = ogr.Feature(featureDef)
+        newFeat.SetGeometry(feat.GetGeometryRef())
+        newFeat.SetField("name", args['name'])
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        if self.IsDoubleFieldSet(feat, "km"):
+            newFeat.SetField("km", feat.GetFieldAsDouble("km"))
+        elif self.IsDoubleFieldSet(feat, "KM"):
+            newFeat.SetField("km", feat.GetFieldAsDouble("KM"))
+        else:
+            return None
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/lines.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,56 @@
+import ogr
+
+from importer import Importer
+
+TABLE_NAME="lines"
+PATH="Geodaesie/Linien"
+NAME="Lines"
+
+
+class Line(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        return geomType == 2 or geomType == -2147483646
+
+
+    def isShapeRelevant(self, name, path):
+        return True
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        newFeat  = ogr.Feature(featureDef)
+        geometry = feat.GetGeometryRef()
+        geometry.SetCoordinateDimension(2)
+
+        newFeat.SetGeometry(geometry)
+        newFeat.SetField("name", args['name'])
+
+        if self.IsFieldSet(feat, "river_id"):
+            newFeat.SetField("river_id", feat.GetField("river_id"))
+        else:
+            newFeat.SetField("river_id", self.river_id)
+
+        if self.IsFieldSet(feat, "TYP"):
+            newFeat.SetField("kind", feat.GetFieldAsDouble("TYP"))
+        else:
+            newFeat.SetField("kind", "DAMM")
+
+        if self.IsFieldSet(feat, "Z"):
+            newFeat.SetField("z", feat.GetFieldAsDouble("Z"))
+        else:
+            newFeat.SetField("z", 9999)
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/run.sh	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# Required
+RIVER_PATH="/path/to/rivers/river"
+RIVER_ID=1
+TARGET_SRS=31466
+HOST=localhost
+USER=the_user
+PASS=the_pass
+
+# Optional
+VERBOSE=1
+SKIP_AXIS=0
+SKIP_KMS=0
+SKIP_CROSSSECTIONS=0
+SKIP_LINES=0
+SKIP_FIXPOINTS=0
+SKIP_BUILDINGS=0
+SKIP_FLOODPLAINS=0
+SKIP_HYDR_BOUNDARIES=0
+SKIP_HWS=0
+SKIP_GAUGE_LOCATION=0
+SKIP_CATCHMENTS=0
+SKIP_UESG=0
+
+exec python shpimporter.py \
+    --directory $RIVER_PATH \
+    --river_id $RIVER_ID \
+    --target_srs $TARGET_SRS \
+    --host $HOST \
+    --user $USER \
+    --password $PASS \
+    --verbose $VERBOSE \
+    --skip_axis $SKIP_AXIS \
+    --skip_kms $SKIP_KMS \
+    --skip_crosssections $SKIP_CROSSSECTIONS \
+    --skip_lines $SKIP_LINES \
+    --skip_fixpoints $SKIP_FIXPOINTS \
+    --skip_buildings $SKIP_BUILDINGS \
+    --skip_floodplains $SKIP_FLOODPLAINS \
+    --skip_hydr_boundaries $SKIP_HYDR_BOUNDARIES \
+    --skip_hws $SKIP_HWS \
+    --skip_gauge_locations $SKIP_GAUGE_LOCATION \
+    --skip_catchments $SKIP_CATCHMENTS \
+    --skip_uesgs $SKIP_UESG
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/shpimporter.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,171 @@
+import ogr
+
+import utils, optparse
+
+from uesg  import UESG
+from axis  import Axis
+from km    import KM
+from lines import Line
+from fixpoints import Fixpoint
+from buildings import Building
+from crosssectiontracks import CrosssectionTrack
+from floodplains import Floodplain
+from boundaries import HydrBoundary, HydrBoundaryPoly
+from hws import HWS
+from gauges import GaugeLocation
+from catchments import Catchment
+
+
+VERBOSE_DEBUG=2
+VERBOSE_INFO=1
+
+
+def DEBUG(msg):
+    config = getConfig()
+    if config.verbose >= VERBOSE_DEBUG:
+        print "DEBUG: %s" % msg
+
+def INFO(msg):
+    config = getConfig()
+    if config.verbose >= VERBOSE_INFO:
+        print "INFO: %s" % msg
+
+def ERROR(msg):
+    config = getConfig()
+    print "ERROR: %s" % msg
+
+
+def getImporters(config):
+    return [
+        Axis(config),
+        KM(config),
+        CrosssectionTrack(config),
+        Line(config),
+        Fixpoint(config),
+        Building(config),
+        Floodplain(config),
+        HydrBoundary(config),
+        HydrBoundaryPoly(config),
+        HWS(config),
+        GaugeLocation(config),
+        Catchment(config),
+        UESG(config)
+        ]
+
+
+def getConfig():
+    parser = optparse.OptionParser()
+    parser.add_option("--directory", type="string")
+    parser.add_option("--target_srs", type="int")
+    parser.add_option("--host", type="string")
+    parser.add_option("--user", type="string")
+    parser.add_option("--password", type="string")
+    parser.add_option("--river_id", type="int")
+    parser.add_option("--verbose", type="int", default=1)
+    parser.add_option("--dry_run", type="int", default=0)
+    parser.add_option("--skip_axis", type="int")
+    parser.add_option("--skip_hydr_boundaries", type="int")
+    parser.add_option("--skip_buildings", type="int")
+    parser.add_option("--skip_crosssections", type="int")
+    parser.add_option("--skip_lines", type="int")
+    parser.add_option("--skip_fixpoints", type="int")
+    parser.add_option("--skip_floodplains", type="int")
+    parser.add_option("--skip_hws", type="int")
+    parser.add_option("--skip_gauge_locations", type="int")
+    parser.add_option("--skip_catchments", type="int")
+    parser.add_option("--skip_kms", type="int")
+    parser.add_option("--skip_uesgs", type="int")
+    (config, args) = parser.parse_args()
+
+    if config.directory == None:
+        ERROR("No river directory specified!")
+        raise Exception("Invalid config")
+    elif config.host == None:
+        ERROR("No database host specified!")
+        raise Exception("Invalid config")
+    elif config.user == None:
+        ERROR("No databaser user specified!")
+        raise Exception("Invalid config")
+    elif config.password == None:
+        ERROR("No password specified!")
+        raise Exception("Invalid config")
+    elif config.river_id == None:
+        ERROR("No river id specified!")
+        raise Exception("Invalid config")
+
+    return config
+
+
+def skip_importer(config, importer):
+    if config.skip_axis == 1 and isinstance(importer, Axis):
+        return True
+    elif config.skip_hydr_boundaries == 1 and isinstance(importer, HydrBoundary):
+        return True
+    elif config.skip_hydr_boundaries == 1 and isinstance(importer, HydrBoundaryPoly):
+        return True
+    elif config.skip_buildings == 1 and isinstance(importer, Building):
+        return True
+    elif config.skip_crosssections == 1 and isinstance(importer, CrosssectionTrack):
+        return True
+    elif config.skip_lines == 1 and isinstance(importer, Line):
+        return True
+    elif config.skip_fixpoints == 1 and isinstance(importer, Fixpoint):
+        return True
+    elif config.skip_floodplains == 1 and isinstance(importer, Floodplain):
+        return True
+    elif config.skip_hws == 1 and isinstance(importer, HWS):
+        return True
+    elif config.skip_gauge_locations == 1 and isinstance(importer, GaugeLocation):
+        return True
+    elif config.skip_catchments == 1 and isinstance(importer, Catchment):
+        return True
+    elif config.skip_kms == 1 and isinstance(importer, KM):
+        return True
+    elif config.skip_uesgs == 1 and isinstance(importer, UESG):
+        return True
+
+    return False
+
+
+def parse():
+    config=None
+    try:
+        config = getConfig()
+    except:
+        return
+
+    if config == None:
+        ERROR("Unable to read config from command line!")
+        return
+
+    if config.dry_run > 0:
+        INFO("You enable 'dry_run'. No database transaction will take place!")
+
+    importers = getImporters(config)
+    types = {}
+
+    for importer in importers:
+        if skip_importer(config, importer):
+            INFO("Skip import of '%s'" % importer.getName())
+            continue
+
+        INFO("Start import of '%s'" % importer.getName())
+
+        shapes = utils.findShapefiles(importer.getPath(config.directory))
+        DEBUG("Found %i Shapefiles" % len(shapes))
+
+        for shpTuple in shapes:
+            geomType = importer.walkOverShapes(shpTuple)
+            try:
+                if geomType is not None:
+                    num = types[geomType]
+                    types[geomType] = num+1
+            except:
+                types[geomType] = 1
+
+    for key in types:
+        DEBUG("%i x geometry type %s" % (types[key], key))
+
+
+if __name__ == '__main__':
+    parse()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/uesg.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,94 @@
+import ogr
+
+from importer import Importer
+
+
+TABLE_NAME="floodmaps"
+PATH="Hydrologie/UeSG/Berechnung"
+NAME="UESG"
+
+
+class UESG(Importer):
+
+    def getPath(self, base):
+        return "%s/%s" % (base, PATH)
+
+
+    def getTablename(self):
+        return TABLE_NAME
+
+
+    def getName(self):
+        return NAME
+
+
+    def isGeometryValid(self, geomType):
+        if geomType == 3 or geomType == 6:
+            return True
+        else:
+            return False
+
+
+    def getKind(self, path):
+        kind = 0
+        if path.find("Berechnung") > 0:
+            kind = kind + 100
+
+            if path.find("Aktuell") > 0:
+                kind = kind + 10
+            else:
+                kind = kind + 20
+
+            if path.find("Land") > 0:
+                kind = kind + 2
+            else:
+                kind = kind + 1
+        else:
+            kind = kind + 200
+
+        return kind
+
+
+    def createNewFeature(self, featureDef, feat, **args):
+        kind  = self.getKind(args['path'])
+
+        newFeat = ogr.Feature(featureDef)
+        newFeat.SetGeometry(feat.GetGeometryRef())
+
+        if self.IsFieldSet(feat, "river_id"):
+            riverId = feat.GetField(feat)
+        else:
+            riverId = self.river_id
+
+        if self.IsFieldSet(feat, "diff"):
+            diff = feat.GetFieldAsDouble("diff")
+        else:
+            diff = 0
+
+        if self.IsFieldSet(feat, "count"):
+            count = feat.GetFieldAsInteger("count")
+        else:
+            count = 0
+
+        if self.IsFieldSet(feat, "area"):
+            area = feat.GetFieldAsDouble("area")
+        else:
+            area = 0
+
+        if self.IsFieldSet(feat, "perimeter"):
+            perimeter = feat.GetFieldAsDouble("perimeter")
+        else:
+            perimeter = 0
+
+        groupId = 2
+
+        newFeat.SetField("river_id", riverId)
+        newFeat.SetField("diff", diff)
+        newFeat.SetField("count", count)
+        newFeat.SetField("area", area)
+        newFeat.SetField("perimeter", perimeter)
+        newFeat.SetField("kind", kind)
+        newFeat.SetField("name", args['name'])
+
+        return newFeat
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/contrib/shpimporter/utils.py	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,21 @@
+import os
+from shpimporter import DEBUG, INFO, ERROR
+
+SHP='.shp'
+
+def findShapefiles(path):
+    shapes = []
+
+    for root, dirs, files in os.walk(path):
+        if len(files) == 0:
+            continue
+
+        DEBUG("Processing directory '%s' with %i files " % (root, len(files)))
+
+        for f in files:
+            idx = f.find(SHP)
+            if (idx+len(SHP)) == len(f):
+                shapes.append((f.replace(SHP, ''), root + "/" + f))
+
+    return shapes
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/README.txt	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,527 @@
+FLYS3-Importer
+
+Der FLYS3-Importer dient dazu, hydrologische und morphologische
+Gewässerdaten aus dem Dateisystem in die FLYS3-Datenbank zu importieren.
+Das Werkzeug orientiert sich hierbei an der Dateihierachie,
+so wie sie auch von Desktop-FLYS ausgelesen wird.
+
+Als Startargument bekommt der Importer den Pfad zu einer
+GEW-Datei übergeben. 
+
+Wichtig für den Importer sind in dieser Datei
+die Zeilen, die mit "WSTDatei:" beginnen. In ihnen wird der 
+Pfad zu der zentralen WST-Datei des jeweiligen Gewässers angegeben.
+Alle anderen importierten Dateien werden in ihrer Lage relativ zur 
+Lage dieser Datei betrachtet.
+
+Das Verhalten des Importes kann mit sogenannten
+System-Properties gesteuert werden. Diese werden im
+Allgemeinen in der Form -Dkey=value angegeben.
+
+Will man z.B. mit dem Importer nur in simulierierten Import
+durchführen, dann kann dies über die Angabe von
+'-Dflys.backend.importer.dry.run=true' erfolgen.
+
+!!! Der Import geht wie Desktop-FLYS davon aus, dass die Dateien
+!!! Latin-1 encodiert vorliegen.
+
+Für den Importer stellt jeweils der Import eines Gewässers eine
+transaktionale Einheit dar. Wird der Import während eines Gewässers
+abgebrochen, werden alle Änderungen bzgl. dieses Gewässers zurück gerollt.
+
+Importierte Daten:
+
+Der Importer importiert folgende Datentypen:
+
+- Streckenfavoriten (*.km-Dateien)
+  Der Import kann mit '-Dflys.backend.importer.skip.annotations=true'
+  unterdrückt werden.
+
+  Zur Klassifikation von Streckenfavoriten kann mit
+  -Dflys.backend.importer.annotation.types=DATEI
+  der Pfad zu einer XML-Datei angegeben werden, in der über
+  Regeln festgelegt wird, wie diese geschehen soll.
+  Details hierzu im Anhang 'Klassifikation von Streckenfavoriten'.
+
+- Pegel, Stammdaten (*.glt, *.sta-Dateien):
+  Der Import kann mit '-Dflys.backend.importer.skip.gauges=true'
+  unterdrückt werden.
+  Die .glt-Datei, die neben der .wst-Datei liegt, wird zuerst
+  ausgelesen. Es werden nur *.sta-Datei von Pegeln geladen, die
+  in der .glt-Datei vermerkt sind.
+
+  Wenn "-Dflys.backend.sta.parse.gauge.numbers=true' wird versucht,
+  die offiziellen Pegelnummern aus den Stammdaten zu extrahieren.
+  !!! Dies ist mit Vorsicht zu behandeln, denn die meisten STA-Dateien
+  !!! Enthalten invalide Pegelnummern.
+
+  Die System-Property "flys.backend.main.value.types" kann einen
+  String mit gültigen Typen von Stammdaten enthalten. Vorbelegt
+  ist "QWTD". In der Praxis ist "QWD" eine sinnvolle Belegung.
+
+- Basis-Wasserstände (gewaesser.wst-Dateien):
+  Der Import kann mit '-Dflys.backend.importer.skip.wst=true'
+  unterdrückt werden.
+
+- Zusätzliche Längsschnitte (*.zus, *.wst-Dateien)
+  Der Import kann mit '-Dflys.backend.importer.skip.extra.wsts=true'
+  unterdrückt werden.
+  Es werden die *.zus- und *.wst-Dateien aus dem Verzeichnis
+  "../Zus.Längsschnitte" relativ zur gewaesser.wst-Datei betrachtet.
+
+- Fixierungen (*.wst-Dateien)
+  Der Import kann mit '-Dflys.backend.importer.skip.fixations=true'
+  unterdrückt werden.
+  Es werden die *.wst-Dateien aus dem Verzeichnis
+  "../Fixierungen" relativ zur gewaesser.wst-Datei betrachtet.
+
+- Amtliche Linien (*.wst-Dateien)
+  Der Import kann mit '-Dflys.backend.importer.skip.official.lines=true'
+  unterdrückt werden.
+  Es werden die "Amtl_Linien.wst"-Dateien aus dem Verzeichnis
+  "../Basisdaten" und "../Fixierungen" relativ zur gewaesser.wst-Datei betrachtet.
+
+- Profilspuren (*.prf-Dateien)
+  Der Import kann mit '-Dflys.backend.importer.skip.prfs=true'
+  unterdrückt werden.
+  Es werden rekursiv alle *.prf-Dateien aus "../../.." relativ
+  zur gewaesser.wst-Datei betrachtet. Vor dem Import werden
+  mithilfe eines Längen- und eines MD5-Summen-Vergleichs
+  inhaltliche Duplikate ausgeschlossen.
+
+- Hydraulische Kennzahlen (*.hyk)
+  Der Import kann mit '-Dflys.backend.importer.skip.hyks=true'
+  unterdrückt werden.
+  Es werden rekursiv alle *.hyk-Dateien aus "../../.." relativ
+  zur gewaesser.wst-Datei betrachtet. Vor dem Import werden
+  mithilfe eines Längen- und eines MD5-Summen-Vergleichs
+  inhaltliche Duplikate ausgeschlossen.
+
+- Hochwassermarken (*.zus, *.wst)
+  Der Import kann mit '-Dflys.backend.importer.skip.flood.water=true'
+  unterdrückt werden.
+  Es werden die *.zus- und *.wst-Dateien aus dem Verzeichnis
+  "../HW-Marken" relativ zur gewaesser.wst-Datei betrachtet.
+
+- Hochwasserschutzanlagen (*.zus)
+  Der Import kann mit '-Dflys.backend.importer.skip.flood.protection=true'
+  unterdrückt werden.
+  Es werden die *.zus- und *.wst-Dateien aus dem Verzeichnis
+  "../HW-Schutzanlagen" relativ zur gewaesser.wst-Datei betrachtet.
+
+  TODO INGO:
+
+  flys.backend.importer.skip.bed.height.single
+  flys.backend.importer.skip.bed.height.epoch
+  flys.backend.importer.skip.sediment.density
+  flys.backend.importer.skip.morphological.width
+  flys.backend.importer.skip.flow.velocity
+  flys.backend.importer.skip.sediment.yield
+  flys.backend.importer.skip.waterlevels
+  flys.backend.importer.skip.waterlevel.differences
+  flys.backend.importer.skip.sq.relation
+
+Für die Verbindung zur Datenbank ist es nötig, dem Import
+die Verbindungsdaten zu übergeben. Dies geschieht ebenfalls
+über System-Properties:
+
+  -Dflys.backend.user=NUTZER
+   Datenbanknutzer
+
+  -Dflys.backend.password=PASSWORT
+   Datenbankpasswort
+
+  -Dflys.backend.url=URL
+   URL zur Datenbank. Typische wäre im Fall einer Oracle-XE-Edition z.B.:
+   jdbc:oracle:thin:@//RECHNER:PORT/XE
+   mit RECHNER Name des Servers, auf dem die Datenbank läuft
+   und PORT der Port auf dem die Datenbank konkret zu erreichen ist.
+   Weitere Details unter http://www.orafaq.com/wiki/JDBC
+
+ -Dflys.backend.driver=TREIBER
+  mit TREIBER dem Namen des JDBC-Treibers, der es erlaubt
+  das Protokoll der Datenbank zu sprechen. Im Falle
+  einer Oracle XE wäre dies z.B.:
+  oracle.jdbc.OracleDriver
+
+ -Dflys.backend.dialect=DIALECT
+  mit DIALECT dem Hibernate-Dialekt, den die Datenbank versteht.
+  Im Falle eine Oracle-XE wäre dies z.B.:
+  org.hibernate.dialect.OracleDialect
+
+
+Hinweise zum Betrieb:
+---------------------
+
+    Der Speicherverbrauch des Importers ist sehr hoch. Es ist empfehlenswert,
+    der JVM mindestens 8GiB Hauptspeicher zuzuordnen: '-Xmx8192m'
+    Besonders speicherintensiv ist der Import der HYKs und der PRFs.
+    Hier ist es unter Umständen empfehlenswert, diese in zwei oder drei
+    Schritten zu importieren. Zuerst die sonstigen hydrologischen Daten
+    (hierbei mit flys.backend.importer.skip.hyks=true und flys.backend.importer.skip.prfs
+    den Import der HYKs und PRFs verhindern). Dann die HYKs (mit flys.backend.importer.skip.*
+    der anderen Daten) und im finalen Schritt dann die PRFs.
+
+Anhang 'Klassifikation von Streckenfavoriten'
+---------------------------------------------
+Streckenfavoriten werden aus KM-Dateien importiert. Um die einzelnen Einträge
+eine Kategorie (Brücken, Pegel, etc.) zuzuordnen, kann eine XML angegeben werden,
+in der Regeln für diese Klassifikation definiert werden. Schematisch gliedert
+sich diese Datei in die zwei Bereiche 'types' und 'patterns':
+
+<annotation>
+    <types> ...  </types>
+    <patterns> ...  </patterns>
+</annotation>
+
+In der Sektion 'types' werden die Kategorien vereinbart, in die
+klassifiziert werden sollen. Die geschieht mit einzelnen
+
+  <type name="Pegel"/>
+  <type name="Brücke"/>
+  ...
+  <type name="Sonstige" default="true"/>
+
+Das Attribut 'default' kann einmal vergeben werden und
+besagt, dass diese Kategorie gewählt werden soll, wenn
+keine andere Kategorie zugeordnet werden kann.
+
+In der Sektion 'patterns' werden dann die Regel
+definiert, die einzelne Einträge den definierten Kategorien
+zuordnet. Hierfür können zwei Arten von Definitionen
+angegeben werden:
+
+  <file pattern="^Brücken$" type="Brücke"/>
+
+oder
+
+  <line pattern="^Brücke[:\s].*$" type="Brücke"/>
+
+Die erste Variante bestimmt die Kategorie, die pro KM-Datei
+gelten soll. 'pattern' ist hierbei ein regulärer Ausdruck,
+der auf den Dateinamen angewandt wird. Passt der Name
+der Datei auf den regulären Ausdruck, wird 'type' als
+Vorgabe angenommen. Treffen mehrere <file>-Regeln zu,
+wird der erste Treffer angewandt. Findet keine der <file>-Regeln
+Anwendung, wird die Kategorie ausgewählt, die in der <types>-Section
+das Attribut 'default' gesetzt hat.
+
+Die zweite Regel-Variante <line> wird auf jeden Eintrag
+innerhalb einer KM-Datei auf den Bezeichner der Streckenfavoriten
+angewandt. Als Muster dient auch hier ein regulärer Ausdruck,
+der über das Attribut 'pattern' definiert wird. Die Kategorie
+wird in Trefferfall über das Attribut 'type' bestimmt. Treffen
+mehrere Regeln zu, wird die Kategorie gewählt, die zum ersten
+Treffer gehört. Trifft keine Regel zu wird der Eintrag der
+Kategorie zugeteilt, die für die beinhaltende Datei als Vorgabe
+gilt.
+
+Anhang 'Fehler und Warnungen':
+=============================
+
+Fehler:
+-------
+
+- 'error while parsing gew'
+  Die GEW-Datei ist fehlerhaft oder konnte nicht geöffnet werden.
+
+- 'File 'XYZ' is broken!'
+  Die Datei XYZ ist inkonsistent und führt zu Fehlern.
+
+- 'Error while parsing file for morph. width.'
+  Beim Lesen der morphologischen Breite trat ein Fehler auf.
+
+- 'Error while storing flow velocity model.'
+  Beim Schreiben eines Fliessgeschwindigkeitsmodells trat ein Fehler auf.
+
+- 'Error while storing flow velocity measurement.'
+  Beim Schreiben einer Fliessgeschwindigkeitsmessung trat ein Fehler auf. 
+
+- 'Error while storing sediment yield.'
+  Beim Schreiben einer Sedimentablagerung trat ein Fehler auf.
+
+- 'Error while storing waterlevel diff.'
+  Beim Schreiben einer Wassspiegeldifferenz trat ein Fehler auf.
+
+- 'Error while storing sq relation.'
+  Beim Schreiben einer S(Q) Beziehung trat ein Fehler auf.
+
+- 'Error reading PRF file.'
+  Beim Lesen einer PRF-Datei trat ein Fehler auf.
+
+- 'Error closing PRF file.'
+  Beim Schliessen einer PRF-Datei trat ein Fehler auf.
+
+- 'HYK 1: not enough elements in line #'
+- 'HYK 2: not enough elements in line #'
+- 'HYK 5: not enough elements in line #'
+- 'HYK 6: not enough elements in line #'
+  Eine Zeile in einer HYK-Datei hat nicht genügend Elemente.
+
+- 'HYK: parsing num zones, bottom or top height failed in line #'
+- 'HYK: HYK: number of flow zones mismatches in line #'
+  Die Anzahl der Zonen oder Daten über die Zonen sind nicht korrekt.
+
+- 'HYK: cannot parse number in line #'
+  Eine Zahl wurde erwartet.
+
+- 'HYK: Error reading file.'
+  Beim Lesen einer HYK-Datei trat ein Fehler auf.
+
+- 'HYK: Error closing file.'
+  Beim Schliessen einer HYK-Datei trat ein Fehler auf.
+
+Warnungen:
+----------
+
+- 'annotation type file 'XYZ' is not readable.'
+  Die Datein XYZ kann nicht gelesen werden.
+
+- 'cannot parse annotation types file.'
+  Während der Verarbeitung der Annotationsdatei ist Fehler aufgetreten.
+
+- 'Cannot read directory.'
+  verzeichnis konnte nicht gelesen werden.
+
+- 'no official lines wst file found'
+  Keine Datei mit amtlichen Linien gefunden.
+
+- 'cannot read fixations wst file directory'
+  Das Verzeichnis mit den Fixierungen kann nicht gelesen werden.
+
+- 'cannot read extra longitudinal wst file directory'
+  Das Verzeichnis mit den zusätzlichen Längsschnitten kann nicht gelesen werden.
+
+- 'cannot read gauges from 'XYZ''
+  Die Pegelgültigkeiten können nicht gelesen werden.
+
+- 'HYK file 'XYZ' seems to be a duplicate.'
+  Die HYK-Datei wurde unter anderem Namen aber gleichen Inhalts
+  bereits gefunden.
+
+- 'PRF file 'XYZ' seems to be a duplicate.'
+  Die PRF-Datei wurde unter anderem Namen aber gleichen Inhalts
+  bereits gefunden.
+
+- 'Skip invalid SedimentYield: time interval or unit null!'
+  Eine Sedimentablagerung ist ungültig und wurde ausgelassen.
+
+- 'skip flow velocity model: No discharge zone specified.'
+  Da kein Abflussbereich angegeben wurde, wurde das Fliessgeschwindigkeitsmodell ausgelassen.
+
+- 'skip invalid waterlevel - no unit set!'
+  Ein einheitenloser Wasserstand wurde ausgelassen.
+
+- 'Cannot parse time range.'
+  Das Zeitformat wurde nicht erkannt.
+
+- 'skip invalid data line #'
+  Ungültige Datenzeile wurde ausgelassen.
+
+- 'Error while parsing sq relation row #'
+  Eine Zeile in der S(Q)-Beziehung ist ungültig.
+
+- 'GLT: no gauge found in line #'
+  In der GLT-Datei wurde ein Pegel erwartet, aber nicht gefunden.
+
+- 'GLT: line # has not enough columns.'
+  Eine Zeile in der Pegelgültigkeitsdatei hat nicht genug spalten.
+
+- 'Error while parsing flow velocity values.'
+- 'skip invalid data line: #'
+  Invalide Datenzeile in einer Datei mit einer Fliessgeschwindigkeitsmessung.
+
+- 'skip invalid waterlevel line: #'
+- 'Error while parsing value: #'
+- 'Error while parsing station: #'
+  Invalide Datenzeile in einer Datei mit Wasserstandsdifferenzen.
+
+- 'skip invalid MainValue part: #'
+- 'skip invalid gauge part: #'
+- 'Error while parsing Q value: <Q>'
+- 'skip invalid data line: #'
+- 'Error while parsing flow velocity values.'
+  Invalide Datenzeile in einer Datei Fliessgeschwindigkeitsmodellen.
+
+- 'Error while parsing number from data row: #'
+  TODO INGO
+
+- 'Unknown meta line: #'
+- 'Error while parsing numbers in: #'
+- 'skip invalid data line: #'
+- 'Error while parsing numbers in #'
+  Invalide Datenzeile in einer Datei mit Sedimentdichten.
+
+- 'STA file is empty'
+- 'STA file has not enough lines'
+- 'STA file is too short'
+  Stammdatendatei ist leer oder hat zu wenige Zeilen.
+
+- 'First line in STA file is too short.'
+  Die erste Zeile der Stammdaten ist zu kurz.
+
+- 'STA: second line is too short'
+  Die zweite Zeile ist zu kurz.
+
+- 'STA: parsing of the datum of the gauge failed'
+
+- 'STA: 'XYZ' is not a valid long number.'
+  Die Pegelnummer ist invalide.
+
+- 'STA: Not enough columns for aeo and datum.
+  AEO und Pegelnullpunkt können nicht ermittelt werden.
+
+- 'STA: cannot parse aeo or datum.'
+  AEO oder Pegelnullpunkt sind invalide.
+
+- 'STA: value not parseable in line #'
+  Wert ist nicht als Zahl zu interpretieren.
+  
+- 'PRF: cannot open file <FILE>'
+  Die PRF kann nicht geöffnet werden.
+
+- PRF: file is empty
+- PRF: First line does not look like a PRF data pattern.
+- PRF: premature EOF. Expected integer in line 2
+- PRF: Expected <num> in line 2
+- PRF: invalid integer in line 2
+- PRF: premature EOF. Expected pattern for km extraction
+- PRF: line 4 does not look like a PRF km extraction pattern.
+- PRF: premature EOF. Expected skip row count.
+- PRF: line 5 is not an positive integer.
+- PRF: cannot extract km in line #
+  Das PRF-Format ist komplex. Hier sollten weitere Information
+  zur genaueren Analyse herangezogen werden.
+
+- 'cannot access WST file <FILE>'
+  Die WST-Datei konnte nicht gefunden werden.
+
+- 'Found an invalid row in the AT file.'
+  Eine Zeile in einer AT-Datei ist nicht korrekt.
+
+- 'AT: invalid number <XYZ>'
+  Eine Zahl wurde erwartet aber nicht gefunden.
+
+- 'Try to add Q range without waterlevel!'
+  Q-Bereich ohne Wasserstand gefunden.
+
+- 'Error while parsing Q range: #'
+  Invalider Q-Bereich
+
+- 'skip invalid waterlevel line: #'
+  Ungültige Wasserstandslinie
+
+- 'Error while parsing number values: #'
+  Ungültige Zahlenwerte.
+
+- 'ANN: not enough columns in line #'
+  Nicht genug Zeichenspalten in KM-Datei
+
+- 'ANN: invalid number in line #'
+  Ungültige Zahl.
+
+- 'ANN: cannot parse 'Unterkante' in line #'
+  Die Unterkante in einer KM-Datei konnte nicht gelesen werden.
+
+- 'ANN: cannot parse 'Unterkante' or 'Oberkante' in line #'
+  Unter- oder Oberkannte liegen in einem falschen Format vor.
+
+- 'ANN: duplicated annotation 'XYZ' in line #'
+  Ein Duplikat eines Streckenfavoriten wurde gefunden.
+
+- 'ANN: 'XYZ' is not a directory.'
+  Unterverzeichnis konnte nicht geöffnet werden.
+
+- 'ANN: cannot list directory 'XYZ''
+  Unterverzeichnis konnte nicht durchsucht werden.
+
+- 'BHP: Meta line did not match any known type: #'
+  Unbekannter Typ.
+
+- 'BHP: Error while parsing timeinterval!'
+  Ungültiges Zeitinterval.
+
+- 'BHP: Error while parsing year!'
+  Ungültige Jahresangabe.
+
+- 'BHP: Error while parsing sounding width!'
+  Unbekannte Peilungsbreite.
+
+- 'BHP: Error while parsing range!'
+  Bereichsangabe fehlerhaft.
+
+- 'MWP: Unknown meta line: #'
+  Meta-Informationen ungültig.
+
+- 'MWP: skip invalid data line: #'
+  Ungültige Datenzeile wurde übersprungen.
+
+- 'MWP: Error while parsing numbers in #'
+  Falsche Zahlenformat.
+
+- 'ANNCLASS: rule has no name'
+  Klassifizierungsregel für Streckenfavoriten hat keinen Namen.
+
+- 'ANNCLASS: pattern has no 'pattern' attribute.'
+  Klassifizierungsmuster für Streckenfavoriten hat kein Muster.
+
+- 'ANNCLASS: pattern has unknown type 'XYZ''
+  Klassifizierungsmuster für Streckenfavoriten konnte keinem Typ zugeordnet werden.
+
+- 'ANNCLASS: pattern 'XYZ' is invalid.'
+  Klassifizierungsmuster für Streckenfavoriten ist ungültig.
+
+- 'BSP: Error while parsing data row.'
+  Ungültige Datenzeile.
+
+- 'SYP: Unknown meta line: #'
+  Ungültige Metadatenzeile.
+
+- 'SYP: skip invalid data line #'
+  Ungültige Datenzeile wurde übersprungen.
+
+- 'SYP: Error while parsing numbers in #'
+  Ungültige Zahlenformatierung.
+
+- 'SYP: Unknown time interval string <XYZ>'
+  Falsches Datumformat.
+
+- 'SYP: Error while parsing years <XYZ>'
+  Falsches Jahreszahlformat.
+ 
+- 'SYP: Error while parsing ranges of <XYZ>'
+  Bereichsangaben fehlerhaft.
+
+- 'SYP: Unknown grain fraction <XYZ>'
+  Unbekannte Kornfraktion.
+
+- 'WST: invalid number.'
+  Ungültige Zahl.
+
+- 'WST: km <km> (<Zeile>) found more than once. -> ignored.'
+  Ein Kilometer ist doppelt in einer WST-Datei enthalten.
+
+- 'HYK: zone coordinates swapped in line #'
+  Fliesszonenkordinaten wurden in umgekehrter Reihenfolge angeben.
+
+- 'BHS: Skip invalid file 'XYZ''
+  Die Inhalte der Datei sind ungültig.
+
+- 'ISQ: Unable to store sq relation value.'
+  S(Q) Beziehung konnte nicht gespeichert werden.
+
+- 'ISQ: Cannot determine sq relation without time interval.'
+  Einer S(Q)-Beziehung ist keine zeitliche Gültigkeit zugeordnet.
+
+- 'IWD: skip invalid waterlevel difference - no unit set!'
+  Wasserstandsdifferenz hat keine Einheit.
+
+- 'BHE: Skip file - invalid current elevation model.'
+  Höhenmodell ungültig.
+
+- 'BHE: Skip file - invalid time range.'
+  Zeitbereich ungültig.
+
+- 'BHE: Skip file - invalid km range.'
+  Kilometerbereich ungültig.
+  
--- a/flys-backend/doc/annotation-types.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/doc/annotation-types.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -47,6 +47,7 @@
         <line pattern="^Landkreis[:\s].*$" type="Landkreis"/>
         <line pattern="^Meldestelle[:\s].*$" type="Meldestelle"/>
         <line pattern="^Messstelle[:\s].*$" type="Messstelle"/>
+        <line pattern="^Geschiebemessstelle[:\s].*$" type="Messstelle"/>
         <line pattern="^Pegel[:\s].*$" type="Pegel"/>
         <line pattern="^Staatsgrenze[:\s].*$" type="Staatsgrenze"/>
         <line pattern="^Staat[:\s].*$" type="Staat"/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/documentation/de/Makefile	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,3492 @@
+# Copyright 2004 Chris Monson (shiblon@gmail.com)
+# Latest version available at http://www.bouncingchairs.net/oss
+#
+#    This file is part of ``Chris Monson's Free Software''.
+#
+#    ``Chris Monson's Free Software'' is free software; you can redistribute it
+#    and/or modify it under the terms of the GNU General Public License as
+#    published by the Free Software Foundation, Version 2.
+#
+#    ``Chris Monson's Free Software'' is distributed in the hope that it will
+#    be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+#    Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License along
+#    with ``Chris Monson's Free Software''; if not, write to the Free Software
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+#    It is also available on the web at http://www.gnu.org/copyleft/gpl.html
+#
+#    Note that using this makefile to build your documents does NOT place them
+#    under the GPL unless you, the author, specifically do so.  In other words,
+#    I, Chris Monson, the copyright holder and author of this makefile,
+#    consider it impossible to ``link'' to this makefile in any way covered by
+#    the GPL.
+#
+# TO OBTAIN INSTRUCTIONS FOR USING THIS FILE, RUN:
+#    make help
+#
+fileinfo	:= LaTeX Makefile
+author		:= Chris Monson
+version		:= 2.2.0-rc1
+#
+# Note that the user-global version is imported *after* the source directory,
+# so that you can use stuff like ?= to get proper override behavior.
+.PHONY: Makefile GNUmakefile Makefile.ini $(HOME)/.latex-makefile/Makefile.ini
+-include Makefile.ini
+-include $(HOME)/.latex-makefile/Makefile.ini
+#
+# This can be pdflatex or latex - you can change this by adding the following line to your Makefile.ini:
+# BUILD_STRATEGY := latex
+BUILD_STRATEGY		?= pdflatex
+#
+# Sets LC_ALL=C, by default, so that the locale-aware tools, like sort, be
+# # immune to changes to the locale in the user environment.
+export LC_ALL		?= C
+#
+#
+# If you specify sources here, all other files with the same suffix
+# will be treated as if they were _include_ files.
+#onlysources.tex	?= main.tex
+#onlysources.tex.sh	?=
+#onlysources.tex.pl	?=
+#onlysources.tex.py	?=
+#onlysources.rst	?=
+#onlysources.fig	?=
+#onlysources.gpi	?=
+#onlysources.dot	?=
+#onlysources.xvg	?=
+#onlysources.svg	?=
+#onlysources.eps.gz	?=
+#onlysources.eps	?=
+#
+# If you list files here, they will be treated as _include_ files
+#includes.tex		?= file1.tex file2.tex
+#includes.tex.sh	?=
+#includes.tex.pl	?=
+#includes.tex.py	?=
+#includes.rst		?=
+#includes.fig		?=
+#includes.gpi		?=
+#includes.dot		?=
+#includes.xvg		?=
+#includes.svg		?=
+#includes.eps.gz	?=
+#includes.eps		?=
+#
+# If you list files or wildcards here, they will *not* be cleaned - default is
+# to allow everything to be cleaned.
+#neverclean		?= *.pdf
+#
+# Alternatively (recommended), you can add those lines to a Makefile.ini file
+# and it will get picked up automatically without your having to edit this
+# Makefile.
+#
+# KNOWN ISSUES:
+#	* The following occurs:
+#		file with: \usepackage{named}\bibliographystyle{named}
+#		Compile
+#		change to: \usepackage{apalike}\bibliographystyle{apalike}
+#		Compile again -- BARF!
+#
+#		The workaround: make clean-nographics; make
+#
+#		Note that we may not be able to fix this.  LaTeX itself barfs
+#		on this, not the makefile.  The very first invocation of LaTeX
+#		(when something like this has happened) reads the existing .aux
+#		file and discovers invalid commands like \citeauthoryear that
+#		are only valid in the package that was just removed.  It then
+#		tries to parse them and explodes.  It's not at all clear to me
+#		how to fix this.  I tried removing the .aux files on the first
+#		run of LaTeX, but that necessarily requires more subsequent
+#		rebuilds on common edits.  There does not appear to be a
+#		graceful solution to this issue.
+#
+# CHANGES:
+# Chris Monson (2010-04-08):
+# 	* Bumped version to 2.2.0-rc1
+# 	* Added back in the rst_style_file stuff that got broken when switching
+# 		rst -> tex to use the script mechanism
+# Chris Monson (2010-03-23):
+#	* Bumped version to 2.2.0-beta8
+#	* Work on issue 76: bad backtick escape for some sed versions, failure
+#		to clear out the hold buffer when outputting MISSING comment.
+#		- Backed out 2>&1 to &> (doesn't work in sh)
+#		- Backed out using . to source variables
+# Chris Monson (2010-03-22):
+# 	* Bumped version to 2.2.0-beta7
+# 	* Issue 72: Fix latex/bibtex invocation order for annotated bib styles
+# 	* Fixed informational output to reflect which LaTeX run we're on
+# 	* Fixed graphic detection to include graphics that are already there in
+# 		.d files
+# 	* Tightened up the .d file output to only make .d depend on graphic
+# 		*source* files.  This means that building foo.d no longer
+# 		builds all of the graphics files on which foo.tex depends.
+# 		Had to use .SECONDEXPANSION trickery to make it work.
+# 	* Changed get-graphics to only accept a stem.
+# 	* Fixed build-once logic for scripted .tex to work better
+# 	* Made get-inputs sed script more maintainable.
+# 	* Moved Makefile.ini import up higher.
+# 	* Changed bare stems to not recursively invoke make
+# 	* Updated diff output to be more silent everywhere
+# 	* Added a MISSING comment to the .d file if stuff isn't found - forces
+# 		removal of .1st.make file, which often forces it to try again.
+# 	* Fixed broken graphics-target function
+# 	* Added sleep to .d file generation when stuff is missing - if it
+# 		builds too fast, make doesn't realize it needs to be reloaded,
+# 		and thus never discovers some deeper dependencies (especially
+# 		evident when graphics are included from scripted include
+# 		files).
+# Chris Monson (2010-03-17):
+# 	* Bumped version to 2.2.0-beta6
+# 	* Fixed bareword builds to actually work (requires static patterns)
+# 	* Fixed colorization to work with new paragraph stuff
+# Chris Monson (2010-03-17):
+# 	* Bumped version to 2.2.0-beta5
+# 	* Fixed graphic detection to be much more focused - splits log file
+# 		into paragraphs before doing pattern matching.
+# 	* Fixed make foo to work properly (recursively calls make foo.pdf)
+# 	* Fixed gpi -> pdf generation to not waste time building .eps *after*
+# 		the pdf already exists.
+# 	* Changed log copies to include MAKE_RESTARTS as part of the name.
+# 	* Fixed missing include file detection (also makes use of the paragraph
+# 		stuff) to detect missing scripted include files.
+# Chris Monson (2010-03-16):
+# 	* Bumped version to 2.2.0-beta4
+# 	* issue 70: .pdf not moved out of the way properly on first
+# 		compilation, resulting in early error detection failure.
+# 	* issue 74: fixed broken error on missing .aux files: the
+# 		implementation was masking real errors.
+# Chris Monson (2010-03-15):
+# 	* Bumped version to 2.2.0-beta3
+# 	* issue 71: Made the tput dependency optional
+# 	* issue 73: Made .tex targets not pull in .d files (building them from
+# 		scripts should not require a .d)
+# 	* issue 74: Output a much saner error when a .aux file is not produced
+# 		(e.g., when you are typing "make" without arguments in a
+# 		directory with included .tex files that are not named with
+# 		._include_.)
+# Chris Monson (2010-03-11):
+# 	* Bumped version to 2.2.0-beta2
+# 	* Fixed clean-graphics to get rid of intermediate .eps files that may
+# 		be hanging around
+# 	* Added an automatic setting to use eps terminals in pdflatex mode for
+# 		gnuplot if it doesn't understand pdf.
+# 	* issue 66: Removed grayscale generation via magic suffix.  Grayscale
+# 		generation is now only available via GRAY=1
+# 	* issue 68: Added explicit handling of LC_ALL for locale-aware tools
+# 		like "sort"
+# Chris Monson (2010-03-10):
+# 	* Bumped version to 2.2.0-beta1
+# 	* Fixed success message to handle output message in different places
+# 	* Added name of produced file to success message
+# Chris Monson (2010-03-10):
+# 	* Bumped version to 2.2.0-alpha3
+# 	* Added meaningful error message for wrong hyperref options
+# 	* Added meaningful error message for incorrect graphics extensions
+# Chris Monson (2010-03-09):
+# 	* Bumped version to 2.2.0-alpha2
+# 	* Updated graphics handling (gnuplot and fig generate pdf natively)
+# 	* Changed xmgrace to output monochrome natively
+# Chris Monson (2010-03-09):
+# 	* Bumped version to 2.2.0-alpha1 - major change!
+# 	* Support pdflatex natively and by default (issue 6 - a long time coming)
+# 	* Add ability to have a single $HOME/.latex-makefile/Makefile.ini for
+# 		all invocations
+# 	* Reworked graphic inclusion detection so that extensions need not be
+# 		specified for either build strategy (e.g.,
+# 		\includegraphics{test1.eps} -> \includegrahpics{test1})
+# 	* Changed log format to include filenames and line numbers
+# Chris Monson (2010-02-04):
+# 	* Bumped version to 2.1.43
+# 	* All of the following are for issue 63 (thanks to mojoh81):
+# 	* Added documentation about fixing Makefile.ini default target
+# 	* Added perl and python script targets
+# 	* Fixed run logic to allow included .tex files to be scripted (the
+# 		run-again logic now detects missing .tex files, and the MV
+# 		command has been switched out for a command that only invokes
+# 		MV if the files exist)
+# 	* Changed scripted generation to only run once per make invocation
+# 	* Added dependency on expr
+# Chris Monson (2010-01-19):
+# 	* Bumped version to 2.1.42
+# 	* issue 62: Added .brf extension to cleanable files (backrefs)
+# Chris Monson (2010-01-07):
+# 	* Bumped version to 2.1.41
+# 	* issue 60: bad makeindex runs now error out on subsequent tries
+# Chris Monson (2009-12-01):
+# 	* Bumped version to 2.1.40
+# 	* issue 36: build all indices (for e.g., splitidx usage)
+# 	* issue 59: clean up all generated files (including indices)
+# Chris Monson (2009-11-23):
+# 	* Bumped version to 2.1.39
+# 	* issue 57: change ps2pdf invocations to just use gs directly
+# Chris Monson (2009-11-19):
+# 	* Bumped version to 2.1.38
+# 	* issue 57: Added some limited support for Cygwin (spaces in filenames)
+# Chris Monson (2009-11-15):
+# 	* Bumped version to 2.1.37
+# 	* Removed svninfo, since this is now managed by mercurial
+# 	* Fixed typo in changelist
+# 	* Issue 52: added jpg->eps conversion (thanks to brubakee)
+# 	* Issue 54: fix missing Overfull colorization due to lack of a blank
+# 		line preceding the first error.
+#	* Issue 51: remove head.tmp and body.tmp in make clean invocation
+#	* Issue 56: maintain multiple versions of log files (for debugging)
+# Chris Monson (2009-11-14):
+# 	* Bumped version to 2.1.36
+# 	* Issues 53 and 49: added .brf, .mtc, and .maf to the cleanables
+# Chris Monson (2009-11-05):
+# 	* Bumped version to 2.1.35
+# 	* Added nomenclature support (see issue 48)
+# Chris Monson (2009-10-29):
+# 	* Bumped version to 2.1.34
+# 	* Fixed _out_ creation bug introduced in 2.1.33 (it was always created)
+# 	* Fixed erroneous help output for $HOME in BINARY_TARGET_DIR
+# 	* Changed contact email address - bring on the spam!
+# Chris Monson (2009-10-21):
+# 	* Bumped version to 2.1.33
+# 	* Fixed issue 46, adding support for dot2tex (thanks to fdemesmay)
+# 	* Made all_files.* settable in Makefile.ini (using ?= instead of :=)
+# 	* Fixed issue 47, thanks to fdemesmay: add binary copy directory, copy
+# 		dvi, pdf, and ps if it exists
+# Chris Monson (2009-09-25):
+# 	* Bumped version to 2.1.32
+# 	* Fixed so that a changed lol file will cause a rebuild
+# 	* Added .lol files to the cleanable list
+# Chris Monson (2009-09-08):
+# 	* Bumped version to 2.1.31
+# 	* Closed issue 43: evince doesn't notice pdf change w/out touch
+# Chris Monson (2009-08-28):
+# 	* Bumped version to 2.1.30
+# 	* Closed issue 39: Capture multi-line log warnings/errors to output
+# Chris Monson (2009-08-26):
+# 	* Bumped version to 2.1.29
+# 	* Closed issue 42: add svg support using inkscape
+# Chris Monson (2009-08-17):
+# 	* Bumped version to 2.1.28
+# 	* Patch from paul.biggar for issue 38: package warnings are overlooked
+# Chris Monson (2009-08-07):
+# 	* Bumped version to 2.1.27
+# 	* Included patch for issue 37 - removes pdf/ps files before copying,
+# 		allowing some broken viewers to see changes properly.
+# Chris Monson (2009-05-15):
+# 	* Bumped version to 2.1.26
+# 	* Included patch for issue 9 from favonia - detects .fig changes for
+# 		pstex files during regular compilation, so long as the pstex
+# 		has been built at least once with make all-pstex.
+# Chris Monson (2009-03-27):
+# 	* Bumped version to 2.1.25
+# 	* Cleaned up a bunch of variable setting stuff - more stuff is now
+# 		settable from Makefile.ini
+# 	* Cleaned up documentation for various features, especially settable
+# 		variables.
+# 	* issue 28: support for png -> eps conversion (it even looks good!)
+# 	* issue 29: support for "neverclean" files in Makefile.ini
+# 	* issue 30: make ps2pdf14 the default - fall back when not there
+# Chris Monson (2009-03-09):
+# 	* Bumped version to 2.1.24
+# 	* issue 27: xmgrace support (thanks to rolandschulzhd)
+# Chris Monson (2008-10-23):
+# 	* Bumped version to 2.1.23
+# 	* issue 23: fixed _check_programs to not use bash string subs
+# Chris Monson (2008-09-02):
+# 	* Bumped version to 2.1.22
+# 	* Appled patch from Holger <yllohy@googlemail.com> to add include
+# 		sources and some documentation updates.
+# 	* Updated backup_patterns to be a bit more aggressive (also thanks to
+# 		Holger)
+# Chris Monson (2008-08-30):
+# 	* Bumped version to 2.1.21
+# 	* Added ability to specify onlysources.* variables to indicate the only
+# 		files that should *not* be considered includes.  Thanks to Holger
+# 		<yllohy@googlemail.com> for this patch.
+# 	* Added an automatic include of Makefile.ini if it exists.  Allows
+# 		settings to be made outside of this makefile.
+# Chris Monson (2008-05-21):
+# 	* Bumped version to 2.1.20
+# 	* Added manual pstex compilation support (run make all-pstex first)
+# 	* Removed all automatic pstex support.  It was totally breaking
+# 		everything and is very hard to incorporate into the makefile
+# 		concept because it requires LaTeX to *fail* before it can
+# 		determine that it needs the files.
+# Chris Monson (2008-04-17):
+# 	* Bumped version to 2.1.19
+# 	* Changed the pstex build hack to be on by default
+# Chris Monson (2008-04-09):
+# 	* Bumped version to 2.1.18
+# 	* issue 16: fixed pstex build problems, seems nondeterministic.  Added
+# 		gratuitious hack for testing: set PSTEX_BUILD_ALL_HACK=1.
+# Chris Monson (2008-04-09):
+# 	* Bumped version to 2.1.17
+# 	* issue 20: fixed accumulation of <pid>*.make files - wildcard was
+#		refusing to work on files that are very recently created.
+# Chris Monson (2008-04-02):
+# 	* Bumped version to 2.1.16
+# 	* issue 19: Removed the use of "type" to fix broken "echo" settings
+# Chris Monson (2008-03-27):
+# 	* Bumped version to 2.1.15
+# 	* issue 18: Favors binary echo over builtin, as binary understands -n
+# 	* issue 16: Fixed handling of missing pstex_t files in the log
+# 	* issue 9: Added .SECONDARY target for .pstex files
+# Chris Monson (2008-03-21):
+# 	* Bumped version to 2.1.14
+# 	* Fixed broken aux file flattening, which caused included bibs to be
+# 		missed.
+# Chris Monson (2008-03-20):
+# 	* Bumped version to 2.1.13
+# 	* Changed error output colorization to show errors for missing files
+# 		that are not graphics files.
+# Chris Monson (2008-03-20):
+# 	* Bumped version to 2.1.12
+# 	* Fixed a regression introduced in r28 that makes bibtex fail when
+# 		there is no index file present
+# Chris Monson (2008-03-03):
+# 	* Bumped version to 2.1.11
+# 	* Fixed issue 11 (handle index files, reported by abachn)
+# 	* Cleaned up some comments and help text
+# Chris Monson (2008-01-24):
+# 	* Bumped version to 2.1.10
+#	* Fixed to work when 'sh' is a POSIX shell like 'dash'
+# Chris Monson (2007-12-12):
+# 	* Bumped version to 2.1.9
+# 	* Fixed documentation and dependency graph for pstex files
+# Chris Monson (2007-12-12):
+# 	* Bumped version to 2.1.8
+# 	* Added basic pstex_t support for fig files (Issue 9 by favonia)
+# 		I still suggest that psfrag be used instead.
+# Chris Monson (2007-10-16):
+# 	* Bumped version to 2.1.7
+# 	* Removed todo item: allow other comment directives for rst conversion
+# 	* Added ability to use global rst style file _rststyle_._include_.tex
+# 	* Added help text to that effect
+# Chris Monson (2007-05-20):
+# 	* Bumped version to 2.1.6
+# 	* Changed default paper size for rst files
+# 	* Added todo item: fix paper size for rst files
+# 	* Added todo item: allow other comment directives for rst conversion
+# Chris Monson (2007-04-02):
+# 	* Bumped version to 2.1.5
+# 	* Addressed Issue 7, incorrect .gpi.d generation in subdirectories
+# Chris Monson (2007-03-28):
+# 	* Bumped version to 2.1.4
+# 	* Fixed syntax error in dot output
+# Chris Monson (2007-03-01):
+# 	* Bumped version to 2.1.3
+# 	* Added reST to the included documentation
+# 	* Fixed graphics and script generation to be settable in the
+# 		environment.
+# Chris Monson (2007-02-23):
+# 	* Bumped version to 2.1.2
+# 	* Added the ability to generate .tex files from .rst files
+# Chris Monson (2006-10-17):
+# 	* Bumped version to 2.1.1
+# 	* Fixed includes from subdirectories (sed-to-sed slash escape problem)
+# Chris Monson (2006-10-05):
+# 	* Bumped version to 2.1.0 (pretty serious new feature added)
+# 	* New feature: bib files can now be anywhere on the BIBINPUTS path
+# 	* New programs: kpsewhich (with tetex) and xargs (BSD)
+# Chris Monson (2006-09-28):
+# 	* Bumped version to 2.0.9
+# 	* Added ability to parse more than one bibliography
+# Chris Monson (2006-06-01):
+# 	* Bumped version to 2.0.8
+# 	* Added .vrb to the list of cleaned files
+# Chris Monson (2006-04-26):
+# 	* Bumped version to 2.0.7
+# 	* Fixed so that clean-nographics does not remove .gpi.d files
+# 	* Removed jpg -> eps hack (not working properly -- just pre-convert)
+# 	* Fixed so that postscript grayscale can be done with BSD sed
+# Chris Monson (2006-04-25):
+# 	* Bumped version to 2.0.6
+# 	* Fixed so that changed toc, lot, lof, or out causes a rebuild
+# Chris Monson (2006-04-17):
+# 	* Bumped version to 2.0.5
+# 	* Added jpg -> eps conversion target
+# Chris Monson (2006-04-12):
+# 	* Bumped version to 2.0.4
+# 	* Fixed BSD sed invocation to not use \| as a branch delimiter
+# 	* Added a comment section on what is and is not allowed in BSD sed
+# 	* Made paper size handling more robust while I was at it
+# 	* Fixed postscript RGB grayscale to use a weighted average
+# 	* Fixed postscript HSB grayscale to convert to RGB first
+# 	* Fixed a problem with rebuilding .bbl files
+# Chris Monson (2006-04-11):
+# 	* Bumped version to 2.0.3
+# 	* Fixed some BSD sed problems: can't use \n in substitutions
+# Chris Monson (2006-04-10):
+# 	* Bumped version to 2.0.2
+# 	* Once again removed ability to create .tex files from scripts
+# 	* \includeonly works again
+# Chris Monson (2006-04-09):
+# 	* Bumped version to 2.0.1
+# 	* Fixed grayscale postscript handling to be more robust
+# 	* Added ability to generate ._gray_. files from eps and eps.gz
+# 	* Added ability to clean ._gray_.eps files created from .eps files
+# Chris Monson (2006-04-07):
+# 	* Bumped version to 2.0.0
+# 	* Removed clunky ability to create included .tex files from scripts
+# 	* Added note in the help about included tex scripting not working
+# 	* Fixed the .eps generation to delete %.gpihead.make when finished
+# 	* Abandoned designs to use shell variables to create sed scripts
+# 	* Abandoned __default__.tex.sh idea: it causes recursion with %: .
+# 	* Removed web page to-do.  All items are now complete.
+# 	* Added better grayscale conversion for dot figures (direct ps fixup).
+# 	* Include files can now be scripted (at the expense of \includeonly).
+# 	* Updated dependency graph to contain better node names.
+# Chris Monson (2006-04-06):
+# 	* Bumped version to 2.0b3
+# 	* Top level includes now fail if there is no rule to build them
+# 	* A helpful message is printed when they do fail
+# 	* Grayscale has been changed to be ._gray_, other phonies use _ now, too
+# 	* Grayscale handling has been completed
+# 	* Changed _include_stems target to _includes target.
+# 	* Fixed _includes target to be useful by itself.
+# 	* Removed the ability to specify clean and build targets at once
+# 	* Verified that epsfig works fine with current code
+# 	* Fixed included scripts so that they are added to the dep files
+# 	* Fixed so that graphics includes don't happen if they aren't for gpi
+# 	* Fixed dot output to allow grayscale.
+# Chris Monson (2006-04-05):
+#	* Bumped version to 2.0b2
+#	* Removed automatic -gray output.  It needs fixing in a bad way.
+#	* Revamped dependency creation completely.
+#	* Fixed conditional inclusion to actually work (test.nobuild.d, test.d).
+#	* Fixed clean target to remove log targets
+#	* Added the 'monochrome' word for gray gpi output
+#	* Added a _check_gpi_files target that checks for common problems
+#	* Changed the _version target into the version target (no _)
+#	* Added better handling of grayscale files.  Use the .gray.pdf target.
+#	* Fixed testing for rebuilds
+# Chris Monson (2006-04-04):
+#	* Bumped version to 2.0b1
+#	* Changed colorization of output
+#	* Made .auxbbl and .auxtex .make files secondary targets
+#	* Shortened and simplified the final latex invocation loop
+#	* Added version-specific output ($$i vs. $$$$i) in latex loop
+#	* Added a build message for the first .dvi run (Building .dvi (0))
+#	* Removed some build messages that most people don't care about.
+#	* Simplified procedure for user-set colors -- simple text specification
+#	* Fixed diff output to...not output.
+#	* Fixed rerun bug -- detect not only when preceded with LaTeX Warning
+#	* Sped up gpi plotting
+#	* Added error handling and colorized output for gpi failure
+#	* Documented color changing stuff.
+#	* Now sort the flattened aux file to avoid false recompilation needs
+#	* Added clean-nographics target
+#	* Don't remove self.dvi file if self.aux is missing in the log
+#	* Clarified some code.  Did some very minor adjusting.
+# Chris Monson (2006-04-03):
+#	* Bumped version to 2.0a7
+#	* Added .dvi and .ps files as secondary files.
+#	* Fixed handling of multiple run detection when includeonly is in use.
+#	* Added code to flatten .aux files.
+#	* Added more files as .SECONDARY prerequisites to avoid recompilation.
+#	* Fixed the inputs generation to be much simpler and to use pipes.
+#	* Added the dependency graph directly into the makefile.
+#	* Changed flatten-aux to remove \@writefile \relax \newlabel, etc.
+#	* Undid pipe changes with sed usage (BSD sed doesn't know -f-).
+#	* Added a _check_programs target that tells you what your system has.
+#	* Fixed an error in colorization that made unnecessary errors appear
+#	* Added view targets.
+#	* Updated help text.
+#	* Augmented cookies so that .aux can trigger .bbl and .dvi rebuilds
+#	* Added more informative error handling for dvips and ps2pdf
+# Chris Monson (2006-04-02):
+#	* Bumped version to 2.0a6
+#	* Added indirection to .bbl dependencies to avoid rebuilding .bbl files
+#	* Streamlined the diff invocation to eliminate an existence test
+#	* Removed special shell quote escape variables
+#	* Moved includes to a more prominent location
+#	* Fixed .inputs.make to not contain .aux files
+#	* Fixed embedding to use a file instead of always grepping.
+#	* Added *.make.temp to the list of cleanable files
+#	* Fixed Ruby.  It should now be supported properly.
+#	* Now differentiate between all, default, and buildable files.
+#	* Fixed to bail out on serious errors.
+#	* Revised the handling of includable files.  Still working on it.
+# Chris Monson (2006-03-31):
+#	* Bumped version to 2.0a5
+#	* Fixed a bug with LaTeX error detection (there can be spaces)
+#	* Added .bbl support, simplifying everything and making it more correct
+#	* Refactored some tests that muddy the code
+#	* Did a little cleanup of some shell loops that can safely be make loops
+#	* Added support for graphviz .dot files
+#	* Made _all_programs output easier to read
+#	* Added the ruby support that has long been advertised
+#	* Font embedding was screwed up for PostScript -- now implicit
+#	* Changed the generation of -gray.gpi files to a single command
+#	* Changed any make-generated file that is not included from .d to .make
+# Chris Monson (2006-03-30):
+#	* Bumped version to 2.0a4
+#	* Fixed a bug with very long graphics file names
+#	* Added a todo entry for epsfig support
+#	* Fixed a bug paper size bug: sometimes more than one entry appears
+#	* Fixed DVI build echoing to display the number instead of process ID
+#	* DVI files are now removed on first invocation if ANY file is missing
+#	* Added a simple grayscale approach: if a file ends with -gray.gpi, it
+#		is created from the corresponding .gpi file with a special
+#		comment ##GRAY in its header, which causes coloring to be
+#		turned off.
+#	* Fixed a bug in the handling of .tex.sh files.  For some reason I had
+#		neglected to define file stems for scripted output.
+#	* Removed a trailing ; from the %.graphics dependencies
+#	* Added dvips embedding (I think it works, anyway)
+# Chris Monson (2006-03-29):
+#	* Bumped version to 2.0a3
+#	* Fixed error in make 3.79 with MAKEFILE_LIST usage
+#	* Added the presumed filename to the _version output
+#	* Added a vim macro for converting sed scripts to make commands
+#	* Added gpi dependency support (plotting external files and loading gpi)
+#	* Allow .gpi files to be ignored if called .include.gpi or .nobuild.gpi
+#	* Fixed sed invocations where \+ was used.  BSD sed uses \{1,\}.
+# Chris Monson (2006-03-28):
+#	* Bumped version to 2.0a2
+#	* Added SHELL_DEBUG and VERBOSE options
+#	* Changed the default shell back to /bin/sh (unset, in other words)
+#	* Moved .PHONY declarations closer to their targets
+#	* Moved help text into its own define block to obtain better formatting
+#	* Removed need for double-entry when adding a new program invocation
+#	* Moved .SECONDARY declaration closer to its relevant occurrence
+#	* Commented things more heavily
+#	* Added help text about setting terminal and output in gnuplot
+#	* Created more fine-grained clean targets
+#	* Added a %.graphics target that generates all of %'s graphics
+#	* Killed backward-compatible graphics generation (e.g., eps.gpi=gpi.eps)
+#	* For now, we're just GPL 2, not 3.  Maybe it will change later
+#	* Made the version and svninfo into variables
+# Chris Monson (2006-03-27):
+#	* Bumped version to 2.0a1
+#	* Huge, sweeping changes -- automatic dependencies
+
+# IMPORTANT!
+#
+# When adding to the following list, do not introduce any blank lines.  The
+# list is extracted for documentation using sed and is terminated by a blank
+# line.
+#
+# EXTERNAL PROGRAMS:
+# = ESSENTIAL PROGRAMS =
+# == Basic Shell Utilities ==
+CAT		?= cat
+CP		?= cp -f
+DIFF		?= diff
+ECHO		?= echo
+EGREP		?= egrep
+ENV		?= env
+EXPR		?= expr
+MV		?= mv -f
+SED		?= sed
+SORT		?= sort
+TOUCH		?= touch
+UNIQ		?= uniq
+WHICH		?= which
+XARGS		?= xargs
+SLEEP		?= sleep
+# == LaTeX (tetex-provided) ==
+BIBTEX		?= bibtex
+DVIPS		?= dvips
+LATEX		?= latex
+PDFLATEX	?= pdflatex
+EPSTOPDF	?= epstopdf
+MAKEINDEX	?= makeindex
+KPSEWHICH	?= kpsewhich
+GS		?= gs
+# = OPTIONAL PROGRAMS =
+# == Makefile Color Output ==
+TPUT		?= tput
+# == TeX Generation ==
+PERL		?= perl
+PYTHON		?= python
+RST2LATEX	?= rst2latex.py
+# == EPS Generation ==
+CONVERT		?= convert	# ImageMagick
+DOT		?= dot		# GraphViz
+DOT2TEX		?= dot2tex	# dot2tex - add options (not -o) as needed
+FIG2DEV		?= fig2dev	# XFig
+GNUPLOT		?= gnuplot	# GNUplot
+INKSCAPE	?= inkscape	# Inkscape (svg support)
+XMGRACE		?= xmgrace	# XMgrace
+PNGTOPNM	?= pngtopnm	# From NetPBM - step 1 for png -> eps
+PPMTOPGM	?= ppmtopgm	# From NetPBM - (gray) step 2 for png -> eps
+PNMTOPS		?= pnmtops	# From NetPBM - step 3 for png -> eps
+GUNZIP		?= gunzip	# GZipped EPS
+# == Beamer Enlarged Output ==
+PSNUP		?= psnup
+# == Viewing Stuff ==
+VIEW_POSTSCRIPT	?= gv
+VIEW_PDF	?= xpdf
+VIEW_GRAPHICS	?= display
+
+# Command options for embedding fonts and postscript->pdf conversion
+PS_EMBED_OPTIONS	?= -dPDFSETTINGS=/printer -dEmbedAllFonts=true -dSubsetFonts=true -dMaxSubsetPct=100
+PS_COMPATIBILITY	?= 1.4
+
+# Defaults for GPI
+DEFAULT_GPI_EPS_FONTSIZE	?= 22
+DEFAULT_GPI_PDF_FONTSIZE	?= 12
+
+# Style file for ReST
+RST_STYLE_FILE			?= $(wildcard _rststyle_._include_.tex)
+
+# This ensures that even when echo is a shell builtin, we still use the binary
+# (the builtin doesn't always understand -n)
+FIXED_ECHO	:= $(if $(findstring -n,$(shell $(ECHO) -n)),$(shell which echo),$(ECHO))
+ECHO		:= $(if $(FIXED_ECHO),$(FIXED_ECHO),$(ECHO))
+
+define determine-gnuplot-output-extension
+$(if $(shell $(WHICH) $(GNUPLOT)),
+     $(if $(findstring unknown or ambiguous, $(shell $(GNUPLOT) -e "set terminal pdf" 2>&1)),
+	  eps, pdf),
+     none)
+endef
+
+GNUPLOT_OUTPUT_EXTENSION	?= $(strip $(call determine-gnuplot-output-extension))
+
+# Directory into which we place "binaries" if it exists.
+# Note that this can be changed on the commandline or in Makefile.ini:
+#
+# Command line:
+#   make BINARY_TARGET_DIR=$HOME/pdfs myfile.pdf
+#
+# Also, you can specify a relative directory (relative to the Makefile):
+#   make BINARY_TARGET_DIR=pdfs myfile.pdf
+#
+# Or, you can use Makefile.ini:
+#
+#   BINARY_TARGET_DIR := $(HOME)/bin_out
+#
+BINARY_TARGET_DIR	?= _out_
+
+RESTARTS		:= $(if $(MAKE_RESTARTS),$(MAKE_RESTARTS),0)
+# SH NOTES
+#
+# On some systems, /bin/sh, which is the default shell, is not linked to
+# /bin/bash.  While bash is supposed to be sh-compatible when invoked as sh, it
+# just isn't.  This section details some of the things you have to stay away
+# from to remain sh-compatible.
+#
+#	* File pattern expansion does not work for {}
+#	* [ "$x" = "$y" ] has to be [ x"$x" x"$y" ]
+#	* &> for stderr redirection doesn't work, use 2>&1 instead
+#
+# BSD SED NOTES
+#
+# BSD SED is not very nice compared to GNU sed, but it is the most
+# commonly-invoked sed on Macs (being based on BSD), so we have to cater to
+# it or require people to install GNU sed.  It seems like the GNU
+# requirement isn't too bad since this makefile is really a GNU makefile,
+# but apparently GNU sed is much less common than GNU make in general, so
+# I'm supporting it here.
+#
+# Sad experience has taught me the following about BSD sed:
+#
+# 	* \+ is not understood to mean \{1,\}
+# 	* \| is meaningless (does not branch)
+# 	* \n cannot be used as a substitution character
+# 	* ? does not mean \{0,1\}, but is literal
+# 	* a\ works, but only reliably for a single line if subsequent lines
+# 		have forward slashes in them (as is the case in postscript)
+#
+# For more info (on the Mac) you can consult
+#
+# man -M /usr/share/man re_format
+#
+# And look for the word "Obsolete" near the bottom.
+
+#
+# EXTERNAL PROGRAM DOCUMENTATION SCRIPT
+#
+
+# $(call output-all-programs,[<output file>])
+define output-all-programs
+	[ -f '$(this_file)' ] && \
+	$(SED) \
+		-e '/^[[:space:]]*#[[:space:]]*EXTERNAL PROGRAMS:/,/^$$/!d' \
+		-e '/EXTERNAL PROGRAMS/d' \
+		-e '/^$$/d' \
+		-e '/^[[:space:]]*#/i\ '\
+		-e 's/^[[:space:]]*#[[:space:]][^=]*//' \
+		$(this_file) $(if $1,> '$1',) || \
+	$(ECHO) "Cannot determine the name of this makefile."
+endef
+
+# If they misspell gray, it should still work.
+GRAY	?= $(call get-default,$(GREY),)
+
+#
+# Utility Functions and Definitions
+#
+
+# While not exactly a make function, this vim macro is useful.  It takes a
+# verbatim sed script and converts each line to something suitable in a command
+# context.  Just paste the script's contents into the editor, yank this into a
+# register (starting at '0') and run the macro once for each line of the
+# original script:
+#
+# 0i	-e :s/\$/$$/eg
:s/'/'"'"'/eg
^Ela'A' \:noh
j
+
+# don't call this directly - it is here to avoid calling wildcard more than
+# once in remove-files.
+remove-files-helper	= $(if $1,$(RM) $1,$(sh_true))
+
+# $(call remove-files,file1 file2)
+remove-files		= $(call remove-files-helper,$(wildcard $1))
+
+# Removes all cleanable files in the given list
+# $(call clean-files,file1 file2 file3 ...)
+# Works exactly like remove-files, but filters out files in $(neverclean)
+clean-files		= \
+	$(call remove-files-helper,$(call cleanable-files,$(wildcard $1)))
+
+# Outputs all generated files to STDOUT, along with some others that are
+# created by these (e.g., .idx files end up producing .ilg and .ind files).
+# Discovered by reading *.fls OUTPUT lines and producing corresponding .ind
+# filenames as needed.
+#
+# $(call get-generated-names,<source recorder file (*.fls)>)
+define get-generated-names
+[ -f '$1' ] && \
+$(SED) \
+	-e '/^OUTPUT /{' \
+	-e '  s///' \
+	-e '  p' \
+	-e '  s/\.idx/\.ind/p' \
+	-e '  s/\.ind/\.ilg/p' \
+	-e '}' \
+	-e 'd' \
+	'$1' \
+| $(SORT) | $(UNIQ)
+endef
+
+# This removes files without checking whether they are there or not.  This
+# sometimes has to be used when the file is created by a series of shell
+# commands, but there ends up being a race condition: make doesn't know about
+# the file generation as quickly as the system does, so $(wildcard ...) doesn't
+# work right.  Blech.
+# $(call remove-temporary-files,filenames)
+remove-temporary-files	= $(if $1,$(RM) $1,:)
+
+# Create an identifier from a file name
+# $(call cleanse-filename,filename)
+cleanse-filename	= $(subst .,_,$(subst /,__,$1))
+
+# Escape dots
+# $(call escape-dots,str)
+escape-dots		= $(subst .,\\.,$1)
+
+# Test that a file exists
+# $(call test-exists,file)
+test-exists		= [ -e '$1' ]
+
+# $(call move-files,source,destination)
+move-if-exists		= $(call test-exists,$1) && $(MV) '$1' '$2'
+
+# Copy file1 to file2 only if file2 doesn't exist or they are different
+# $(call copy-if-different,sfile,dfile)
+copy-if-different	= $(call test-different,$1,$2) && $(CP) '$1' '$2'
+copy-if-exists		= $(call test-exists,$1) && $(CP) '$1' '$2'
+move-if-different	= $(call test-different,$1,$2) && $(MV) '$1' '$2'
+replace-if-different-and-remove	= \
+	$(call test-different,$1,$2) \
+	&& $(MV) '$1' '$2' \
+	|| $(call remove-files,'$1')
+
+# Note that $(DIFF) returns success when the files are the SAME....
+# $(call test-different,sfile,dfile)
+test-different		= ! $(DIFF) -q '$1' '$2' >/dev/null 2>&1
+test-exists-and-different	= \
+	$(call test-exists,$2) && $(call test-different,$1,$2)
+
+# Return value 1, or value 2 if value 1 is empty
+# $(call get-default,<possibly empty arg>,<default value if empty>)
+get-default	= $(if $1,$1,$2)
+
+# Copy a file and log what's going on
+# $(call copy-with-logging,<source>,<target>)
+define copy-with-logging
+if [ -d '$2/' ]; then \
+	if $(CP) '$1' '$2/'; then \
+		$(ECHO) "$(C_INFO)Copied '$1' to '$2/'$(C_RESET)"; \
+	else \
+		$(ECHO) "$(C_ERROR)Failed to copy '$1' to '$2/'$(C_RESET)"; \
+	fi; \
+fi
+endef
+
+# Gives a reassuring message about the failure to find include files
+# $(call include-message,<list of include files>)
+define include-message
+$(strip \
+$(if $(filter-out $(wildcard $1),$1),\
+	$(shell $(ECHO) \
+	"$(C_INFO)NOTE: You may ignore warnings about the"\
+	"following files:" >&2;\
+	$(ECHO) >&2; \
+	$(foreach s,$(filter-out $(wildcard $1),$1),$(ECHO) '     $s' >&2;)\
+	$(ECHO) "$(C_RESET)" >&2)
+))
+endef
+# Characters that are hard to specify in certain places
+space		:= $(empty) $(empty)
+colon		:= \:
+comma		:= ,
+
+# Useful shell definitions
+sh_true		:= :
+sh_false	:= ! :
+
+# Clear out the standard interfering make suffixes
+.SUFFIXES:
+
+# Turn off forceful rm (RM is usually mapped to rm -f)
+ifdef SAFE_RM
+RM	:= rm
+endif
+
+# Turn command echoing back on with VERBOSE=1
+ifndef VERBOSE
+QUIET	:= @
+endif
+
+# Turn on shell debugging with SHELL_DEBUG=1
+# (EVERYTHING is echoed, even $(shell ...) invocations)
+ifdef SHELL_DEBUG
+SHELL	+= -x
+endif
+
+# Get the name of this makefile (always right in 3.80, often right in 3.79)
+# This is only really used for documentation, so it isn't too serious.
+ifdef MAKEFILE_LIST
+this_file	:= $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
+else
+this_file	:= $(wildcard GNUmakefile makefile Makefile)
+endif
+
+# Terminal color definitions
+
+REAL_TPUT 	:= $(if $(NO_COLOR),,$(shell $(WHICH) $(TPUT)))
+
+# $(call get-term-code,codeinfo)
+# e.g.,
+# $(call get-term-code,setaf 0)
+get-term-code = $(if $(REAL_TPUT),$(shell $(REAL_TPUT) $1),)
+
+black	:= $(call get-term-code,setaf 0)
+red	:= $(call get-term-code,setaf 1)
+green	:= $(call get-term-code,setaf 2)
+yellow	:= $(call get-term-code,setaf 3)
+blue	:= $(call get-term-code,setaf 4)
+magenta	:= $(call get-term-code,setaf 5)
+cyan	:= $(call get-term-code,setaf 6)
+white	:= $(call get-term-code,setaf 7)
+bold	:= $(call get-term-code,bold)
+uline	:= $(call get-term-code,smul)
+reset	:= $(call get-term-code,sgr0)
+
+#
+# User-settable definitions
+#
+LATEX_COLOR_WARNING	?= magenta
+LATEX_COLOR_ERROR	?= red
+LATEX_COLOR_INFO	?= green
+LATEX_COLOR_UNDERFULL	?= magenta
+LATEX_COLOR_OVERFULL	?= red bold
+LATEX_COLOR_PAGES	?= bold
+LATEX_COLOR_BUILD	?= cyan
+LATEX_COLOR_GRAPHIC	?= yellow
+LATEX_COLOR_DEP		?= green
+LATEX_COLOR_SUCCESS	?= green bold
+LATEX_COLOR_FAILURE	?= red bold
+
+# Gets the real color from a simple textual definition like those above
+# $(call get-color,ALL_CAPS_COLOR_NAME)
+# e.g., $(call get-color,WARNING)
+get-color	= $(subst $(space),,$(foreach c,$(LATEX_COLOR_$1),$($c)))
+
+#
+# STANDARD COLORS
+#
+C_WARNING	:= $(call get-color,WARNING)
+C_ERROR		:= $(call get-color,ERROR)
+C_INFO		:= $(call get-color,INFO)
+C_UNDERFULL	:= $(call get-color,UNDERFULL)
+C_OVERFULL	:= $(call get-color,OVERFULL)
+C_PAGES		:= $(call get-color,PAGES)
+C_BUILD		:= $(call get-color,BUILD)
+C_GRAPHIC	:= $(call get-color,GRAPHIC)
+C_DEP		:= $(call get-color,DEP)
+C_SUCCESS	:= $(call get-color,SUCCESS)
+C_FAILURE	:= $(call get-color,FAILURE)
+C_RESET		:= $(reset)
+
+#
+# PRE-BUILD TESTS
+#
+
+# Check that clean targets are not combined with other targets (weird things
+# happen, and it's not easy to fix them)
+hascleangoals	:= $(if $(sort $(filter clean clean-%,$(MAKECMDGOALS))),1)
+hasbuildgoals	:= $(if $(sort $(filter-out clean clean-%,$(MAKECMDGOALS))),1)
+ifneq "$(hasbuildgoals)" ""
+ifneq "$(hascleangoals)" ""
+$(error $(C_ERROR)Clean and build targets specified together$(C_RESET)))
+endif
+endif
+
+#
+# VARIABLE DECLARATIONS
+#
+
+# Names of sed scripts that morph gnuplot files -- only the first found is used
+GNUPLOT_SED	:= global-gpi.sed gnuplot.sed
+GNUPLOT_GLOBAL	:= global._include_.gpi gnuplot.global
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+default_graphic_extension	?= eps
+latex_build_program		?= $(LATEX)
+build_target_extension		?= dvi
+hyperref_driver_pattern		?= hdvips
+hyperref_driver_error		?= Using dvips: specify ps2pdf in the hyperref options.
+else
+default_graphic_extension	?= pdf
+latex_build_program		?= $(PDFLATEX)
+build_target_extension		?= pdf
+hyperref_driver_pattern		?= hpdf.*
+hyperref_driver_error		?= Using pdflatex: specify pdftex in the hyperref options (or leave it blank).
+endif
+
+# Files of interest
+all_files.tex		?= $(wildcard *.tex)
+all_files.tex.sh	?= $(wildcard *.tex.sh)
+all_files.tex.pl	?= $(wildcard *.tex.pl)
+all_files.tex.py	?= $(wildcard *.tex.py)
+all_files.rst		?= $(wildcard *.rst)
+all_files.fig		?= $(wildcard *.fig)
+all_files.gpi		?= $(wildcard *.gpi)
+all_files.dot		?= $(wildcard *.dot)
+all_files.xvg		?= $(wildcard *.xvg)
+all_files.svg		?= $(wildcard *.svg)
+all_files.png		?= $(wildcard *.png)
+all_files.jpg		?= $(wildcard *.jpg)
+all_files.eps.gz	?= $(wildcard *.eps.gz)
+all_files.eps		?= $(wildcard *.eps)
+
+# Utility function for obtaining all files not specified in $(neverclean)
+# $(call cleanable-files,file1 file2 file3 ...)
+# Returns the list of files that is not in $(wildcard $(neverclean))
+cleanable-files = $(filter-out $(wildcard $(neverclean)), $1)
+
+# Utility function for getting all .$1 files that are to be ignored
+#  * files listed in $(includes.$1)
+#  * files not listed in $(onlysources.$1) if it is defined
+ignore_files = \
+  $(includes.$1) \
+  $(if $(onlysources.$1),$(filter-out $(onlysources.$1), $(all_files.$1)))
+
+# Patterns to never be allowed as source targets
+ignore_patterns	:= %._include_
+
+# Patterns allowed as source targets but not included in 'all' builds
+nodefault_patterns := %._nobuild_ $(ignore_patterns)
+
+# Utility function for getting targets suitable building
+# $(call filter-buildable,suffix)
+filter-buildable	= \
+	$(filter-out $(call ignore_files,$1) \
+		$(addsuffix .$1,$(ignore_patterns)),$(all_files.$1))
+
+# Utility function for getting targets suitable for 'all' builds
+# $(call filter-default,suffix)
+filter-default		= \
+	$(filter-out $(call ignore_files,$1) \
+		$(addsuffix .$1,$(nodefault_patterns)),$(all_files.$1))
+
+# Top level sources that can be built even when they are not by default
+files.tex	:= $(call filter-buildable,tex)
+files.tex.sh	:= $(call filter-buildable,tex.sh)
+files.tex.pl	:= $(call filter-buildable,tex.pl)
+files.tex.py	:= $(call filter-buildable,tex.py)
+files.rst	:= $(call filter-buildable,rst)
+files.gpi	:= $(call filter-buildable,gpi)
+files.dot	:= $(call filter-buildable,dot)
+files.fig	:= $(call filter-buildable,fig)
+files.xvg	:= $(call filter-buildable,xvg)
+files.svg	:= $(call filter-buildable,svg)
+files.png	:= $(call filter-buildable,png)
+files.jpg	:= $(call filter-buildable,jpg)
+files.eps.gz	:= $(call filter-buildable,eps.gz)
+
+# Make all pstex targets secondary.  The pstex_t target requires the pstex
+# target, and nothing else really depends on it, so it often gets deleted.
+# This avoids that by allowing *all* fig files to be pstex targets, which is
+# perfectly valid and causes no problems even if they're going to become eps
+# files in the end.
+.SECONDARY:	$(patsubst %.fig,%.pstex,$(files.fig))
+
+# Top level sources that are built by default targets
+default_files.tex	:= $(call filter-default,tex)
+default_files.tex.sh	:= $(call filter-default,tex.sh)
+default_files.tex.pl	:= $(call filter-default,tex.pl)
+default_files.tex.py	:= $(call filter-default,tex.py)
+default_files.rst	:= $(call filter-default,rst)
+default_files.gpi	:= $(call filter-default,gpi)
+default_files.dot	:= $(call filter-default,dot)
+default_files.fig	:= $(call filter-default,fig)
+default_files.xvg	:= $(call filter-default,xvg)
+default_files.svg	:= $(call filter-default,svg)
+default_files.png	:= $(call filter-default,png)
+default_files.jpg	:= $(call filter-default,jpg)
+default_files.eps.gz	:= $(call filter-default,eps.gz)
+
+# Utility function for creating larger lists of files
+# $(call concat-files,suffixes,[prefix])
+concat-files	= $(foreach s,$1,$($(if $2,$2_,)files.$s))
+
+# Useful file groupings
+all_files_source	:= $(call concat-files,tex,all)
+all_files_scripts	:= $(call concat-files,tex.sh tex.pl tex.py rst,all)
+
+.PHONY: $(all_files_scripts)
+
+default_files_source	:= $(call concat-files,tex,default)
+default_files_scripts	:= $(call concat-files,tex.sh tex.pl tex.py rst,default)
+
+files_source	:= $(call concat-files,tex)
+files_scripts	:= $(call concat-files,tex.sh tex.pl tex.py rst)
+
+# Utility function for obtaining stems
+# $(call get-stems,suffix,[prefix])
+get-stems	= $(sort $($(if $2,$2_,)files.$1:%.$1=%))
+
+# List of all stems (including ._include_ and ._nobuild_ file stems)
+all_stems.tex		:= $(call get-stems,tex,all)
+all_stems.tex.sh	:= $(call get-stems,tex.sh,all)
+all_stems.tex.pl	:= $(call get-stems,tex.pl,all)
+all_stems.tex.py	:= $(call get-stems,tex.py,all)
+all_stems.rst		:= $(call get-stems,rst,all)
+all_stems.fig		:= $(call get-stems,fig,all)
+all_stems.gpi		:= $(call get-stems,gpi,all)
+all_stems.dot		:= $(call get-stems,dot,all)
+all_stems.xvg		:= $(call get-stems,xvg,all)
+all_stems.svg		:= $(call get-stems,svg,all)
+all_stems.png		:= $(call get-stems,png,all)
+all_stems.jpg		:= $(call get-stems,jpg,all)
+all_stems.eps.gz	:= $(call get-stems,eps.gz,all)
+all_stems.eps		:= $(call get-stems,eps,all)
+
+# List of all default stems (all default PDF targets):
+default_stems.tex		:= $(call get-stems,tex,default)
+default_stems.tex.sh		:= $(call get-stems,tex.sh,default)
+default_stems.tex.pl		:= $(call get-stems,tex.pl,default)
+default_stems.tex.py		:= $(call get-stems,tex.py,default)
+default_stems.rst		:= $(call get-stems,rst,default)
+default_stems.fig		:= $(call get-stems,fig,default)
+default_stems.gpi		:= $(call get-stems,gpi,default)
+default_stems.dot		:= $(call get-stems,dot,default)
+default_stems.xvg		:= $(call get-stems,xvg,default)
+default_stems.svg		:= $(call get-stems,svg,default)
+default_stems.png		:= $(call get-stems,png,default)
+default_stems.jpg		:= $(call get-stems,jpg,default)
+default_stems.eps.gz		:= $(call get-stems,eps.gz,default)
+
+# List of all stems (all possible bare PDF targets created here):
+stems.tex		:= $(call get-stems,tex)
+stems.tex.sh		:= $(call get-stems,tex.sh)
+stems.tex.pl		:= $(call get-stems,tex.pl)
+stems.tex.py		:= $(call get-stems,tex.py)
+stems.rst		:= $(call get-stems,rst)
+stems.fig		:= $(call get-stems,fig)
+stems.gpi		:= $(call get-stems,gpi)
+stems.dot		:= $(call get-stems,dot)
+stems.xvg		:= $(call get-stems,xvg)
+stems.svg		:= $(call get-stems,svg)
+stems.png		:= $(call get-stems,png)
+stems.jpg		:= $(call get-stems,jpg)
+stems.eps.gz		:= $(call get-stems,eps.gz)
+
+# Utility function for creating larger lists of stems
+# $(call concat-stems,suffixes,[prefix])
+concat-stems	= $(sort $(foreach s,$1,$($(if $2,$2_,)stems.$s)))
+
+# The most likely to be source but not finished product go first
+graphic_source_extensions	:= fig \
+				   gpi \
+				   xvg \
+				   svg \
+				   dot \
+				   eps.gz
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+graphic_source_extensions	+= png jpg
+graphic_target_extensions	:= eps ps
+else
+graphic_source_extensions	+= eps
+graphic_target_extensions	:= pdf png jpg mps tif
+endif
+
+all_stems_source	:= $(call concat-stems,tex,all)
+all_stems_script	:= $(call concat-stems,tex.sh tex.pl tex.py rst,all)
+all_stems_graphic	:= $(call concat-stems,$(graphic_source_extensions),all)
+all_stems_ss		:= $(sort $(all_stems_source) $(all_stems_script))
+all_stems_sg		:= $(sort $(all_stems_script))
+all_stems_ssg		:= $(sort $(all_stems_ss))
+
+default_stems_source	:= $(call concat-stems,tex,default)
+default_stems_script	:= $(call concat-stems,tex.sh tex.pl tex.py rst,default)
+default_stems_ss	:= $(sort $(default_stems_source) $(default_stems_script))
+default_stems_sg	:= $(sort $(default_stems_script))
+default_stems_ssg	:= $(sort $(default_stems_ss))
+
+stems_source		:= $(call concat-stems,tex)
+stems_script		:= $(call concat-stems,tex.sh tex.pl tex.py rst)
+stems_graphic		:= $(call concat-stems,$(graphic_source_extensions))
+stems_gg		:= $(sort $(stems_graphic))
+stems_ss		:= $(sort $(stems_source) $(stems_script))
+stems_sg		:= $(sort $(stems_script))
+stems_ssg		:= $(sort $(stems_ss))
+
+# Calculate names that can generate the need for an include file.  We can't
+# really do this with patterns because it's too easy to screw up, so we create
+# an exhaustive list.
+allowed_source_suffixes	:= \
+	pdf \
+	ps \
+	dvi \
+	ind \
+	nls \
+	bbl \
+	aux \
+	aux.make \
+	d \
+	auxbbl.make \
+	_graphics \
+	_show
+allowed_source_patterns		:= $(addprefix %.,$(allowed_source_suffixes))
+
+allowed_graphic_suffixes	:= \
+	pdf \
+	eps \
+	gpihead.make \
+	gpi.d
+allowed_graphic_patterns	:= $(addprefix %.,$(allowed_graphic_suffixes))
+
+# All targets allowed to build documents
+allowed_source_targets	:= \
+	$(foreach suff,$(allowed_source_suffixes),\
+	$(addsuffix .$(suff),$(stems_ssg)))
+
+# All targets allowed to build graphics
+allowed_graphic_targets	:= \
+	$(foreach suff,$(allowed_graphic_suffixes),\
+	$(addsuffix .$(suff),$(stems_gg)))
+
+# All targets that build multiple documents (like 'all')
+allowed_batch_source_targets	:= \
+	all \
+	all-pdf \
+	all-ps \
+	all-dvi \
+	all-bbl \
+	all-ind \
+	all-gls \
+	all-nls \
+	show
+
+# All targets that build multiple graphics (independent of document)
+allowed_batch_graphic_targets	:= \
+	all-graphics \
+	all-pstex \
+	all-dot2tex \
+	show-graphics
+
+# Now we figure out which stuff is available as a make target for THIS RUN.
+real_goals	:= $(call get-default,$(filter-out _includes,$(MAKECMDGOALS)),\
+			all)
+
+specified_source_targets	:= $(strip \
+	$(filter $(allowed_source_targets) $(stems_ssg),$(real_goals)) \
+	)
+
+specified_batch_source_targets	:= $(strip \
+	$(filter $(allowed_batch_source_targets),$(real_goals)) \
+	)
+
+specified_graphic_targets	:= $(strip \
+	$(filter $(allowed_graphic_targets),$(real_goals)) \
+	)
+
+specified_batch_graphic_targets	:= $(strip \
+	$(filter $(allowed_batch_graphic_targets),$(real_goals)) \
+	)
+
+specified_gpi_targets	:= $(patsubst %.gpi,%.$(default_graphic_extension),\
+	$(filter $(patsubst %.$(default_graphic_extension),%.gpi,$(specified_graphic_targets)),\
+		$(all_files.gpi)) \
+	)
+
+# Determine which .d files need including from the information gained above.
+# This is done by first checking whether a batch target exists.  If it does,
+# then all *default* stems are used to create possible includes (nobuild need
+# not apply for batch status).  If no batch targets exist, then the individual
+# targets are considered and appropriate includes are taken from them.
+source_stems_to_include	:= \
+	$(sort\
+	$(if $(specified_batch_source_targets),\
+		$(default_stems_ss),\
+		$(foreach t,$(specified_source_targets),\
+		$(foreach p,$(allowed_source_patterns),\
+			$(patsubst $p,%,$(filter $p $(stems_ssg),$t)) \
+		)) \
+	))
+
+# Determine which .gpi.d files are needed using the above information.  We
+# first check whether a batch target is specified, then check individual
+# graphics that may have been specified.
+graphic_stems_to_include	:= \
+	$(sort\
+	$(if $(specified_batch_graphic_targets),\
+		$(default_stems.gpi),\
+		$(foreach t,$(specified_gpi_targets),\
+		$(foreach p,$(allowed_graphic_patterns),\
+			$(patsubst $p,%,$(filter $p,$t)) \
+		)) \
+	))
+
+# All dependencies for the 'all' targets
+all_pdf_targets		:= $(addsuffix .pdf,$(stems_ssg))
+all_ps_targets		:= $(addsuffix .ps,$(stems_ssg))
+all_dvi_targets		:= $(addsuffix .dvi,$(stems_ssg))
+all_tex_targets		:= $(addsuffix .tex,$(stems_sg))
+all_d_targets		:= $(addsuffix .d,$(stems_ssg))
+all_graphics_targets	:= $(addsuffix .$(default_graphic_extension),$(stems_gg))
+intermediate_graphics_targets	:= $(if $(filter pdf,$(default_graphic_extension)),$(addsuffix .eps,$(stems_gg)),)
+all_pstex_targets	:= $(addsuffix .pstex_t,$(stems.fig))
+all_dot2tex_targets	:= $(addsuffix .dot_t,$(stems.dot))
+
+all_known_graphics	:= $(sort $(all_graphics_targets) $(wildcard *.$(default_graphic_extension)))
+
+default_pdf_targets	:= $(addsuffix .pdf,$(default_stems_ss))
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+default_ps_targets	:= $(addsuffix .ps,$(default_stems_ss))
+default_dvi_targets	:= $(addsuffix .dvi,$(default_stems_ss))
+pre_pdf_extensions	:= dvi ps
+endif
+
+# Extensions generated by LaTeX invocation that can be removed when complete
+rm_ext		:= \
+	log *.log aux $(pre_pdf_extensions) pdf blg bbl out nav snm toc lof lot lol pfg \
+	fls vrb idx ind ilg glg glo gls lox nls nlo nlg brf mtc maf brf
+backup_patterns	:= *~ *.bak *.backup body.tmp head.tmp
+
+graph_stem	:= _graph
+
+# All LaTeX-generated files that can be safely removed
+
+rm_tex := \
+	$(foreach e,$(rm_ext),$(addsuffix .$e,$(all_stems_source))) \
+	$(foreach e,$(rm_ext) tex,$(addsuffix .$e,$(all_stems_sg))) \
+	$(addsuffix .log,$(all_ps_targets) $(all_pdf_targets)) \
+	$(addsuffix .*.log,$(stems_graphic))
+
+# These are the files that will affect .gpi transformation for all .gpi files.
+#
+# Use only the first one found.  Backward compatible values are at the end.
+# Note that we use foreach, even though wildcard also returns a list, to ensure
+# that the order in the uppercase variables is preserved.  Directory listings
+# provide no such guarantee, so we avoid relying on them.
+gpi_sed		:= $(strip \
+	$(firstword $(foreach f,$(GNUPLOT_SED),$(wildcard $f))))
+gpi_global	:= $(strip \
+	$(firstword $(foreach f,$(GNUPLOT_GLOBAL),$(wildcard $f))))
+
+#
+# Functions used in generating output
+#
+
+# Outputs all source dependencies to stdout.  The first argument is the file to
+# be parsed, the second is a list of files that will show up as dependencies in
+# the new .d file created here.
+#
+# NOTE: BSD sed does not understand \|, so we have to do something more
+# clunky to extract suitable extensions.
+#
+# Also, we do a little bit of funny rewriting up front (TARGETS=) to make sure
+# that we can properly backslash-escape spaces in file names (e.g, on Cygwin
+# for tex distributions that have "Program Files" in their name).
+#
+# $(call get-inputs,<parsed file>,<target files>)
+define get-inputs
+$(SED) \
+-e '/^INPUT/!d' \
+-e 's!^INPUT \(\./\)\{0,1\}!!' \
+-e 's/[[:space:]]/\\ /g' \
+-e 's/\(.*\)\.aux$$/\1.tex/' \
+-e '/\.tex$$/b addtargets' \
+-e '/\.cls$$/b addtargets' \
+-e '/\.sty$$/b addtargets' \
+-e '/\.pstex_t$$/b addtargets' \
+-e '/\.dot_t$$/b addtargets' \
+-e 'd' \
+-e ':addtargets' \
+-e 's/^/$2: /' \
+$1 | $(SORT) | $(UNIQ)
+endef
+
+# $(call get-missing-inputs,<log file>,<target files>)
+define get-missing-inputs
+$(SED) \
+-e '$$ b para' \
+-e '/^$$/b para' \
+-e 'H' \
+-e 'd' \
+-e ':para' \
+-e 'x' \
+-e '/^$$/d' \
+-e 's/^\n*//' \
+-e '/^! LaTeX Error: File /{' \
+-e '  s/^/::DOUBLE_PARAGRAPH::/' \
+-e '  h' \
+-e '  d' \
+-e '}' \
+-e 's/^::DOUBLE_PARAGRAPH:://' \
+-e '/Default extension: /!d' \
+-e 's/[[:space:]]\{1,\}/ /g' \
+-e 's/\n\{1,\}/ /g' \
+-e 's/^.*File `//' \
+-e 's/'"'"' not found\..*//' \
+-e '/\.tex/!s/$$/.tex/' \
+-e 's/[[:space:]]/\\ /g' \
+-e 'h' \
+-e 's/.*/# MISSING input "&" - (presence of comment affects build)/' \
+-e 'p' \
+-e 's/.*//' \
+-e 'x' \
+-e 's/^/$2: /' \
+$1 | $(SORT) | $(UNIQ)
+endef
+
+# Get source file for specified graphics stem.
+#
+# $(call graphics-source,<stem>)
+define graphics-source
+$(strip $(firstword \
+	$(wildcard \
+		$(addprefix $1.,\
+			$(graphic_source_extensions))) \
+	$1 \
+))
+endef
+
+# Get the target file for the specified graphics file/stem
+#
+# $(call graphics-target,<stem>)
+define graphics-target
+$(strip $(if 	$(filter $(addprefix %.,$(graphic_target_extensions)),$1), $1,
+	$(firstword $(patsubst $(addprefix %.,$(graphic_source_extensions) $(graphic_target_extensions)), %, $1).$(default_graphic_extension) $1.$(default_graphic_extension))))
+endef
+
+# Outputs all of the graphical dependencies to stdout.  The first argument is
+# the stem of the source file being built, the second is a list of suffixes
+# that will show up as dependencies in the generated .d file.
+#
+# Note that we try to escape spaces in filenames where possible.  We have to do
+# it with three backslashes so that as the name percolates through the makefile
+# it eventually ends up with the proper escaping when the build rule is found.
+# Ugly, but it appears to work.  Note that graphicx doesn't allow filenames
+# with spaces, so this could in many ways be moot unless you're using something
+# like grffile.
+#
+# For pdflatex, we really need the missing file to be specified without an
+# extension, otherwise compilation barfs on the first missing file.  Truly
+# annoying, but there you have it.
+#
+# It turns out that the graphics errors, although they have lines with empty
+# space, are only made of two paragraphs.  So, we just use some sed magic to
+# get everything into paragraphs, detect when it's a paragraph that interests
+# us, and double it up.  Then we get the filename only if we're missing
+# extensions (a sign that it's graphicx complaining).
+#
+# $(call get-graphics,<target file stem>)
+#.log,$(addprefix $*.,d $(build_target_extension) _graphics)
+define get-graphics
+$(SED) \
+-e '$$ b para' \
+-e '/^$$/b para' \
+-e 'H' \
+-e 'd' \
+-e ':para' \
+-e 'x' \
+-e '/^$$/d' \
+-e 's/^\n*//' \
+-e '/^! LaTeX Error: File `/{' \
+-e '  s/^/::DOUBLE_PARAGRAPH::/' \
+-e '  h' \
+-e '  d' \
+-e '}' \
+-e 's/^::DOUBLE_PARAGRAPH:://' \
+-e '/could not locate the file with any of these extensions:/{' \
+-e '  s/\n\{1,\}/ /g' \
+-e '  s/[[:space:]]\{1,\}/ /g' \
+-e '  s/^.*File `//' \
+-e '  s/'"'"' not found\..*//' \
+-e '  h' \
+-e '  s/.*/# MISSING stem "&" - (presence of comment affects build)/' \
+-e '  p' \
+-e '  g' \
+-e '  b addtargets' \
+-e '}' \
+-e '/.*File: \(.*\) Graphic file (type [^)]*).*/{' \
+-e '  s//\1/' \
+-e '  b addtargets' \
+-e '}' \
+-e 'd' \
+-e ':addtargets' \
+-e 's/[[:space:]]/\\\\\\&/g' \
+-e 'h' \
+-e 's/.*/-include &.gpi.d/' \
+-e 'p' \
+-e 'g' \
+-e 's/.*/$(addprefix $1,.d): $$$$(call graphics-source,&)/' \
+-e 'p' \
+-e 's/.*//' \
+-e 'x' \
+-e 's/.*/$(addprefix $1.,$(build_target_extension) _graphics): $$$$(call graphics-target,&)/' \
+-e 'p' \
+-e 'd' \
+$*.log
+endef
+
+# Checks for build failure due to pstex inclusion, and gives instructions.
+#
+# $(call die-on-pstexs,<parsed file>)
+define die-on-pstexs
+if $(EGREP) -q '^! LaTeX Error: File .*\.pstex.* not found' $1; then \
+	$(ECHO) "$(C_ERROR)Missing pstex_t file(s)$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)Please run$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)  make all-pstex$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)before proceeding.$(C_RESET)"; \
+	exit 1; \
+fi
+endef
+
+# Checks for build failure due to dot2tex, and gives instructions.
+#
+# $(call die-on-dot2tex,<parsed file>)
+define die-on-dot2tex
+if $(EGREP) -q ' LaTeX Error: File .*\.dot_t.* not found' $1; then \
+	$(ECHO) "$(C_ERROR)Missing dot_t file(s)$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)Please run$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)  make all-dot2tex$(C_RESET)"; \
+	$(ECHO) "$(C_ERROR)before proceeding.$(C_RESET)"; \
+	exit 1; \
+fi
+endef
+
+# Checks for the existence of a .aux file, and dies with an error message if it
+# isn't there.  Note that we pass the file stem in, not the full filename,
+# e.g., to check for foo.aux, we call it thus: $(call die-on-no-aux,foo)
+#
+# $(call die-on-no-aux,<aux stem>)
+define die-on-no-aux
+if [ ! -e '$1.aux' ]; then \
+	$(call colorize-latex-errors,$1.log); \
+	exit 1; \
+fi
+endef
+
+# Outputs all index files to stdout.  Arg 1 is the source file stem, arg 2 is
+# the list of targets for the discovered dependency.
+#
+# $(call get-log-index,<log file stem>,<target files>)
+define get-log-index
+$(SED) \
+-e 's/^No file \(.*\.ind\)\.$$/TARGETS=\1/' \
+-e 's/^No file \(.*\.[gn]ls\)\.$$/TARGETS=\1/' \
+-e 's/[[:space:]]/\\&/g' \
+-e '/^TARGETS=/{' \
+-e '  h' \
+-e '  s/^TARGETS=/$2: /p' \
+-e '  g' \
+-e '  s/^TARGETS=\(.*\)/\1: $1.tex/p' \
+-e '}' \
+-e 'd' \
+'$1.log' | $(SORT) | $(UNIQ)
+endef
+
+
+# Outputs all bibliography files to stdout.  Arg 1 is the source stem, arg 2 is
+# a list of targets for each dependency found.
+#
+# The script kills all lines that do not contain bibdata.  Remaining lines have
+# the \bibdata macro and delimiters removed to create a dependency list.  A
+# trailing comma is added, then all adjacent commas are collapsed into a single
+# comma.  Then commas are replaced with the string .bib[space], and the
+# trailing space is killed off.  Finally, all filename spaces are escaped.
+# This produces a list of space-delimited .bib filenames, which is what the
+# make dep file expects to see.
+#
+# Note that we give kpsewhich a bogus argument so that a failure of sed to
+# produce output will not cause an error.
+#
+# $(call get-bibs,<aux file>,<targets>)
+define get-bibs
+$(SED) \
+-e '/^\\bibdata/!d' \
+-e 's/\\bibdata{\([^}]*\)}/\1,/' \
+-e 's/,\{2,\}/,/g' \
+-e 's/[[:space:]]/\\&/g' \
+-e 's/,/.bib /g' \
+-e 's/ \{1,\}$$//' \
+$1 | $(XARGS) $(KPSEWHICH) '#######' | \
+$(SED) \
+-e 's/^/$2: /' | \
+\$(SORT) | $(UNIQ)
+endef
+
+# Makes a an aux file that only has stuff relevant to the target in it
+# $(call make-auxtarget-file,<flattened-aux>,<new-aux>)
+define make-auxtarget-file
+$(SED) \
+-e '/^\\newlabel/!d' \
+$1 > $2
+endef
+
+# Makes an aux file that only has stuff relevant to the bbl in it
+# $(call make-auxbbl-file,<flattened-aux>,<new-aux>)
+define make-auxbbl-file
+$(SED) \
+-e '/^\\newlabel/d' \
+$1 > $2
+endef
+
+# Makes a .gpi.d file from a .gpi file
+# $(call make-gpi-d,<.gpi>,<.gpi.d>)
+define make-gpi-d
+$(ECHO) '# vim: ft=make' > $2; \
+$(ECHO) 'ifndef INCLUDED_$(call cleanse-filename,$2)' >> $2; \
+$(ECHO) 'INCLUDED_$(call cleanse-filename,$2) := 1' >> $2; \
+$(call get-gpi-deps,$1,$(addprefix $(2:%.gpi.d=%).,$(GNUPLOT_OUTPUT_EXTENSION) gpi.d)) >> $2; \
+$(ECHO) 'endif' >> $2;
+endef
+
+# Parse .gpi files for data and loaded dependencies, output to stdout
+#
+# The sed script here tries to be clever about obtaining valid
+# filenames from the gpi file.  It assumes that the plot command starts its own
+# line, which is not too difficult a constraint to satisfy.
+#
+# This command script also generates 'include' directives for every 'load'
+# command in the .gpi file.  The load command must appear on a line by itself
+# and the file it loads must have the suffix .gpi.  If you don't want it to be
+# compiled when running make graphics, then give it a suffix of ._include_.gpi.
+#
+# $(call get-gpi-deps,<gpi file>,<targets>)
+define get-gpi-deps
+$(SED) \
+-e '/^[[:space:]]*s\{0,1\}plot/,/[^\\]$$/{' \
+-e ' H' \
+-e ' /[^\\]$$/{' \
+-e '  s/.*//' \
+-e '  x' \
+-e '  s/\\\{0,1\}\n//g' \
+-e '  s/^[[:space:]]*s\{0,1\}plot[[:space:]]*\(\[[^]]*\][[:space:]]*\)*/,/' \
+-e '  s/[[:space:]]*\(['\''"][^'\''"]*['\''"]\)\{0,1\}[^,]*/\1/g' \
+-e '  s/,['\''"]-\{0,1\}['\''"]//g' \
+-e '  s/[,'\''"]\{1,\}/ /g' \
+-e '  s!.*!$2: &!' \
+-e '  p' \
+-e ' }' \
+-e ' d' \
+-e '}' \
+-e 's/^[[:space:]]*load[[:space:]]*['\''"]\([^'\''"]*\.gpi\)['\''"].*$$/-include \1.d/p' \
+-e 'd' \
+$1
+endef
+
+# Colorizes real, honest-to-goodness LaTeX errors that can't be overcome with
+# recompilation.
+#
+# Note that we only ignore file not found errors for things that we know how to
+# build, like graphics files.
+#
+# $(call colorize-latex-errors,<log file>)
+define colorize-latex-errors
+$(SED) \
+-e '$$ b para' \
+-e '/^$$/b para' \
+-e 'H' \
+-e 'd' \
+-e ':para' \
+-e 'x' \
+-e '/^$$/d' \
+-e 's/^\n*//' \
+-e '/^! LaTeX Error: File /{' \
+-e '  s/^/::DOUBLE_PARAGRAPH::/' \
+-e '  h' \
+-e '  d' \
+-e '}' \
+-e 's/^::DOUBLE_PARAGRAPH:://' \
+-e '/could not locate the file with any of these extensions:/d' \
+-e '/Missing .begin.document/{' \
+-e '  h' \
+-e '  s/.*/Are you trying to build an include file?/' \
+-e '  x' \
+-e '  G' \
+-e '}' \
+-e '/ LaTeX Error: Cannot determine size/d' \
+-e 's/.* LaTeX Error .*/$(C_ERROR)&$(C_RESET)/p' \
+-e 's/Error: pdflatex (file .*/$(C_ERROR)& - try specifying it without an extension$(C_RESET)/p' \
+-e '/.*\*hyperref using.*driver \(.*\)\*.*/{' \
+-e '  s//\1/' \
+-e '  /^$(hyperref_driver_pattern)$$/!{' \
+-e '    s/.*//' \
+-e '    p' \
+-e '    s/.*/$(C_ERROR)--- Using incorrect driver for hyperref! ---$(C_RESET)/' \
+-e '    p' \
+-e '    s/.*/$(C_ERROR)$(hyperref_driver_error)$(C_RESET)/' \
+-e '    p' \
+-e '  }' \
+-e '  d' \
+-e '}' \
+-e '/ LaTeX Error: Unknown graphics extension/{' \
+-e '  s/^/     /' \
+-e '  h' \
+-e '  s/.*/--- Graphics extension error:/' \
+-e '  G' \
+-e '  h' \
+-e '  s/.*/--- If you specified the extension explicitly in your .tex file, try removing it./' \
+-e '  H' \
+-e '  g' \
+-e '  s/.*/$(C_ERROR)&$(C_RESET)/' \
+-e '  p' \
+-e '  s/.*//' \
+-e '  h' \
+-e '  b' \
+-e '}' \
+-e 's/.*\(\n\{0,\}! .*\)/$(C_ERROR)\1$(C_RESET)/p' \
+-e 'd' \
+$1
+endef
+
+# Colorize Makeindex errors
+define colorize-makeindex-errors
+$(SED) \
+-e '/^!! /{' \
+-e '  N' \
+-e '  s/^.*$$/$(C_ERROR)&$(C_RESET)/' \
+-e '  p' \
+-e '}' \
+-e 'd' \
+$1
+endef
+
+# Colorize epstopdf errors
+#
+# $(call colorize-epstopdf-errors,<log file>)
+define colorize-epstopdf-errors
+$(SED) \
+-e '/^Error:/,/^Execution stack:/{' \
+-e '  /^Execution stack:/d' \
+-e '  s/.*/$(C_ERROR)&$(C_RESET)/' \
+-e '  p' \
+-e '}' \
+-e 'd' \
+$1
+endef
+
+# Colorize GNUplot errors
+#
+# $(call colorize-gnuplot-errors,<log file>)
+define colorize-gnuplot-errors
+$(SED) \
+-e '/, line [0-9]*:/!{' \
+-e '  H' \
+-e '  x' \
+-e '  s/.*\n\(.*\n.*\)$$/\1/' \
+-e '  x' \
+-e '}' \
+-e '/, line [0-9]*:/{' \
+-e '  H' \
+-e '  /unknown.*terminal type/{' \
+-e '    s/.*/--- Try changing the GNUPLOT_OUTPUT_EXTENSION variable to 'eps'./' \
+-e '	H' \
+-e '  }' \
+-e '  /gpihead/{' \
+-e '    s/.*/--- This could be a Makefile bug - contact the maintainer./' \
+-e '    H' \
+-e '  }' \
+-e '  g' \
+-e '  s/.*/$(C_ERROR)&$(C_RESET)/' \
+-e '  p' \
+-e '}' \
+-e '/^gnuplot>/,/^$$/{' \
+-e '  s/^gnuplot.*/$(C_ERROR)&/' \
+-e '  s/^$$/$(C_RESET)/' \
+-e '  p' \
+-e '}' \
+-e 'd' \
+$1
+endef
+
+# Colorize GraphViz errors
+#
+# $(call colorize-dot-errors,<log file>)
+define colorize-dot-errors
+$(SED) \
+-e '/^Error:/,/context:/s/.*/$(C_ERROR)&$(C_RESET)/p' \
+-e 's/^Warning:.*/$(C_WARNING)&$(C_RESET)/p' \
+-e 'd' \
+'$1'
+endef
+
+# Get all important .aux files from the top-level .aux file and merges them all
+# into a single file, which it outputs to stdout.
+#
+# $(call flatten-aux,<toplevel aux>,<output file>)
+define flatten-aux
+$(SED) \
+-e '/\\@input{\(.*\)}/{' \
+-e     's//\1/' \
+-e     's![.:]!\\&!g' \
+-e     'h' \
+-e     's!.*!\\:\\\\@input{&}:{!' \
+-e     'p' \
+-e     'x' \
+-e     's/\\././g' \
+-e     's/.*/r &/p' \
+-e     's/.*/d/p' \
+-e     's/.*/}/p' \
+-e     'd' \
+-e '}' \
+-e 'd' \
+'$1' > "$1.$$$$.sed.make"; \
+$(SED) -f "$1.$$$$.sed.make" '$1' > "$1.$$$$.make"; \
+$(SED) \
+-e '/^\\relax/d' \
+-e '/^\\bibcite/d' \
+-e 's/^\(\\newlabel{[^}]\{1,\}}\).*/\1/' \
+"$1.$$$$.make" | $(SORT) > '$2'; \
+$(call remove-temporary-files,$1.$$$$.make $1.$$$$.sed.make)
+endef
+
+# Generate pdf from postscript
+#
+# Note that we don't just call ps2pdf, since there are so many versions of that
+# script on various systems.  Instead, we call the postscript interpreter
+# directly.
+#
+# $(call ps2pdf,infile,outfile,[embed fonts])
+define ps2pdf
+	$(GS) \
+		-dSAFER -dCompatibilityLevel=$(PS_COMPATIBILITY) \
+		$(if $3,$(PS_EMBED_OPTIONS)) \
+		-q -dNOPAUSE -dBATCH \
+		-sDEVICE=pdfwrite -sstdout=%stderr \
+		'-sOutputFile=$2' \
+		-dSAFER -dCompatibilityLevel=$(PS_COMPATIBILITY) \
+		$(if $3,$(PS_EMBED_OPTIONS)) \
+		-c .setpdfwrite \
+		-f '$1'
+endef
+
+# Colorize LaTeX output.
+# This uses a neat trick from the Sed & Awk Book from O'Reilly:
+# 1) If a line has a single ending paren, delete it to make a blank line (so
+#	that we catch the first error, which is not always preceded by a blank
+#	line).
+# 2) Ensure that the last line of the file gets appended to the hold buffer,
+# 	and blank it out to trigger end-of-paragraph logic below.
+# 3) When encountering a blank line (LaTeX output helpfully breaks output on
+# 	newlines)
+# 	a) swap the hold buffer (containing the paragraph) into the pattern buffer (putting a blank line into the hold buffer),
+# 	b) remove the newline at the beginning (don't ask),
+# 	c) apply any colorizing substitutions necessary to ensure happiness.
+# 	d) get the newline out of the hold buffer and append it
+# 	e) profit! (print)
+# 4) Anything not colorized is deleted, unless in verbose mode.
+color_tex	:= \
+	$(SED) \
+	-e '$${' \
+	-e '  /^$$/!{' \
+	-e '    H' \
+	-e '    s/.*//' \
+	-e '  }' \
+	-e '}' \
+	-e '/^$$/!{' \
+	-e '  H' \
+	-e '  d' \
+	-e '}' \
+	-e '/^$$/{' \
+	-e '  x' \
+	-e '  s/^\n//' \
+	-e '  /Output written on /{' \
+	-e '    s/.*Output written on \([^(]*\) (\([^)]\{1,\}\)).*/Success!  Wrote \2 to \1/' \
+	-e '    s/[[:digit:]]\{1,\}/$(C_PAGES)&$(C_RESET)/g' \
+	-e '    s/Success!/$(C_SUCCESS)&$(C_RESET)/g' \
+	-e '    s/to \(.*\)$$/to $(C_SUCCESS)\1$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	-e '  / *LaTeX Error:.*/{' \
+	-e '    s/.*\( *LaTeX Error:.*\)/$(C_ERROR)\1$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	-e '  /.*Warning:.*/{' \
+	-e '    s//$(C_WARNING)&$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	-e '  /Underfull.*/{' \
+	-e '    s/.*\(Underfull.*\)/$(C_UNDERFULL)\1$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	-e '  /Overfull.*/{' \
+	-e '    s/.*\(Overfull.*\)/$(C_OVERFULL)\1$(C_RESET)/' \
+	-e '    b end' \
+	-e '  }' \
+	$(if $(VERBOSE),,-e '  d') \
+	-e '  :end' \
+	-e '  G' \
+	-e '}' \
+
+# Colorize BibTeX output.
+color_bib	:= \
+	$(SED) \
+	-e 's/^Warning--.*/$(C_WARNING)&$(C_RESET)/' -e 't' \
+	-e '/---/,/^.[^:]/{' \
+	-e '  H' \
+	-e '  /^.[^:]/{' \
+	-e '    x' \
+	-e '    s/\n\(.*\)/$(C_ERROR)\1$(C_RESET)/' \
+	-e '	p' \
+	-e '    s/.*//' \
+	-e '    h' \
+	-e '    d' \
+	-e '  }' \
+	-e '  d' \
+	-e '}' \
+	-e '/(.*error.*)/s//$(C_ERROR)&$(C_RESET)/' \
+	$(if $(VERBOSE),,-e 'd')
+
+
+# Make beamer output big enough to print on a full page.  Landscape doesn't
+# seem to work correctly.
+enlarge_beamer	= $(PSNUP) -l -1 -W128mm -H96mm -pletter
+
+# $(call test-run-again,<source stem>)
+test-run-again	= $(EGREP) -q '^(.*Rerun .*|No file $1\.[^.]+\.)$$' $1.log
+
+# This tests whether the build target commands should be run at all, from
+# viewing the log file.
+# $(call test-log-for-need-to-run,<source stem>)
+define test-log-for-need-to-run
+$(SED) \
+-e '/^No file $(call escape-dots,$1)\.aux\./d' \
+$1.log \
+| $(EGREP) -q '^(.*Rerun .*|No file $1\.[^.]+\.|No file .+\.tex\.|LaTeX Warning: File.*)$$'
+endef
+
+# LaTeX invocations
+#
+# $(call latex,<tex file>,[<extra LaTeX args>])
+run-latex	= $(latex_build_program) --interaction=batchmode $(if $2,$2,) $1 > /dev/null
+
+# $(call latex-color-log,<LaTeX stem>)
+latex-color-log	= $(color_tex) $1.log
+
+# $(call run-makeindex,<input>,<output>,<log>,<extra flags>)
+define run-makeindex
+success=1; \
+if ! $(MAKEINDEX) -q $1 -t $3 -o $2 $4 > /dev/null || $(EGREP) -q '^!!' $3; then \
+	$(call colorize-makeindex-errors,$3); \
+	$(RM) -f '$2'; \
+	success=0; \
+fi; \
+[ "$$success" = "1" ] && $(sh_true) || $(sh_false);
+endef
+
+# This runs the given script to generate output, and it uses MAKE_RESTARTS to
+# ensure that it never runs it more than once for a particular root make
+# invocation.
+#
+# $(call run-script,<interpreter>,<input>,<output>)
+define run-script
+[ ! -e '$2.cookie' ] && $(ECHO) "restarts=$(RESTARTS)" > $2.cookie && $(ECHO) "level=$(MAKELEVEL)" >> $2.cookie; \
+restarts=`$(SED) -n -e 's/^restarts=//p' $2.cookie`; \
+level=`$(SED) -n -e 's/^level=//p' $2.cookie`; \
+if $(EXPR) $(MAKELEVEL) '<=' $$level '&' $(RESTARTS) '<=' $$restarts >/dev/null; then \
+	$(call echo-build,$2,$3,$(RESTARTS)-$(MAKELEVEL)); \
+	$1 '$2' '$3'; \
+	$(ECHO) "restarts=$(RESTARTS)" > '$2.cookie'; \
+	$(ECHO) "level=$(MAKELEVEL)" >> '$2.cookie'; \
+fi
+endef
+
+# BibTeX invocations
+#
+# $(call run-bibtex,<tex stem>)
+run-bibtex	= $(BIBTEX) $1 | $(color_bib)
+
+
+# $(call convert-eps-to-pdf,<eps file>,<pdf file>,[gray])
+# Note that we don't use the --filter flag because it has trouble with bounding boxes that way.
+define convert-eps-to-pdf
+$(if $3,$(CAT) '$1' | $(call kill-ps-color) > '$1.cookie',$(CP) '$1' '$1.cookie'); \
+$(EPSTOPDF) '$1.cookie' --outfile='$2' > $1.log; \
+$(call colorize-epstopdf-errors,$1.log);
+endef
+
+# $(call convert-gpi,<gpi file>,<output file>,[gray])
+#
+define convert-gpi
+$(ECHO) 'set terminal $(if $(filter %.pdf,$2),pdf enhanced,postscript enhanced eps)' \
+$(if $(filter %.pdf,$2),fsize ,)$(call get-default,$(strip \
+$(firstword \
+	$(shell \
+		$(SED) \
+			-e 's/^\#\#FONTSIZE=\([[:digit:]]\{1,\}\)/\1/p' \
+			-e 'd' \
+			$1 $(strip $(gpi_global)) \
+	) \
+) \
+),$(if $(filter %.pdf,$2),$(DEFAULT_GPI_PDF_FONTSIZE),$(DEFAULT_GPI_EPS_FONTSIZE))) \
+$(strip $(if $3,monochrome,$(if \
+$(shell $(EGREP) '^\#\#[[:space:]]*GRAY[[:space:]]*$$' $< $(gpi_global)),\
+,color))) > $1head.make; \
+$(ECHO) 'set output "$2"' >> $1head.make; \
+$(if $(gpi_global),$(CAT) $(gpi_global) >> $1head.make;,) \
+fnames='$1head.make $1';\
+$(if $(gpi_sed),\
+	$(SED) -f '$(gpi_sed)' $$fnames > $1.temp.make; \
+	fnames=$1.temp.make;,\
+) \
+success=1; \
+if ! $(GNUPLOT) $$fnames 2>$1.log; then \
+	$(call colorize-gnuplot-errors,$1.log); \
+	success=0; \
+fi; \
+$(if $(gpi_sed),$(call remove-temporary-files,$1.temp.make);,) \
+$(call remove-temporary-files,$1head.make); \
+[ "$$success" = "1" ] && $(sh_true) || $(sh_false);
+endef
+
+# Creation of .eps files from .png files
+#
+# The intermediate step of PNM (using NetPBM) produces much nicer output than
+# ImageMagick's "convert" binary.  I couldn't get the right combination of
+# flags to make it look nice, anyway.
+#
+# To handle gray scale conversion, we pipe things through ppmtopgm in the
+# middle.
+#
+# $(call convert-png,<png file>,<eps file>)
+define convert-png
+$(PNGTOPNM) "$1" \
+	$(if $3,| $(PPMTOPGM),) \
+	| $(PNMTOPS) -noturn \
+	> "$2"
+endef
+
+# Creation of .eps files from .jpg files
+#
+# Thanks to brubakee for this solution.
+#
+# Uses Postscript level 2 to avoid file size bloat
+# $(call convert-jpg,<jpg file>,<eps file>)
+define convert-jpg
+$(CONVERT) $(if $3,-type Grayscale,) '$1' eps2:'$2'
+endef
+
+# Creation of .eps files from .fig files
+# $(call convert-fig,<fig file>,<output file>,[gray])
+convert-fig	= $(FIG2DEV) -L $(if $(filter %.pdf,$2),pdf,eps) $(if $3,-N,) $1 $2
+
+# Creation of .pstex files from .fig files
+# $(call convert-fig-pstex,<fig file>,<pstex file>)
+convert-fig-pstex	= $(FIG2DEV) -L pstex $1 $2 > /dev/null 2>&1
+
+# Creation of .pstex_t files from .fig files
+# $(call convert-fig-pstex-t,<fig file>,<pstex file>,<pstex_t file>)
+convert-fig-pstex-t	= $(FIG2DEV) -L pstex_t -p $3 $1 $2 > /dev/null 2>&1
+
+# Creation of .dot_t files from .dot files
+# #(call convert-dot-tex,<dot file>,<dot_t file>)
+convert-dot-tex		= $(DOT2TEX) '$1' > '$2'
+
+# Converts svg files into .eps files
+#
+# $(call convert-svg,<svg file>,<eps file>,[gray])
+convert-svg	= $(INKSCAPE) --export-eps='$2' '$1'
+
+# Converts xvg files into .eps files
+#
+# $(call convert-xvg,<xvg file>,<eps file>,[gray])
+convert-xvg	= $(XMGRACE) '$1' -printfile - -hardcopy -hdevice $(if $3,-mono,) EPS > '$2'
+
+# Converts .eps.gz files into .eps files
+#
+# $(call convert-epsgz,<eps.gz file>,<eps file>,[gray])
+convert-epsgz	= $(GUNZIP) -c '$1' $(if $3,| $(call kill-ps-color)) > '$2'
+
+# Converts .eps files into .eps files (usually a no-op, but can make grayscale)
+#
+# $(call convert-eps,<in file>,<out file>,[gray])
+convert-eps	= $(if $3,$(call kill-ps-color) $1 > $2)
+
+# The name of the file containing special postscript commands for grayscale
+gray_eps_file	:= gray.eps.make
+
+# Changes sethsbcolor and setrgbcolor calls in postscript to always produce
+# grayscale.  In general, this is accomplished by writing new versions of those
+# functions into the user dictionary space, which is looked up before the
+# global or system dictionaries (userdict is one of the permanent dictionaries
+# in postscript and is not read-only like systemdict).
+#
+# For setrgbcolor, the weighted average of the triple is computed and the
+# triple is replaced with three copies of that average before the original
+# procedure is called: .299R + .587G + .114B
+#
+# For sethsbcolor, the color is first converted to RGB, then to grayscale by
+# the new setrgbcolor operator as described above.  Why is this done?
+# Because simply using the value component will tend to make pure colors
+# white, a very undesirable thing.  Pure blue should not translate to white,
+# but to some level of gray.  Conversion to RGB does the right thing.  It's
+# messy, but it works.
+#
+# From
+# http://en.wikipedia.org/wiki/HSV_color_space#Transformation_from_HSV_to_RGB,
+# HSB = HSV (Value = Brightness), and the formula used to convert to RGB is
+# as follows:
+#
+# Hi = int(floor(6 * H)) mod 6
+# f = 6 * H - Hi
+# p = V(1-S)
+# q = V(1-fS)
+# t = V(1-(1-f)S)
+# if Hi = 0: R G B <-- V t p
+# if Hi = 1: R G B <-- q V p
+# if Hi = 2: R G B <-- p V t
+# if Hi = 3: R G B <-- p q V
+# if Hi = 4: R G B <-- t p V
+# if Hi = 5: R G B <-- V p q
+#
+# The messy stack-based implementation is below
+# $(call create-gray-eps-file,filename)
+define create-gray-eps-file
+$(ECHO) -n -e '\
+/OLDRGB /setrgbcolor load def\n\
+/setrgbcolor {\n\
+    .114 mul exch\n\
+    .587 mul add exch\n\
+    .299 mul add\n\
+    dup dup\n\
+    OLDRGB\n\
+} bind def\n\
+/OLDHSB /sethsbcolor load def\n\
+/sethsbcolor {\n\
+    2 index                     % H V S H\n\
+    6 mul floor cvi 6 mod       % Hi V S H\n\
+    3 index                     % H Hi V S H\n\
+    6 mul                       % 6H Hi V S H\n\
+    1 index                     % Hi 6H Hi V S H\n\
+    sub                         % f Hi V S H\n\
+    2 index 1                   % 1 V f Hi V S H\n\
+    4 index                     % S 1 V f Hi V S H\n\
+    sub mul                     % p f Hi V S H\n\
+    3 index 1                   % 1 V p f Hi V S H\n\
+    6 index                     % S 1 V p f Hi V S H\n\
+    4 index                     % f S 1 V p f Hi V S H\n\
+    mul sub mul                 % q p f Hi V S H\n\
+    4 index 1 1                 % 1 1 V q p f Hi V S H\n\
+    5 index                     % f 1 1 V q p f Hi V S H\n\
+    sub                         % (1-f) 1 V q p f Hi V S H\n\
+    8 index                     % S (1-f) 1 V q p f Hi V S H\n\
+    mul sub mul                 % t q p f Hi V S H\n\
+    4 -1 roll pop               % t q p Hi V S H\n\
+    7 -2 roll pop pop           % t q p Hi V\n\
+    5 -2 roll                   % Hi V t q p\n\
+    dup 0 eq\n\
+    {1 index 3 index 6 index}\n\
+    {\n\
+        dup 1 eq\n\
+        {3 index 2 index 6 index}\n\
+        {\n\
+            dup 2 eq\n\
+            {4 index 2 index 4 index}\n\
+            {\n\
+                dup 3 eq\n\
+                {4 index 4 index 3 index}\n\
+                {\n\
+                    dup 4 eq\n\
+                    {2 index 5 index 3 index}\n\
+                    {\n\
+                        dup 5 eq\n\
+                        {1 index 5 index 5 index}\n\
+                        {0 0 0}\n\
+                        ifelse\n\
+                    }\n\
+                    ifelse\n\
+                }\n\
+                ifelse\n\
+            }\n\
+            ifelse\n\
+        }\n\
+        ifelse\n\
+    }\n\
+    ifelse                      % B G R Hi V t q p\n\
+    setrgbcolor\n\
+    5 {pop} repeat\n\
+} bind def\n'\
+> $1
+endef
+
+# This actually inserts the color-killing code into a postscript file
+# $(call kill-ps-color)
+define kill-ps-color
+$(SED) -e '/%%EndComments/r $(gray_eps_file)'
+endef
+
+# Converts graphviz .dot files into .eps files
+# Grayscale is not directly supported by dot, so we pipe it through fig2dev in
+# that case.
+# $(call convert-dot,<dot file>,<eps file>,<log file>,[gray])
+define convert-dot
+$(DOT) -Tps '$1' 2>'$3' $(if $4,| $(call kill-ps-color)) > $2; \
+$(call colorize-dot-errors,$3)
+endef
+
+# Convert DVI to Postscript
+# $(call make-ps,<dvi file>,<ps file>,<log file>,[<paper size>])
+make-ps		= \
+	$(DVIPS) -o '$2' $(if $(filter-out BEAMER,$4),-t$(firstword $4),) '$1' \
+		$(if $(filter BEAMER,$4),| $(enlarge_beamer)) > $3 2>&1
+
+# Convert Postscript to PDF
+# $(call make-pdf,<ps file>,<pdf file>,<log file>,<embed file>)
+make-pdf	= \
+	$(call ps2pdf,$1,$2,$(filter 1,$(shell $(CAT) '$4'))) > '$3' 2>&1
+
+# Display information about what is being done
+# $(call echo-build,<input file>,<output file>,[<run number>])
+echo-build	= $(ECHO) "$(C_BUILD)= $1 --> $2$(if $3, ($3),) =$(C_RESET)"
+echo-graphic	= $(ECHO) "$(C_GRAPHIC)= $1 --> $2 =$(C_RESET)"
+echo-dep	= $(ECHO) "$(C_DEP)= $1 --> $2 =$(C_RESET)"
+
+# Display a list of something
+# $(call echo-list,<values>)
+echo-list	= for x in $1; do $(ECHO) "$$x"; done
+
+#
+# DEFAULT TARGET
+#
+
+.PHONY: all
+all: $(default_pdf_targets) ;
+
+.PHONY: all-pdf
+all-pdf: $(default_pdf_targets) ;
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+.PHONY: all-ps
+all-ps: $(default_ps_targets) ;
+
+.PHONY: all-dvi
+all-dvi: $(default_dvi_targets) ;
+endif
+
+#
+# VIEWING TARGET
+#
+.PHONY: show
+show: all
+	$(QUIET)for x in $(default_pdf_targets); do \
+		[ -e "$$x" ] && $(VIEW_PDF) $$x & \
+	done
+
+#
+# INCLUDES
+#
+source_includes	:= $(addsuffix .d,$(source_stems_to_include))
+graphic_includes := $(addsuffix .gpi.d,$(graphic_stems_to_include))
+
+# Include only the dependencies used
+ifneq "" "$(source_includes)"
+include $(source_includes)$(call include-message,$(source_includes))
+endif
+ifneq "" "$(graphic_includes)"
+include $(graphic_includes)$(call include-message,$(graphic_includes))
+endif
+
+#
+# MAIN TARGETS
+#
+
+# Note that we don't just say %: %.pdf here - this can tend to mess up our
+# includes, which detect what kind of file we are asking for.  For example,
+# asking to build foo.pdf is much different than asking to build foo when
+# foo.gpi exists, because we look through all of the goals for *.pdf that
+# matches *.gpi, then use that to determine which include files we need to
+# build.
+#
+# Thus, we invoke make recursively with better arugments instead, restarting
+# all of the appropriate machinery.
+.PHONY: $(default_stems_ss)
+$(default_stems_ss): %: %.pdf ;
+
+# This builds and displays the wanted file.
+.PHONY: $(addsuffix ._show,$(stems_ssg))
+%._show: %.pdf
+	$(QUIET)$(VIEW_PDF) $< &
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+.SECONDARY: $(all_pdf_targets)
+%.pdf: %.ps %.embed.make
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call make-pdf,$<,$@.temp,$@.log,$*.embed.make); \
+	if [ x"$$?" = x"0" ]; then \
+	    $(if $(VERBOSE),$(CAT) $@.log,:); \
+	    $(RM) -f '$@'; \
+	    $(MV) '$@.temp' '$@'; \
+	    $(TOUCH) '$@'; \
+	    $(call copy-with-logging,$@,$(BINARY_TARGET_DIR)); \
+	else \
+	    $(CAT) $@.log; \
+	    $(call remove-temporary-files,'$@.temp'); \
+	    $(sh_false); \
+	fi
+
+.SECONDARY: $(all_ps_targets)
+%.ps: %.dvi %.paper.make
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call make-ps,$<,$@.temp,$@.log,\
+			$(firstword $(shell $(CAT) $*.paper.make))); \
+	if [ x"$$?" = x"0" ]; then \
+	    $(if $(VERBOSE),$(CAT) $@.log,:); \
+	    $(RM) -f '$@'; \
+	    $(MV) '$@.temp' '$@'; \
+	    $(TOUCH) '$@'; \
+	    $(call copy-with-logging,$@,$(BINARY_TARGET_DIR)); \
+	else \
+	    $(CAT) $@.log; \
+	    $(call remove-temporary-files,'$@.temp'); \
+	    $(sh_false); \
+	fi
+endif
+
+# Build the final target (dvi or pdf) file.  This is a very tricky rule because
+# of the way that latex runs multiple times, needs graphics after the first run
+# (or maybe already has them), and relies on bibliographies or indices that may
+# not exist.
+#
+#	Check the log for fatal errors.  If they exist, colorize and bail.
+#
+#	Create the .auxtarget.cookie file.  (Needed for next time if not present)
+#
+#	If any of the following are true, we must rebuild at least one time:
+#
+#	* the .bbl was recently rebuilt
+#
+#		check a cookie, then delete it
+#
+#	* any of several output files was created or changed:
+#
+#		check $*.run.cookie, then delete it
+#
+#	* the .aux file changed in a way that necessitates attention
+#
+#		Note that if the .auxtarget.make file doesn't exist, this means
+#		that we are doing a clean build, so it doesn't figure into the
+#		test for running again.
+#
+#		compare against .auxtarget.make
+#
+#		move if different, remove if not
+#
+#	* the .log file has errors or warnings requiring at least one more run
+#
+#	We use a loop over a single item to simplify the process of breaking
+#	out when we find one of the conditions to be true.
+#
+#	If we do NOT need to run latex here, then we move the $@.1st.make file
+#	over to $@ because the target file has already been built by the first
+#	dependency run and is valid.
+#
+#	If we do, we delete that cookie file and do the normal multiple-runs
+#	routine.
+#
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+.SECONDARY: $(all_dvi_targets)
+endif
+%.$(build_target_extension): %.bbl %.aux %.$(build_target_extension).1st.make
+	$(QUIET)\
+	fatal=`$(call colorize-latex-errors,$*.log)`; \
+	if [ x"$$fatal" != x"" ]; then \
+		$(ECHO) "$$fatal"; \
+		exit 1; \
+	fi; \
+	$(call make-auxtarget-file,$*.aux.make,$*.auxtarget.cookie); \
+	run=0; \
+	for i in 1; do \
+		if $(call test-exists,$*.bbl.cookie); then \
+			run=1; \
+			break; \
+		fi; \
+		if $(call test-exists,$*.run.cookie); then \
+			run=1; \
+		    	break; \
+		fi; \
+		if $(call \
+		test-exists-and-different,$*.auxtarget.cookie,$*.auxtarget.make);\
+		then \
+			run=1; \
+			break; \
+		fi; \
+		if $(call test-log-for-need-to-run,$*); then \
+			run=1; \
+			break; \
+		fi; \
+	done; \
+	$(call remove-temporary-files,$*.bbl.cookie $*.run.cookie); \
+	$(MV) $*.auxtarget.cookie $*.auxtarget.make; \
+	if [ x"$$run" = x"1" ]; then \
+		$(call remove-files,$@.1st.make); \
+		for i in 2 3 4 5; do \
+			$(if $(findstring 3.79,$(MAKE_VERSION)),\
+				$(call echo-build,$*.tex,$@,$(RESTARTS)-$$$$i),\
+				$(call echo-build,$*.tex,$@,$(RESTARTS)-$$i)\
+			); \
+			$(call run-latex,$*); \
+			$(CP) '$*.log' '$*.'$(RESTARTS)-$$i'.log'; \
+			$(call test-run-again,$*) || break; \
+		done; \
+	else \
+		$(MV) '$@.1st.make' '$@'; \
+	fi; \
+	$(call copy-with-logging,$@,$(BINARY_TARGET_DIR)); \
+	$(call latex-color-log,$*)
+
+# Build the .bbl file.  When dependencies are included, this will (or will
+# not!) depend on something.bib, which we detect, acting accordingly.  The
+# dependency creation also produces the %.auxbbl.make file.  BibTeX is a bit
+# finicky about what you call the actual files, but we can rest assured that if
+# a .auxbbl.make file exists, then the .aux file does, as well.  The
+# .auxbbl.make file is a cookie indicating whether the .bbl needs to be
+# rewritten.  It only changes if the .aux file changes in ways relevant to .bbl
+# creation.
+#
+# Note that we do NOT touch the .bbl file if there is no need to
+# create/recreate it.  We would like to leave existing files alone if they
+# don't need to be changed, thus possibly avoiding a rebuild trigger.
+%.bbl: %.auxbbl.make
+	$(QUIET)\
+	$(if $(filter %.bib,$^),\
+		$(call echo-build,$(filter %.bib,$?) $*.aux,$@); \
+		$(call run-bibtex,$*); \
+		$(TOUCH) $@.cookie; \
+	) \
+	if $(EGREP) -q 'bibstyle.(apacann|chcagoa|[^}]*annot)' '$*.aux'; then \
+		$(call echo-build,** annotated extra latex **,output ignored,$(RESTARTS)-1); \
+		$(call run-latex,$*); \
+		$(CP) '$*.log' '$*.$(RESTARTS)-annotated.log'; \
+		$(if $(filter %.bib,$^),\
+			$(call echo-build,** annotated extra bibtex ** $(filter %.bib,$?) $*.aux,$@); \
+			$(call run-bibtex,$*); \
+			$(TOUCH) $@.cookie; \
+		) \
+		$(call echo-build,** annotated extra latex **,output ignored,$(RESTARTS)-2); \
+		$(call run-latex,$*); \
+	fi
+
+# Create the index file - note that we do *not* depend on %.tex here, since
+# that unnecessarily restricts the kinds of indices that we can build to those
+# with exactly the same stem as the source file.  Things like splitidx create
+# idx files with other names.
+#
+# Therefore, we add the .tex dependency in the sourcestem.d file in the call to
+# get index file dependencies from the logs.
+%.ind:	%.idx
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call run-makeindex,$<,$@,$*.ilg)
+
+# Create the glossary file
+%.gls:	%.glo %.tex
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call run-makeindex,$<,$@,$*.glg,-s nomencl.ist)
+
+# Create the nomenclature file
+%.nls:	%.nlo %.tex
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call run-makeindex,$<,$@,$*.nlg,-s nomencl.ist)
+
+# SCRIPTED LaTeX TARGETS
+#
+# Keep the generated .tex files around for debugging if needed.
+.SECONDARY: $(all_tex_targets)
+
+%.tex::	%.tex.sh
+	$(QUIET)$(call run-script,$(SHELL),$<,$@)
+
+%.tex::	%.tex.py
+	$(QUIET)$(call run-script,$(PYTHON),$<,$@)
+
+%.tex::	%.tex.pl
+	$(QUIET)$(call run-script,$(PERL),$<,$@)
+
+%.tex::	%.rst $(RST_STYLE_FILE)
+	$(QUIET)\
+	$(call run-script,$(RST2LATEX)\
+		--documentoptions=letterpaper\
+		$(if $(RST_STYLE_FILE),--stylesheet=$(RST_STYLE_FILE),),$<,$@)
+
+#
+# GRAPHICS TARGETS
+#
+.PHONY: all-graphics
+all-graphics:	$(all_graphics_targets);
+
+ifneq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+.PHONY: all-pstex
+all-pstex:	$(all_pstex_targets);
+endif
+
+.PHONY: all-dot2tex
+all-dot2tex:	$(all_dot2tex_targets);
+
+.PHONY: show-graphics
+show-graphics: all-graphics
+	$(VIEW_GRAPHICS) $(all_known_graphics)
+
+$(gray_eps_file):
+	$(QUIET)$(call echo-build,$^,$@)
+	$(QUIET)$(call create-gray-eps-file,$@)
+
+ifeq "$(strip $(BUILD_STRATEGY))" "pdflatex"
+%.pdf: %.eps $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-eps-to-pdf,$<,$@,$(GRAY))
+
+ifeq "$(strip $(GNUPLOT_OUTPUT_EXTENSION))" "pdf"
+%.pdf:	%.gpi %.gpi.d $(gpi_sed)
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-gpi,$<,$@,$(GRAY))
+endif
+
+%.pdf:	%.fig
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-fig,$<,$@,$(GRAY))
+
+endif
+
+%.eps:	%.gpi %.gpi.d $(gpi_sed)
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-gpi,$<,$@,$(GRAY))
+
+%.eps: %.fig
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-fig,$<,$@,$(GRAY))
+
+%.eps: %.dot $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-dot,$<,$@,$<.log,$(GRAY))
+
+%.eps: %.xvg $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-xvg,$<,$@,$(GRAY))
+
+%.eps: %.svg $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-svg,$<,$@,$(GRAY))
+
+%.eps: %.jpg $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-jpg,$<,$@,$(GRAY))
+
+%.eps: %.png $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-png,$<,$@,$(GRAY))
+
+%.eps: %.eps.gz $(if $(GRAY),$(gray_eps_file))
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-epsgz,$<,$@,$(GRAY))
+
+%.pstex: %.fig
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-fig-pstex,$<,$@,$(GRAY))
+
+%.pstex_t: %.fig %.pstex
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-fig-pstex-t,$<,$@,$*.pstex,$(GRAY))
+
+%.dot_t: %.dot
+	$(QUIET)$(call echo-graphic,$^,$@)
+	$(QUIET)$(call convert-dot-tex,$<,$@)
+
+#
+# DEPENDENCY-RELATED TARGETS.
+#
+
+# Generate all of the information needed to get dependencies
+# As a side effect, this creates a .dvi or .pdf file (depending on the build
+# strategy).  We need to be sure to remove it if there are errors.  Errors can
+# take several forms and all of them are found within the log file:
+#	* There was a LaTeX error
+#	* A needed file was not found
+#	* Cross references need adjustment
+#
+# Behavior:
+#	This rule is responsible for generating the following:
+#	%.aux
+#	%.d
+#	%.aux.make
+#	%.(pdf|dvi).1st.make (the .pdf or .dvi output file, moved)
+#
+#	Steps:
+#
+#	Run latex
+#	Move .pdf or .dvi somewhere else (make no judgements about success)
+#	Flatten the .aux file into another file
+#	Add source dependencies
+#	Add graphic dependencies
+#	Add bib dependencies
+#
+#	Create cookies for various suffixes that may represent files that
+#	need to be read by LaTeX in order for it to function properly.
+#
+#	Note that if some of the dependencies are discovered because they turn
+#	up missing in the log file, we really need the .d file to be reloaded.
+#	Adding a sleep command helps with this.  Otherwise make is extremely
+#	nondeterministic, sometimes working, sometimes not.
+#
+#	Usually we can force this by simply removing the generated pdf file and
+#	not creating a .1st.make file..
+#
+%.$(build_target_extension).1st.make %.d %.aux %.aux.make %.fls: %.tex
+	$(QUIET)$(call echo-build,$<,$*.d $*.$(build_target_extension).1st.make,$(RESTARTS)-1)
+	$(QUIET)\
+	$(call run-latex,$<,--recorder) || $(sh_true); \
+	$(CP) '$*.log' '$*.$(RESTARTS)-1.log'; \
+	$(call die-on-dot2tex,$*.log); \
+	$(call die-on-no-aux,$*); \
+	$(call flatten-aux,$*.aux,$*.aux.make); \
+	$(ECHO) "# vim: ft=make" > $*.d; \
+	$(ECHO) ".PHONY: $*._graphics" >> $*.d; \
+	$(call get-inputs,$*.fls,$(addprefix $*.,aux aux.make d $(build_target_extension))) >> $*.d; \
+	$(call get-missing-inputs,$*.log,$(addprefix $*.,aux aux.make d $(build_target_extension))) >> $*.d; \
+	$(ECHO) ".SECONDEXPANSION:" >> $*.d; \
+	$(call get-graphics,$*) >> $*.d; \
+	$(call get-log-index,$*,$(addprefix $*.,d aux aux.make)) >> $*.d; \
+	$(call get-bibs,$*.aux.make,$(addprefix $*.,bbl aux aux.make)) >> $*.d; \
+	$(EGREP) -q "# MISSING" $*.d && $(SLEEP) 1 && $(RM) $*.pdf; \
+	$(call move-if-exists,$*.$(build_target_extension),$*.$(build_target_extension).1st.make); \
+	for s in toc out lot lof lol nav; do \
+		if [ -e "$*.$$s" ]; then \
+			if ! $(DIFF) -q $*.$$s $*.$$s.make >/dev/null 2>&1; then \
+				$(TOUCH) $*.run.cookie; \
+			fi; \
+			$(CP) $*.$$s $*.$$s.make; \
+		fi; \
+	done
+
+# This is a cookie that is updated if the flattened aux file has changed in a
+# way that affects the bibliography generation.
+.SECONDARY: $(addsuffix .auxbbl.make,$(stems_ssg))
+%.auxbbl.make: %.aux.make
+	$(QUIET)\
+	$(call make-auxbbl-file,$<,$@.temp); \
+	$(call replace-if-different-and-remove,$@.temp,$@)
+
+# Build a dependency file for .gpi files.  These often plot data files that
+# also reside in the directory, so if a data file changes, it's nice to know
+# about it.  This also handles loaded .gpi files, whose filename should have
+# _include_. in it.
+%.gpi.d: %.gpi
+	$(QUIET)$(call echo-build,$<,$@)
+	$(QUIET)$(call make-gpi-d,$<,$@)
+
+# Store the paper size for this document -- note that if beamer is used we set
+# it to the special BEAMER paper size.  We only do this, however, if the
+# special comment exists, in which case we enlarge the output with psnup.
+#
+#	The paper size is extracted from a documentclass attribute.
+%.paper.make: %.tex
+	$(QUIET)$(SED) \
+	-e '/\\documentclass/,/}/{' \
+	-e '  s/%.*//' \
+	-e '  H' \
+	-e '  /}/{' \
+	-e '    s/.*//' \
+	-e '    x' \
+	-e '    /\\documentclass/!d' \
+	-e '    s/[\n[:space:]]*//g' \
+	-e '    s/\([,{[]\)\([[:alnum:]]\{1,\}\)paper\([],}]\)/\1%-\2-%\3/g' \
+	-e '    s/\([,{[]\)\(landscape\)\([],}]\)/\1%-\2-%\3/g' \
+	-e '    s/^[^%]*%-//' \
+	-e '    s/-%[^%]*$$//' \
+	-e '    s/-%[^%]%-/ /g' \
+	-e '    p' \
+	-e '  }' \
+	-e '  d' \
+	-e '}' \
+	-e 'd' \
+	$< > $@; \
+	$(EGREP) -q '^[^%]*\\documentclass[^{]*{beamer}' $< && \
+	(\
+		$(EGREP) -q '^%%[[:space:]]*BEAMER[[:space:]]*LARGE$$' $< && \
+		$(ECHO) "BEAMER" > $@ || \
+		: > $@ \
+	) || $(sh_true)
+
+# Store embedding instructions for this document using a special comment
+%.embed.make: %.tex
+	$(QUIET)$(EGREP) '^%%[[:space:]]*NO[[:space:]]*EMBED[[:space:]]*$$' $< \
+		&& $(ECHO) '' > $@ \
+		|| $(ECHO) '1' > $@;
+
+#
+# HELPFUL PHONY TARGETS
+#
+
+.PHONY: _all_programs
+_all_programs:
+	$(QUIET)$(ECHO) "== All External Programs Used =="
+	$(QUIET)$(call output-all-programs)
+
+.PHONY: _check_programs
+_check_programs:
+	$(QUIET)$(ECHO) "== Checking Makefile Dependencies =="; $(ECHO)
+	$(QUIET) \
+	$(ECHO) hi; \
+	allprogs=`\
+	 ($(call output-all-programs)) | \
+	 $(SED) \
+	 -e 's/^[[:space:]]*//' \
+	 -e '/^#/d' \
+	 -e 's/[[:space:]]*#.*//' \
+	 -e '/^=/s/[[:space:]]/_/g' \
+	 -e '/^[[:space:]]*$$/d' \
+	 -e 's/^[^=].*=[[:space:]]*\([^[:space:]]\{1,\}\).*$$/\\1/' \
+	 `; \
+	spaces='                             '; \
+	for p in $${allprogs}; do \
+	case $$p in \
+		=*) $(ECHO); $(ECHO) "$$p";; \
+		*) \
+			$(ECHO) -n "$$p:$$spaces" | $(SED) -e 's/^\(.\{0,20\}\).*$$/\1/'; \
+			loc=`$(WHICH) $$p`; \
+			if [ x"$$?" = x"0" ]; then \
+				$(ECHO) "$(C_SUCCESS)Found:$(C_RESET) $$loc"; \
+			else \
+				$(ECHO) "$(C_FAILURE)Not Found$(C_RESET)"; \
+			fi; \
+			;; \
+	esac; \
+	done
+
+.PHONY: _check_gpi_files
+_check_gpi_files:
+	$(QUIET)$(ECHO) "== Checking all .gpi files for common errors =="; \
+	$(ECHO); \
+	for f in $(files.gpi); do \
+	result=`$(EGREP) '^([^#]*set terminal |set output )' $$f`; \
+	$(ECHO) -n "$$f: "; \
+	if [ x"$$result" = x"" ]; then \
+		$(ECHO) "$(C_SUCCESS)Okay$(C_RESET)"; \
+	else \
+		$(ECHO) "$(C_FAILURE)Warning: Problematic commands:$(C_RESET)";\
+		$(ECHO) "$(C_ERROR)$$result$(C_RESET)"; \
+	fi; \
+	done; \
+	$(ECHO)
+
+.PHONY: _all_stems
+_all_stems:
+	$(QUIET)$(ECHO) "== All Stems =="
+	$(QUIET)$(call echo-list,$(sort $(default_stems_ss)))
+
+.PHONY: _includes
+_includes:
+	$(QUIET)$(ECHO) "== Include Stems =="
+	$(QUIET)$(ECHO) "=== Sources ==="
+	$(QUIET)$(call echo-list,$(sort $(source_includes)))
+	$(QUIET)$(ECHO) "=== Graphics ==="
+	$(QUIET)$(call echo-list,$(sort $(graphic_includes)))
+
+.PHONY: _all_sources
+_all_sources:
+	$(QUIET)$(ECHO) "== All Sources =="
+	$(QUIET)$(call echo-list,$(sort $(all_files.tex)))
+
+.PHONY: _dependency_graph
+_dependency_graph:
+	$(QUIET)$(ECHO) "/* LaTeX Dependency Graph */"
+	$(QUIET)$(call output-dependency-graph)
+
+.PHONY: _show_dependency_graph
+_show_dependency_graph:
+	$(QUIET)$(call output-dependency-graph,$(graph_stem).dot)
+	$(QUIET)$(DOT) -Tps -o $(graph_stem).eps $(graph_stem).dot
+	$(QUIET)$(VIEW_POSTSCRIPT) $(graph_stem).eps
+	$(QUIET)$(call remove-temporary-files,$(graph_stem).*)
+
+.PHONY: _sources
+_sources:
+	$(QUIET)$(ECHO) "== Sources =="
+	$(QUIET)$(call echo-list,$(sort $(files.tex)))
+
+.PHONY: _scripts
+_scripts:
+	$(QUIET)$(ECHO) "== Scripts =="
+	$(QUIET)$(call echo-list,$(sort $(files_scripts)))
+
+.PHONY: _graphic_outputs
+_graphic_outputs:
+	$(QUIET)$(ECHO) "== Graphic Outputs =="
+	$(QUIET)$(call echo-list,$(sort $(all_graphics_targets)))
+
+.PHONY: _env
+_env:
+ifdef .VARIABLES
+	$(QUIET)$(ECHO) "== MAKE VARIABLES =="
+	$(QUIET)$(call echo-list,$(foreach var,$(sort $(.VARIABLES)),'$(var)'))
+endif
+	$(QUIET)$(ECHO) "== ENVIRONMENT =="
+	$(QUIET)$(ENV)
+
+#
+# CLEAN TARGETS
+#
+# clean-generated is somewhat unique - it relies on the .fls file being
+# properly built so that it can determine which of the files was generated, and
+# which was not.  Expect it to silently fail if the .fls file is missing.
+#
+# This is used to, e.g., clean up index files that are generated by the LaTeX.
+.PHONY: clean-generated
+clean-generated:
+	$(QUIET)$(call clean-files,$(foreach e,$(addsuffix .fls,$(all_stems_source)),\
+						$(shell $(call get-generated-names,$e))))
+
+.PHONY: clean-deps
+clean-deps:
+	$(QUIET)$(call clean-files,$(all_d_targets) *.make *.make.temp *.cookie)
+
+.PHONY: clean-tex
+clean-tex: clean-deps
+	$(QUIET)$(call clean-files,$(rm_tex))
+
+.PHONY: clean-graphics
+# TODO: This *always* deletes pstex files, even if they were not generated by
+# anything....  In other words, if you create a pstex and pstex_t pair by hand
+# an drop them in here without the generating fig file, they will be deleted
+# and you won't get them back.  It's a hack put in here because I'm not sure we
+# even want to keep pstex functionality, so my motivation is not terribly high
+# for doing it right.
+clean-graphics:
+	$(QUIET)$(call clean-files,$(all_graphics_targets) $(intermediate_graphics_targets) *.gpi.d *.pstex *.pstex_t *.dot_t)
+
+.PHONY: clean-backups
+clean-backups:
+	$(QUIET)$(call clean-files,$(backup_patterns) *.temp)
+
+.PHONY: clean-auxiliary
+clean-auxiliary:
+	$(QUIET)$(call clean-files,$(graph_stem).*)
+
+.PHONY: clean-nographics
+clean-nographics: clean-tex clean-deps clean-backups clean-auxiliary ;
+
+.PHONY: clean
+clean:	clean-generated clean-tex clean-graphics clean-deps clean-backups clean-auxiliary
+
+#
+# HELP TARGETS
+#
+
+.PHONY: help
+help:
+	$(help_text)
+
+.PHONY: version
+version:
+	$(QUIET)\
+	$(ECHO) "$(fileinfo) Version $(version)"; \
+	$(ECHO) "by $(author)"; \
+
+#
+# HELP TEXT
+#
+
+define help_text
+# $(fileinfo) Version $(version)
+#
+# by $(author)
+#
+# Generates a number of possible output files from a LaTeX document and its
+# various dependencies.  Handles .bib files, \include and \input, and .eps
+# graphics.  All dependencies are handled automatically by running LaTeX over
+# the source.
+#
+# USAGE:
+#
+#    make [GRAY=1] [VERBOSE=1] [SHELL_DEBUG=1] <target(s)>
+#
+# STANDARD OPTIONS:
+#    GRAY:
+#        Setting this variable forces all recompiled graphics to be grayscale.
+#        It is useful when creating a document for printing.  The default is
+#        to allow colors.  Note that it only changes graphics that need to be
+#        rebuilt!  It is usually a good idea to do a 'make clean' first.
+#
+#    VERBOSE:
+#        This turns off all @ prefixes for commands invoked by make.  Thus,
+#        you get to see all of the gory details of what is going on.
+#
+#    SHELL_DEBUG:
+#        This enables the -x option for sh, meaning that everything it does is
+#        echoed to stderr.  This is particularly useful for debugging
+#        what is going on in $$(shell ...) invocations.  One of my favorite
+#        debugging tricks is to do this:
+#
+#        make -d SHELL_DEBUG=1 VERBOSE=1 2>&1 | less
+#
+# STANDARD AUXILIARY FILES:
+#
+#      Makefile.ini
+#
+#          This file can contain variable declarations that override various
+#          aspects of the makefile.  For example, one might specify
+#
+#          neverclean := *.pdf *.ps
+#          onlysources.tex := main.tex
+#          LATEX_COLOR_WARNING := 'bold red uline'
+#
+#          And this would override the neverclean setting to ensure that pdf
+#          and ps files always remain behind, set the makefile to treat all
+#          .tex files that are not "main.tex" as includes (and therefore not
+#          default targets).  It also changes the LaTeX warning output to be
+#          red, bold, and underlined.
+#
+#          There are numerous variables in this file that can be overridden in
+#          this way.  Search for '?=' to find them all.
+#
+#          Also, you can put arbitrary targets into it if, for example, you
+#          want your source built from something else, e.g.:
+#
+#          generated.tex: generating_script.weird_lang depA depB
+#          	./generating_script.weird_lang > $$@
+#
+#          Note that if you are not careful, you can override the default
+#          target (what happens when you type "make" without arguments), so if
+#          you do use Makefile.ini, you probably want to start it with
+#          something like the following line:
+#
+#          default: all
+#
+#          Since the first target in any makefile is automatically the default,
+#          and the makefile already has a sensible "all" target, this will do
+#          what you want.
+#
+#          The Makefile.ini is imported before *anything else* is done, so go
+#          wild with your ideas for changes to this makefile in there.  It
+#          makes it easy to test them before submitting patches.
+#
+# STANDARD ENVIRONMENT VARIABLES:
+#
+#      LATEX_COLOR_WARNING		'$(LATEX_COLOR_WARNING)'
+#      LATEX_COLOR_ERROR		'$(LATEX_COLOR_ERROR)'
+#      LATEX_COLOR_UNDERFULL		'$(LATEX_COLOR_UNDERFULL)'
+#      LATEX_COLOR_OVERFULL		'$(LATEX_COLOR_OVERFULL)'
+#      LATEX_COLOR_PAGES		'$(LATEX_COLOR_PAGES)'
+#      LATEX_COLOR_BUILD		'$(LATEX_COLOR_BUILD)'
+#      LATEX_COLOR_GRAPHIC		'$(LATEX_COLOR_GRAPHIC)'
+#      LATEX_COLOR_DEP			'$(LATEX_COLOR_DEP)'
+#      LATEX_COLOR_SUCCESS		'$(LATEX_COLOR_SUCCESS)'
+#      LATEX_COLOR_FAILURE		'$(LATEX_COLOR_FAILURE)'
+#
+#   These may be redefined in your environment to be any of the following:
+#
+#      black
+#      red
+#      green
+#      yellow
+#      blue
+#      magenta
+#      cyan
+#      white
+#
+#   Bold or underline may be used, as well, either alone or in combination
+#   with colors:
+#
+#      bold
+#      uline
+#
+#   Order is not important.  You may want, for example, to specify:
+#
+#   export LATEX_COLOR_SUCCESS='bold blue uline'
+#
+#   in your .bashrc file.  I don't know why, but you may want to.
+#
+# STANDARD TARGETS:
+#
+#    all:
+#        Make all possible documents in this directory.  The documents are
+#        determined by scanning for .tex and .tex.sh (described in more detail
+#        later) and omitting any file that ends in ._include_.tex or
+#        ._nobuild_.tex.  The output is a set of .pdf files.
+#
+#        If you wish to omit files without naming them with the special
+#        underscore names, set the following near the top of the Makefile,
+#        or (this is recommended) within a Makefile.ini in the same directory:
+#
+#        	includes.tex := file1.tex file2.tex
+#
+#        This will cause the files listed to be considered as include files.
+#
+#        If you have only few source files, you can set
+#
+#        	onlysources.tex := main.tex
+#
+#        This will cause only the source files listed to be considered in
+#        dependency detection.  All other .tex files will be considered as
+#        include files.  Note that these options work for *any* source type,
+#        so you could do something similar with includes.gpi, for example.
+#        Note that this works for *any valid source* target.  All of the
+#        onlysources.* variables are commented out in the shipping version of
+#        this file, so it does the right thing when they simply don't exist.
+#        The comments are purely documentation.  If you know, for example, that
+#        file.mycoolformat is supported by this Makefile, but don't see the
+#        "onlysources.mycoolformat" declared in the comments, that doesn't mean
+#        you can't use it.  Go ahead and set "onlysources.mycoolformat" and it
+#        should do the right thing.
+#
+#    show:
+#        Builds and displays all documents in this directory.  It uses the
+#        environment-overridable value of VIEW_PDF (currently $(VIEW_PDF)) to
+#        do its work.
+#
+#    all-graphics:
+#        Make all of the graphics in this directory.
+#
+#    all-pstex (only for BUILD_STRATEGY=latex):
+#        Build all fig files into pstex and pstex_t files.  Gray DOES NOT WORK.
+#
+#    all-gray-pstex (only for BUILD_STRATEGY=latex):
+#    	 Build all fig files into grayscale pstex and pstex_t files.
+#
+#    all-dot2tex:
+#    	 Build all dot files into tex files.
+#
+#    show-graphics:
+#        Builds and displays all graphics in this directory.  Uses the
+#        environment-overridable value of VIEW_GRAPHICS (currently
+#        $(VIEW_GRAPHICS)) to do its work.
+#
+#    clean:
+#        Remove ALL generated files, leaving only source intact.
+#        This will *always* skip files mentioned in the "neverclean" variable,
+#        either in this file or specified in Makefile.ini:
+#
+#        	neverclean := *.pdf *.ps
+#
+#       The neverclean variable works on all "clean" targets below, as well.
+#
+#    clean-graphics:
+#        Remove all generated graphics files.
+#
+#    clean-backups:
+#        Remove all backup files: $(backup_patterns)
+#        (XFig and other editors have a nasty habit of leaving them around)
+#        Also removes Makefile-generated .temp files
+#
+#    clean-tex:
+#        Remove all files generated from LaTeX invocations except dependency
+#        information.  Leaves graphics alone.
+#
+#    clean-deps:
+#        Removes all auto-generated dependency information.
+#
+#    clean-auxiliary:
+#        Removes extra files created by various targets (like the dependency
+#        graph output).
+#
+#    clean-nographics:
+#        Cleans everything *except* the graphics files.
+#
+#    help:
+#        This help text.
+#
+#    version:
+#        Version information about this LaTeX makefile.
+#
+# DEBUG TARGETS:
+#
+#    _all_programs:
+#        A list of the programs used by this makefile.
+#
+#    _check_programs:
+#        Checks your system for the needed software and reports what it finds.
+#
+#    _check_gpi_files:
+#        Checks the .gpi files in the current directory for common errors, such
+#        as specification of the terminal or output file inside of the gpi file
+#        itself.
+#
+#    _dependency_graph:
+#        Outputs a .dot file to stdout that represents a graph of LaTeX
+#        dependencies.  To see it, use the _show_dependency_graph target or
+#        direct the output to a file, run dot on it, and view the output, e.g.:
+#
+#        make _dependency_graph > graph.dot
+#        dot -T ps -o graph.eps graph.dot
+#        gv graph.eps
+#
+#    _show_dependency_graph:
+#        Makes viewing the graph simple: extracts, builds and displays the
+#        dependency graph given in the _dependency_graph target using the value
+#        of the environment-overridable VIEW_POSTSCRIPT variable (currently set
+#        to $(VIEW_POSTSCRIPT)).  The postscript viewer is used because it
+#        makes it easier to zoom in on the graph, a critical ability for
+#        something so dense and mysterious.
+#
+#    _all_sources:
+#        List all .tex files in this directory.
+#
+#    _sources:
+#        Print out a list of all compilable sources in this directory.  This is
+#        useful for determining what make thinks it will be using as the
+#        primary source for 'make all'.
+#
+#    _scripts:
+#        Print out a list of scripts that make knows can be used to generate
+#        .tex files (described later).
+#
+#    _all_stems:
+#        Print a list of stems.  These represent bare targets that can be
+#        executed.  Listing <stem> as a bare target will produce <stem>.pdf.
+#
+#    _includes:
+#        A list of .d files that would be included in this run if _includes
+#        weren't specified.  This target may be used alone or in conjunction
+#        with other targets.
+#
+#    _graphic_outputs:
+#        A list of all generated .eps files
+#
+#    _env:
+#        A list of environment variables and their values.  If supported by
+#        your version of make, also a list of variables known to make.
+#
+# FILE TARGETS:
+#
+#    %, %.pdf:
+#        Build a PDF file from the corresponding %.tex file.
+#
+#        If BUILD_STRATEGY=pdflatex, then this builds the pdf directly.
+#        Otherwise, it uses this old-school but effective approach:
+#
+#            latex -> dvips -> ps2pdf
+#
+#        The BUILD_STRATEGY can be overridden in Makefile.ini in the same
+#        directory.  The default is pdflatex.
+#
+#        Reasons for using latex -> dvips include the "psfrag" package, and the
+#        generation of postscript instead of PDF.  Arguments for using pdflatex
+#        include "new and shiny" and "better supported."  I can't argue with
+#        either of those, and supporting them both didn't turn out to be that
+#        difficult, so there you have it.  Choices.
+#
+#    %._show:
+#        A phony target that builds the pdf file and then displays it using the
+#        environment-overridable value of VIEW_PDF ($(VIEW_PDF)).
+#
+#    %._graphics:
+#        A phony target that generates all graphics on which %.pdf (or %.dvi)
+#        depends.
+#
+#    %.ps (only for BUILD_STRATEGY=latex):
+#        Build a Postscript file from the corresponding %.tex file.
+#        This is done using dvips.  Paper size is automatically
+#        extracted from the declaration
+#
+#        \documentclass[<something>paper]
+#
+#        or it is the system default.
+#
+#        If using beamer (an excellent presentation class), the paper
+#        size is ignored.  More on this later.
+#
+#    %.dvi (only for BUILD_STRATEGY=latex):
+#        Build the DVI file from the corresponding %.tex file.
+#
+#    %.ind:
+#        Build the index for this %.tex file.
+#
+#    %.gls:
+#        Build the nomenclature glossary for this %.tex file.
+#
+#    %.nls:
+#        Build the (newer) nomenclature file for this %.tex file.
+#
+#    %.eps:
+#        Build an eps file from one of the following file types:
+#
+#       .dot    : graphviz
+#       .gpi    : gnuplot
+#       .fig    : xfig
+#       .xvg    : xmgrace
+#       .svg    : scalable vector graphics (goes through inkscape)
+#       .png    : png (goes through NetPBM)
+#       .jpg	: jpeg (goes through ImageMagick)
+#       .eps.gz : gzipped eps
+#
+#       The behavior of this makefile with each type is described in
+#       its own section below.
+#
+#    %.pstex{,_t} (only for BUILD_STRATEGY=latex):
+#       Build a .pstex_t file from a .fig file.
+#
+# FEATURES:
+#
+#    Optional Binary Directory:
+#        If you create the _out_ directory in the same place as the makefile,
+#        it will automatically be used as a dumping ground for .pdf (or .dvi,
+#        .ps, and .pdf) output files.
+#
+#        Alternatively, you can set the BINARY_TARGET_DIR variable, either as a
+#        make argument or in Makefile.ini, to point to your directory of
+#        choice.  Note that no pathname wildcard expansion is done in the
+#        makefile, so make sure that the path is complete before going in
+#        there.  E.g., if you want to specify something in your home directory,
+#        use $$HOME/ instead of ~/ so that the shell expands it before it gets
+#        to the makefile.
+#
+#    External Program Dependencies:
+#        Every external program used by the makefile is represented by an
+#        ALLCAPS variable at the top of this file.  This should allow you to
+#        make judgments about whether your system supports the use of this
+#        makefile.  The list is available in the ALL_PROGRAMS variable and,
+#        provided that you are using GNU make 3.80 or later (or you haven't
+#        renamed this file to something weird like "mylatexmakefile" and like
+#        invoking it with make -f) can be viewed using
+#
+#        make _all_programs
+#
+#        Additionally, the availability of these programs can be checked
+#        automatically for you by running
+#
+#        make _check_programs
+#
+#        The programs are categorized according to how important they are and
+#        what function they perform to help you decide which ones you really
+#        need.
+#
+#    Colorized Output:
+#        The output of commands is colorized to highlight things that are often
+#        important to developers.  This includes {underfull,overfull}
+#        {h,v}boxes, general LaTeX Errors, each stage of document building, and
+#        the number of pages in the final document.  The colors are obtained
+#        using 'tput', so colorization should work pretty well on any terminal.
+#
+#        The colors can be customized very simply by setting any of the
+#        LATEX_COLOR_<CONTEXT> variables in your environment (see above).
+#
+#    Predecessors to TeX Files:
+#        Given a target <target>, if no <target>.tex file exists but a
+#        corresponding script or predecessor file exists, then appropriate
+#        action will be taken to generate the tex file.
+#
+#        Currently supported script or predecessor languages are:
+#
+#        sh:     %.tex.sh
+#        perl:   %.tex.pl
+#        python: %.tex.py
+#
+#           Calls the script using the appropriate interpreter, assuming that
+#           its output is a .tex file.
+#
+#           The script is called thus:
+#
+#              <interpreter> <script file name> <target tex file>
+#
+#           and therefore sees exactly one parameter: the name of the .tex
+#           file that it is to create.
+#
+#           Why does this feature exist?  I ran into this while working on
+#           my paper dissertation.  I wrote a huge bash script that used a
+#           lot of sed to bring together existing papers in LaTeX.  It
+#           would have been nice had I had something like this to make my
+#           life easier, since as it stands I have to run the script and
+#           then build the document with make.  This feature provides hooks
+#           for complicated stuff that you may want to do, but that I have
+#           not considered.  It should work fine with included dependencies,
+#           too.
+#
+#           Scripts are run every time make is invoked.  Some trickery is
+#           employed to make sure that multiple restarts of make don't cause
+#           them to be run again.
+#
+#        reST: %.rst
+#
+#           Runs the reST to LaTeX converter to generate a .tex file
+#           If it finds a file names _rststyle_._include_.tex, uses it as
+#           the "stylesheet" option to rst2latex.
+#
+#           Note that this does not track sub-dependencies in rst files.  It
+#           assumes that the top-level rst file will change if you want a
+#           rebuild.
+#
+#    Dependencies:
+#
+#        In general, dependencies are extracted directly from LaTeX output on
+#        your document.  This includes
+#
+#        *    Bibliography information
+#        *    \include or \input files (honoring \includeonly, too)
+#        *    Graphics files inserted by the graphicx package
+#
+#        Where possible, all of these are built correctly and automatically.
+#        In the case of graphics files, these are generated from the following
+#        file types:
+#
+#        GraphViz:      .dot
+#        GNUPlot:       .gpi
+#        XFig:          .fig
+#        XMgrace:       .xvg
+#        SVG:           .svg
+#        PNG:           .png
+#        JPEG:          .jpg
+#        GZipped EPS:   .eps.gz
+#
+#        If the file exists as a .eps already, it is merely used (and will not
+#        be deleted by 'clean'!).
+#
+#        LaTeX and BibTeX are invoked correctly and the "Rerun to get
+#        cross-references right" warning is heeded a reasonable number of
+#        times.  In my experience this is enough for even the most troublesome
+#        documents, but it can be easily changed (if LaTeX has to be run after
+#        BibTeX more than three times, it is likely that something is moving
+#        back and forth between pages, and no amount of LaTeXing will fix
+#        that).
+#
+#        \includeonly is honored by this system, so files that are not
+#        specified there will not trigger a rebuild when changed.
+#
+#    Beamer:
+#        A special TeX source comment is recognized by this makefile (only when
+#        BUILD_STRATEGY=latex, since this invokes psnup):
+#
+#        %%[[:space:]]*BEAMER[[:space:]]*LARGE
+#
+#        The presence of this comment forces the output of dvips through psnup
+#        to enlarge beamer slides to take up an entire letter-sized page.  This
+#        is particularly useful when printing transparencies or paper versions
+#        of the slides.  For some reason landscape orientation doesn't appear
+#        to work, though.
+#
+#        If you want to put multiple slides on a page, use this option and then
+#        print using mpage, a2ps, or psnup to consolidate slides.  My personal
+#        favorite is a2ps, but your mileage may vary.
+#
+#        When beamer is the document class, dvips does NOT receive a paper size
+#        command line attribute, since beamer does special things with sizes.
+#
+#    GNUPlot Graphics:
+#        When creating a .gpi file, DO NOT INCLUDE the "set terminal" or "set
+#        output" commands!  The makefile will include terminal information for
+#        you.  Besides being unnecessary and potentially harmful, including the
+#        terminal definition in the .gpi file makes it harder for you, the one
+#        writing the document, to preview your graphics, e.g., with
+#
+#           gnuplot -persist myfile.gpi
+#
+#        so don't do specify a terminal or an output file in your .gpi files.
+#
+#        When building a gpi file into an eps file, there are several features
+#        available to the document designer:
+#
+#        Global Header:
+#            The makefile searches for the files in the variable GNUPLOT_GLOBAL
+#            in order:
+#
+#            ($(GNUPLOT_GLOBAL))
+#
+#            Only the first found is used.  All .gpi files in the directory are
+#            treated as though the contents of GNUPLOT_GLOBAL were directly
+#            included at the top of the file.
+#
+#            NOTE: This includes special comments! (see below)
+#
+#        Font Size:
+#            A special comment in a .gpi file (or a globally included file) of
+#            the form
+#
+#            ## FONTSIZE=<number>
+#
+#            will change the font size of the GPI output.  If font size is
+#            specified in both the global file and the GPI file, the
+#            specification in the individual GPI file is used.
+#
+#        Grayscale Output:
+#            GNUplot files also support a special comment to force them to be
+#            output in grayscale *no matter what*:
+#
+#            ## GRAY
+#
+#            This is not generally advisable, since you can always create a
+#            grayscale document using the forms mentioned above.  But, if your
+#            plot simply must be grayscale even in a document that allows
+#            colors, this is how you do it.
+#
+#    XFig Graphics:
+#            No special handling is done with XFig, except when a global
+#            grayscale method is used, e.g.
+#
+#                make GRAY=1 document
+#
+#            In these cases the .eps files is created using the -N switch to
+#            fig2dev to turn off color output.  (Only works with eps, not pstex
+#            output)
+#
+#    GraphVis Graphics:
+#            Color settings are simply ignored here.  The 'dot' program is used
+#            to transform a .dot file into a .eps file.
+#
+#            If you want, you can use the dot2tex program to convert dot files
+#            to tex graphics.  The default is to just call dot2tex with no
+#            arguments, but you can change the DOT2TEX definition to include
+#            options as needed (in your Makefile.ini).
+#
+#            Note that, as with pstex, the makefile cannot use latex's own
+#            output to discover all missing dot_t (output) files, since anytime
+#            TeX includes TeX, it has to bail when it can't find the include
+#            file.  It can therefore only stop on the first missing file it
+#            discovers, and we can't get a large list of them out easily.
+#
+#            So, the makefile errors out if it's missing an included dot_t
+#            file, then prompts the user to run this command manually:
+#
+#                make all-dot2tex
+#
+#    GZipped EPS Graphics:
+#
+#        A .eps.gz file is sometimes a nice thing to have.  EPS files can get
+#        very large, especially when created from bitmaps (don't do this if you
+#        don't have to).  This makefile will unzip them (not in place) to
+#        create the appropriate EPS file.
+#
+endef
+
+#
+# DEPENDENCY CHART:
+#
+#digraph "g" {
+#    rankdir=TB
+#    size="9,9"
+#    edge [fontsize=12 weight=10]
+#    node [shape=box fontsize=14 style=rounded]
+#
+#    eps [
+#        shape=Mrecord
+#        label="{{<gpi> GNUplot|<epsgz> GZip|<dot> Dot|<fig> XFig}|<eps> eps}"
+#        ]
+#    pstex [label="%.pstex"]
+#    pstex_t [label="%.pstex_t"]
+#    tex_outputs [shape=point]
+#    extra_tex_files [shape=point]
+#    gpi_data [label="<data>"]
+#    gpi_includes [label="_include_.gpi"]
+#    aux [label="%.aux"]
+#    fls [label="%.fls"]
+#    idx [label="%.idx"]
+#    glo [label="%.glo"]
+#    ind [label="%.ind"]
+#    log [label="%.log"]
+#    tex_sh [label="%.tex.sh"]
+#    rst [label="%.rst"]
+#    tex [
+#        shape=record
+#        label="<tex> %.tex|<include> _include_.tex"
+#        ]
+#    include_aux [label="_include_.aux"]
+#    file_bib [label=".bib"]
+#    bbl [label="%.bbl"]
+#    dvi [label="%.dvi"]
+#    ps [label="%.ps"]
+#    pdf [label="%.pdf"]
+#    fig [label=".fig"]
+#    dot [label=".dot"]
+#    gpi [label=".gpi"]
+#    eps_gz [label=".eps.gz"]
+#
+#    gpi_files [shape=point]
+#
+#    rst -> tex:tex [label="reST"]
+#    tex_sh -> tex:tex [label="sh"]
+#    tex_pl -> tex:tex [label="perl"]
+#    tex_py -> tex:tex [label="python"]
+#    tex -> tex_outputs [label="latex"]
+#    tex_outputs -> dvi
+#    tex_outputs -> aux
+#    tex_outputs -> log
+#    tex_outputs -> fls
+#    tex_outputs -> idx
+#    tex_outputs -> include_aux
+#    aux -> bbl [label="bibtex"]
+#    file_bib -> bbl [label="bibtex"]
+#    idx -> ind [label="makeindex"]
+#    glo -> gls [label="makeindex"]
+#    nlo -> nls [label="makeindex"]
+#    gls -> extra_tex_files
+#    nls -> extra_tex_files
+#    ind -> extra_tex_files
+#    bbl -> extra_tex_files
+#    eps -> extra_tex_files
+#    extra_tex_files -> dvi [label="latex"]
+#    gpi_files -> eps:gpi [label="gnuplot"]
+#    gpi -> gpi_files
+#    gpi_data -> gpi_files
+#    gpi_includes -> gpi_files
+#    eps_gz -> eps:epsgz [label="gunzip"]
+#    fig -> eps:fig [label="fig2dev"]
+#    fig -> pstex [label="fig2dev"]
+#    fig -> pstex_t [label="fig2dev"]
+#    pstex -> pstex_t [label="fig2dev"]
+#    dot -> eps:dot [label="dot"]
+#    dvi -> ps [label="dvips"]
+#    include_aux -> bbl [label="bibtex"]
+#    ps -> pdf [label="ps2pdf"]
+#
+#    edge [ color=blue label="" style=dotted weight=1 fontcolor=blue]
+#    fls -> tex:include [label="INPUT: *.tex"]
+#    fls -> file_bib [label="INPUT: *.aux"]
+#    aux -> file_bib [label="\\bibdata{...}"]
+#    include_aux -> file_bib [label="\\bibdata{...}"]
+#    log -> gpi [label="Graphic file"]
+#    log -> fig [label="Graphic file"]
+#    log -> eps_gz [label="Graphic file"]
+#    log -> dot [label="Graphic file"]
+#    log -> idx [label="No file *.ind"]
+#    log -> glo [label="No file *.gls"]
+#    log -> nlo [label="No file *.nls"]
+#    gpi -> gpi_data [label="plot '...'"]
+#    gpi -> gpi_includes [label="load '...'"]
+#    tex:tex -> ps [label="paper"]
+#    tex:tex -> pdf [label="embedding"]
+#}
+
+#
+# DEPENDENCY CHART SCRIPT
+#
+# $(call output_dependency_graph,[<output file>])
+define output-dependency-graph
+	if [ -f '$(this_file)' ]; then \
+	$(SED) \
+		-e '/^[[:space:]]*#[[:space:]]*DEPENDENCY CHART:/,/^$$/!d' \
+		-e '/DEPENDENCY CHART/d' \
+		-e '/^$$/d' \
+		-e 's/^[[:space:]]*#//' \
+		$(this_file) $(if $1,> '$1',); \
+	else \
+		$(ECHO) "Cannot determine the name of this makefile."; \
+	fi
+endef
+# vim: noet sts=0 sw=8 ts=8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/documentation/de/README	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,4 @@
+Zum Erzeugen der Dokumentation folgenden Befehl auf
+der Kommandozeile absetzen:
+
+  make importer-manual.pdf
Binary file flys-backend/doc/documentation/de/figures/bfg_logo.png has changed
Binary file flys-backend/doc/documentation/de/figures/intevation-logo.pdf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/documentation/de/importer-geodaesie.tex	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,356 @@
+\section{Geodatenimport}
+
+Der Geodaten Importer ist ein in Python geschriebenes Kommandozeilen Tool zum
+Import von Shapefiles in eine Datenbank. Zum Lesen der Shapefiles und zum
+Schreiben der Geodaten in die Datenbank wird GDAL verwendet. Der Import in eine
+Oracle Datenbank erfordert, dass GDAL und GDAL Python Bindungs mit
+Oracle Unterstützung installiert sind. Weitere Details hierzu befinden sich im
+Kapitel \ref{Systemanforderungen} und \ref{Installationsanleitung}.
+
+Der Importer kann mit einem Shellscript von der Kommandozeile gestartet werden
+(siehe Kapitel \ref{Starten des Geodaten Importers}). Nach dem Start wird anhand der
+Konfiguration festgestellt, welche Klassen von Shapefiles aus dem Dateisystem
+importiert werden sollen. Für jede Klasse gibt es einen speziellen
+Parser, der die speziellen Attribute eines Shapefiles liest und in die entsprechende
+Relation der Datenbank schreibt. Die Parser sind speziell auf das
+Dateisystem der BfG ausgerichtet. So wird z.B. erwartet, dass die Shapefiles der
+Gewässerachse im Ordner $Geodaesie/Flussachse+km$ liegen. Weitere Informationen zu
+den einzelnen Parsern sind dem nächsten Kapitel \ref{Beschreibung der Parser} zu
+entnehmen. Der Erfolg oder Misserfolg eines Shape-Imports wird je nach
+Konfiguration im Logfile vermerkt. Folgende Einträge können dem Logfile
+entnommen werden:
+
+\textbf{INFO: Inserted 4 features}
+\\Gibt die Anzahl der erfolgreich importierten Features an.\\
+
+\textbf{INFO: Failed to create 2 features}
+\\Gibt die Anzahl der Features an, die nicht importiert werden konnten.\\
+
+\textbf{INFO: Found 3 unsupported features}
+\\Gibt die Anzahl der Features an, die aufgrund ihres Datentyps nicht importiert
+werden konnten. Z.B: es werden Linien erwartet, im Shapefile sind jedoch
+Polygone enthalten.\\
+
+\textbf{ERROR: No source SRS given! No transformation possible!}
+\\Das Shapefile enthält keine Information, in welcher Projektion die Geometrien
+vorliegen. Es findet keine Transformation in die Zielprojektion statt. Bitte
+beachten Sie, dass FLYS diese Geometrien später ggf nicht korrekt darstellen
+kann.
+
+\textbf{ERROR: Unable to insert feature: DETAIL}
+\\Beim Lesen der Attribute eines Features ist ein Fehler aufgetreten.
+Das Feature konnte nicht in die Datenbank geschrieben werden.\\
+
+\textbf{ERROR: Exception while committing transaction}
+\\Beim Abschluss des Schreib-Vorgangs in die Datenbank ist ein unerwarteter
+Fehler aufgetreten. Die Features des Shapes sind nicht importiert worden.\\
+
+\textbf{ERROR 1: ORA-01017: invalid username/password; logon denied}
+\\Es konnte keine Verbindung zur Oracle Datenbank hergestellt werden. Prüfen Sie
+die Verbindungseinstellungen.
+
+Damit die Geodaten eines Shapes später eindeutig in der Datenbank identifiziert
+werden können, wird für jede Geometrie der Pfad des Shapes im Dateisystem in
+einer Spalte der Datenbank gespeichert. Anwendungen, die auf der Datenbank
+aufbauen, können die Geodaten eines Shapefiles später anhand dieses Merkmals
+gruppieren und anzeigen.
+
+
+\subsection{Beschreibung der Parser}
+\label{Beschreibung der Parser}
+
+Wie im letzten Kapitel beschrieben, sind die Parser speziell an das Dateisystem
+der BfG ausgerichtet. Im Folgenden werden zu jedem Parser folgende Informationen
+angegeben:
+
+\textbf{Pfad}
+\\Der Pfad, in dem die Shapefiles im Dateisystem abgelegt sein müssen ausgehend
+vom Gewässer Verzeichnis.
+
+\textbf{Geometrie}
+\\Der Geometrie Typ, der für diese Klasse von Shapefiles erwartet wird.
+
+\textbf{Attribute}
+\\Eine Liste der Attribute, die vom Parser aus dem Shape gelesen werden.
+
+
+\subsubsection{Achsen}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Geodaesie/Flussachse+km \\
+Geometrie   &   LINESTRING \\
+Attribute   &   name, kind \\
+\end{tabular}
+
+
+\subsubsection{Hydrologische Grenzen}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Hydrologie/Hydr.Grenzen/Linien \\
+Geometrie   &   LINESTRING, POLYGON \\
+Attribute   &   name, kind \\
+\end{tabular}
+
+\subsubsection{Bauwerke}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Geodaesie/Bauwerke \\
+Geometrie   &   LINESTRING \\
+Attribute   &   name, Name, KWNAAM \\
+\end{tabular}
+
+
+\subsubsection{Einzugsgebiete}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Hydrologie/Einzugsgebiet \\
+Geometrie   &   POLYGON, MULTIPOLYGON \\
+Attribute   &   name, Name, AREA, area \\
+\end{tabular}
+
+
+\subsubsection{Querprofilspuren}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Geodaesie/Querprofile \\
+Geometrie   &   LINESTRING \\
+Attribute   &   KILOMETER, KM, STATION, ELEVATION \\
+\end{tabular}
+
+
+\subsubsection{Festpunkte}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Geodaesie/Festpunkte \\
+Geometrie   &   POINT \\
+Attribute   &   name, KM, ELBE\_KM, X, Y, HPGP \\
+\end{tabular}
+
+
+\subsubsection{Talaue}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Hydrologie/Hydr.Grenzen \\
+Geometrie   &   POLYGON, MULTIPOLYGON \\
+Attribute   &   name \\
+\end{tabular}
+
+
+\subsubsection{Pegelstationen}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Hydrologie/Streckendaten \\
+Geometrie   &   POINT \\
+Attribute   &   Name, name, MPNAAM \\
+\end{tabular}
+
+
+\subsubsection{Hochwasserschutzanlagen}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Hydrologie/HW-Schutzanlagen \\
+Geometrie   &   LINESTRING \\
+Attribute   &   TYP, Bauart, Name, name \\
+\end{tabular}
+
+
+\subsubsection{Kilometrierung}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Geodaesie/Flussachse+km \\
+Geometrie   &   POINT \\
+Attribute   &   name, km, KM \\
+\end{tabular}
+
+
+\subsubsection{Linien}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Geodaesie/Linien \\
+Geometrie   &   LINESTRING, MULTILINESTRING \\
+Attribute   &   name, TYP, Z \\
+
+Anmerkung   & Wenn kein Attribut 'TYP' definiert ist, wird standardmäßig der Wert \\
+            & 'DAMM' angenommen. Fehlt ein Attribut 'Z' wird '9999' als Höhe \\
+            & angenommen. \\
+\end{tabular}
+
+
+\subsubsection{Überschwemmungsfläche}
+\hspace{1cm}
+\begin{tabular}[t]{ll}
+Pfad        &   Hydrologie/UeSG/Berechnung \\
+Geometrie   &   POLYGON, MULTIPOLYGON \\
+Attribut    &   name, diff, count, area, perimeter \\
+\end{tabular}
+
+
+\subsection{Systemanforderungen}
+\label{Systemanforderungen}
+\begin{itemize}
+  \item Oracle Datenbank inkl. Schema für FLYS
+  \item GDAL Binding für Python mit Oracle Support
+  \item ogr2ogr
+  \item Python $>=$ 2.6
+\end{itemize}
+
+
+\subsection{Installationsanleitung}
+\label{Installationsanleitung}
+\begin{itemize}
+
+ \item Python\\
+ Zum Starten des Importers ist es notwendig Python zu installieren. Dies können
+ Sie mit folgendem Befehl auf der Kommandozeile erledigen:
+
+ \begin{lstlisting}
+    zypper in python
+ \end{lstlisting}
+
+ \item Oracle Instantclient\\
+ Der Oracle Instantclient 11.2 wird benötigt, damit der Importer mittels Python
+ und GDAL in die bestehende Oracle Datenbank schreiben kann. Dazu ist es
+ erforderlich, folgende Archive von Oracle herunterzuladen. Zu finden sind die
+ folgenden Pakete unter\\
+ \href{http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html}{http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html}
+
+ \begin{itemize}
+    \item instantclient-basic-linux-x86-64-11.2.0.2.0.zip
+    \item instantclient-sdk-linux-x86-64-11.2.0.2.0.zip
+    \item instantclient-sqlplus-linux-x86-64-11.2.0.2.0.zip
+ \end{itemize}
+
+ Anschließend führen Sie folgende Befehle auf der Kommandozeile aus:
+
+ \begin{lstlisting}
+
+    mkdir /opt
+
+    unzip ~/instantclient-basic-linux-x86-64-11.2.0.2.0.zip -d /opt
+    unzip ~/instantclient-sdk-linux-x86-64-11.2.0.2.0.zip -d /opt
+    unzip ~/instantclient-sqlplus-linux-x86-64-11.2.0.2.0.zip -d /opt
+
+    mkdir /opt/instantclient_11_2/lib
+    cd /opt/instantclient_11_2/lib
+    ln -s ../libclntsh.so.11.1 .
+    ln -s ../libclntsh.so.11.1 libclntsh.so
+    ln -s ../libnnz11.so .
+    ln -s ../libocci.so.11.1 .
+    ln -s ../libocci.so.11.1 libocci.so
+    ln -s ../libociei.so .
+    ln -s ../libocijdbc11.so .
+    ln -s ../libsqlplusic.so .
+    ln -s ../libsqlplus.so .
+
+    rpm -i --nodeps ~/flys-importer/rpm/RPMS/x86_64/libgdal1180-1.8.0-intevation1.x86_64.rpm 
+    rpm -i --nodeps ~/flys-importer/rpm/RPMS/x86_64/libgdal180-devel-1.8.0-intevation1.x86_64.rpm
+    rpm -i --nodeps ~/flys-importer/rpm/RPMS/x86_64/gdal180-1.8.0-intevation1.x86_64.rpm
+
+ \end{lstlisting}
+
+ Sollten keine Fehler aufgetreten sein, haben Sie den \textit{Oracle
+ Instantclient 11.2} erfolgreich entpackt und im Dateisystem unter
+ \textit{/opt/instantclient\_11\_2} abgelegt. Mit den Befehlen $rpm -i --nodeps$
+ haben Sie anschließend die notwendigen Bindings installiert, damit der Importer
+ die Geodaten in die Oracle Datenbank schreiben kann.
+
+\end{itemize}
+
+
+\subsection{Konfiguration}
+\label{Konfiguration}
+Der Geodaten Importer kann über die Datei \textit{contrib/run\_geo.sh}
+konfiguriert werden. Öffnen Sie die Datei mit einem Texteditor Ihrer Wahl.
+In den Zeilen 4-9 werden Optionen definiert, die zwangsläufig angepasst
+werden müssen:
+
+\textbf{RIVER\_PATH}
+\\Der Pfad zum Gewässer im Dateisystem.
+
+\textbf{RIVER\_ID}
+\\Die Datenbank ID des zu importierenden Gewässers.
+
+\textbf{TARGET\_SRS}
+\\Das EPSG Referenzsystem in das die Geodaten beim Import projeziert werden
+sollen.
+
+\textbf{HOST}
+\\Der Host der Datenbank.
+
+\textbf{USER}
+\\Der Nutzer, der zum Verbinden zur Datenbank verwendet wird.
+
+\textbf{PASS}
+\\Das Passwort für USER zum Verbinden zur Datenbank.
+
+In den Zeilen 12-23 werden weitere Optionen definiert, die bei Bedarf angepasst
+werden können. Falls nicht anders angegeben, können die Optionen mit den Werten
+`0` und `1` belegt werden.
+
+\textbf{VERBOSE}
+\\Dieser Wert gibt die Granularität der Log-Ausgaben während des
+Imports an. Je höher der Wert, desto mehr Informationen werden
+in das Logfile geschrieben. Aktuell sind die Werte `0`, `1` und
+`2` definiert. Wird der Wert `0` gesetzt, werden nur Fehler und
+Warnungen in das Logfile geschrieben. Bei `1` werden neben
+Fehlern und Warnungen auch Infos in das Logfile geschrieben. Bei
+`2` werden sämtliche Ausgaben des Programms geschrieben. Dieser
+Modus ist hauptsächlich für die Entwicklung gedacht.
+
+\textbf{SKIP\_AXIS}
+\\Bei gesetztem Wert `1` werden keine Flussachsen importiert.
+
+\textbf{SKIP\_KMS}
+\\Bei gesetztem Wert `1` werden keine Kilometrierungen importiert.
+
+\textbf{SKIP\_CROSSSECTIONS}
+\\Bei gesetztem Wert `1` werden keine Querprofilespuren importiert.
+
+\textbf{SKIP\_LINES}
+\\Bei gesetztem Wert `1` werden keine Linien importiert.
+
+\textbf{SKIP\_FIXPOINTS}
+\\Bei gesetztem Wert `1` werden keine Festpunkte importiert.
+
+\textbf{SKIP\_BUILDINGS}
+\\Bei gesetztem Wert `1` werden keine Bauwerke importiert.
+
+\textbf{SKIP\_FLOODPLAINS}
+\\Bei gesetztem Wert `1` werden keine Talauen importiert.
+
+\textbf{SKIP\_HYDR\_BOUNDARIES}
+\\Bei gesetztem Wert `1` werden keine hydrologischen Grenzen importiert.
+
+\textbf{SKIP\_HWS}
+\\Bei gesetztem Wert `1` werden kein Hochwasserschutzanlagen importiert.
+
+\textbf{SKIP\_GAUGE\_LOCATION}
+\\Bei gesetztem Wert `1` werden keine Pegelorte importiert.
+
+\textbf{SKIP\_CATCHMENTS}
+\\Bei gesetztem Wert `1` werden keine Einzugsgebiete importiert.
+
+\textbf{SKIP\_UESG}
+\\Bei gesetztem Wert `1` werden keine Überschwemmungsflächen importiert.
+
+
+\subsection{Starten des Geodaten Importers}
+\label{Starten des Geodaten Importers}
+Der Geodaten Importer wird mittels eines Shellskripts von einer Konsole
+gestartet. Dazu führen Sie folgenden Befehl aus:\\
+
+\begin{lstlisting}
+    sh contrib/run_geo.sh > geo-import.log
+\end{lstlisting}
+
+Der Importer wird nun gestartet. Sämtliche Log-Ausgaben werden in die Datei
+$geo-import.log$ geschrieben.
+
+\textbf{Hinweis}
+\\Bitte beachten Sie, dass der Geodaten Importer aufgrund der eingesetzten
+Technologien derzeit nicht in der Lage ist, lesend auf die Oracle Datenbank
+zuzugreifen. Entsprechend kann beim Import nicht festgestellt werden, ob sich
+Shapefiles bereits in der Datenbank befinden, oder nicht. Ein erneuter Import
+Vorgang der Geodaten würde also dazu führen, dass Geometrien doppelt in der
+Datenbank abgelegt werden.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/documentation/de/importer-hydr-morph.tex	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,749 @@
+\section{Fachdatenimport}
+
+Der Fachdatenimporter dient dazu, hydrologische und morphologische Gewässerdaten
+aus dem Dateisystem in die FLYS3-Datenbank zu importieren. Das Werkzeug
+orientiert sich hierbei an der Dateihierachie, so wie sie auch von Desktop-FLYS
+ausgelesen wird. Der Import Vorgang ist in zwei Phasen unterteilt:
+
+\begin{itemize}
+    \item Lesen aller Daten eines Gewässers aus dem Dateisystem.
+    \item Schreiben der erfolgreich eingelesenen Daten in die Datenbank.
+\end{itemize}
+
+Sollte beim Lese- oder Schreib-Vorgang eines Gewässers ein Fehler auftreten, so
+werden sämtliche Daten des Gewässers verworfen. Beide Phasen zusammen bilden
+somit eine Transaktion.
+
+\textbf{Hinweis}
+\\Der Import geht wie auch Desktop-FLYS davon aus, dass die Dateien Latin-1
+encodiert vorliegen! Stellen Sie also sicher, dass das von Ihnen verwendete
+Encoding korrekt ist. Andernfalls ist es möglich, dass es während des Imports zu
+unerwarteten Problemen kommt.
+
+Der Importer ist ein in Java geschriebenes Werkzeug und kann von der Konsole aus
+gestartet werden. Sämtlich Konfigurationen können über sogenannte
+\textit{System-Properties} übergeben werden. Eine \textit{System-Property} wird
+dabei mittels \textit{-Dkey=value} beim Start übergeben. Im folgenden Beispiel
+würde der Importer mit einer Konfiguration \textit{flys.backend.importer.dry.run},
+welche den Wert \textit{true} gesetzt hat, gestartet.
+
+\begin{lstlisting}
+    java -Dflys.backend.importer.dry.run=true de.intevation.flys.importer.Importer
+\end{lstlisting}
+
+Auf gleiche Weise können dem Importer sämtliche Optionen zur Konfiguration
+beim Start mitgegeben werden. Im folgenden werden die möglichen System-Properties und
+ihre Auswirkung auf den Import genauer beschrieben. In den Kapiteln
+\ref{configuration} und \ref{start-hydr} wird zur Einfachheit jedoch ein
+Shellskript verwendet, das eine Standardkonfiguration vorgibt und den Importer
+mit allen erforderlichen Konfigurationen startet.
+
+
+\subsection{Importierte Daten}
+In diesem Kapitel werden die Datentypen aufgelistet und erläutert, wie sie vom
+Importer eingelesen werden.
+
+\subsubsection{Streckenfavoriten (*.km-Dateien)}
+Der Import der Streckenfavoriten kann mit \textbf{-Dflys.backend.importer.skip.annotations=true}
+unterdrückt werden.
+
+Zur Klassifikation von Streckenfavoriten muss mittels\\
+\textbf{-Dflys.backend.importer.annotation.types=DATEI} der Pfad zu einer
+XML-Datei angegeben werden. In dieser Datei werden die Typen und Regeln
+festgelegt, anhand derer die Klassifikation während des Import-Vorgangs
+vorgenommen wird. Details hierzu befinden sich im Kapitel \ref{annotation-types}.
+
+\subsubsection{Pegel, Stammdaten (*.glt, *.sta-Dateien)}
+Der Import von Pegel- und Stammdaten kann mit \textbf{'-Dflys.backend.importer.skip.gauges=true'}
+unterdrückt werden. Die .glt-Datei, die neben der .wst-Datei liegt, wird zuerst
+ausgelesen. Es werden nur *.sta-Datei von Pegeln geladen, die in der .glt-Datei
+vermerkt sind.
+
+Mittels \textbf{-Dflys.backend.sta.parse.gauge.numbers=true'} wird versucht, die
+offiziellen Pegelnummern aus den Stammdaten zu extrahieren.
+\textbf{Dies ist mit Vorsicht zu behandeln, denn die meisten STA-Dateien
+enthalten invalide Pegelnummern.}
+
+Die System-Property \textbf{flys.backend.main.value.types} kann einen String
+mit gültigen Typen von Stammdaten enthalten. Vorbelegt ist \textit{QWTD}. In der
+Praxis ist \textit{QWD} eine sinnvolle Belegung.
+
+\subsubsection{Basis-Wasserstände (gewaesser.wst-Dateien)}
+Der Import von Wasserständen kann mit \textbf{-Dflys.backend.importer.skip.wst=true} unterdrückt werden.
+
+\subsubsection{Zusätzliche Längsschnitte (*.zus, *.wst-Dateien)}
+Der Import von zusätzlichen Längsschnitten kann mit \textbf{-Dflys.backend.importer.skip.extra.wsts=true}
+unterdrückt werden. Es werden die *.zus- und *.wst-Dateien aus dem Verzeichnis
+\textit{../Zus.Längsschnitte} relativ zur gewaesser.wst-Datei betrachtet.
+
+\subsubsection{Fixierungen (*.wst-Dateien)}
+Der Import von Fixierungen kann mit \textbf{-Dflys.backend.importer.skip.fixations=true}
+unterdrückt werden. Es werden die *.wst-Dateien aus dem Verzeichnis
+\textit{../Fixierungen} relativ zur gewaesser.wst-Datei betrachtet.
+
+\subsubsection{Amtliche Linien (*.wst-Dateien)}
+Der Import von amtlichen Linien kann mit \textbf{-Dflys.backend.importer.skip.official.lines=true}
+unterdrückt werden. Es werden die \textit{Amtl\_Linien.wst}-Dateien aus dem
+Verzeichnis \textit{../Basisdaten} und \textit{../Fixierungen} relativ zur
+\textit{gewaesser.wst}-Datei betrachtet.
+
+\subsubsection{Profilspuren (*.prf-Dateien)}
+Der Import von Profilspuren kann mit \textbf{-Dflys.backend.importer.skip.prfs=true}
+unterdrückt werden. Es werden rekursiv alle *.prf-Dateien aus \textit{../../..}
+relativ zur gewaesser.wst-Datei betrachtet. Vor dem Import werden mit Hilfe
+eines Längen- und eines MD5-Summen-Vergleichs inhaltliche Duplikate
+ausgeschlossen.
+
+\subsubsection{Hydraulische Kennzahlen (*.hyk)}
+Der Import von hydraulischen Kennzahlen kann mit \textbf{-Dflys.backend.importer.skip.hyks=true} unterdrückt
+werden. Es werden rekursiv alle *.hyk-Dateien aus \textit{../../..} relativ zur
+gewaesser.wst-Datei betrachtet. Vor dem Import werden mit Hilfe eines Längen- und
+eines MD5-Summen-Vergleichs inhaltliche Duplikate ausgeschlossen.
+
+\subsubsection{Hochwassermarken (*.zus, *.wst)}
+Der Import von Hochwassermarken kann mit \textbf{-Dflys.backend.importer.skip.flood.water=true}
+unterdrückt werden. Es werden die *.zus- und *.wst-Dateien aus dem Verzeichnis
+\textit{../HW-Marken} relativ zur gewaesser.wst-Datei betrachtet.
+
+\subsubsection{Hochwasserschutzanlagen (*.zus)}
+Der Import von Hochwasserschutzanlagen kann mit \textbf{-Dflys.backend.importer.skip.flood.protection=true}
+unterdrückt werden. Es werden die *.zus- und *.wst-Dateien aus dem Verzeichnis
+\textit{../HW-Schutzanlagen} relativ zur \textit{gewaesser.wst}-Datei betrachtet.
+
+\subsubsection{Sohlhöhen (Peilungen)}
+Der Import von Sohlhöhen-Peilungen kann mit \textbf{-Dflys.backend.importer.skip.bed.height.single=true}
+unterdrückt werden. Es werden die Dateien aus dem Verzeichnis
+\textit{Morphologie/Sohlhoehen/Einzeljahre} geladen.
+
+\subsubsection{Sohlhöhen (Epochen)}
+Der Import Sohlhöhen-Epochen kann mit \textbf{-Dflys.backend.importer.skip.bed.height.epoch=true}
+unterdrückt werden. Es werden die Dateien aus dem Verzeichnis
+\textit{Morphologie/Sohlhoehen/Epochen} geladen.
+
+\subsubsection{Sedimentdichte}
+Der Import der Sedimentdichte kann mit
+\textbf{-Dflys.backend.importer.skip.sediment.density=true}
+unterdrückt werden. Es werden alle Dateien aus dem Verzeichnis
+\textit{Morphologie/Sedimentdichte} geladen.
+
+\subsubsection{Morphologische Breite}
+Der Import der morphologischen Breite kann mit
+\textbf{-Dflys.backend.importer.skip.morphological.width=true}
+unterdrückt werden. Es werden alle Dateien aus dem Verzeichnis
+\textit{Morphologie/morphologische\_Breite} geladen.
+
+\subsubsection{Fließgeschwindigkeit}
+Der Import der Fließgeschwindigkeit kann mit
+\textbf{-Dflys.backend.importer.skip.flow.velocity=true}
+unterdrückt werden. Es werden alle Modellrechnungen aus dem Verzeichnis\\
+\textit{Morphologie/Geschwindigkeit\_Schubspannung/Modellrechnungen} und\\
+\textit{Morphologie/Geschwindigkeit\_Schubspannung/v-Messungen} geladen.
+
+\subsubsection{Sedimentfracht}
+Der Import der Sedimentfracht kann mit
+\textbf{-Dflys.backend.importer.skip.sediment.yield=true}
+unterdrückt werden. Es werden alle Dateien aus dem Verzeichnis
+\textit{Morphologie/Fracht} geladen. Dabei werden die Dateien aus dem
+Unterverzeichnissen \textit{Einzeljahre} und \textit{Epochen} entsprechend als
+\textit{Einzeljahre} und \textit{Epochen} vermerkt.
+
+\subsubsection{Wasserspiegellagen für MINFO}
+Der Import der MINFO spezifischen Wasserspiegellagen kann mit\\
+\textbf{-Dflys.backend.importer.skip.waterlevels=true}
+unterdrückt werden. Es werden alle Dateien aus dem Verzeichnis
+\textit{Morphologie/Fixierungsanalyse/Wasserspiegellagen} geladen.
+
+\subsubsection{Wasserspiegeldifferenzen für MINFO}
+Der Import der Wasserspiegellagendifferenzen kann mit\\
+\textbf{-Dflys.backend.importer.skip.waterlevel.differences=true}
+unterdrückt werden. Es werden alle Dateien aus dem Verzeichnis
+\textit{Morphologie/Fixierungsanalyse/Wasserspiegeldifferenzen} geladen.
+
+\subsubsection{Transport Abfluss Beziehung}
+Der Import der Daten für die Transport Abfluss Beziehung kann mit\\
+\textbf{flys.backend.importer.skip.sq.relation=true} unterdrückt
+werden. Es werden alle Dateien unter
+\textit{Feststofftransport-Abfluss-Beziehung} geladen.
+
+
+\subsection{Klassifikation von Streckenfavoriten}
+\label{annotation-types}
+Streckenfavoriten werden aus KM-Dateien importiert. Um die einzelnen Einträge
+einer Kategorie (Brücke, Pegel, etc.) zuzuordnen, kann eine XML angegeben werden,
+in der Regeln für diese Klassifikation definiert werden. Schematisch gliedert
+sich diese Datei in die zwei Bereiche 'types' und 'patterns':
+
+\begin{lstlisting}
+    <annotation>
+        <types>
+            <type>...</type>
+            <type>...</type>
+            ...
+        </types>
+        <patterns>
+            <pattern>...</pattern>
+            <pattern>...</pattern>
+            ...
+        </patterns>
+    </annotation>
+\end{lstlisting}
+
+In der Sektion \textit{types} werden die Kategorien vereinbart, in die klassifiziert
+werden soll. Dies geschieht mit entsprechenden Zeilen in der XML Datei. Es folgt
+ein Auszug aus einer solchen Datei:
+
+\begin{lstlisting}
+  <type name="Pegel"/>
+  <type name="Brücke"/>
+  ...
+  <type name="Sonstige" default="true"/>
+\end{lstlisting}
+
+Das Attribut 'default' darf maximal einmal vergeben werden und besagt, dass diese
+Kategorie gewählt werden soll, wenn keine andere Kategorie zugeordnet werden kann.
+
+In der Sektion 'patterns' werden dann die Regeln definiert, die einzelne Einträge
+den zuvor definierten Kategorien zuordnet. Hierfür können zwei Arten von
+Definitionen angegeben werden:
+
+\begin{lstlisting}
+  <file pattern="^Brücken$" type="Brücke"/>
+\end{lstlisting}
+
+oder
+
+\begin{lstlisting}
+  <line pattern="^Brücke[:\s].*$" type="Brücke"/>
+\end{lstlisting}
+
+Die erste Variante bestimmt die Kategorie, die pro KM-Datei gelten soll.
+\textit{pattern} ist hierbei ein regulärer Ausdruck, der auf den Dateinamen
+angewandt wird. Passt der Name der Datei auf den regulären Ausdruck, wird
+\textit{type} als Vorgabe angenommen. Treffen mehrere \textit{file}-Regeln zu,
+wird der erste Treffer angewandt. Findet keine der \textit{file}-Regeln Anwendung, wird
+die Kategorie ausgewählt, die in der \textit{types}-Section das Attribut
+\textit{default} gesetzt hat.
+
+Die zweite Regel-Variante \textit{line} wird auf jeden Eintrag innerhalb einer KM-Datei
+auf den Bezeichner der Streckenfavoriten angewandt. Als Muster dient auch hier
+ein regulärer Ausdruck, der über das Attribut \textit{pattern} definiert wird.
+Die Kategorie wird im Trefferfall über das Attribut \textit{type} bestimmt.
+Treffen mehrere Regeln zu, wird die Kategorie gewählt, die zum ersten Treffer
+gehört. Trifft keine Regel zu wird der Eintrag der Kategorie zugeteilt, die für
+die beinhaltende Datei als Vorgabe gilt.
+
+
+\subsection{Konfiguration}
+\label{configuration}
+Zum Starten des Importers ist es notwendig, in der Datei
+\textit{contrib/run\_hydr\_morph.sh} die Variablen am Anfang der Datei
+anzupassen. Im folgenden werden notwendige und optionale Einstellungen
+beschrieben, die beim Starten des Importers berücksichtigt werden. Folgende
+Einstellungen sind zwangsläufig an die bestehende Umgebung anzupassen:
+
+\textbf{INFO\_GEW}
+\\Diese Option muss auf eine valide *.gew Datei verweisen (bekannt aus
+Desktop-FLYS). Wichtig für den Importer sind in dieser Datei die Zeilen, die mit
+\textit{WSTDatei:} beginnen. In ihnen wird der Pfad zu der zentralen WST-Datei
+des jeweiligen Gewässers angegeben. Alle anderen importierten Dateien werden in
+ihrer Lage im Dateisystem relativ zur Lage dieser Datei betrachtet.
+
+\textbf{BACKEND\_USER}
+\\Der Nutzername, der zum Verbinden zur Datenbank verwendet werden soll.
+
+\textbf{BACKEND\_PASS}
+\\Das Passwort, welches in Kombination mit \textbf{BACKEND\_USER} zum Verbinden
+zur Datenbank verwendet werden soll.
+
+\textbf{BACKEND\_HOST}
+\\Der Datenbank-Host. In der Regel sollte hier \textit{localhost} eingetragen
+werden, da es empfohlen wird, den Importer auf dem selben Host zu starten, auf
+dem auch die Datenbank läuft.
+
+\textbf{BACKEND\_PORT}
+\\Der Port auf dem die Datenbank zu erreichen ist. Bei einer Oracle XE Instanz
+z.B.: \textit{1521}, sofern nicht anders konfiguriert.
+
+\textbf{BACKEND\_NAME}
+\\Der Name der Datenbank Instanz. Beispielsweise \textit{XE} bei einer Oracle XE
+Instanz.
+
+\textbf{BACKEND\_DB\_PREFIX}
+\\Der Präfix zum Aufbau einer Datenbankverbindung. Für Oracle z.B.: \textit{jdbc:oracle:thin:@}.
+
+\textbf{BACKEND\_DB\_DRIVER}
+\\Der Name des JDBC-Treibers, der es erlaubt das Protokoll der Datenbank zu
+sprechen. Im Falle einer Oracle XE wäre dies z.B.: \textit{oracle.jdbc.OracleDriver}.
+
+\textbf{BACKEND\_DB\_DIALECT}
+\\Der Hibernate-Dialekt, den die Datenbank versteht. Im Falle einer Oracle-XE
+wäre dies z.B.: \textit{org.hibernate.dialect.OracleDialect}.
+
+
+Weitere Details zum Verbinden zu einer Oracle Datenbank finden Sie unter\\
+\href{http://www.orafaq.com/wiki/JDBC}{http://www.orafaq.com/wiki/JDBC}. Alle weiteren Einstellungen sind
+optional anpassbar:
+
+\textbf{LOG4J\_CONFIG}
+\\Der Fachdatenimport verwendet die externe Bibliothek \textit{Apache Log4J} zum Loggen
+von Informationen. Dazu ist es notwendig eine entsprechende Konfiguration beim
+Start anzugeben. \textit{LOG4J\_CONFIG} verweist in diesem Fall auf eine externe
+Datei zur Konfiguration von Log4J. Im Standardfall wird die Datei
+\textit{conf/log4j.properties} verwendet, welche eine sinnvolle Standardkonfiguration
+enthält. Sollten Sie diese Konfiguration verwenden, wird beim Import eine
+Log-Datei namens \textit{import.log} erstellt, die maximal 100 MB groß werden
+kann. Sollte die Log-Datei größer als 100 MB anwachsen, wird die aktuelle Datei
+nach \textit{import.log.1} umbenannt und eine neue Datei \textit{import.log}
+wird begonnen. Maximal werden 10 Log-Dateien gespeichert. Für weitere Details
+zu Log4J siehe Online Dokumentation unter
+\href{http://logging.apache.org/log4j/1.2/}{http://logging.apache.org/log4j/1.2/}
+
+
+\textbf{IMPORTER\_MAINVALUE\_TYPES}
+\\Diese Einstellung erlaubt die Angabe eines Textes, der aus den gültigen Typen
+für Hauptwerte zusammengesetzt ist. \textit{QWTD} ist standardmäßig gesetzt.
+
+\textbf{IMPORTER\_ANNOTATION\_TYPES}
+\\Diese Einstellung verweist auf eine Datei (relativ zum Ort der \textit{run.sh}
+im Dateisystem), die die möglichen Typen von Streckenfavoriten und deren Regeln
+definiert. Siehe hierzu auch Kapitel \ref{annotation-types}.
+
+
+Die im folgenden beschriebenen Einstellungen können jeweils die Werte
+\textit{true} oder \textit{false} annehmen und sind optional anzupassen.
+
+\textbf{IMPORTER\_DRY\_RUN}
+\\Falls \textit{true} gesetzt wird, wird der Import nur simuliert. Es werden
+keine Daten in die Datenbank geschrieben. Dies kann z.B.: zum Ermitteln
+potentieller Dateninkonsistenzen sinnvoll sein.
+
+\textbf{IMPORTER\_SKIP\_GAUGES}
+\\Wenn \textit{true} gesetzt ist werden keine Pegel- und Stammdaten bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_ANNOTATIONS}
+\\Wenn \textit{true} gesetzt ist werden keine Streckenfavoriten bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_WST}
+\\Wenn \textit{true} gesetzt ist werden keine WST Dateien bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_PRFS}
+\\Wenn \textit{true} gesetzt ist werden keine Querprofilspuren bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_HYKS}
+\\Wenn \textit{true} gesetzt ist werden keine HYK Dateien bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_EXTRA\_WST}
+\\Wenn \textit{true} gesetzt ist werden keine zusätzlichen Längsschnitte
+bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_FIXATIONS}
+\\Wenn \textit{true} gesetzt ist werden keine Fixierungen bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_OFFICIAL\_LINES}
+\\Wenn \textit{true} gesetzt ist werden keine offiziellen Linien bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_FLOOD\_WATER}
+\\Wenn \textit{true} gesetzt ist werden keine Hochwassermarken bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_FLOOD\_PROTECTION}
+\\Wenn \textit{true} gesetzt ist werden keine Hochwasserschutzanlagen
+bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_BED\_HEIGHT\_SINGLE}
+\\Wenn \textit{true} gesetzt ist werden keine mittleren Sohlhöhen (Peilungen) bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_BED\_HEIGHT\_EPOCH}
+\\Wenn \textit{true} gesetzt ist werden keine mittleren Sohlhöhen (Epochen)
+bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_SEDIMENT\_DENSITY}
+\\Wenn \textit{true} gesetzt ist werden keine Dateien zur Sedimentdichte
+bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_MORPHOLOGICAL\_WIDTH}
+\\Wenn \textit{true} gesetzt ist wird keine morphologische Breite bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_FLOW\_VELOCITY}
+\\Wenn \textit{true} gesetzt ist werden keine Fließgeschwindigkeiten bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_SEDIMENT\_YIELD}
+\\Wenn \textit{true} gesetzt ist werden keine Sedimentfrachten bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_WATERLEVELS}
+\\Wenn \textit{true} gesetzt ist werden keine Wasserspiegellagen für MINFO bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_WATERLEVEL\_DIFFERENCES}
+\\Wenn \textit{true} gesetzt ist werden keine Wasserspiegellagendifferenzen für
+MINFO bearbeitet.
+
+\textbf{IMPORTER\_SKIP\_SQ\_RELATION}
+\\Wenn \textit{true} gesetzt ist werden keine Daten für die Berechnungsart
+SQ-Beziehung bearbeitet.
+
+
+
+\subsection{Fehler und Warnungen}
+
+\subsubsection{Fehler}
+
+\textbf{error while parsing gew}
+\\Die GEW-Datei ist fehlerhaft oder konnte nicht geöffnet werden.
+
+\textbf{File 'XYZ' is broken!}
+\\Die Datei XYZ ist inkonsistent und führt zu Fehlern.
+
+\textbf{Error while parsing file for morph. width.}
+\\Beim Lesen der morphologischen Breite trat ein Fehler auf.
+
+\textbf{Error while storing flow velocity model.}
+\\Beim Schreiben eines Fließgeschwindigkeitsmodells trat ein Fehler auf.
+
+\textbf{Error while storing flow velocity measurement.}
+\\Beim Schreiben einer Fließgeschwindigkeitsmessung trat ein Fehler auf.
+
+\textbf{Error while storing sediment yield.}
+\\Beim Schreiben einer Sedimentablagerung trat ein Fehler auf.
+
+\textbf{Error while storing waterlevel diff.}
+\\Beim Schreiben einer Wasserspiegeldifferenz trat ein Fehler auf.
+
+\textbf{Error while storing sq relation.}
+\\Beim Schreiben einer S(Q) Beziehung trat ein Fehler auf.
+
+\textbf{Error reading PRF file.}
+\\Beim Lesen einer PRF-Datei trat ein Fehler auf.
+
+\textbf{Error closing PRF file.}
+\\Beim Schließen einer PRF-Datei trat ein Fehler auf.
+
+\textbf{HYK 1: not enough elements in line \#}
+\\Eine Zeile in einer HYK-Datei hat nicht genügend Elemente.
+
+\textbf{HYK 2: not enough elements in line \#}
+\\Eine Zeile in einer HYK-Datei hat nicht genügend Elemente.
+
+\textbf{HYK 5: not enough elements in line \#}
+\\Eine Zeile in einer HYK-Datei hat nicht genügend Elemente.
+
+\textbf{HYK 6: not enough elements in line \#}
+\\Eine Zeile in einer HYK-Datei hat nicht genügend Elemente.
+
+\textbf{HYK: parsing num zones, bottom or top height failed in line \#}
+\\Die Anzahl der Zonen oder Daten über die Zonen sind nicht korrekt.
+
+\textbf{HYK: HYK: number of flow zones mismatches in line \#}
+\\Die Anzahl der Zonen oder Daten über die Zonen sind nicht korrekt.
+
+\textbf{HYK: cannot parse number in line \#}
+\\Eine Zahl wurde erwartet.
+
+\textbf{HYK: Error reading file.}
+\\Beim Lesen einer HYK-Datei trat ein Fehler auf.
+
+\textbf{HYK: Error closing file.}
+\\Beim Schließen einer HYK-Datei trat ein Fehler auf.
+
+\subsubsection{Warnungen}
+\textbf{annotation type file 'XYZ' is not readable.}
+\\Die Datein XYZ kann nicht gelesen werden.
+
+\textbf{cannot parse annotation types file.}
+\\Während der Verarbeitung der Annotationsdatei ist Fehler aufgetreten.
+
+\textbf{Cannot read directory.}
+\\Verzeichnis konnte nicht gelesen werden.
+
+\textbf{no official lines wst file found}
+\\Keine Datei mit amtlichen Linien gefunden.
+
+\textbf{cannot read fixations wst file directory}
+\\Das Verzeichnis mit den Fixierungen kann nicht gelesen werden.
+
+\textbf{cannot read extra longitudinal wst file directory}
+\\Das Verzeichnis mit den zusätzlichen Längsschnitten kann nicht gelesen werden.
+
+\textbf{cannot read gauges from 'XYZ'}
+\\Die Pegelgültigkeiten können nicht gelesen werden.
+
+\textbf{HYK file 'XYZ' seems to be a duplicate.}
+\\Die HYK-Datei wurde unter anderem Namen aber gleichen Inhalts bereits
+gefunden.
+
+\textbf{PRF file 'XYZ' seems to be a duplicate.}
+\\Die PRF-Datei wurde unter anderem Namen aber mit gleichem Inhalt bereits
+gefunden.
+
+\textbf{Skip invalid SedimentYield: time interval or unit null!}
+\\Eine Sedimentablagerung ist ungültig und wurde ausgelassen.
+
+\textbf{skip flow velocity model: No discharge zone specified.}
+\\Da kein Abflussbereich angegeben wurde, wurde das Fließgeschwindigkeitsmodell ausgelassen.
+
+\textbf{skip invalid waterlevel - no unit set!}
+\\Ein einheitenloser Wasserstand wurde ausgelassen.
+
+\textbf{Cannot parse time range.}
+\\Das Zeitformat wurde nicht erkannt.
+
+\textbf{skip invalid data line \#}
+\\Ungültige Datenzeile wurde ausgelassen.
+
+\textbf{Error while parsing sq relation row \#}
+\\Eine Zeile in der S(Q)-Beziehung ist ungültig.
+
+\textbf{GLT: no gauge found in line \#}
+\\In der GLT-Datei wurde ein Pegel erwartet, aber nicht gefunden.
+
+\textbf{GLT: line \# has not enough columns.}
+\\Eine Zeile in der Pegelgültigkeitsdatei hat nicht genug Spalten.
+
+\textbf{Error while parsing flow velocity values.}
+\\Invalide Datenzeile in einer Datei mit einer Fliessgeschwindigkeitsmessung.
+
+\textbf{skip invalid data line: \#}
+\\Invalide Datenzeile in einer Datei mit einer Fliessgeschwindigkeitsmessung.
+
+\textbf{skip invalid waterlevel line: \#}
+\\Invalide Datenzeile in einer Datei mit Wasserstandsdifferenzen.
+
+\textbf{Error while parsing value: \#}
+\\Invalide Datenzeile in einer Datei mit Wasserstandsdifferenzen.
+
+\textbf{Error while parsing station: \#}
+\\Invalide Datenzeile in einer Datei mit Wasserstandsdifferenzen.
+
+\textbf{skip invalid MainValue part: \#}
+\\Invalide Datenzeile in einer Datei Fließgeschwindigkeitsmodellen.
+
+\textbf{skip invalid gauge part: \#}
+\\Invalide Datenzeile in einer Datei Fließgeschwindigkeitsmodellen.
+
+\textbf{Error while parsing Q value: $<Q>$}
+\\Invalide Datenzeile in einer Datei Fließgeschwindigkeitsmodellen.
+
+\textbf{skip invalid data line: \#}
+\\Invalide Datenzeile in einer Datei Fließgeschwindigkeitsmodellen.
+
+\textbf{Error while parsing flow velocity values.}
+\\Invalide Datenzeile in einer Datei Fließgeschwindigkeitsmodellen.
+
+\textbf{Error while parsing number from data row: \#}
+\\In der eingelesenen Zeile konnte keine Zahl gefunden werden.
+
+\textbf{Unknown meta line: \#}
+\\Invalide Datenzeile in einer Datei mit Sedimentdichten.
+
+\textbf{Error while parsing numbers in: \#}
+\\Invalide Datenzeile in einer Datei mit Sedimentdichten.
+
+\textbf{skip invalid data line: \#}
+\\Invalide Datenzeile in einer Datei mit Sedimentdichten.
+
+\textbf{Error while parsing numbers in \#}
+\\Invalide Datenzeile in einer Datei mit Sedimentdichten.
+
+\textbf{STA file is empty}
+\\Stammdatendatei ist leer oder hat zu wenige Zeilen.
+
+\textbf{STA file has not enough lines}
+\\Stammdatendatei ist leer oder hat zu wenige Zeilen.
+
+\textbf{STA file is too short}
+\\Stammdatendatei ist leer oder hat zu wenige Zeilen.
+
+\textbf{First line in STA file is too short.}
+\\Die erste Zeile der Stammdaten ist zu kurz.
+
+\textbf{STA: second line is too short}
+\\Die zweite Zeile ist zu kurz.
+
+\textbf{STA: parsing of the datum of the gauge failed}
+\\Das Datum in der Stammdatendatei konnte nicht gelesen werden.
+
+\textbf{STA: 'XYZ' is not a valid long number.}
+\\Die Pegelnummer ist invalide.
+
+\textbf{STA: Not enough columns for aeo and datum}
+\\AEO und Pegelnullpunkt können nicht ermittelt werden.
+
+\textbf{STA: cannot parse aeo or datum.}
+\\AEO oder Pegelnullpunkt sind invalide.
+
+\textbf{STA: value not parseable in line \#}
+\\Wert ist nicht als Zahl zu interpretieren.
+
+\textbf{PRF: cannot open file $<FILE>$}
+\\Die PRF kann nicht geöffnet werden.
+
+\textbf{PRF: file is empty}\\
+\textbf{PRF: First line does not look like a PRF data pattern.}\\
+\textbf{PRF: premature EOF. Expected integer in line 2}\\
+\textbf{PRF: Expected $<num>$ in line 2}\\
+\textbf{PRF: invalid integer in line 2}\\
+\textbf{PRF: premature EOF. Expected pattern for km extraction}\\
+\textbf{PRF: line 4 does not look like a PRF km extraction pattern.}\\
+\textbf{PRF: premature EOF. Expected skip row count.}\\
+\textbf{PRF: line 5 is not an positive integer.}\\
+\textbf{PRF: cannot extract km in line \#}
+\\Das PRF-Format ist komplex. Bei oben genannten Fehlern sollten weitere
+Information zur genaueren Analyse herangezogen werden.
+
+\textbf{cannot access WST file $FILE$}
+\\Die WST-Datei konnte nicht gefunden werden.
+
+\textbf{Found an invalid row in the AT file.}
+\\Eine Zeile in einer AT-Datei ist nicht korrekt.
+
+\textbf{AT: invalid number $XYZ$}
+\\Eine Zahl wurde erwartet aber nicht gefunden.
+
+\textbf{Try to add Q range without waterlevel!}
+\\Q-Bereich ohne Wasserstand gefunden.
+
+\textbf{Error while parsing Q range: \#}
+\\Invalider Q-Bereich
+
+\textbf{skip invalid waterlevel line: \#}
+\\Ungültige Wasserstandslinie
+
+\textbf{Error while parsing number values: \#}
+\\Ungültige Zahlenwerte.
+
+\textbf{ANN: not enough columns in line \#}
+\\Nicht genug Zeichenspalten in KM-Datei
+
+\textbf{ANN: invalid number in line \#}
+\\Ungültige Zahl.
+
+\textbf{ANN: cannot parse 'Unterkante' in line \#}
+\\Die Unterkante in einer KM-Datei konnte nicht gelesen werden.
+
+\textbf{ANN: cannot parse 'Unterkante' or 'Oberkante' in line \#}
+\\Unter- oder Oberkannte liegen in einem falschen Format vor.
+
+\textbf{ANN: duplicated annotation 'XYZ' in line \#}
+\\Ein Duplikat eines Streckenfavoriten wurde gefunden.
+
+\textbf{ANN: 'XYZ' is not a directory.}
+\\Unterverzeichnis konnte nicht geöffnet werden.
+
+\textbf{ANN: cannot list directory 'XYZ'}
+\\Unterverzeichnis konnte nicht durchsucht werden.
+
+\textbf{BHP: Meta line did not match any known type: \#}
+\\Unbekannter Typ.
+
+\textbf{BHP: Error while parsing timeinterval!}
+\\Ungültiges Zeitinterval.
+
+\textbf{BHP: Error while parsing year!}
+\\Ungültige Jahresangabe.
+
+\textbf{BHP: Error while parsing sounding width!}
+\\Unbekannte Peilungsbreite.
+
+\textbf{BHP: Error while parsing range!}
+\\Bereichsangabe fehlerhaft.
+
+\textbf{MWP: Unknown meta line: \#}
+\\Meta-Informationen ungültig.
+
+\textbf{MWP: skip invalid data line: \#}
+\\Ungültige Datenzeile wurde übersprungen.
+
+\textbf{MWP: Error while parsing numbers in \#}
+\\Falsche Zahlenformat.
+
+\textbf{ANNCLASS: rule has no name}
+\\Klassifizierungsregel für Streckenfavoriten hat keinen Namen.
+
+\textbf{ANNCLASS: pattern has no 'pattern' attribute.}
+\\Klassifizierungsmuster für Streckenfavoriten hat kein Muster.
+
+\textbf{ANNCLASS: pattern has unknown type 'XYZ'}
+\\Klassifizierungsmuster für Streckenfavoriten konnte keinem Typ zugeordnet werden.
+
+\textbf{ANNCLASS: pattern 'XYZ' is invalid.}
+\\Klassifizierungsmuster für Streckenfavoriten ist ungültig.
+
+\textbf{BSP: Error while parsing data row.}
+\\Ungültige Datenzeile.
+
+\textbf{SYP: Unknown meta line: \#}
+\\Ungültige Metadatenzeile.
+
+\textbf{SYP: skip invalid data line \#}
+\\Ungültige Datenzeile wurde übersprungen.
+
+\textbf{SYP: Error while parsing numbers in \#}
+\\Ungültige Zahlenformatierung.
+
+\textbf{SYP: Unknown time interval string 'XYZ'}
+\\Falsches Datumformat.
+
+\textbf{SYP: Error while parsing years 'XYZ'}
+\\Falsches Jahreszahlformat.
+
+\textbf{SYP: Error while parsing ranges of 'XYZ'}
+\\Bereichsangaben fehlerhaft.
+
+\textbf{SYP: Unknown grain fraction 'XYZ'}
+\\Unbekannte Kornfraktion.
+
+\textbf{WST: invalid number.}
+\\Ungültige Zahl.
+
+\textbf{WST: km $km$ ($<Zeile>$) found more than once. $->$ ignored.}
+\\Ein Kilometer ist doppelt in einer WST-Datei enthalten.
+
+\textbf{HYK: zone coordinates swapped in line \#}
+\\Fließzonenkordinaten wurden in umgekehrter Reihenfolge angeben.
+
+\textbf{BHS: Skip invalid file 'XYZ'}
+\\Die Inhalte der Datei sind ungültig.
+
+\textbf{ISQ: Unable to store sq relation value.}
+\\S(Q) Beziehung konnte nicht gespeichert werden.
+
+\textbf{ISQ: Cannot determine sq relation without time interval.}
+\\Einer S(Q)-Beziehung ist keine zeitliche Gültigkeit zugeordnet.
+
+\textbf{IWD: skip invalid waterlevel difference - no unit set!}
+\\Wasserstandsdifferenz hat keine Einheit.
+
+\textbf{BHE: Skip file - invalid current elevation model.}
+\\Höhenmodell ungültig.
+
+\textbf{BHE: Skip file - invalid time range.}
+\\Zeitbereich ungültig.
+
+\textbf{BHE: Skip file - invalid km range.}
+\\Kilometerbereich ungültig.
+
+
+\subsection{Hinweise zum Betrieb}
+Aufgrund des hohen Speicherverbrauchs des Importers wird empfohlen, der JVM
+mindestens 8 GiB Hauptspeicher zuzuordnen. Dies kann beim Starten des Java
+Prozesses mittels folgendem Parameter '-Xmx8192m' getan werden. Das
+Shellskript zum Starten des Importers setzt diesen Wert standardmäßig.
+Besonders speicherintensiv ist der Import der HYKs und der PRFs.
+Hier ist es unter Umständen empfehlenswert, diese in zwei oder drei
+Schritten zu importieren. Zuerst die sonstigen hydrologischen Daten importieren;
+anschließend einen Import-Vorgang ausschließlich für HYKs starten; anschließend
+einen Import-Vorgang für PRFs starten. Siehe Kapitel \ref{configuration} für
+weitere Informationen zum Aktivieren/Deaktivieren einzelner Dateitypen beim
+Import.
+
+
+\subsection{Starten des Fachdaten Importers}
+\label{start-hydr}
+Der Fachdaten Importer wird mit Hilfe eines Shellskripts von einer Konsole
+gestartet. Dazu führen folgenden Befehl aus:\\
+
+\begin{lstlisting}
+    contrib/run_hydr_morph.sh
+\end{lstlisting}
+
+Nachdem der Prompt der Konsole zurückkehrt, ist der Import abgeschlossen oder es
+ist ein Fehler aufgetreten. Weitere Informationen entnehmen Sie der Log-Datei.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/documentation/de/importer-manual.tex	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,204 @@
+\documentclass[12pt]{scrartcl}
+
+%----------------------------------------------
+% Load packages
+
+\usepackage{a4}
+\usepackage{times}
+\usepackage[latin1]{inputenc}
+\usepackage{fancyhdr}
+%\usepackage{german}
+%\usepackage[marvosym]{eurofont}
+%\usepackage[all, light]{draftcopy}
+%\usepackage{supertabular}
+%\usepackage{colortbl}
+%\usepackage{epsf}
+\usepackage{graphicx}
+\usepackage{lastpage}
+%\usepackage{proposal}
+\usepackage{listings}
+\usepackage[hyperindex=true, bookmarks=true, breaklinks=true,
+colorlinks=true, linkcolor=red,bookmarksopen]{hyperref}
+
+%----------------------------------------------
+% Document DATE and VERSION
+% set these values when releasing a new version
+
+\newcommand{\documentdate}{30. August 2012}
+\newcommand{\documentversion}{1.0}
+\newcommand{\documentrevision}{rev5303}
+\newcommand{\documentID}{importer-manual.tex}
+%----------------------------------------------
+
+%----------------------------------------------
+% Document TITLE
+\newcommand{\documenttitle}{FLYS: Datenimport von Fach- und Geodaten}
+
+\newcommand{\todo}{\textcolor{red}{ TODO }}
+
+
+%----------------------------------------------
+% Some parameters for layouting
+
+\paperwidth=21cm
+\hoffset=-0.54cm
+\textwidth=16cm
+
+\paperheight=29.7cm
+\voffset=-1.5cm
+\topmargin=0cm
+\headheight=1cm
+\textheight=24cm
+
+\setcounter{secnumdepth}{4}
+\setcounter{tocdepth}{4}
+
+%----------------------------------------------
+
+\begin{document}
+
+\lstset{ %
+language=sh,
+basicstyle=\ttfamily,       % the size of the fonts that are used for the code
+numbers=left,                   % where to put the line-numbers
+numberstyle=\footnotesize,      % the size of the fonts that are used for the line-numbers
+numbersep=5pt,                  % how far the line-numbers are from the code
+% backgroundcolor=\color{white},  % choose the background color. You must add \usepackage{color}
+showspaces=false,               % show spaces adding particular underscores
+showstringspaces=false,         % underline spaces within strings
+showtabs=false,                 % show tabs within strings adding particular underscores
+frame=single,                   % adds a frame around the code
+tabsize=2,                      % sets default tabsize to 2 spaces
+captionpos=b,                   % sets the caption-position to bottom
+breaklines=true,                % sets automatic line breaking
+breakatwhitespace=false,        % sets if automatic breaks should only happen at whitespace
+title=\lstname,                 % show the filename of files included with \lstinputlisting; also try caption instead of title
+escapeinside={\%*}{*)}          % if you want to add a comment within your code
+% morekeywords={*,...}            % if you want to add more keywords to the set
+}
+
+%-----------------------------------
+% HEADER/FOOTER DEFINITION
+
+% for some pages latex switches back to pagestyle plain :-(
+\fancypagestyle{plain}{%
+	\fancyhf{} % clear all header and footer fields
+	\fancyhead[LO,RE]{\footnotesize \documenttitle\\ \leftmark}
+	\fancyfoot[RO,LE]{\footnotesize Intevation GmbH} % Author
+	\fancyfoot[CO,CE]{\footnotesize \thepage/\pageref{LastPage}}
+	\fancyfoot[LO,RE]{\footnotesize \documentdate
+	\\\documentID}
+	\renewcommand{\footrulewidth}{0.4pt}
+}
+
+% and now define pagestyle fancy
+\fancyhead{} % clear all fields
+\fancyhead[LO]{\footnotesize \documenttitle\\ \leftmark}
+
+\fancyfoot{}% clear all fields
+\fancyfoot[RO]{\footnotesize Intevation GmbH} % Author
+\fancyfoot[CO]{\footnotesize \thepage/\pageref{LastPage}}
+\fancyfoot[LO]{\footnotesize \documentdate
+\\\documentID}
+
+\renewcommand{\footrulewidth}{0.4pt}
+
+%
+% END Header/Footer Definition
+%-----------------------------------
+
+%----------------------------------------------
+% MACRO DEFINITION
+%
+%   \Fig{figure}{lof text}{caption} :
+%			places 'figure' and
+%                       writes 'caption' at the bottom with leading
+%                       'Abbildung figno:'. 'lof text' is added to the list of
+%                       figures.
+%                       Example:
+%                       \Fig{\epsfxsize30mm \epsffile{x.eps}}{the x}{the x}
+%
+%   \FigNoEntry{}{} :
+%			same as above, no entry in figures list
+%
+%   \FigCaption{} :
+%			line with figure caption, setting figure
+%                       counter and figures list
+%
+%   \Tab{table}{lot text}{caption} :
+%			places 'table' and writes caption on top of the table
+%			with leading 'Tabelle tabno:'. 'lot text' is added to
+%			the list of tables.
+%****************************************************************************
+%       Figure makro for graphics continously enumerated.
+%
+
+\newcounter{FigCnt}
+\newcounter{TabCnt}
+
+\newcommand{\Fig}[3]%
+{
+        \refstepcounter{FigCnt}
+        \addcontentsline{lof}{figure}%
+                {\protect\numberline{\arabic{FigCnt}}{#2}}
+        \mbox{#1}
+
+\nopagebreak
+        {Abbildung \arabic{FigCnt}: #3}
+
+}
+
+\newcommand{\FigNoEntry}[2]%
+{
+        \refstepcounter{FigCnt}
+        \mbox{#1}
+
+\nopagebreak
+        {Abbildung \arabic{FigCnt}: #2}
+
+}
+
+\newcommand{\FigCaption}[1]%
+{
+        \refstepcounter{FigCnt}
+        \addcontentsline{lof}{figure}%
+                {\protect\numberline{\arabic{FigCnt}}{#1}}
+
+        %{Figure \thesection.\arabic{FigCnt}: #1}
+}
+
+\newcommand{\Tab}[3]%
+{
+        \refstepcounter{TabCnt}
+        \addcontentsline{lot}{figure}%
+                {\protect\numberline{\arabic{TabCnt}}{#2}}
+        {Tabelle \arabic{TabCnt}: #3}
+\nopagebreak
+        #1
+
+}
+
+\hyphenation{Intevation}
+% end macro definition
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newcounter{schritt}
+\renewcommand{\theschritt}{\Roman{schritt}}
+%\makeatletter\renewcommand{\p@schritt}{Abschnitt~\thesubsubsection~}\makeatother
+
+%-----------------------------------
+% DOCUMENT SETTINGS
+\pagestyle{fancy}
+\setlength{\parindent}{0cm}
+\setlength{\parskip}{5pt plus 2pt minus 1pt}
+
+% Start actual content here
+\include{title}
+\newpage
+\tableofcontents
+\include{overview}
+\include{importer-hydr-morph}
+\include{importer-geodaesie}
+
+\end{document}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/documentation/de/overview.tex	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,104 @@
+\section{Übersicht}
+
+Diese Dokumentation beschreibt die von Intevation entwickelten Werkzeuge zum
+Importieren der hydrologischen, morphologischen und geodätischen Daten der BfG.
+Die im folgenden\\ beschriebenen Werkzeuge zum Importieren der fachlichen und
+geodätischen Daten sind speziell auf das Verzeichnissystem der BfG ausgerichtet.
+Dabei wird angenommen, dass sich das Verzeichnis eines Gewässers auf oberster
+Ebene in drei Unterverzeichnisse aufgliedert:
+
+\begin{itemize}
+    \item Geodaesie
+    \item Hydrologie
+    \item Morphologie
+\end{itemize}
+
+Desweiteren beziehen sich die Befehle, die auf der Kommandozeile abgesetzt
+werden, auf ein SuSE-Linux-Enterprise-Server Version 11. Bitte beachten Sie
+auch, dass einige der Befehle \textit{root}-Rechte benötigen.
+
+\subsection{Vorbereitungen}
+
+\subsubsection{Entpacken des Datenimporters}
+
+Damit die Software performant und korrekt ausgeführt werden kann, ist es
+erforderlich, dass sie auf dem selben System installiert und ausgeführt wird,
+wie auch die Datenbank installiert ist. Sollten Sie das Paket nicht auf dem
+Zielsystem selbst heruntergeladen haben, sind ggf. weitere Werkzeuge notwendig.
+Im Fall, dass das Sie von einem Windows System auf das Zielsystem zugreifen
+wollen, können Sie beispielsweise folgende Werkzeuge verwenden:
+
+\begin{itemize}
+\item WinSCP \\
+WinSCP ist ein Open Source Werkzeug zum Transferieren von Dateien zwischen zwei
+Systemen. Um das heruntergeladene Paket auf das Zielsystem zu transferieren,
+können Sie WinSCP benutzen. Für weitere Informationen und den Gebrauch von
+WinSCP lesen Sie bitte unter folgender Adresse nach:
+\href{http://winscp.net/}{http://winscp.net/}.
+
+\item Putty \\
+Putty ist ein Open Source Werkzeug, mit dem Sie sich von einem Windows System
+per SSH auf das Zielsystem verbinden können. Anschließend können Sie über die
+Kommandozeile auf dem Zielsystem die Befehle, die in diesem Dokument beschrieben
+sind, ausführen. Für weitere Informationen zu Putty und dessen Gebrauch lesen
+Sie bitte unter folgender Adresse nach: \href{http://www.putty.org/}
+{http://www.putty.org/}.
+\end{itemize}
+
+Bitte beachten Sie, dass diese Werkzeuge nicht zur Installtion und zum Betrieb
+der Software selbst notwendig sind!
+
+
+\subsubsection{Vorbereiten der Datenbank}
+
+Nachdem Sie das Paket nun in das Heimatverzeichnis des Nutzers auf das
+Zielsystem kopiert haben, entpacken Sie es mit folgenden Befehlen:
+
+\begin{lstlisting}
+    cd ~
+    tar xvfz flys-importer.tar.gz
+    cd flys-importer
+\end{lstlisting}
+
+Bevor die Importer verwendet werden können, ist es notwendig, dass eine leere
+Oracle Datenbank vorhanden ist. Anschließend müssen folgende SQL Skripte in
+diese Datenbank eingespielt werden:
+
+\begin{enumerate}
+\item oracle.sql \\
+In diesem SQL Skript befindet sich das Schema zum Speichern der hydrologischen
+Daten.
+
+\item oracle-minfo.sql \\
+In diesem SQL Skript befindet sich das Schema zum Speichern der morphologischen
+Daten.
+
+\item oracle-spatial.sql \\
+In diesem SQL Skript befindet sich das Schema zum Speichern der geodätischen
+Daten.
+
+\item oracle-spatial\_idx.sql \\
+Mittels diesem SQL Skript werden die Indizes zum geodätischen Datenbankschema\\
+hinzugefügt.
+
+\item import-dems.sql \\
+In diesem Skript sind Befehle zum Einfügen der digitalen Geländemodelle
+enthalten. Die Dateipfade in diesem Skript sind so anzupassen, dass sie auf die
+entsprechenden Geländemodelle im Dateisystem verweisen. Es ist notwendig die
+Pfade absolut anzugeben.
+
+\end{enumerate}
+
+Zum Einspielen dieser Schemata setzen Sie folgende Befehle auf der Kommandozeile
+ab. Beachten Sie, dass $sqlplus$ im Pfad liegen muss, und der Linux-Nutzer
+dies Kommando ausführen können muss. Außerdem sind $benutzername$ und $passwort$
+entsprechend Ihres Datenbank-Zugangs anzupassen.
+
+\begin{lstlisting}
+    sqlplus benutzername/passwort @schema/oracle.sql
+    sqlplus benutzername/passwort @schema/oracle-minfo.sql
+    sqlplus benutzername/passwort @schema/oracle-spatial.sql
+    sqlplus benutzername/passwort @schema/oracle-spatial_idx.sql
+    sqlplus benutzername/passwort @schema/import-dems.sql
+\end{lstlisting}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/documentation/de/title.tex	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,52 @@
+%-----------------------------------
+% TITLE PAGE
+
+\begin{figure}[ht]
+  \begin{minipage}[b]{0.5\linewidth}
+    \centering
+     \includegraphics[scale=0.75]{figures/bfg_logo} \\
+     {\tt http://www.bafg.de}\\[4.0cm]
+  \end{minipage}
+  \begin{minipage}[b]{0.5\linewidth}
+    \centering
+    \includegraphics[width=0.75\textwidth]{figures/intevation-logo}
+     {\tt http://intevation.de/geospatial}\\[2.0cm]
+  \end{minipage}
+\end{figure}
+
+ \vspace{4cm}
+ 
+ {
+ 	\sffamily\large
+ 	Dokumentation Datenimport FLYS, BfG
+ 
+ 	\vspace{1cm}
+ 	{
+ 		\bfseries\huge
+ 		Installation, Konfiguration, Betrieb
+ 	}
+ 
+ 	\vspace{1cm}
+ 	Version \documentversion
+
+    Datum: \documentdate
+ 
+ 	Revision: \documentrevision
+ }
+ 
+ \vspace{4cm}
+ 
+ \thispagestyle{empty}
+ 
+ \vfill
+ 
+ \begin{flushleft}
+ {\bf Authors}:\\
+ Ingo Weinzierl$<$ingo.weinzierl@intevation.de$>$\\
+ Sascha Teichmann $<$sascha.teichmann@intevation.de$>$\\
+ {\bf Intevation GmbH},\\
+ Neuer Graben 17, 49074 Osnabrück, Germany\\
+ Tel: ++49 541 33 50 83 - 0 \\
+ \url{http://www.intevation.net/geospatial}
+ 
+ \end{flushleft}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/schema/import-dems.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,24 @@
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Elbe'), 'GRD_00000_01010', 0.0, 101.0, 2003, 2007, 'GK-3', 'DHHN92', 'ESRI-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Elbe/Geodaesie/Hoehenmodelle/m_00000_10110.grd');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Elbe'), 'GRD_00992_02030', 99.0, 203.0, 2003, 2007, 'GK-3', 'DHHN92', 'ESRI-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Elbe/Geodaesie/Hoehenmodelle/m_09920_20300.grd');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Elbe'), 'GRD_02020_02998', 202.0, 300.0, 2003, 2007, 'GK-3', 'DHHN92', 'ESRI-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Elbe/Geodaesie/Hoehenmodelle/m_20200_29980.grd');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Elbe'), 'GRD_02981_04010', 298.0, 401.0, 2003, 2007, 'GK-3', 'DHHN92', 'ESRI-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Elbe/Geodaesie/Hoehenmodelle/m_29810_40100.grd');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Elbe'), 'GRD_04000_05009', 400.0, 501.0, 2003, 2007, 'GK-3', 'DHHN92', 'ESRI-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Elbe/Geodaesie/Hoehenmodelle/m_40000_50090.grd');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Elbe'), 'GRD_05001_05830', 500.0, 583.0, 2003, 2007, 'GK-3', 'DHHN92', 'ESRI-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Elbe/Geodaesie/Hoehenmodelle/m_50010_58330.grd');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_00000_00058', 0.0, 6.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/0000-0580.xyz');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_00058_00153', 6.0, 15.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/0058-0153.xyz');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_00153_00416', 15.0, 42.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/0153-0416.xyz');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_00414_01012_O', 41.0, 101.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', 'muss überarbeitet werden', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/0414-1012O.xyz');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_00414_01012_W', 41.0, 101.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', 'muss überarbeitet werden', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/0414-1012W.xyz');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_01012_01488', 101.0, 145.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/1012-1488.xyz');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_01488_01666', 145.0, 167.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/1488-1666.xyz');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_01666_01960', 167.0, 196.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/1666-1960.xyz');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_01960_02044', 196.0, 204.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/1960-2044.XYZ');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_02044_02184', 204.0, 218.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/2044-2184.XYZ');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Mosel'), 'GRD_02184_02420', 218.0, 242.0, null, null, 'GK-2', 'DHHN85', 'ASCII-Grid', false, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Mosel/Geodaesie/Hoehenmodelle/DGMW-ASCII/525480MO.XYZ');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Saar'), 'GRD_00000_00079', 0.0, 8.0, 1999, 2002, 'GK-2', '', 'ASCII-Grid', true, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Saar/Geodaesie/Hoehenmodelle/km0000-0079_long.txt');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Saar'), 'GRD_00080_00204', 8.0, 20.0, 1999, 2002, 'GK-2', '', 'ASCII-Grid', true, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Saar/Geodaesie/Hoehenmodelle/km0080-0204_long.txt');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Saar'), 'GRD_00205_00314', 20.0, 31.0, 1999, 2002, 'GK-2', '', 'ASCII-Grid', true, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Saar/Geodaesie/Hoehenmodelle/km0205-0314_long.txt');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Saar'), 'GRD_00315_00541', 31.0, 54.0, 1999, 2002, 'GK-2', '', 'ASCII-Grid', true, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Saar/Geodaesie/Hoehenmodelle/km0315-0541_long.txt');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Saar'), 'GRD_00542_00655', 54.0, 65.0, 1999, 2002, 'GK-2', '', 'ASCII-Grid', true, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Saar/Geodaesie/Hoehenmodelle/km0542-0655_long.txt');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Saar'), 'GRD_00656_00828', 65.0, 83.0, 1999, 2002, 'GK-2', '', 'ASCII-Grid', true, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Saar/Geodaesie/Hoehenmodelle/km0656-0828_long.txt');
+INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,projection, elevation_state, format, border_break, resolution, description, path) VALUES ((SELECT id from rivers WHERE name = 'Saar'), 'GRD_00829_00931', 83.0, 93.0, 1999, 2002, 'GK-2', '', 'ASCII-Grid', true, '2', '', '/vol1/projects/Geospatial/flys-3.0/testdaten/Gewaesser/Saar/Geodaesie/Hoehenmodelle/km0829-0931_erweitert.txt');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/schema/oracle-drop-minfo.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,102 @@
+SET AUTOCOMMIT ON;
+
+ALTER TABLE elevation_model DROP CONSTRAINT fk_unit;
+ALTER TABLE bed_height_single DROP CONSTRAINT fk_bed_single_river_id;
+ALTER TABLE bed_height_single DROP CONSTRAINT fk_type;
+ALTER TABLE bed_height_single DROP CONSTRAINT fk_location_system;
+ALTER TABLE bed_height_single DROP CONSTRAINT fk_cur_elevation_model;
+ALTER TABLE bed_height_single DROP CONSTRAINT fk_old_elevation_model;
+ALTER TABLE bed_height_single DROP CONSTRAINT fk_range;
+ALTER TABLE bed_height_single_values DROP CONSTRAINT fk_bed_single_values_parent;
+ALTER TABLE bed_height_epoch_values DROP CONSTRAINT fk_bed_epoch_values_parent;
+ALTER TABLE bed_height_epoch DROP CONSTRAINT fk_epoch_cur_elevation_model;
+ALTER TABLE bed_height_epoch DROP CONSTRAINT fk_epoch_old_elevation_model;
+ALTER TABLE bed_height_epoch DROP CONSTRAINT fk_epoch_range;
+ALTER TABLE depths DROP CONSTRAINT fk_depths_unit_id;
+ALTER TABLE sediment_density DROP CONSTRAINT fk_sd_depth_id;
+ALTER TABLE sediment_density DROP CONSTRAINT fk_sd_unit_id;
+ALTER TABLE sediment_density_values DROP CONSTRAINT fk_sdv_sediment_density_id;
+ALTER TABLE morphologic_width DROP CONSTRAINT fk_mw_river_id;
+ALTER TABLE morphologic_width DROP CONSTRAINT fk_mw_unit_id;
+ALTER TABLE morphologic_width_values DROP CONSTRAINT fk_mwv_morphologic_width_id;
+ALTER TABLE flow_velocity_model_values DROP CONSTRAINT fk_fvv_flow_velocity_model_id;
+ALTER TABLE flow_velocity_model DROP CONSTRAINT fk_fvm_river_id;
+ALTER TABLE flow_velocity_model DROP CONSTRAINT fk_fvm_discharge_zone_id;
+ALTER TABLE discharge_zone DROP CONSTRAINT fk_dz_river_id;
+ALTER TABLE flow_velocity_measurements DROP CONSTRAINT fk_fvm_rivers_id;
+ALTER TABLE flow_velocity_measure_values DROP CONSTRAINT fk_fvmv_measurements_id;
+ALTER TABLE grain_fraction DROP CONSTRAINT fk_gf_unit_id;
+ALTER TABLE sediment_yield DROP CONSTRAINT fk_sy_grain_fraction_id;
+ALTER TABLE sediment_yield DROP CONSTRAINT fk_sy_unit_id;
+ALTER TABLE sediment_yield DROP CONSTRAINT fk_sy_time_interval_id;
+ALTER TABLE sediment_yield DROP CONSTRAINT fk_sy_river_id;
+ALTER TABLE sediment_yield_values DROP CONSTRAINT fk_syv_sediment_yield_id;
+ALTER TABLE waterlevel DROP CONSTRAINT fk_w_river_id;
+ALTER TABLE waterlevel DROP CONSTRAINT fk_w_unit_id;
+ALTER TABLE waterlevel_q_range DROP CONSTRAINT fk_wqr_waterlevel_id;
+ALTER TABLE waterlevel_values DROP CONSTRAINT fk_wv_waterlevel_q_range_id;
+ALTER TABLE waterlevel_difference DROP CONSTRAINT fk_wd_river_id;
+ALTER TABLE waterlevel_difference DROP CONSTRAINT fk_wd_unit_id;
+ALTER TABLE waterlevel_difference_column DROP CONSTRAINT fk_wdc_difference_id;
+ALTER TABLE waterlevel_difference_values DROP CONSTRAINT fk_wdv_column_id;
+ALTER TABLE sq_relation DROP CONSTRAINT fk_sqr_tinterval_id;
+ALTER TABLE sq_relation DROP CONSTRAINT fk_sqr_river_id;
+ALTER TABLE sq_relation_value DROP CONSTRAINT fk_sqr_id;
+
+DROP TABLE bed_height_type;
+DROP TABLE location_system;
+DROP TABLE elevation_model;
+DROP TABLE bed_height_single;
+DROP TABLE bed_height_single_values;
+DROP TABLE bed_height_epoch_values;
+DROP TABLE bed_height_epoch;
+DROP TABLE depths;
+DROP TABLE sediment_density;
+DROP TABLE sediment_density_values;
+DROP TABLE morphologic_width;
+DROP TABLE morphologic_width_values;
+DROP TABLE discharge_zone;
+DROP TABLE flow_velocity_model;
+DROP TABLE flow_velocity_model_values;
+DROP TABLE flow_velocity_measurements;
+DROP TABLE flow_velocity_measure_values;
+DROP TABLE grain_fraction;
+DROP TABLE sediment_yield;
+DROP TABLE sediment_yield_values;
+DROP TABLE waterlevel;
+DROP TABLE waterlevel_q_range;
+DROP TABLE waterlevel_values;
+DROP TABLE waterlevel_difference;
+DROP TABLE waterlevel_difference_column;
+DROP TABLE waterlevel_difference_values;
+DROP TABLE sq_relation_value;
+DROP TABLE sq_relation;
+
+DROP SEQUENCE BED_HEIGHT_TYPE_SEQ;
+DROP SEQUENCE LOCATION_SYSTEM_SEQ;
+DROP SEQUENCE ELEVATION_MODEL_SEQ;
+DROP SEQUENCE BED_HEIGHT_SINGLE_ID_SEQ;
+DROP SEQUENCE BED_SINGLE_VALUES_ID_SEQ;
+DROP SEQUENCE BED_EPOCH_VALUES_ID_SEQ;
+DROP SEQUENCE BED_HEIGHT_EPOCH_ID_SEQ;
+DROP SEQUENCE DEPTHS_ID_SEQ;
+DROP SEQUENCE SEDIMENT_DENSITY_ID_SEQ;
+DROP SEQUENCE SEDIMENT_DENSITY_VALUES_ID_SEQ;
+DROP SEQUENCE MORPHOLOGIC_WIDTH_ID_SEQ;
+DROP SEQUENCE MORPH_WIDTH_VALUES_ID_SEQ;
+DROP SEQUENCE DISCHARGE_ZONE_ID_SEQ;
+DROP SEQUENCE FLOW_VELOCITY_MODEL_ID_SEQ;
+DROP SEQUENCE FLOW_VELOCITY_M_VALUES_ID_SEQ;
+DROP SEQUENCE FV_MEASURE_ID_SEQ;
+DROP SEQUENCE FV_MEASURE_VALUES_ID_SEQ;
+DROP SEQUENCE GRAIN_FRACTION_ID_SEQ;
+DROP SEQUENCE SEDIMENT_YIELD_ID_SEQ;
+DROP SEQUENCE SEDIMENT_YIELD_VALUES_ID_SEQ;
+DROP SEQUENCE WATERLEVEL_ID_SEQ;
+DROP SEQUENCE WATERLEVEL_Q_RANGES_ID_SEQ;
+DROP SEQUENCE WATERLEVEL_VALUES_ID_SEQ;
+DROP SEQUENCE WATERLEVEL_DIFFERENCE_ID_SEQ;
+DROP SEQUENCE WATERLEVEL_DIFF_COLUMN_ID_SEQ;
+DROP SEQUENCE WATERLEVEL_DIFF_VALUES_ID_SEQ;
+DROP SEQUENCE SQ_RELATION_ID_SEQ;
+DROP SEQUENCE SQ_RELATION_VALUES_ID_SEQ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/schema/oracle-drop-spatial.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,68 @@
+DROP TRIGGER river_axes_trigger;
+DROP TABLE river_axes;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'RIVER_AXES';
+DROP SEQUENCE RIVER_AXES_ID_SEQ;
+
+DROP TRIGGER river_axes_km_trigger;
+DROP TABLE river_axes_km;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'RIVER_AXES_KM';
+DROP SEQUENCE RIVER_AXES_KM_ID_SEQ;
+
+DROP TRIGGER cross_section_tracks_trigger;
+DROP TABLE cross_section_tracks;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'CROSS_SECTION_TRACKS';
+DROP SEQUENCE CROSS_SECTION_TRACKS_ID_SEQ;
+
+DROP TRIGGER lines_trigger;
+DROP TABLE lines;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'LINES';
+DROP SEQUENCE LINES_ID_SEQ;
+
+DROP TRIGGER buildings_trigger;
+DROP TABLE buildings;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'BUILDINGS';
+DROP SEQUENCE BUILDINGS_ID_SEQ;
+
+DROP TRIGGER fixpoints_trigger;
+DROP TABLE fixpoints;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'FIXPOINTS';
+DROP SEQUENCE FIXPOINTS_ID_SEQ;
+
+DROP TRIGGER floodplain_trigger;
+DROP TABLE floodplain;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'FLOODPLAIN';
+DROP SEQUENCE FLOODPLAIN_ID_SEQ;
+
+DROP TRIGGER dem_trigger;
+DROP TABLE dem;
+DROP SEQUENCE DEM_ID_SEQ;
+
+DROP TRIGGER catchment_trigger;
+DROP TABLE catchment;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'CATCHMENT';
+DROP SEQUENCE CATCHMENT_ID_SEQ;
+
+DROP TRIGGER hws_trigger;
+DROP TABLE hws;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'HWS';
+DROP SEQUENCE HWS_ID_SEQ;
+
+DROP TRIGGER floodmaps_trigger;
+DROP TABLE floodmaps;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'FLOODMAPS';
+DROP SEQUENCE FLOODMAPS_ID_SEQ;
+
+DROP TRIGGER hydr_boundaries_trigger;
+DROP TABLE hydr_boundaries;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'HYDR_BOUNDARIES';
+DROP SEQUENCE HYDR_BOUNDARIES_ID_SEQ;
+
+DROP TRIGGER hydr_boundaries_poly_trigger;
+DROP TABLE hydr_boundaries_poly;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'HYDR_BOUNDARIES_POLY';
+DROP SEQUENCE HYDR_BOUNDARIES_POLY_ID_SEQ;
+
+DROP TRIGGER gauge_location_trigger;
+DROP TABLE gauge_location;
+DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = 'GAUGE_LOCATION';
+DROP SEQUENCE GAUGE_LOCATION_ID_SEQ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/schema/oracle-drop.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,90 @@
+ALTER TABLE annotations DROP CONSTRAINT cAnnotationsRanges;
+ALTER TABLE annotations DROP CONSTRAINT cAnnotationsEdges;
+ALTER TABLE annotations DROP CONSTRAINT cAnnotationsPositions;
+ALTER TABLE annotations DROP CONSTRAINT cAnnotationsAttributes;
+ALTER TABLE annotations DROP CONSTRAINT cAnnotationsTypes;
+ALTER TABLE cross_section_lines DROP CONSTRAINT cQPSLinesCrossSections;
+ALTER TABLE cross_section_points DROP CONSTRAINT cQPSPointsCrossSectionLines;
+ALTER TABLE cross_sections DROP CONSTRAINT cCrossSectionsRivers;
+ALTER TABLE cross_sections DROP CONSTRAINT cCrossSectionsTimeIntervals;
+ALTER TABLE discharge_tables DROP CONSTRAINT cDischargeTablesTime_intervals;
+ALTER TABLE discharge_tables DROP CONSTRAINT cDischargeTablesGauges;
+ALTER TABLE gauges DROP CONSTRAINT cGaugesRivers;
+ALTER TABLE gauges DROP CONSTRAINT cGaugesRanges;
+ALTER TABLE hyk_entries DROP CONSTRAINT cHykEntriesHyks;
+ALTER TABLE hyk_flow_zones DROP CONSTRAINT cHykFlowZonesHykFormations;
+ALTER TABLE hyk_flow_zones DROP CONSTRAINT cHykFlowZonesHykFlowZoneTypes;
+ALTER TABLE hyks DROP CONSTRAINT cHyksRivers;
+ALTER TABLE hyk_formations DROP CONSTRAINT cHykFormationsHykEntries;
+ALTER TABLE main_values DROP CONSTRAINT cMainValuesTimeIntervals;
+ALTER TABLE main_values DROP CONSTRAINT cMainValuesGauges;
+ALTER TABLE main_values DROP CONSTRAINT cMainValuesNamedMainValues;
+ALTER TABLE named_main_values DROP CONSTRAINT cNamedMainValuesMainValueTypes;
+ALTER TABLE ranges DROP CONSTRAINT cRangesRivers;
+ALTER TABLE rivers DROP CONSTRAINT cRiversUnits;
+ALTER TABLE wst_column_q_ranges DROP CONSTRAINT cWstColumnQRangesWstColums;
+ALTER TABLE wst_column_q_ranges DROP CONSTRAINT cWstColumnQRangesWstQRanges;
+ALTER TABLE wst_column_values DROP CONSTRAINT cWstColumnValuesWstColumns;
+ALTER TABLE wst_columns DROP CONSTRAINT cWstColumnsTime_intervals;
+ALTER TABLE wst_columns DROP CONSTRAINT cWstColumnsWsts;
+ALTER TABLE wst_q_ranges DROP CONSTRAINT cWstQRangesRanges;
+ALTER TABLE wsts DROP CONSTRAINT cWstsRivers;
+DROP TABLE annotation_types;
+DROP TABLE annotations;
+DROP TABLE attributes;
+DROP TABLE cross_section_lines;
+DROP TABLE cross_section_points;
+DROP TABLE cross_sections;
+DROP TABLE discharge_table_values;
+DROP TABLE discharge_tables;
+DROP TABLE edges;
+DROP TABLE gauges;
+DROP TABLE hyk_entries;
+DROP TABLE hyk_flow_zone_types;
+DROP TABLE hyk_flow_zones;
+DROP TABLE hyk_formations;
+DROP TABLE hyks;
+DROP TABLE main_value_types;
+DROP TABLE main_values;
+DROP TABLE named_main_values;
+DROP TABLE positions;
+DROP TABLE ranges;
+DROP TABLE rivers;
+DROP TABLE time_intervals;
+DROP TABLE units;
+DROP TABLE wst_column_q_ranges;
+DROP TABLE wst_column_values;
+DROP TABLE wst_columns;
+DROP TABLE wst_q_ranges;
+DROP TABLE wsts;
+DROP SEQUENCE ANNOTATION_TYPES_ID_SEQ;
+DROP SEQUENCE ANNOTATIONS_ID_SEQ;
+DROP SEQUENCE ATTRIBUTES_ID_SEQ;
+DROP SEQUENCE CROSS_SECTION_LINES_ID_SEQ;
+DROP SEQUENCE CROSS_SECTION_POINTS_ID_SEQ;
+DROP SEQUENCE CROSS_SECTIONS_ID_SEQ;
+DROP SEQUENCE DISCHARGE_TABLE_VALUES_ID_SEQ;
+DROP SEQUENCE DISCHARGE_TABLES_ID_SEQ;
+DROP SEQUENCE EDGES_ID_SEQ;
+DROP SEQUENCE GAUGES_ID_SEQ;
+DROP SEQUENCE HYK_ENTRIES_ID_SEQ;
+DROP SEQUENCE HYK_FLOW_ZONE_TYPES_ID_SEQ;
+DROP SEQUENCE HYK_FLOW_ZONES_ID_SEQ;
+DROP SEQUENCE HYK_FORMATIONS_ID_SEQ;
+DROP SEQUENCE HYKS_ID_SEQ;
+DROP SEQUENCE MAIN_VALUE_TYPES_ID_SEQ;
+DROP SEQUENCE MAIN_VALUES_ID_SEQ;
+DROP SEQUENCE NAMED_MAIN_VALUES_ID_SEQ;
+DROP SEQUENCE POSITIONS_ID_SEQ;
+DROP SEQUENCE RANGES_ID_SEQ;
+DROP SEQUENCE RIVERS_ID_SEQ;
+DROP SEQUENCE TIME_INTERVALS_ID_SEQ;
+DROP SEQUENCE UNITS_ID_SEQ;
+DROP SEQUENCE WST_COLUMN_Q_RANGES_ID_SEQ;
+DROP SEQUENCE WST_COLUMN_VALUES_ID_SEQ;
+DROP SEQUENCE WST_COLUMNS_ID_SEQ;
+DROP SEQUENCE WST_Q_RANGES_ID_SEQ;
+DROP SEQUENCE WSTS_ID_SEQ;
+DROP VIEW wst_value_table;
+DROP VIEW wst_w_values ;
+DROP VIEW wst_q_values;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/schema/oracle-minfo.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,381 @@
+SET AUTOCOMMIT ON;
+
+CREATE SEQUENCE LOCATION_SYSTEM_SEQ;
+
+CREATE TABLE location_system (
+    id          NUMBER(38,0) NOT NULL,
+    name        VARCHAR(32)  NOT NULL,
+    description VARCHAR(255),
+    PRIMARY KEY(id)
+);
+
+
+CREATE SEQUENCE ELEVATION_MODEL_SEQ;
+
+CREATE TABLE elevation_model (
+    id          NUMBER(38,0) NOT NULL,
+    name        VARCHAR(32)  NOT NULL,
+    unit_id     NUMBER(38,0) NOT NULL,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_unit FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+CREATE SEQUENCE BED_HEIGHT_TYPE_SEQ;
+
+CREATE TABLE bed_height_type (
+    id          NUMBER(38,0) NOT NULL,
+    name        VARCHAR(16)  NOT NULL,
+    description VARCHAR(255),
+    PRIMARY KEY(id)
+);
+
+
+
+CREATE SEQUENCE BED_HEIGHT_SINGLE_ID_SEQ;
+
+CREATE TABLE bed_height_single (
+    id                      NUMBER(38,0) NOT NULL,
+    river_id                NUMBER(38,0) NOT NULL,
+    year                    NUMBER(38,0) NOT NULL,
+    sounding_width          NUMBER(38,0) NOT NULL,
+    type_id                 NUMBER(38,0) NOT NULL,
+    location_system_id      NUMBER(38,0) NOT NULL,
+    cur_elevation_model_id  NUMBER(38,0) NOT NULL,
+    old_elevation_model_id  NUMBER(38,0),
+    range_id                NUMBER(38,0) NOT NULL,
+    evaluation_by           VARCHAR(255),
+    description             VARCHAR(255),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_bed_single_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_type FOREIGN KEY (type_id) REFERENCES bed_height_type(id),
+    CONSTRAINT fk_location_system FOREIGN KEY (location_system_id) REFERENCES location_system(id),
+    CONSTRAINT fk_cur_elevation_model FOREIGN KEY (cur_elevation_model_id) REFERENCES elevation_model(id),
+    CONSTRAINT fk_old_elevation_model FOREIGN KEY (old_elevation_model_id) REFERENCES elevation_model(id),
+    CONSTRAINT fk_range FOREIGN KEY (range_id) REFERENCES ranges(id)
+);
+
+
+CREATE SEQUENCE BED_HEIGHT_EPOCH_ID_SEQ;
+
+CREATE TABLE bed_height_epoch (
+    id                      NUMBER(38,0) NOT NULL,
+    river_id                NUMBER(38,0) NOT NULL,
+    time_interval_id        NUMBER(38,0) NOT NULL,
+    -- sounding_with           NUMBER(38,0) NOT NULL,
+    -- type_id                 NUMBER(38,0) NOT NULL,
+    cur_elevation_model_id  NUMBER(38,0) NOT NULL,
+    old_elevation_model_id  NUMBER(38,0),
+    range_id                NUMBER(38,0) NOT NULL,
+    evaluation_by           VARCHAR(255),
+    description             VARCHAR(255),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_time_interval FOREIGN KEY (time_interval_id) REFERENCES time_intervals(id),
+    CONSTRAINT fk_epoch_cur_elevation_model FOREIGN KEY (cur_elevation_model_id) REFERENCES elevation_model(id),
+    CONSTRAINT fk_epoch_old_elevation_model FOREIGN KEY (old_elevation_model_id) REFERENCES elevation_model(id),
+    CONSTRAINT fk_epoch_range FOREIGN KEY (range_id) REFERENCES ranges(id)
+);
+
+
+CREATE SEQUENCE BED_SINGLE_VALUES_ID_SEQ;
+
+CREATE TABLE bed_height_single_values (
+    id                      NUMBER(38,0) NOT NULL,
+    bed_height_single_id    NUMBER(38,0) NOT NULL,
+    station                 NUMBER(38,2) NOT NULL,
+    height                  NUMBER(38,2),
+    uncertainty             NUMBER(38,2),
+    data_gap                NUMBER(38,2),
+    sounding_width          NUMBER(38,2),
+    width                   NUMBER(38,2),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_bed_single_values_parent FOREIGN KEY (bed_height_single_id) REFERENCES bed_height_single(id)
+);
+
+
+CREATE SEQUENCE BED_EPOCH_VALUES_ID_SEQ;
+
+CREATE TABLE bed_height_epoch_values (
+    id                      NUMBER(38,0) NOT NULL,
+    bed_height_epoch_id     NUMBER(38,0) NOT NULL,
+    station                 NUMBER(38,2) NOT NULL,
+    height                  NUMBER(38,2),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_bed_epoch_values_parent FOREIGN KEY (bed_height_epoch_id) REFERENCES bed_height_epoch(id)
+);
+
+
+CREATE SEQUENCE DEPTHS_ID_SEQ;
+
+CREATE TABLE depths (
+    id      NUMBER(38,0) NOT NULL,
+    lower   NUMBER(38,2) NOT NULL,
+    upper   NUMBER(38,2) NOT NULL,
+    unit_id NUMBER(38,0) NOT NULL,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_depths_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE SEDIMENT_DENSITY_ID_SEQ;
+
+CREATE TABLE sediment_density (
+    id          NUMBER(38,0) NOT NULL,
+    river_id    NUMBER(38,0) NOT NULL,
+    depth_id    NUMBER(38,0) NOT NULL,
+    unit_id     NUMBER(38,0) NOT NULL,
+    description VARCHAR(256),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_sd_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_sd_depth_id FOREIGN KEY (depth_id) REFERENCES depths(id),
+    CONSTRAINT fk_sd_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE SEDIMENT_DENSITY_VALUES_ID_SEQ;
+
+CREATE TABLE sediment_density_values (
+    id                  NUMBER(38,0) NOT NULL,
+    sediment_density_id NUMBER(38,0) NOT NULL,
+    station             NUMBER(38,2) NOT NULL,
+    density             NUMBER(38,2) NOT NULL,
+    description         VARCHAR(256),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_sdv_sediment_density_id FOREIGN KEY(sediment_density_id) REFERENCES sediment_density(id)
+);
+
+
+CREATE SEQUENCE MORPHOLOGIC_WIDTH_ID_SEQ;
+
+CREATE TABLE morphologic_width (
+    id          NUMBER(38,0) NOT NULL,
+    river_id    NUMBER(38,0) NOT NULL,
+    unit_id     NUMBER(38,0) NOT NULL,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_mw_river_id FOREIGN KEY(river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_mw_unit_id FOREIGN KEY(unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE MORPH_WIDTH_VALUES_ID_SEQ;
+
+CREATE TABLE morphologic_width_values (
+    id                      NUMBER(38,0) NOT NULL,
+    morphologic_width_id    NUMBER(38,0) NOT NULL,
+    station                 NUMBER(38,3) NOT NULL,
+    width                   NUMBER(38,3) NOT NULL,
+    description             VARCHAR(256),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_mwv_morphologic_width_id FOREIGN KEY (morphologic_width_id) REFERENCES morphologic_width(id)
+);
+
+
+CREATE SEQUENCE DISCHARGE_ZONE_ID_SEQ;
+
+CREATE TABLE discharge_zone (
+    id                      NUMBER(38,0) NOT NULL,
+    river_id                NUMBER(38,0) NOT NULL,
+    gauge_name              VARCHAR(64)  NOT NULL, -- this is not very proper, but there are gauges with no db instance
+    value                   NUMBER(38,3) NOT NULL,
+    lower_discharge         VARCHAR(16)  NOT NULL,
+    upper_discharge         VARCHAR(16),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_dz_river_id FOREIGN KEY (river_id) REFERENCES rivers(id)
+);
+
+
+CREATE SEQUENCE FLOW_VELOCITY_MODEL_ID_SEQ;
+
+CREATE TABLE flow_velocity_model (
+    id                  NUMBER(38,0) NOT NULL,
+    river_id            NUMBER(38,0) NOT NULL,
+    discharge_zone_id   NUMBER(38,0) NOT NULL,
+    description         VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_fvm_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_fvm_discharge_zone_id FOREIGN KEY (discharge_zone_id) REFERENCES discharge_zone (id)
+);
+
+
+CREATE SEQUENCE FLOW_VELOCITY_M_VALUES_ID_SEQ;
+
+CREATE TABLE flow_velocity_model_values (
+    id                      NUMBER(38,0) NOT NULL,
+    flow_velocity_model_id  NUMBER(38,0) NOT NULL,
+    station                 NUMBER(38,3) NOT NULL,
+    q                       NUMBER(38,3) NOT NULL,
+    total_channel           NUMBER(38,3) NOT NULL,
+    main_channel            NUMBER(38,3) NOT NULL,
+    shear_stress            NUMBER(38,3) NOT NULL,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_fvv_flow_velocity_model_id FOREIGN KEY (flow_velocity_model_id) REFERENCES flow_velocity_model(id)
+);
+
+
+
+CREATE SEQUENCE FV_MEASURE_ID_SEQ;
+
+CREATE TABLE flow_velocity_measurements (
+    id          NUMBER(38,0) NOT NULL,
+    river_id    NUMBER(38,0) NOT NULL,
+    description VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_fvm_rivers_id FOREIGN KEY (river_id) REFERENCES rivers(id)
+);
+
+CREATE SEQUENCE FV_MEASURE_VALUES_ID_SEQ;
+
+CREATE TABLE flow_velocity_measure_values (
+    id              NUMBER(38,0) NOT NULL,
+    measurements_id NUMBER(38,0) NOT NULL,
+    station         NUMBER(38,3) NOT NULL,
+    datetime        TIMESTAMP,
+    w               NUMBER(38,3) NOT NULL,
+    q               NUMBER(38,3) NOT NULL,
+    v               NUMBER(38,3) NOT NULL,
+    description     VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_fvmv_measurements_id FOREIGN KEY (measurements_id) REFERENCES flow_velocity_measurements (id)
+);
+
+
+CREATE SEQUENCE GRAIN_FRACTION_ID_SEQ;
+
+CREATE TABLE grain_fraction (
+    id      NUMBER(38,0)   NOT NULL,
+    name    VARCHAR(64)    NOT NULL,
+    lower   NUMBER(38,3),
+    upper   NUMBER(38,3),
+    unit_id NUMBER(38,0),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_gf_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE SEDIMENT_YIELD_ID_SEQ;
+
+CREATE TABLE sediment_yield (
+    id                  NUMBER(38,0) NOT NULL,
+    river_id            NUMBER(38,0) NOT NULL,
+    grain_fraction_id   NUMBER(38,0),
+    unit_id             NUMBER(38,0) NOT NULL,
+    time_interval_id    NUMBER(38,0) NOT NULL,
+    description         VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_sy_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_sy_grain_fraction_id FOREIGN KEY (grain_fraction_id) REFERENCES grain_fraction(id),
+    CONSTRAINT fk_sy_unit_id FOREIGN KEY (unit_id) REFERENCES units(id),
+    CONSTRAINT fk_sy_time_interval_id FOREIGN KEY (time_interval_id) REFERENCES time_intervals(id)
+);
+
+
+CREATE SEQUENCE SEDIMENT_YIELD_VALUES_ID_SEQ;
+
+CREATE TABLE sediment_yield_values (
+    id                  NUMBER(38,0) NOT NULL,
+    sediment_yield_id   NUMBER(38,0) NOT NULL,
+    station             NUMBER(38,3) NOT NULL,
+    value               NUMBER(38,3) NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_syv_sediment_yield_id FOREIGN KEY (sediment_yield_id) REFERENCES sediment_yield(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_ID_SEQ;
+
+CREATE TABLE waterlevel (
+    id          NUMBER(38,0) NOT NULL,
+    river_id    NUMBER(38,0) NOT NULL,
+    unit_id     NUMBER(38,0) NOT NULL,
+    description VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_w_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_w_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_Q_RANGES_ID_SEQ;
+
+CREATE TABLE waterlevel_q_range (
+    id              NUMBER(38,0) NOT NULL,
+    waterlevel_id   NUMBER(38,0) NOT NULL,
+    q               NUMBER(38,2) NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wqr_waterlevel_id FOREIGN KEY (waterlevel_id) REFERENCES waterlevel(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_VALUES_ID_SEQ;
+
+CREATE TABLE waterlevel_values (
+    id                      NUMBER(38,0) NOT NULL,
+    waterlevel_q_range_id   NUMBER(38,0) NOT NULL,
+    station                 NUMBER(38,3) NOT NULL,
+    w                       NUMBER(38,2) NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wv_waterlevel_q_range_id FOREIGN KEY (waterlevel_q_range_id) REFERENCES waterlevel_q_range(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_DIFFERENCE_ID_SEQ;
+
+CREATE TABLE waterlevel_difference (
+    id          NUMBER(38,0) NOT NULL,
+    river_id    NUMBER(38,0) NOT NULL,
+    unit_id     NUMBER(38,0) NOT NULL,
+    description VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wd_river_id FOREIGN KEY (river_id) REFERENCES rivers (id),
+    CONSTRAINT fk_wd_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_DIFF_COLUMN_ID_SEQ;
+
+CREATE TABLE waterlevel_difference_column (
+    id              NUMBER(38,0) NOT NULL,
+    difference_id   NUMBER(38,0) NOT NULL,
+    description     VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wdc_difference_id FOREIGN KEY (difference_id) REFERENCES waterlevel_difference (id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_DIFF_VALUES_ID_SEQ;
+
+CREATE TABLE waterlevel_difference_values (
+    id          NUMBER(38,0) NOT NULL,
+    column_id   NUMBER(38,0) NOT NULL,
+    station     NUMBER(38,3) NOT NULL,
+    value       NUMBER(38,2) NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wdv_column_id FOREIGN KEY (column_id) REFERENCES waterlevel_difference_column (id)
+);
+
+
+CREATE SEQUENCE SQ_RELATION_ID_SEQ;
+
+CREATE TABLE sq_relation (
+    id               NUMBER(38,0) NOT NULL,
+    river_id         NUMBER(38,0) NOT NULL,
+    time_interval_id NUMBER(38,0) NOT NULL,
+    description      VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_sqr_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_sqr_tinterval_id FOREIGN KEY (time_interval_id) REFERENCES time_intervals(id)
+);
+
+
+CREATE SEQUENCE SQ_RELATION_VALUES_ID_SEQ;
+
+CREATE TABLE sq_relation_value (
+    id             NUMBER(38,0) NOT NULL,
+    sq_relation_id NUMBER(38,0) NOT NULL,
+    parameter      VARCHAR(16)  NOT NULL,
+    fraction       VARCHAR(32)  NOT NULL,
+    function       VARCHAR(32)  NOT NULL,
+    km             NUMBER(38,3) NOT NULL,
+    a              NUMBER(38, 3) NOT NULL,
+    b              NUMBER(38,3) NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_sqr_id FOREIGN KEY (sq_relation_id) REFERENCES sq_relation(id)
+);
--- a/flys-backend/doc/schema/oracle-spatial.sql	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/doc/schema/oracle-spatial.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -5,6 +5,8 @@
     GEOM MDSYS.SDO_GEOMETRY,
     river_id NUMBER(38),
     kind     NUMBER(38) DEFAULT 0 NOT NULL,
+    name     VARCHAR(64),
+    path     VARCHAR(256),
     ID NUMBER PRIMARY KEY NOT NULL
 );
 INSERT INTO USER_SDO_GEOM_METADATA VALUES ('river_axes', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
@@ -23,6 +25,8 @@
     GEOM MDSYS.SDO_GEOMETRY,
     river_id NUMBER(38),
     km NUMBER(6,3),
+    name     VARCHAR(64),
+    path     VARCHAR(256),
     ID NUMBER PRIMARY KEY NOT NULL
 );
 INSERT INTO USER_SDO_GEOM_METADATA VALUES ('river_axes_km', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
@@ -42,6 +46,8 @@
     river_id NUMBER(38),
     km       NUMBER(38,12) NOT NULL,
     z        NUMBER(38,12) DEFAULT 0 NOT NULL,
+    name     VARCHAR(64),
+    path     VARCHAR(256),
     ID NUMBER PRIMARY KEY NOT NULL
 );
 INSERT INTO USER_SDO_GEOM_METADATA VALUES ('cross_section_tracks', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
@@ -62,6 +68,8 @@
     river_id NUMBER(38),
     kind     VARCHAR2(16) NOT NULL,
     z        NUMBER(38,12) DEFAULT 0,
+    name     VARCHAR(64),
+    path     VARCHAR(256),
     ID NUMBER PRIMARY KEY NOT NULL
 );
 INSERT INTO USER_SDO_GEOM_METADATA VALUES ('lines', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
@@ -85,6 +93,7 @@
     GEOM MDSYS.SDO_GEOMETRY,
     river_id NUMBER(38),
     name VARCHAR2(255),
+    path     VARCHAR(256),
     ID NUMBER PRIMARY KEY NOT NULL
 );
 INSERT INTO USER_SDO_GEOM_METADATA VALUES ('buildings', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
@@ -106,6 +115,8 @@
     y NUMBER(38,11),
     km NUMBER(38,11) NOT NULL,
     HPGP VARCHAR2(255),
+    name VARCHAR(64),
+    path     VARCHAR(256),
     ID NUMBER PRIMARY KEY NOT NULL
 );
 INSERT INTO USER_SDO_GEOM_METADATA VALUES ('fixpoints', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
@@ -123,6 +134,8 @@
     OGR_FID NUMBER(38),
     GEOM MDSYS.SDO_GEOMETRY,
     river_id NUMBER(38),
+    name     VARCHAR(64),
+    path     VARCHAR(256),
     ID NUMBER PRIMARY KEY NOT NULL
 );
 INSERT INTO USER_SDO_GEOM_METADATA VALUES ('floodplain', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
@@ -142,10 +155,18 @@
     ID NUMBER PRIMARY KEY NOT NULL,
     river_id NUMBER(38),
     -- XXX Should we use the ranges table instead?
-    lower    NUMBER(38),
-    upper    NUMBER(38),
-    path     VARCHAR(256),
-    UNIQUE (river_id, lower, upper)
+    name            VARCHAR(64),
+    lower           NUMBER(19,5),
+    upper           NUMBER(19,5),
+    year_from       VARCHAR(32) NOT NULL,
+    year_to         VARCHAR(32) NOT NULL,
+    projection      VARCHAR(32) NOT NULL,
+    elevation_state VARCHAR(32),
+    format          VARCHAR(32),
+    border_break    BOOLEAN NOT NULL DEFAULT FALSE,
+    resolution      VARCHAR(16),
+    description     VARCHAR(256),
+    path            VARCHAR(256)
 );
 CREATE OR REPLACE TRIGGER dem_trigger BEFORE INSERT ON dem FOR each ROW
     BEGIN
@@ -162,6 +183,7 @@
     river_id NUMBER(38),
     area NUMBER(19,5),
     name VARCHAR2(255),
+    path     VARCHAR(256),
     ID NUMBER PRIMARY KEY NOT NULL
 );
 INSERT INTO USER_SDO_GEOM_METADATA VALUES ('CATCHMENT', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
@@ -181,6 +203,8 @@
     river_id NUMBER(38),
     hws_facility VARCHAR2(255),
     type VARCHAR2(255),
+    name VARCHAR(64),
+    path     VARCHAR(256),
     ID NUMBER PRIMARY KEY NOT NULL
 );
 INSERT INTO USER_SDO_GEOM_METADATA VALUES ('hws', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
@@ -190,3 +214,84 @@
     END;
 /
 --CREATE INDEX hws_spatial_idx ON hws(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=LINE');
+
+
+--Hydrologie/UeSG
+CREATE SEQUENCE FLOODMAPS_ID_SEQ;
+CREATE TABLE floodmaps (
+    OGR_FID NUMBER(38),
+    GEOM MDSYS.SDO_GEOMETRY,
+    river_id NUMBER(38),
+    name VARCHAR(255),
+    kind NUMBER(38),
+    diff NUMBER(19,5),
+    count NUMBER(38),
+    area NUMBER(19,5),
+    perimeter NUMBER(19,5),
+    path     VARCHAR(256),
+    id NUMBER PRIMARY KEY NOT NULL
+);
+INSERT INTO USER_SDO_GEOM_METADATA VALUES ('floodmaps', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
+CREATE OR REPLACE TRIGGER floodmaps_trigger BEFORE INSERT ON floodmaps FOR each ROW
+    BEGIN
+        SELECT FLOODMAPS_ID_SEQ.nextval INTO :new.id FROM dual;
+    END;
+/
+CREATE INDEX floodmaps_spatial_idx ON floodmaps(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=MULTIPOLYGON');
+
+
+--Hydrologie/Hydr.Grenzen/Linien
+CREATE SEQUENCE HYDR_BOUNDARIES_ID_SEQ;
+CREATE TABLE hydr_boundaries (
+    OGR_FID NUMBER(38),
+    GEOM MDSYS.SDO_GEOMETRY,
+    river_id NUMBER(38),
+    name VARCHAR(255),
+    kind NUMBER(38),
+    path     VARCHAR(256),
+    id NUMBER PRIMARY KEY NOT NULL
+);
+INSERT INTO USER_SDO_GEOM_METADATA VALUES ('hydr_boundaries', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
+CREATE OR REPLACE TRIGGER hydr_boundaries_trigger BEFORE INSERT ON hydr_boundaries FOR each ROW
+    BEGIN
+        SELECT HYDR_BOUNDARIES_ID_SEQ.nextval INTO :new.id FROM dual;
+    END;
+/
+CREATE INDEX hydr_boundaries_idx ON hydr_boundaries(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=LINE');
+
+CREATE SEQUENCE HYDR_BOUNDARIES_POLY_ID_SEQ;
+CREATE TABLE hydr_boundaries_poly (
+    OGR_FID NUMBER(38),
+    GEOM MDSYS.SDO_GEOMETRY,
+    river_id NUMBER(38),
+    name VARCHAR(255),
+    kind NUMBER(38),
+    path     VARCHAR(256),
+    id NUMBER PRIMARY KEY NOT NULL
+);
+INSERT INTO USER_SDO_GEOM_METADATA VALUES ('hydr_boundaries_poly', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
+CREATE OR REPLACE TRIGGER hydr_boundaries_poly_trigger BEFORE INSERT ON hydr_boundaries_poly FOR each ROW
+    BEGIN
+        SELECT HYDR_BOUNDARIES_POLY_ID_SEQ.nextval INTO :new.id FROM dual;
+    END;
+/
+CREATE INDEX hydr_boundaries_poly_idx ON hydr_boundaries_poly(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=MULTIPOLYGON');
+
+
+-- Hydrologie/Streckendaten/
+CREATE SEQUENCE GAUGE_LOCATION_ID_SEQ;
+CREATE TABLE gauge_location (
+    OGR_FID     NUMBER(38),
+    GEOM        MDSYS.SDO_GEOMETRY,
+    river_id    NUMBER(38),
+    name        VARCHAR(64),
+    path     VARCHAR(256),
+    id          NUMBER PRIMARY KEY NOT NULL
+);
+INSERT INTO USER_SDO_GEOM_METADATA VALUES ('gauge_location', 'GEOM', MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',3282450,3912240,0.001),MDSYS.SDO_DIM_ELEMENT('Y',5248260,6100130,0.001),MDSYS.SDO_DIM_ELEMENT('Z',-100000,100000,0.002)), 31467);
+CREATE OR REPLACE TRIGGER gauge_location_trigger BEFORE INSERT ON gauge_location FOR EACH ROW
+    BEGIN
+        SELECT GAUGE_LOCATION_ID_SEQ.nextval INTO :new.id FROM dual;
+    END;
+/
+CREATE INDEX gauge_location_idx ON gauge_location(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=POINT');
--- a/flys-backend/doc/schema/oracle-spatial_idx.sql	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/doc/schema/oracle-spatial_idx.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -1,4 +1,4 @@
-CREATE INDEX catchment_spatial_idx ON catchment(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=polygon');
+CREATE INDEX catchment_spatial_idx ON catchment(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=multipolygon');
 CREATE INDEX river_axes_km_spatial_idx ON river_axes_km(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=point');
 CREATE INDEX buildings_spatial_idx ON buildings(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=LINE');
 CREATE INDEX fixpoints_spatial_idx ON fixpoints(GEOM) indextype IS MDSYS.SPATIAL_INDEX parameters ('LAYER_GTYPE=POINT');
--- a/flys-backend/doc/schema/oracle.sql	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/doc/schema/oracle.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -57,9 +57,9 @@
 
 
 -- CROSS_SECTIONS
-create sequence CROSS_SECTIONS_ID_SEQ;
+CREATE SEQUENCE CROSS_SECTIONS_ID_SEQ;
 
-create table cross_sections (
+CREATE TABLE cross_sections (
     id                  NUMBER(38,0) NOT NULL,
     description         VARCHAR2(255),
     river_id            NUMBER(38,0),
@@ -67,6 +67,11 @@
     PRIMARY KEY         (id)
 );
 
+-- Indices for faster access of the points
+CREATE INDEX cross_section_lines_km_idx
+    ON cross_section_lines(km);
+CREATE INDEX cross_section_points_line_idx
+    ON cross_section_points(cross_section_line_id);
 
 -- DISCHARGE_TABLE_VALUES
 CREATE SEQUENCE DISCHARGE_TABLE_VALUES_ID_SEQ;
@@ -244,6 +249,7 @@
 
 CREATE TABLE rivers (
     id                  NUMBER(38,0) NOT NULL,
+    official_number     NUMBER(38,0),
     km_up               NUMBER(38,0),
     name                VARCHAR2(255),
     wst_unit_id         NUMBER(38,0),
@@ -288,8 +294,8 @@
 
 CREATE TABLE wst_column_values (
     id                  NUMBER(38,0) NOT NULL,
-    position            NUMBER(38,2),
-    w                   NUMBER(38,2),
+    position            NUMBER(38,5),
+    w                   NUMBER(38,5),
     wst_column_id       NUMBER(38,0),
     PRIMARY KEY         (id)
 );
@@ -314,7 +320,7 @@
 
 CREATE TABLE wst_q_ranges (
     id                  NUMBER(38,0) NOT NULL,
-    q                   NUMBER(38,2),
+    q                   NUMBER(38,5),
     range_id            NUMBER(38,0),
     PRIMARY KEY         (id)
 );
@@ -412,3 +418,58 @@
     JOIN ranges r         ON wqr.range_id        = r.id
     JOIN wst_columns wc   ON wcqr.wst_column_id  = wc.id
     ORDER BY wc.position, wcqr.wst_column_id, r.a;
+
+-- Views to make the 'Amtlichen Linien' easier to access.
+
+CREATE VIEW official_lines
+AS
+  SELECT w.river_id AS river_id,
+         w.id       AS wst_id,
+         wc.id      AS wst_column_id,
+         wc.name    AS name,
+         wc.position AS wst_column_pos
+  FROM   wsts w
+         JOIN wst_columns wc
+           ON wc.wst_id = w.id
+  WHERE  w.kind = 3;
+
+CREATE VIEW q_main_values
+AS
+  SELECT riv.id AS river_id,
+         g.id   AS gauge_id,
+         g.name AS gauge_name,
+         r.a    AS a,
+         r.b    AS b,
+         REGEXP_REPLACE(
+            nmv.name, '[:space:]*\(.*\)[:space:]*', '') AS name,
+         CAST(mv.value AS NUMERIC(38, 5)) AS value
+  FROM   main_values mv
+         JOIN named_main_values nmv
+           ON mv.named_value_id = nmv.id
+         JOIN main_value_types mvt
+           ON nmv.type_id = mvt.id
+         JOIN gauges g
+           ON mv.gauge_id = g.id
+         JOIN ranges r
+           ON g.range_id = r.id
+         JOIN rivers riv
+           ON g.river_id = riv.id
+  WHERE  mvt.name = 'Q'
+  ORDER  BY g.id, CAST(mv.value AS NUMERIC(38,5));
+
+CREATE VIEW official_q_values
+AS
+  SELECT ol.river_id AS river_id,
+         wst_id,
+         wst_column_id,
+         gauge_id,
+         gauge_name,
+         a,
+         b,
+         ol.name,
+         value,
+         wst_column_pos
+  FROM   official_lines ol
+         JOIN q_main_values qmv
+           ON ol.river_id = qmv.river_id
+              AND ol.name = qmv.name;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/schema/postgresql-drop-spatial.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,45 @@
+BEGIN;
+
+DROP TABLE river_axes;
+DROP SEQUENCE RIVER_AXES_ID_SEQ;
+
+DROP TABLE river_axes_km;
+DROP SEQUENCE RIVER_AXES_KM_ID_SEQ;
+
+DROP TABLE cross_section_tracks;
+DROP SEQUENCE CROSS_SECTION_TRACKS_ID_SEQ;
+
+DROP TABLE lines;
+DROP SEQUENCE LINES_ID_SEQ;
+
+DROP TABLE buildings;
+DROP SEQUENCE BUILDINGS_ID_SEQ;
+
+DROP TABLE fixpoints;
+DROP SEQUENCE FIXPOINTS_ID_SEQ;
+
+DROP TABLE floodplain;
+DROP SEQUENCE FLOODPLAIN_ID_SEQ;
+
+DROP TABLE dem;
+DROP SEQUENCE DEM_ID_SEQ;
+
+DROP TABLE catchment;
+DROP SEQUENCE CATCHMENT_ID_SEQ;
+
+DROP TABLE hws;
+DROP SEQUENCE HWS_ID_SEQ;
+
+DROP TABLE floodmaps;
+DROP SEQUENCE FLOODMAPS_ID_SEQ;
+
+DROP TABLE hydr_boundaries;
+DROP SEQUENCE HYDR_BOUNDARIES_ID_SEQ;
+
+DROP TABLE hydr_boundaries_poly;
+DROP SEQUENCE HYDR_BOUNDARIES_POLY_ID_SEQ;
+
+DROP TABLE gauge_location;
+DROP SEQUENCE GAUGE_LOCATION_ID_SEQ;
+
+COMMIT;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/doc/schema/postgresql-minfo.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,382 @@
+BEGIN;
+
+CREATE SEQUENCE LOCATION_SYSTEM_SEQ;
+
+CREATE TABLE location_system (
+    id          int NOT NULL,
+    name        VARCHAR(32)  NOT NULL,
+    description VARCHAR(255),
+    PRIMARY KEY(id)
+);
+
+
+CREATE SEQUENCE ELEVATION_MODEL_SEQ;
+
+CREATE TABLE elevation_model (
+    id          int NOT NULL,
+    name        VARCHAR(32)  NOT NULL,
+    unit_id     int NOT NULL,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_unit FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+CREATE SEQUENCE BED_HEIGHT_TYPE_SEQ;
+
+CREATE TABLE bed_height_type (
+    id          int NOT NULL,
+    name        VARCHAR(16)  NOT NULL,
+    description VARCHAR(255),
+    PRIMARY KEY(id)
+);
+
+
+
+CREATE SEQUENCE BED_HEIGHT_SINGLE_ID_SEQ;
+
+CREATE TABLE bed_height_single (
+    id                      int NOT NULL,
+    river_id                int NOT NULL,
+    year                    int NOT NULL,
+    sounding_width          int NOT NULL,
+    type_id                 int NOT NULL,
+    location_system_id      int NOT NULL,
+    cur_elevation_model_id  int NOT NULL,
+    old_elevation_model_id  int,
+    range_id                int NOT NULL,
+    evaluation_by           VARCHAR(255),
+    description             VARCHAR(255),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_bed_single_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_type FOREIGN KEY (type_id) REFERENCES bed_height_type(id),
+    CONSTRAINT fk_location_system FOREIGN KEY (location_system_id) REFERENCES location_system(id),
+    CONSTRAINT fk_cur_elevation_model FOREIGN KEY (cur_elevation_model_id) REFERENCES elevation_model(id),
+    CONSTRAINT fk_old_elevation_model FOREIGN KEY (old_elevation_model_id) REFERENCES elevation_model(id),
+    CONSTRAINT fk_range FOREIGN KEY (range_id) REFERENCES ranges(id)
+);
+
+
+CREATE SEQUENCE BED_HEIGHT_EPOCH_ID_SEQ;
+
+CREATE TABLE bed_height_epoch (
+    id                      int NOT NULL,
+    river_id                int NOT NULL,
+    time_interval_id        int NOT NULL,
+    -- sounding_with           int NOT NULL,
+    -- type_id                 int NOT NULL,
+    cur_elevation_model_id  int NOT NULL,
+    old_elevation_model_id  int,
+    range_id                int NOT NULL,
+    evaluation_by           VARCHAR(255),
+    description             VARCHAR(255),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_time_interval FOREIGN KEY (time_interval_id) REFERENCES time_intervals(id),
+    CONSTRAINT fk_epoch_cur_elevation_model FOREIGN KEY (cur_elevation_model_id) REFERENCES elevation_model(id),
+    CONSTRAINT fk_epoch_old_elevation_model FOREIGN KEY (old_elevation_model_id) REFERENCES elevation_model(id),
+    CONSTRAINT fk_epoch_range FOREIGN KEY (range_id) REFERENCES ranges(id)
+);
+
+
+CREATE SEQUENCE BED_SINGLE_VALUES_ID_SEQ;
+
+CREATE TABLE bed_height_single_values (
+    id                      int NOT NULL,
+    bed_height_single_id    int NOT NULL,
+    station                 NUMERIC NOT NULL,
+    height                  NUMERIC,
+    uncertainty             NUMERIC,
+    data_gap                NUMERIC,
+    sounding_width          NUMERIC,
+    width                   NUMERIC,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_bed_single_values_parent FOREIGN KEY (bed_height_single_id) REFERENCES bed_height_single(id)
+);
+
+
+CREATE SEQUENCE BED_EPOCH_VALUES_ID_SEQ;
+
+CREATE TABLE bed_height_epoch_values (
+    id                      int NOT NULL,
+    bed_height_epoch_id     int NOT NULL,
+    station                 NUMERIC NOT NULL,
+    height                  NUMERIC,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_bed_epoch_values_parent FOREIGN KEY (bed_height_epoch_id) REFERENCES bed_height_epoch(id)
+);
+
+
+CREATE SEQUENCE DEPTHS_ID_SEQ;
+
+CREATE TABLE depths (
+    id      int NOT NULL,
+    lower   NUMERIC NOT NULL,
+    upper   NUMERIC NOT NULL,
+    unit_id int NOT NULL,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_depths_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE SEDIMENT_DENSITY_ID_SEQ;
+
+CREATE TABLE sediment_density (
+    id          int NOT NULL,
+    river_id    int NOT NULL,
+    depth_id    int NOT NULL,
+    unit_id     int NOT NULL,
+    description VARCHAR(256),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_sd_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_sd_depth_id FOREIGN KEY (depth_id) REFERENCES depths(id),
+    CONSTRAINT fk_sd_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE SEDIMENT_DENSITY_VALUES_ID_SEQ;
+
+CREATE TABLE sediment_density_values (
+    id                  int NOT NULL,
+    sediment_density_id int NOT NULL,
+    station             NUMERIC NOT NULL,
+    density             NUMERIC NOT NULL,
+    description         VARCHAR(256),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_sdv_sediment_density_id FOREIGN KEY(sediment_density_id) REFERENCES sediment_density(id)
+);
+
+
+CREATE SEQUENCE MORPHOLOGIC_WIDTH_ID_SEQ;
+
+CREATE TABLE morphologic_width (
+    id          int NOT NULL,
+    river_id    int NOT NULL,
+    unit_id     int NOT NULL,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_mw_river_id FOREIGN KEY(river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_mw_unit_id FOREIGN KEY(unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE MORPH_WIDTH_VALUES_ID_SEQ;
+
+CREATE TABLE morphologic_width_values (
+    id                      int NOT NULL,
+    morphologic_width_id    int NOT NULL,
+    station                 NUMERIC NOT NULL,
+    width                   NUMERIC NOT NULL,
+    description             VARCHAR(256),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_mwv_morphologic_width_id FOREIGN KEY (morphologic_width_id) REFERENCES morphologic_width(id)
+);
+
+
+CREATE SEQUENCE DISCHARGE_ZONE_ID_SEQ;
+
+CREATE TABLE discharge_zone (
+    id                      int NOT NULL,
+    river_id                int NOT NULL,
+    gauge_name              VARCHAR(64)  NOT NULL, -- this is not very proper, but there are gauges with no db instance
+    value                   NUMERIC NOT NULL,
+    lower_discharge         VARCHAR(16)  NOT NULL,
+    upper_discharge         VARCHAR(16),
+    PRIMARY KEY(id),
+    CONSTRAINT fk_dz_river_id FOREIGN KEY (river_id) REFERENCES rivers(id)
+);
+
+
+CREATE SEQUENCE FLOW_VELOCITY_MODEL_ID_SEQ;
+
+CREATE TABLE flow_velocity_model (
+    id                  int NOT NULL,
+    river_id            int NOT NULL,
+    discharge_zone_id   int NOT NULL,
+    description         VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_fvm_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_fvm_discharge_zone_id FOREIGN KEY (discharge_zone_id) REFERENCES discharge_zone (id)
+);
+
+
+CREATE SEQUENCE FLOW_VELOCITY_M_VALUES_ID_SEQ;
+
+CREATE TABLE flow_velocity_model_values (
+    id                      int NOT NULL,
+    flow_velocity_model_id  int NOT NULL,
+    station                 NUMERIC NOT NULL,
+    q                       NUMERIC NOT NULL,
+    total_channel           NUMERIC NOT NULL,
+    main_channel            NUMERIC NOT NULL,
+    shear_stress            NUMERIC NOT NULL,
+    PRIMARY KEY(id),
+    CONSTRAINT fk_fvv_flow_velocity_model_id FOREIGN KEY (flow_velocity_model_id) REFERENCES flow_velocity_model(id)
+);
+
+
+
+CREATE SEQUENCE FV_MEASURE_ID_SEQ;
+
+CREATE TABLE flow_velocity_measurements (
+    id          int NOT NULL,
+    river_id    int NOT NULL,
+    description VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_fvm_rivers_id FOREIGN KEY (river_id) REFERENCES rivers(id)
+);
+
+CREATE SEQUENCE FV_MEASURE_VALUES_ID_SEQ;
+
+CREATE TABLE flow_velocity_measure_values (
+    id              int NOT NULL,
+    measurements_id int NOT NULL,
+    station         NUMERIC NOT NULL,
+    datetime        TIMESTAMP,
+    w               NUMERIC NOT NULL,
+    q               NUMERIC NOT NULL,
+    v               NUMERIC NOT NULL,
+    description     VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_fvmv_measurements_id FOREIGN KEY (measurements_id) REFERENCES flow_velocity_measurements (id)
+);
+
+
+CREATE SEQUENCE GRAIN_FRACTION_ID_SEQ;
+
+CREATE TABLE grain_fraction (
+    id      int   NOT NULL,
+    name    VARCHAR(64)    NOT NULL,
+    lower   NUMERIC,
+    upper   NUMERIC,
+    unit_id int,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_gf_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE SEDIMENT_YIELD_ID_SEQ;
+
+CREATE TABLE sediment_yield (
+    id                  int NOT NULL,
+    river_id            int NOT NULL,
+    grain_fraction_id   int,
+    unit_id             int NOT NULL,
+    time_interval_id    int NOT NULL,
+    description         VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_sy_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_sy_grain_fraction_id FOREIGN KEY (grain_fraction_id) REFERENCES grain_fraction(id),
+    CONSTRAINT fk_sy_unit_id FOREIGN KEY (unit_id) REFERENCES units(id),
+    CONSTRAINT fk_sy_time_interval_id FOREIGN KEY (time_interval_id) REFERENCES time_intervals(id)
+);
+
+
+CREATE SEQUENCE SEDIMENT_YIELD_VALUES_ID_SEQ;
+
+CREATE TABLE sediment_yield_values (
+    id                  int NOT NULL,
+    sediment_yield_id   int NOT NULL,
+    station             NUMERIC NOT NULL,
+    value               NUMERIC NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_syv_sediment_yield_id FOREIGN KEY (sediment_yield_id) REFERENCES sediment_yield(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_ID_SEQ;
+
+CREATE TABLE waterlevel (
+    id          int NOT NULL,
+    river_id    int NOT NULL,
+    unit_id     int NOT NULL,
+    description VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_w_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_w_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_Q_RANGES_ID_SEQ;
+
+CREATE TABLE waterlevel_q_range (
+    id              int NOT NULL,
+    waterlevel_id   int NOT NULL,
+    q               NUMERIC NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wqr_waterlevel_id FOREIGN KEY (waterlevel_id) REFERENCES waterlevel(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_VALUES_ID_SEQ;
+
+CREATE TABLE waterlevel_values (
+    id                      int NOT NULL,
+    waterlevel_q_range_id   int NOT NULL,
+    station                 NUMERIC NOT NULL,
+    w                       NUMERIC NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wv_waterlevel_q_range_id FOREIGN KEY (waterlevel_q_range_id) REFERENCES waterlevel_q_range(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_DIFFERENCE_ID_SEQ;
+
+CREATE TABLE waterlevel_difference (
+    id          int NOT NULL,
+    river_id    int NOT NULL,
+    unit_id     int NOT NULL,
+    description VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wd_river_id FOREIGN KEY (river_id) REFERENCES rivers (id),
+    CONSTRAINT fk_wd_unit_id FOREIGN KEY (unit_id) REFERENCES units(id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_DIFF_COLUMN_ID_SEQ;
+
+CREATE TABLE waterlevel_difference_column (
+    id              int NOT NULL,
+    difference_id   int NOT NULL,
+    description     VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wdc_difference_id FOREIGN KEY (difference_id) REFERENCES waterlevel_difference (id)
+);
+
+
+CREATE SEQUENCE WATERLEVEL_DIFF_VALUES_ID_SEQ;
+
+CREATE TABLE waterlevel_difference_values (
+    id          int NOT NULL,
+    column_id   int NOT NULL,
+    station     NUMERIC NOT NULL,
+    value       NUMERIC NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_wdv_column_id FOREIGN KEY (column_id) REFERENCES waterlevel_difference_column (id)
+);
+
+
+CREATE SEQUENCE SQ_RELATION_ID_SEQ;
+
+CREATE TABLE sq_relation (
+    id               int NOT NULL,
+    river_id         int NOT NULL,
+    time_interval_id int NOT NULL,
+    description      VARCHAR(256),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_sqr_river_id FOREIGN KEY (river_id) REFERENCES rivers(id),
+    CONSTRAINT fk_sqr_tinterval_id FOREIGN KEY (time_interval_id) REFERENCES time_intervals(id)
+);
+
+
+CREATE SEQUENCE SQ_RELATION_VALUES_ID_SEQ;
+
+CREATE TABLE sq_relation_value (
+    id             int NOT NULL,
+    sq_relation_id int NOT NULL,
+    parameter      VARCHAR(16)  NOT NULL,
+    fraction       VARCHAR(32)  NOT NULL,
+    function       VARCHAR(32)  NOT NULL,
+    km             NUMERIC NOT NULL,
+    a              NUMERIC NOT NULL,
+    b              NUMERIC NOT NULL,
+    PRIMARY KEY (id),
+    CONSTRAINT fk_sqr_id FOREIGN KEY (sq_relation_id) REFERENCES sq_relation(id)
+);
+COMMIT;
--- a/flys-backend/doc/schema/postgresql-spatial.sql	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/doc/schema/postgresql-spatial.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -5,9 +5,11 @@
 CREATE TABLE river_axes (
     id       int PRIMARY KEY NOT NULL,
     river_id int REFERENCES rivers(id),
-    kind     int             NOT NULL DEFAULT 0
+    kind     int             NOT NULL DEFAULT 0,
+    name     VARCHAR(64),
+    path     VARCHAR(256)
 );
-SELECT AddGeometryColumn('river_axes', 'geom', 31466, 'LINESTRING', 2);
+SELECT AddGeometryColumn('river_axes', 'geom', 31467, 'LINESTRING', 2);
 ALTER TABLE river_axes ALTER COLUMN id SET DEFAULT NEXTVAL('RIVER_AXES_ID_SEQ');
 
 
@@ -17,9 +19,11 @@
 CREATE TABLE river_axes_km (
     id       int PRIMARY KEY NOT NULL,
     river_id int REFERENCES rivers(id),
-    km       NUMERIC NOT NULL
+    km       NUMERIC NOT NULL,
+    name     VARCHAR(64),
+    path     VARCHAR(256)
 );
-SELECT AddGeometryColumn('river_axes_km', 'geom', 31466, 'POINT', 2);
+SELECT AddGeometryColumn('river_axes_km', 'geom', 31467, 'POINT', 2);
 ALTER TABLE river_axes_km ALTER COLUMN id SET DEFAULT NEXTVAL('RIVER_AXES_KM_ID_SEQ');
 
 
@@ -29,9 +33,11 @@
     id       int PRIMARY KEY NOT NULL,
     river_id int REFERENCES rivers(id),
     km       NUMERIC NOT NULL,
-    z        NUMERIC NOT NULL DEFAULT 0
+    z        NUMERIC NOT NULL DEFAULT 0,
+    name     VARCHAR(64),
+    path     VARCHAR(256)
 );
-SELECT AddGeometryColumn('cross_section_tracks', 'geom', 31466, 'LINESTRING', 2);
+SELECT AddGeometryColumn('cross_section_tracks', 'geom', 31467, 'LINESTRING', 2);
 ALTER TABLE cross_section_tracks ALTER COLUMN id SET DEFAULT NEXTVAL('CROSS_SECTION_TRACKS_ID_SEQ');
 
 
@@ -41,9 +47,11 @@
     id       int PRIMARY KEY NOT NULL,
     river_id int REFERENCES rivers(id),
     kind     VARCHAR(16) NOT NULL,
-    z        NUMERIC DEFAULT 0
+    z        NUMERIC DEFAULT 0,
+    name     VARCHAR(64),
+    path     VARCHAR(256)
 );
-SELECT AddGeometryColumn('lines', 'geom', 31466, 'LINESTRING', 4);
+SELECT AddGeometryColumn('lines', 'geom', 31467, 'LINESTRING', 3);
 ALTER TABLE lines ALTER COLUMN id SET DEFAULT NEXTVAL('LINES_ID_SEQ');
 -- 'kind':
 -- 0: ROHR1
@@ -55,9 +63,10 @@
 CREATE TABLE buildings (
     id       int PRIMARY KEY NOT NULL,
     river_id int REFERENCES rivers(id),
-    name     VARCHAR(256)
+    name     VARCHAR(256),
+    path     VARCHAR(256)
 );
-SELECT AddGeometryColumn('buildings', 'geom', 31466, 'LINESTRING', 2);
+SELECT AddGeometryColumn('buildings', 'geom', 31467, 'LINESTRING', 2);
 ALTER TABLE buildings ALTER COLUMN id SET DEFAULT NEXTVAL('BUILDINGS_ID_SEQ');
 
 
@@ -69,9 +78,11 @@
     x        int,
     y        int,
     km       NUMERIC NOT NULL,
-    HPGP     VARCHAR(2)
+    HPGP     VARCHAR(2),
+    name     VARCHAR(64),
+    path     VARCHAR(256)
 );
-SELECT AddGeometryColumn('fixpoints', 'geom', 31466, 'POINT', 2);
+SELECT AddGeometryColumn('fixpoints', 'geom', 31467, 'POINT', 2);
 ALTER TABLE fixpoints ALTER COLUMN id SET DEFAULT NEXTVAL('FIXPOINTS_ID_SEQ');
 
 
@@ -79,9 +90,11 @@
 CREATE SEQUENCE FLOODPLAIN_ID_SEQ;
 CREATE TABLE floodplain (
     id       int PRIMARY KEY NOT NULL,
-    river_id int REFERENCES rivers(id)
+    river_id int REFERENCES rivers(id),
+    name     VARCHAR(64),
+    path     VARCHAR(256)
 );
-SELECT AddGeometryColumn('floodplain', 'geom', 31466, 'POLYGON', 2);
+SELECT AddGeometryColumn('floodplain', 'geom', 31467, 'POLYGON', 2);
 ALTER TABLE floodplain ALTER COLUMN id SET DEFAULT NEXTVAL('FLOODPLAIN_ID_SEQ');
 
 
@@ -91,10 +104,18 @@
     id       int PRIMARY KEY NOT NULL,
     river_id int REFERENCES rivers(id),
     -- XXX Should we use the ranges table instead?
-    lower    NUMERIC,
-    upper    NUMERIC,
-    path     VARCHAR(256),
-    UNIQUE (river_id, lower, upper)
+    name            VARCHAR(64),
+    lower           NUMERIC,
+    upper           NUMERIC,
+    year_from       VARCHAR(32) NOT NULL,
+    year_to         VARCHAR(32) NOT NULL,
+    projection      VARCHAR(32) NOT NULL,
+    elevation_state VARCHAR(32),
+    format          VARCHAR(32),
+    border_break    BOOLEAN NOT NULL DEFAULT FALSE,
+    resolution      VARCHAR(16),
+    description     VARCHAR(256),
+    path            VARCHAR(256)
 );
 ALTER TABLE dem ALTER COLUMN id SET DEFAULT NEXTVAL('DEM_ID_SEQ');
 
@@ -105,9 +126,10 @@
     id int PRIMARY KEY NOT NULL,
     river_id int REFERENCES rivers(id),
     area NUMERIC,
-    name VARCHAR(256)
+    name VARCHAR(256),
+    path     VARCHAR(256)
 );
-SELECT AddGeometryColumn('catchment','geom',31466,'POLYGON',2);
+SELECT AddGeometryColumn('catchment','geom',31467,'POLYGON',2);
 ALTER TABLE catchment ALTER COLUMN id SET DEFAULT NEXTVAL('CATCHMENT_ID_SEQ');
 
 
@@ -117,10 +139,74 @@
     id int PRIMARY KEY NOT NULL,
     river_id int REFERENCES rivers(id),
     hws_facility VARCHAR(256),
-    type VARCHAR(256)
+    type VARCHAR(256),
+    name VARCHAR(64),
+    path     VARCHAR(256)
 );
-SELECT AddGeometryColumn('hws','geom',31466,'LINESTRING',2);
-ALTER TABLE hw ALTER COLUMN id SET DEFAULT NEXTVAL('HWS_ID_SEQ');
+SELECT AddGeometryColumn('hws','geom',31467,'LINESTRING',2);
+ALTER TABLE hws ALTER COLUMN id SET DEFAULT NEXTVAL('HWS_ID_SEQ');
 
 
-END;
+--
+--Hydrologie/UeSG
+--
+-- 'kind' can be one of:
+-- 200 = Messung
+-- 111 = Berechnung->Aktuell->BfG
+-- 112 = Berechnung->Aktuell->Land
+-- 121 = Berechnung->Potenziell->BfG
+-- 122 = Berechnung->Potenziell->Land
+--
+CREATE SEQUENCE FLOODMAPS_ID_SEQ;
+CREATE TABLE floodmaps (
+    id         int PRIMARY KEY NOT NULL,
+    river_id   int REFERENCES rivers(id),
+    name       varchar(64) NOT NULL,
+    kind       int NOT NULL,
+    diff       real,
+    count      int,
+    area       real,
+    perimeter  real,
+    path     VARCHAR(256)
+);
+SELECT AddGeometryColumn('floodmaps', 'geom', 31467, 'MULTIPOLYGON', 2);
+ALTER TABLE floodmaps DROP CONSTRAINT enforce_geotype_geom;
+ALTER TABLE floodmaps ADD CONSTRAINT enforce_geotype_geom CHECK (geometrytype(geom) = 'POLYGON'::text OR geometrytype(geom) = 'MULTIPOLYGON'::text);
+ALTER TABLE floodmaps ALTER COLUMN id SET DEFAULT NEXTVAL('FLOODMAPS_ID_SEQ');
+
+
+CREATE SEQUENCE HYDR_BOUNDARIES_ID_SEQ;
+CREATE TABLE hydr_boundaries (
+    id         int PRIMARY KEY NOT NULL,
+    river_id   int REFERENCES rivers(id),
+    name       VARCHAR(255),
+    kind       int,
+    path       VARCHAR(256)
+);
+SELECT AddGeometryColumn('hydr_boundaries','geom',31467,'LINESTRING',3);
+ALTER TABLE hydr_boundaries ALTER COLUMN id SET DEFAULT NEXTVAL('HYDR_BOUNDARIES_ID_SEQ');
+
+
+CREATE SEQUENCE HYDR_BOUNDARIES_POLY_ID_SEQ;
+CREATE TABLE hydr_boundaries_poly (
+    id         int PRIMARY KEY NOT NULL,
+    river_id   int REFERENCES rivers(id),
+    name       VARCHAR(255),
+    kind       int,
+    path       VARCHAR(256)
+);
+SELECT AddGeometryColumn('hydr_boundaries_poly','geom',31467,'POLYGON',3);
+ALTER TABLE hydr_boundaries_poly ALTER COLUMN id SET DEFAULT NEXTVAL('HYDR_BOUNDARIES_POLY_ID_SEQ');
+
+
+CREATE SEQUENCE GAUGE_LOCATION_ID_SEQ;
+CREATE TABLE gauge_location (
+    id         int PRIMARY KEY NOT NULL,
+    river_id   int REFERENCES rivers(id),
+    name       VARCHAR(255),
+    path       VARCHAR(256)
+);
+SELECT AddGeometryColumn('gauge_location','geom',31467,'POINT',2);
+ALTER TABLE gauge_location ALTER COLUMN id SET DEFAULT NEXTVAL('GAUGE_LOCATION_ID_SEQ');
+
+COMMIT;
--- a/flys-backend/doc/schema/postgresql.sql	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/doc/schema/postgresql.sql	Fri Sep 28 12:15:52 2012 +0200
@@ -11,10 +11,11 @@
 CREATE SEQUENCE RIVERS_ID_SEQ;
 
 CREATE TABLE rivers (
-    id          int PRIMARY KEY NOT NULL,
-    name        VARCHAR(256)    NOT NULL UNIQUE,
-    km_up       BOOLEAN         NOT NULL DEFAULT true,
-    wst_unit_id int             NOT NULL REFERENCES units(id)
+    id              int PRIMARY KEY NOT NULL,
+    official_number int8                     UNIQUE,
+    name            VARCHAR(256)    NOT NULL UNIQUE,
+    km_up           BOOLEAN         NOT NULL DEFAULT true,
+    wst_unit_id int                 NOT NULL REFERENCES units(id)
 );
 
 -- Bruecke, Haefen, etc.
@@ -300,6 +301,12 @@
     UNIQUE (cross_section_line_id, col_pos)
 );
 
+-- Indices for faster access of the points
+CREATE INDEX cross_section_lines_km_idx
+    ON cross_section_lines(km);
+CREATE INDEX cross_section_points_line_idx
+    ON cross_section_points(cross_section_line_id);
+
 -- Hydraulische Kenngroessen
 
 CREATE SEQUENCE HYKS_ID_SEQ;
@@ -353,4 +360,57 @@
     CHECK (a <= b)
 );
 
+CREATE VIEW official_lines
+AS
+  SELECT w.river_id AS river_id,
+         w.id       AS wst_id,
+         wc.id      AS wst_column_id,
+         wc.name    AS name,
+         wc.position AS wst_column_pos
+  FROM   wsts w
+         JOIN wst_columns wc
+           ON wc.wst_id = w.id
+  WHERE  w.kind = 3;
+
+CREATE VIEW q_main_values
+AS
+  SELECT riv.id AS river_id,
+         g.id   AS gauge_id,
+         g.name AS gauge_name,
+         r.a    AS a,
+         r.b    AS b,
+         REGEXP_REPLACE(
+            nmv.name, E'[:space:]*\\(.*\\)[:space:]*', '') AS name,
+         CAST(mv.value AS NUMERIC(38, 2)) AS value
+  FROM   main_values mv
+         JOIN named_main_values nmv
+           ON mv.named_value_id = nmv.id
+         JOIN main_value_types mvt
+           ON nmv.type_id = mvt.id
+         JOIN gauges g
+           ON mv.gauge_id = g.id
+         JOIN ranges r
+           ON g.range_id = r.id
+         JOIN rivers riv
+           ON g.river_id = riv.id
+  WHERE  mvt.name = 'Q'
+  ORDER  BY g.id, CAST(mv.value AS NUMERIC(38,2));
+
+CREATE VIEW official_q_values
+AS
+  SELECT ol.river_id AS river_id,
+         wst_id,
+         wst_column_id,
+         gauge_id,
+         gauge_name,
+         a,
+         b,
+         ol.name,
+         value,
+         wst_column_pos
+  FROM   official_lines ol
+         JOIN q_main_values qmv
+           ON ol.river_id = qmv.river_id
+              AND ol.name = qmv.name;
+
 COMMIT;
--- a/flys-backend/pom.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/pom.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -33,8 +33,8 @@
         <artifactId>maven-compiler-plugin</artifactId>
         <version>2.0.2</version>
         <configuration>
-          <source>1.5</source>
-          <target>1.5</target>
+          <source>1.6</source>
+          <target>1.6</target>
         </configuration>
       </plugin>
     </plugins>
@@ -53,6 +53,11 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>net.sf.opencsv</groupId>
+      <artifactId>opencsv</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-core</artifactId>
       <version>3.6.5.Final</version>
--- a/flys-backend/src/main/java/de/intevation/flys/App.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/App.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,6 +1,7 @@
 package de.intevation.flys;
 
 import de.intevation.flys.backend.SessionFactoryProvider;
+import de.intevation.flys.backend.FLYSCredentials;
 
 import org.hibernate.cfg.Configuration;
 
@@ -13,7 +14,7 @@
 
         String [] setupScript = cfg.generateSchemaCreationScript(
             DialectFactory.constructDialect(
-                SessionFactoryProvider.DEFAULT_DIALECT));
+                FLYSCredentials.getDefault().getDialect()));
 
         for (String line: setupScript) {
             System.out.println(line + ";");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/backend/Credentials.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,79 @@
+package de.intevation.flys.backend;
+
+public abstract class Credentials
+{
+    protected String   user;
+    protected String   password;
+    protected String   dialect;
+    protected String   driver;
+    protected String   url;
+    protected Class [] classes;
+
+    public Credentials() {
+    }
+
+    public Credentials(
+        String   user,
+        String   password,
+        String   dialect,
+        String   driver,
+        String   url,
+        Class [] classes
+    ) {
+        this.user     = user;
+        this.password = password;
+        this.dialect  = dialect;
+        this.driver   = driver;
+        this.url      = url;
+        this.classes  = classes;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getDialect() {
+        return dialect;
+    }
+
+    public void setDialect(String dialect) {
+        this.dialect = dialect;
+    }
+
+    public String getDriver() {
+        return driver;
+    }
+
+    public void setDriver(String driver) {
+        this.driver = driver;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public Class [] getClasses() {
+        return classes;
+    }
+
+    public void setClasses(Class [] classes) {
+        this.classes = classes;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/backend/FLYSCredentials.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,231 @@
+package de.intevation.flys.backend;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.flys.model.Annotation;
+import de.intevation.flys.model.AnnotationType;
+import de.intevation.flys.model.Attribute;
+import de.intevation.flys.model.BedHeightEpoch;
+import de.intevation.flys.model.BedHeightEpochValue;
+import de.intevation.flys.model.BedHeightSingle;
+import de.intevation.flys.model.BedHeightSingleValue;
+import de.intevation.flys.model.BedHeightType;
+import de.intevation.flys.model.Building;
+import de.intevation.flys.model.Catchment;
+import de.intevation.flys.model.CrossSection;
+import de.intevation.flys.model.CrossSectionLine;
+import de.intevation.flys.model.CrossSectionPoint;
+import de.intevation.flys.model.CrossSectionTrack;
+import de.intevation.flys.model.DGM;
+import de.intevation.flys.model.Depth;
+import de.intevation.flys.model.DischargeTable;
+import de.intevation.flys.model.DischargeTableValue;
+import de.intevation.flys.model.DischargeZone;
+import de.intevation.flys.model.Edge;
+import de.intevation.flys.model.ElevationModel;
+import de.intevation.flys.model.Fixpoint;
+import de.intevation.flys.model.Floodmaps;
+import de.intevation.flys.model.Floodplain;
+import de.intevation.flys.model.FlowVelocityMeasurement;
+import de.intevation.flys.model.FlowVelocityMeasurementValue;
+import de.intevation.flys.model.FlowVelocityModel;
+import de.intevation.flys.model.FlowVelocityModelValue;
+import de.intevation.flys.model.Gauge;
+import de.intevation.flys.model.GaugeLocation;
+import de.intevation.flys.model.GrainFraction;
+import de.intevation.flys.model.HYK;
+import de.intevation.flys.model.HYKEntry;
+import de.intevation.flys.model.HYKFlowZone;
+import de.intevation.flys.model.HYKFlowZoneType;
+import de.intevation.flys.model.HYKFormation;
+import de.intevation.flys.model.Hws;
+import de.intevation.flys.model.HydrBoundary;
+import de.intevation.flys.model.HydrBoundaryPoly;
+import de.intevation.flys.model.Line;
+import de.intevation.flys.model.LocationSystem;
+import de.intevation.flys.model.MainValue;
+import de.intevation.flys.model.MainValueType;
+import de.intevation.flys.model.MorphologicalWidth;
+import de.intevation.flys.model.MorphologicalWidthValue;
+import de.intevation.flys.model.NamedMainValue;
+import de.intevation.flys.model.Position;
+import de.intevation.flys.model.Range;
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.RiverAxis;
+import de.intevation.flys.model.RiverAxisKm;
+import de.intevation.flys.model.SQRelation;
+import de.intevation.flys.model.SQRelationValue;
+import de.intevation.flys.model.SedimentDensity;
+import de.intevation.flys.model.SedimentDensityValue;
+import de.intevation.flys.model.SedimentYield;
+import de.intevation.flys.model.SedimentYieldValue;
+import de.intevation.flys.model.TimeInterval;
+import de.intevation.flys.model.Unit;
+import de.intevation.flys.model.Waterlevel;
+import de.intevation.flys.model.WaterlevelDifference;
+import de.intevation.flys.model.WaterlevelDifferenceColumn;
+import de.intevation.flys.model.WaterlevelDifferenceValue;
+import de.intevation.flys.model.WaterlevelQRange;
+import de.intevation.flys.model.WaterlevelValue;
+import de.intevation.flys.model.Wst;
+import de.intevation.flys.model.WstColumn;
+import de.intevation.flys.model.WstColumnQRange;
+import de.intevation.flys.model.WstColumnValue;
+import de.intevation.flys.model.WstQRange;
+
+public class FLYSCredentials
+extends      Credentials
+{
+    public static final String XPATH_USER =
+        "/artifact-database/backend-database/user/text()";
+
+    public static final String XPATH_PASSWORD =
+        "/artifact-database/backend-database/password/text()";
+
+    public static final String XPATH_DIALECT =
+        "/artifact-database/backend-database/dialect/text()";
+
+    public static final String XPATH_DRIVER =
+        "/artifact-database/backend-database/driver/text()";
+
+    public static final String XPATH_URL =
+        "/artifact-database/backend-database/url/text()";
+
+    public static final String DEFAULT_USER =
+        System.getProperty("flys.backend.user", "flys");
+
+    public static final String DEFAULT_PASSWORD =
+        System.getProperty("flys.backend.password", "flys");
+
+    public static final String DEFAULT_DIALECT =
+        System.getProperty(
+            "flys.backend.dialect",
+            "org.hibernate.dialect.PostgreSQLDialect");
+
+    public static final String DEFAULT_DRIVER =
+        System.getProperty(
+            "flys.backend.driver",
+            "org.postgresql.Driver");
+
+    public static final String DEFAULT_URL =
+        System.getProperty(
+            "flys.backend.url",
+            "jdbc:postgresql://localhost:5432/flys");
+
+    public static final Class [] CLASSES = {
+        Annotation.class,
+        AnnotationType.class,
+        Attribute.class,
+        BedHeightEpoch.class,
+        BedHeightEpochValue.class,
+        BedHeightSingle.class,
+        BedHeightSingleValue.class,
+        BedHeightType.class,
+        Building.class,
+        Catchment.class,
+        CrossSection.class,
+        CrossSectionLine.class,
+        CrossSectionPoint.class,
+        CrossSectionTrack.class,
+        Depth.class,
+        DGM.class,
+        DischargeTable.class,
+        DischargeTableValue.class,
+        DischargeZone.class,
+        Edge.class,
+        ElevationModel.class,
+        Fixpoint.class,
+        Floodplain.class,
+        Floodmaps.class,
+        FlowVelocityMeasurement.class,
+        FlowVelocityMeasurementValue.class,
+        FlowVelocityModel.class,
+        FlowVelocityModelValue.class,
+        Gauge.class,
+        GaugeLocation.class,
+        GrainFraction.class,
+        Hws.class,
+        HydrBoundary.class,
+        HydrBoundaryPoly.class,
+        HYK.class,
+        HYKEntry.class,
+        HYKFormation.class,
+        HYKFlowZoneType.class,
+        HYKFlowZone.class,
+        Line.class,
+        LocationSystem.class,
+        MainValueType.class,
+        MorphologicalWidth.class,
+        MorphologicalWidthValue.class,
+        NamedMainValue.class,
+        MainValue.class,
+        Position.class,
+        Range.class,
+        River.class,
+        RiverAxis.class,
+        RiverAxisKm.class,
+        SedimentDensity.class,
+        SedimentDensityValue.class,
+        SedimentYield.class,
+        SedimentYieldValue.class,
+        SQRelation.class,
+        SQRelationValue.class,
+        TimeInterval.class,
+        Unit.class,
+        Waterlevel.class,
+        WaterlevelDifference.class,
+        WaterlevelDifferenceColumn.class,
+        WaterlevelDifferenceValue.class,
+        WaterlevelQRange.class,
+        WaterlevelValue.class,
+        WstColumn.class,
+        WstColumnQRange.class,
+        WstColumnValue.class,
+        Wst.class,
+        WstQRange.class
+    };
+
+    public FLYSCredentials() {
+    }
+
+    public FLYSCredentials(
+        String user,
+        String password,
+        String dialect,
+        String driver,
+        String url
+    ) {
+        super(user, password, dialect, driver, url, CLASSES);
+    }
+
+    private static Credentials instance;
+
+    public static synchronized Credentials getInstance() {
+        if (instance == null) {
+            String user =
+                Config.getStringXPath(XPATH_USER, DEFAULT_USER);
+            String password =
+                Config.getStringXPath(XPATH_PASSWORD, DEFAULT_PASSWORD);
+            String dialect =
+                Config.getStringXPath(XPATH_DIALECT, DEFAULT_DIALECT);
+            String driver =
+                Config.getStringXPath(XPATH_DRIVER, DEFAULT_DRIVER);
+            String url =
+                Config.getStringXPath(XPATH_URL, DEFAULT_URL);
+
+            instance = new FLYSCredentials(
+                user, password, dialect, driver, url);
+        }
+        return instance;
+    }
+
+    public static Credentials getDefault() {
+        return new FLYSCredentials(
+            DEFAULT_USER,
+            DEFAULT_PASSWORD,
+            DEFAULT_DIALECT,
+            DEFAULT_DRIVER,
+            DEFAULT_URL);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/backend/SedDBCredentials.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,195 @@
+package de.intevation.flys.backend;
+
+import de.intevation.artifacts.common.utils.Config;
+
+import de.intevation.seddb.model.Bezugspegel;
+import de.intevation.seddb.model.Bezugspegelgew;
+import de.intevation.seddb.model.BezugspegelgewId;
+import de.intevation.seddb.model.Bild;
+import de.intevation.seddb.model.Gewaesser;
+import de.intevation.seddb.model.Gfaenger;
+import de.intevation.seddb.model.Glotlinks;
+import de.intevation.seddb.model.GlotlinksId;
+import de.intevation.seddb.model.Glotrechte;
+import de.intevation.seddb.model.Gprobe;
+import de.intevation.seddb.model.GprobeId;
+import de.intevation.seddb.model.Gsiebsatz;
+import de.intevation.seddb.model.Gsiebung;
+import de.intevation.seddb.model.Gsiebungsieb;
+import de.intevation.seddb.model.GsiebungsiebId;
+import de.intevation.seddb.model.Hpeilpunkt;
+import de.intevation.seddb.model.HpeilpunktId;
+import de.intevation.seddb.model.Hpeilung;
+import de.intevation.seddb.model.Messung;
+import de.intevation.seddb.model.Messunglotcount;
+import de.intevation.seddb.model.MessunglotcountId;
+import de.intevation.seddb.model.Messungsta;
+import de.intevation.seddb.model.MessungstaId;
+import de.intevation.seddb.model.Messunguferbezug;
+import de.intevation.seddb.model.MessunguferbezugId;
+import de.intevation.seddb.model.Mpeilpunkt;
+import de.intevation.seddb.model.MpeilpunktId;
+import de.intevation.seddb.model.Mpeilung;
+import de.intevation.seddb.model.Probebild;
+import de.intevation.seddb.model.Siebanalyse;
+import de.intevation.seddb.model.Slotlinks;
+import de.intevation.seddb.model.SlotlinksId;
+import de.intevation.seddb.model.Slotrechte;
+import de.intevation.seddb.model.Sohlprobe;
+import de.intevation.seddb.model.Sohltest;
+import de.intevation.seddb.model.Sprobe;
+import de.intevation.seddb.model.SprobeId;
+import de.intevation.seddb.model.Ssiebung;
+import de.intevation.seddb.model.Ssiebungsieb;
+import de.intevation.seddb.model.SsiebungsiebId;
+import de.intevation.seddb.model.Station;
+import de.intevation.seddb.model.Stationgew;
+import de.intevation.seddb.model.StationgewId;
+import de.intevation.seddb.model.TmpGloChanged;
+import de.intevation.seddb.model.TmpMesAchanged;
+import de.intevation.seddb.model.TmpMesGchanged;
+import de.intevation.seddb.model.TmpMesQchanged;
+import de.intevation.seddb.model.TmpMesSchanged;
+import de.intevation.seddb.model.Zzarchiv;
+import de.intevation.seddb.model.Zzprobenahmeart;
+import de.intevation.seddb.model.Zzsondierungart;
+import de.intevation.seddb.model.Zzthema;
+
+public class SedDBCredentials
+extends      Credentials
+{
+    public static final String XPATH_USER =
+        "/artifact-database/seddb-database/user/text()";
+
+    public static final String XPATH_PASSWORD =
+        "/artifact-database/seddb-database/password/text()";
+
+    public static final String XPATH_DIALECT =
+        "/artifact-database/seddb-database/dialect/text()";
+
+    public static final String XPATH_DRIVER =
+        "/artifact-database/seddb-database/driver/text()";
+
+    public static final String XPATH_URL =
+        "/artifact-database/seddb-database/url/text()";
+
+    public static final String DEFAULT_USER =
+        System.getProperty("flys.seddb.user", "seddb");
+
+    public static final String DEFAULT_PASSWORD =
+        System.getProperty("flys.seddb.password", "seddb");
+
+    public static final String DEFAULT_DIALECT =
+        System.getProperty(
+            "flys.seddb.dialect",
+            "org.hibernate.dialect.PostgreSQLDialect");
+
+    public static final String DEFAULT_DRIVER =
+        System.getProperty(
+            "flys.seddb.driver",
+            "org.postgresql.Driver");
+
+    public static final String DEFAULT_URL =
+        System.getProperty(
+            "flys.seddb.url",
+            "jdbc:postgresql://localhost:5432/seddb");
+
+    public static final Class [] CLASSES = {
+        BezugspegelgewId.class,
+        Bezugspegelgew.class,
+        Bezugspegel.class,
+        Bild.class,
+        Gewaesser.class,
+        Gfaenger.class,
+        GlotlinksId.class,
+        Glotlinks.class,
+        Glotrechte.class,
+        GprobeId.class,
+        Gprobe.class,
+        Gsiebsatz.class,
+        Gsiebung.class,
+        GsiebungsiebId.class,
+        Gsiebungsieb.class,
+        HpeilpunktId.class,
+        Hpeilpunkt.class,
+        Hpeilung.class,
+        Messung.class,
+        MessunglotcountId.class,
+        Messunglotcount.class,
+        MessungstaId.class,
+        Messungsta.class,
+        MessunguferbezugId.class,
+        Messunguferbezug.class,
+        MpeilpunktId.class,
+        Mpeilpunkt.class,
+        Mpeilung.class,
+        Probebild.class,
+        Siebanalyse.class,
+        SlotlinksId.class,
+        Slotlinks.class,
+        Slotrechte.class,
+        Sohlprobe.class,
+        Sohltest.class,
+        SprobeId.class,
+        Sprobe.class,
+        Ssiebung.class,
+        SsiebungsiebId.class,
+        Ssiebungsieb.class,
+        StationgewId.class,
+        Stationgew.class,
+        Station.class,
+        TmpGloChanged.class,
+        TmpMesAchanged.class,
+        TmpMesGchanged.class,
+        TmpMesQchanged.class,
+        TmpMesSchanged.class,
+        Zzarchiv.class,
+        Zzprobenahmeart.class,
+        Zzsondierungart.class,
+        Zzthema.class
+    };
+
+    private static Credentials instance;
+
+    public SedDBCredentials() {
+    }
+
+    public SedDBCredentials(
+        String user,
+        String password,
+        String dialect,
+        String driver,
+        String url
+    ) {
+        super(user, password, dialect, driver, url, CLASSES);
+    }
+
+    public static synchronized Credentials getInstance() {
+        if (instance == null) {
+            String user =
+                Config.getStringXPath(XPATH_USER, DEFAULT_USER);
+            String password =
+                Config.getStringXPath(XPATH_PASSWORD, DEFAULT_PASSWORD);
+            String dialect =
+                Config.getStringXPath(XPATH_DIALECT, DEFAULT_DIALECT);
+            String driver =
+                Config.getStringXPath(XPATH_DRIVER, DEFAULT_DRIVER);
+            String url =
+                Config.getStringXPath(XPATH_URL, DEFAULT_URL);
+
+            instance = new SedDBCredentials(
+                user, password, dialect, driver, url);
+        }
+        return instance;
+    }
+
+    public static Credentials getDefault() {
+        return new SedDBCredentials(
+            DEFAULT_USER,
+            DEFAULT_PASSWORD,
+            DEFAULT_DIALECT,
+            DEFAULT_DRIVER,
+            DEFAULT_URL);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/backend/SedDBSessionHolder.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,43 @@
+package de.intevation.flys.backend;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+
+public class SedDBSessionHolder
+{
+    private static Logger log =
+        Logger.getLogger(SedDBSessionHolder.class);
+
+    public static final ThreadLocal<Session> HOLDER =
+        new ThreadLocal<Session>() {
+            @Override
+            protected Session initialValue() {
+                return create();
+            }
+        };
+
+    private SedDBSessionHolder() {
+    }
+
+    public synchronized static Session create() {
+        log.debug("create");
+        SessionFactory sessionFactory =
+            SessionFactoryProvider.getSedDBSessionFactory();
+        return sessionFactory.openSession();
+    }
+
+    public static Session acquire() {
+        log.debug("acquire");
+        Session session = create();
+        HOLDER.set(session);
+        return session;
+    }
+
+    public static void release() {
+        log.debug("release");
+        HOLDER.remove();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/backend/SessionFactoryProvider.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,152 +1,68 @@
 package de.intevation.flys.backend;
 
-import de.intevation.artifacts.common.utils.Config;
+import java.lang.management.ManagementFactory;
 
-import java.lang.management.ManagementFactory;
 import java.util.Properties;
 
 import javax.management.InstanceAlreadyExistsException;
-import javax.management.MalformedObjectNameException;
 import javax.management.MBeanRegistrationException;
 import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
 import javax.management.NotCompliantMBeanException;
 import javax.management.ObjectName;
 
-import org.hibernate.SessionFactory;
+import org.apache.log4j.Logger;
 
-import org.hibernate.impl.SessionFactoryImpl;
-
-import org.hibernate.jmx.StatisticsService;
+import org.hibernate.SessionFactory;
 
 import org.hibernate.cfg.Configuration;
 import org.hibernate.cfg.Environment;
 
-import de.intevation.flys.model.Annotation;
-import de.intevation.flys.model.AnnotationType;
-import de.intevation.flys.model.Attribute;
-import de.intevation.flys.model.Building;
-import de.intevation.flys.model.Catchment;
-import de.intevation.flys.model.CrossSection;
-import de.intevation.flys.model.CrossSectionLine;
-import de.intevation.flys.model.CrossSectionPoint;
-import de.intevation.flys.model.CrossSectionTrack;
-import de.intevation.flys.model.DGM;
-import de.intevation.flys.model.DischargeTable;
-import de.intevation.flys.model.DischargeTableValue;
-import de.intevation.flys.model.Edge;
-import de.intevation.flys.model.Fixpoint;
-import de.intevation.flys.model.Floodplain;
-import de.intevation.flys.model.Gauge;
-import de.intevation.flys.model.Hws;
-import de.intevation.flys.model.HYK;
-import de.intevation.flys.model.HYKEntry;
-import de.intevation.flys.model.HYKFormation;
-import de.intevation.flys.model.HYKFlowZoneType;
-import de.intevation.flys.model.HYKFlowZone;
-import de.intevation.flys.model.Line;
-import de.intevation.flys.model.MainValueType;
-import de.intevation.flys.model.NamedMainValue;
-import de.intevation.flys.model.MainValue;
-import de.intevation.flys.model.Position;
-import de.intevation.flys.model.Range;
-import de.intevation.flys.model.River;
-import de.intevation.flys.model.RiverAxis;
-import de.intevation.flys.model.RiverAxisKm;
-import de.intevation.flys.model.TimeInterval;
-import de.intevation.flys.model.Unit;
-import de.intevation.flys.model.WstColumn;
-import de.intevation.flys.model.WstColumnQRange;
-import de.intevation.flys.model.WstColumnValue;
-import de.intevation.flys.model.Wst;
-import de.intevation.flys.model.WstQRange;
+import org.hibernate.impl.SessionFactoryImpl;
 
-import org.apache.log4j.Logger;
+import org.hibernate.jmx.StatisticsService;
 
 public final class SessionFactoryProvider
 {
     private static Logger log = Logger.getLogger(SessionFactoryProvider.class);
 
-    public static final String XPATH_USER =
-        "/artifact-database/backend-database/user/text()";
-
-    public static final String XPATH_PASSWORD =
-        "/artifact-database/backend-database/password/text()";
-
-    public static final String XPATH_DIALECT =
-        "/artifact-database/backend-database/dialect/text()";
-
-    public static final String XPATH_DRIVER =
-        "/artifact-database/backend-database/driver/text()";
-
-    public static final String XPATH_URL =
-        "/artifact-database/backend-database/url/text()";
-
-    public static final String DEFAULT_USER =
-        System.getProperty("flys.backend.user", "flys");
-
-    public static final String DEFAULT_PASSWORD =
-        System.getProperty("flys.backend.password", "flys");
-
-    public static final String DEFAULT_DIALECT =
-        System.getProperty(
-            "flys.backend.dialect",
-            "org.hibernate.dialect.PostgreSQLDialect");
-
-    public static final String DEFAULT_DRIVER =
-        System.getProperty(
-            "flys.backend.driver",
-            "org.postgresql.Driver");
-
-    public static final String DEFAULT_URL =
-        System.getProperty(
-            "flys.backend.url",
-            "jdbc:postgresql://localhost:5432/flys");
-
     public static final boolean ENABLE_JMX =
         Boolean.getBoolean("flys.backend.enablejmx");
 
-    private static SessionFactory sessionFactory;
+    private static SessionFactory flysSessionFactory;
+    private static SessionFactory sedDBSessionFactory;
 
     private SessionFactoryProvider() {
     }
 
     public static synchronized SessionFactory getSessionFactory() {
-        if (sessionFactory == null) {
-            String user =
-                Config.getStringXPath(XPATH_USER, DEFAULT_USER);
-            String password =
-                Config.getStringXPath(XPATH_PASSWORD, DEFAULT_PASSWORD);
-            String dialect =
-                Config.getStringXPath(XPATH_DIALECT, DEFAULT_DIALECT);
-            String driver =
-                Config.getStringXPath(XPATH_DRIVER, DEFAULT_DRIVER);
-            String url =
-                Config.getStringXPath(XPATH_URL, DEFAULT_URL);
-
-            sessionFactory = createSessionFactory(
-                user, password, dialect, driver, url);
+        if (flysSessionFactory == null) {
+            flysSessionFactory =
+                createSessionFactory(FLYSCredentials.getInstance());
         }
-        return sessionFactory;
+        return flysSessionFactory;
     }
 
     public static SessionFactory createSessionFactory() {
-        return createSessionFactory(
-            DEFAULT_USER,
-            DEFAULT_PASSWORD,
-            DEFAULT_DIALECT,
-            DEFAULT_DRIVER,
-            DEFAULT_URL);
+        return createSessionFactory(FLYSCredentials.getDefault());
+    }
+
+    public static synchronized SessionFactory getSedDBSessionFactory() {
+        if (sedDBSessionFactory == null) {
+            sedDBSessionFactory =
+                createSessionFactory(SedDBCredentials.getInstance());
+        }
+        return sedDBSessionFactory;
+    }
+
+    public static SessionFactory createSedDBSessionFactory() {
+        return createSessionFactory(SedDBCredentials.getDefault());
     }
 
     public static SessionFactory createSessionFactory(
-        String user,
-        String password,
-        String dialect,
-        String driver,
-        String url
+        Credentials credentials
     ) {
-        Configuration cfg = createConfiguration(
-            user, password, dialect, driver, url);
+        Configuration cfg = createConfiguration(credentials);
 
         SessionFactory factory = cfg.buildSessionFactory();
 
@@ -160,7 +76,6 @@
         return factory;
     }
 
-
     public static void registerAsMBean(SessionFactory factory) {
 
         StatisticsService statsMBean = new StatisticsService();
@@ -189,70 +104,24 @@
         }
     }
 
-
     public static Configuration createConfiguration() {
-        return createConfiguration(
-            DEFAULT_USER,
-            DEFAULT_PASSWORD,
-            DEFAULT_DIALECT,
-            DEFAULT_DRIVER,
-            DEFAULT_URL);
+        return createConfiguration(FLYSCredentials.getInstance());
     }
 
     public static Configuration createConfiguration(
-        String user,
-        String password,
-        String dialect,
-        String driver,
-        String url
+        Credentials credentials
     ) {
         Configuration cfg = new Configuration();
 
-        // TODO: Use package reflection here.
-        cfg.addAnnotatedClass(Annotation.class);
-        cfg.addAnnotatedClass(AnnotationType.class);
-        cfg.addAnnotatedClass(Attribute.class);
-        cfg.addAnnotatedClass(Building.class);
-        cfg.addAnnotatedClass(Catchment.class);
-        cfg.addAnnotatedClass(CrossSection.class);
-        cfg.addAnnotatedClass(CrossSectionLine.class);
-        cfg.addAnnotatedClass(CrossSectionPoint.class);
-        cfg.addAnnotatedClass(CrossSectionTrack.class);
-        cfg.addAnnotatedClass(DGM.class);
-        cfg.addAnnotatedClass(DischargeTable.class);
-        cfg.addAnnotatedClass(DischargeTableValue.class);
-        cfg.addAnnotatedClass(Edge.class);
-        cfg.addAnnotatedClass(Fixpoint.class);
-        cfg.addAnnotatedClass(Floodplain.class);
-        cfg.addAnnotatedClass(Gauge.class);
-        cfg.addAnnotatedClass(Hws.class);
-        cfg.addAnnotatedClass(HYK.class);
-        cfg.addAnnotatedClass(HYKEntry.class);
-        cfg.addAnnotatedClass(HYKFormation.class);
-        cfg.addAnnotatedClass(HYKFlowZoneType.class);
-        cfg.addAnnotatedClass(HYKFlowZone.class);
-        cfg.addAnnotatedClass(Line.class);
-        cfg.addAnnotatedClass(MainValueType.class);
-        cfg.addAnnotatedClass(NamedMainValue.class);
-        cfg.addAnnotatedClass(MainValue.class);
-        cfg.addAnnotatedClass(Position.class);
-        cfg.addAnnotatedClass(Range.class);
-        cfg.addAnnotatedClass(River.class);
-        cfg.addAnnotatedClass(RiverAxis.class);
-        cfg.addAnnotatedClass(RiverAxisKm.class);
-        cfg.addAnnotatedClass(TimeInterval.class);
-        cfg.addAnnotatedClass(Unit.class);
-        cfg.addAnnotatedClass(WstColumn.class);
-        cfg.addAnnotatedClass(WstColumnQRange.class);
-        cfg.addAnnotatedClass(WstColumnValue.class);
-        cfg.addAnnotatedClass(Wst.class);
-        cfg.addAnnotatedClass(WstQRange.class);
+        for (Class clazz: credentials.getClasses()) {
+            cfg.addAnnotatedClass(clazz);
+        }
 
         if (log.isDebugEnabled()) {
-            log.debug("user: "    + user);
-            log.debug("dialect: " + dialect);
-            log.debug("driver: "  + driver);
-            log.debug("url: "     + url);
+            log.debug("user: "    + credentials.getUser());
+            log.debug("dialect: " + credentials.getDialect());
+            log.debug("driver: "  + credentials.getDriver());
+            log.debug("url: "     + credentials.getUrl());
         }
 
         Properties props = new Properties();
@@ -260,13 +129,13 @@
         // We rely on our own connection pool
         props.setProperty(
             "hibernate.connection.provider_class",
-            "org.hibernate.connection.DBCPConnectionProvider");
+            "de.intevation.flys.utils.DBCPConnectionProvider");
 
-        props.setProperty(Environment.DIALECT, dialect);
-        props.setProperty(Environment.USER,    user);
-        props.setProperty(Environment.PASS,    password);
-        props.setProperty(Environment.DRIVER,  driver);
-        props.setProperty(Environment.URL,     url);
+        props.setProperty(Environment.DIALECT, credentials.getDialect());
+        props.setProperty(Environment.USER,    credentials.getUser());
+        props.setProperty(Environment.PASS,    credentials.getPassword());
+        props.setProperty(Environment.DRIVER,  credentials.getDriver());
+        props.setProperty(Environment.URL,     credentials.getUrl());
 
         cfg.mergeProperties(props);
 
--- a/flys-backend/src/main/java/de/intevation/flys/backend/SessionHolder.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/backend/SessionHolder.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,11 +8,12 @@
 
 public class SessionHolder
 {
-    private static Logger logger =
+    private static Logger log =
         Logger.getLogger(SessionHolder.class);
 
     public static final ThreadLocal<Session> HOLDER =
         new ThreadLocal<Session>() {
+            @Override
             protected Session initialValue() {
                 return create();
             }
@@ -22,21 +23,21 @@
     }
 
     public synchronized static Session create() {
-        logger.debug("create");
+        log.debug("create");
         SessionFactory sessionFactory =
             SessionFactoryProvider.getSessionFactory();
         return sessionFactory.openSession();
     }
 
     public static Session acquire() {
-        logger.debug("acquire");
+        log.debug("acquire");
         Session session = create();
         HOLDER.set(session);
         return session;
     }
 
     public static void release() {
-        logger.debug("release");
+        log.debug("release");
         HOLDER.remove();
     }
 }
--- a/flys-backend/src/main/java/de/intevation/flys/backend/SpatialInfo.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/backend/SpatialInfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -7,9 +7,6 @@
 import org.hibernate.Query;
 import org.hibernate.Session;
 
-import com.vividsolutions.jts.geom.LineString;
-
-import de.intevation.flys.backend.SessionFactoryProvider;
 import de.intevation.flys.model.Building;
 import de.intevation.flys.model.CrossSectionTrack;
 import de.intevation.flys.model.Fixpoint;
@@ -88,11 +85,9 @@
 
 
     protected void doRiverAxisInfo(River river) {
-        RiverAxis axis = RiverAxis.getRiverAxis(river.getName());
-        if (axis != null) {
-            LineString ls = axis.getGeom();
-            logger.info("River axis is " + ls.getLength() + " long.");
-            logger.info("River boundary: " + ls.getBoundary());
+        List<RiverAxis> axis = RiverAxis.getRiverAxis(river.getName());
+        if (axis != null && axis.size() > 0) {
+            logger.debug("TODO: Compute length and boundary.");
         }
         else {
             logger.warn("River has no RiverAxis.");
--- a/flys-backend/src/main/java/de/intevation/flys/importer/Config.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/Config.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,9 +2,15 @@
 
 public class Config
 {
+    public static final String SKIP_DEFAULT =
+        "flys.backend.importer.skip.default";
+
     public static final String DRY_RUN =
         "flys.backend.importer.dry.run";
 
+    public static final String INFO_GEW_FILE =
+        "flys.backend.importer.infogew.file";
+
     public static final String ANNOTATION_TYPES =
         "flys.backend.importer.annotation.types";
 
@@ -38,13 +44,52 @@
     public static final String SKIP_FLOOD_PROTECTION =
         "flys.backend.importer.skip.flood.protection";
 
+    public static final String SKIP_BED_HEIGHT_SINGLE =
+        "flys.backend.importer.skip.bed.height.single";
+
+    public static final String SKIP_BED_HEIGHT_EPOCH =
+        "flys.backend.importer.skip.bed.height.epoch";
+
+    public static final String SKIP_SEDIMENT_DENSITY =
+        "flys.backend.importer.skip.sediment.density";
+
+    public static final String SKIP_MORPHOLOGICAL_WIDTH =
+        "flys.backend.importer.skip.morphological.width";
+
+    public static final String SKIP_FLOW_VELOCITY =
+        "flys.backend.importer.skip.flow.velocity";
+
+    public static final String SKIP_SEDIMENT_YIELD =
+        "flys.backend.importer.skip.sediment.yield";
+
+    public static final String SKIP_WATERLEVELS =
+        "flys.backend.importer.skip.waterlevels";
+
+    public static final String SKIP_WATERLEVEL_DIFFERENCES =
+        "flys.backend.importer.skip.waterlevel.differences";
+
+    public static final String SKIP_SQ_RELATION =
+        "flys.backend.importer.skip.sq.relation";
+
+
     public static final Config INSTANCE = new Config();
 
     private Config () {
     }
 
+    public static final boolean getFlag(String key) {
+        String flag = System.getProperty(key);
+        return flag != null
+            ? Boolean.valueOf(flag)
+            : Boolean.getBoolean(SKIP_DEFAULT);
+    }
+
     public boolean dryRun() {
-        return Boolean.getBoolean(DRY_RUN);
+        return getFlag(DRY_RUN);
+    }
+
+    public String getInfoGewFile() {
+        return System.getProperty(INFO_GEW_FILE);
     }
 
     public String getAnnotationTypes() {
@@ -52,43 +97,79 @@
     }
 
     public boolean skipGauges() {
-        return Boolean.getBoolean(SKIP_GAUGES);
+        return getFlag(SKIP_GAUGES);
     }
 
     public boolean skipAnnotations() {
-        return Boolean.getBoolean(SKIP_ANNOTATIONS);
+        return getFlag(SKIP_ANNOTATIONS);
     }
 
     public boolean skipPRFs() {
-        return Boolean.getBoolean(SKIP_PRFS);
+        return getFlag(SKIP_PRFS);
     }
 
     public boolean skipHYKs() {
-        return Boolean.getBoolean(SKIP_HYKS);
+        return getFlag(SKIP_HYKS);
     }
 
     public boolean skipWst() {
-        return Boolean.getBoolean(SKIP_WST);
+        return getFlag(SKIP_WST);
     }
 
     public boolean skipExtraWsts() {
-        return Boolean.getBoolean(SKIP_EXTRA_WSTS);
+        return getFlag(SKIP_EXTRA_WSTS);
     }
 
     public boolean skipFixations() {
-        return Boolean.getBoolean(SKIP_FIXATIONS);
+        return getFlag(SKIP_FIXATIONS);
     }
 
     public boolean skipOfficialLines() {
-        return Boolean.getBoolean(SKIP_OFFICIAL_LINES);
+        return getFlag(SKIP_OFFICIAL_LINES);
     }
 
     public boolean skipFloodWater() {
-        return Boolean.getBoolean(SKIP_FLOOD_WATER);
+        return getFlag(SKIP_FLOOD_WATER);
     }
 
     public boolean skipFloodProtection() {
-        return Boolean.getBoolean(SKIP_FLOOD_PROTECTION);
+        return getFlag(SKIP_FLOOD_PROTECTION);
+    }
+
+    public boolean skipBedHeightSingle() {
+        return getFlag(SKIP_BED_HEIGHT_SINGLE);
+    }
+
+    public boolean skipBedHeightEpoch() {
+        return getFlag(SKIP_BED_HEIGHT_EPOCH);
+    }
+
+    public boolean skipSedimentDensity() {
+        return getFlag(SKIP_SEDIMENT_DENSITY);
+    }
+
+    public boolean skipMorphologicalWidth() {
+        return getFlag(SKIP_MORPHOLOGICAL_WIDTH);
+    }
+
+    public boolean skipFlowVelocity() {
+        return getFlag(SKIP_FLOW_VELOCITY);
+    }
+
+    public boolean skipSedimentYield() {
+        return getFlag(SKIP_SEDIMENT_YIELD);
+    }
+
+    public boolean skipWaterlevels() {
+        return getFlag(SKIP_WATERLEVELS);
+    }
+
+    public boolean skipWaterlevelDifferences() {
+        return getFlag(SKIP_WATERLEVEL_DIFFERENCES);
+    }
+
+    public boolean skipSQRelation() {
+        return getFlag(SKIP_SQ_RELATION);
     }
 }
 // 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-backend/src/main/java/de/intevation/flys/importer/ImportBedHeight.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,44 @@
+package de.intevation.flys.importer;
+
+
+import java.sql.SQLException;
+
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.River;
+
+
+public interface ImportBedHeight {
+
+    String getDescription();
+
+    void addValue(ImportBedHeightValue value);
+
+    void storeDependencies(River river)
+    throws SQLException, ConstraintViolationException;
+
+    Object getPeer(River river);
+
+    int getValueCount();
+
+    void setYear(int year);
+
+    void setTimeInterval(ImportTimeInterval timeInterval);
+
+    void setSoundingWidth(int soundingWidth);
+
+    void setDescription(String description);
+
+    void setEvaluationBy(String evaluationBy);
+
+    void setRange(ImportRange range);
+
+    void setType(ImportBedHeightType type);
+
+    void setLocationSystem(ImportLocationSystem locationSystem);
+
+    void setCurElevationModel(ImportElevationModel model);
+
+    void setOldElevationModel(ImportElevationModel model);
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportBedHeightEpoch.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,202 @@
+package de.intevation.flys.importer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.BedHeightEpoch;
+import de.intevation.flys.model.ElevationModel;
+import de.intevation.flys.model.Range;
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.TimeInterval;
+
+
+/** Import Bed Height Data, 'epoch' type from csv file. */
+public class ImportBedHeightEpoch implements ImportBedHeight {
+
+    /** Private logger. */
+    private static Logger log = Logger.getLogger(ImportBedHeightEpoch.class);
+
+    protected String evaluationBy;
+
+    /** De facto the file name. */
+    protected String description;
+
+    protected ImportTimeInterval timeInterval;
+    protected ImportRange range;
+    protected ImportElevationModel curElevationModel;
+    protected ImportElevationModel oldElevationModel;
+
+    protected List<ImportBedHeightEpochValue> values;
+
+    protected BedHeightEpoch peer;
+
+    public ImportBedHeightEpoch(String description) {
+        this.description = description;
+        this.values = new ArrayList<ImportBedHeightEpochValue>();
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public int getValueCount() {
+        return values.size();
+    }
+
+    public void setTimeInterval(ImportTimeInterval timeInterval) {
+        this.timeInterval = timeInterval;
+    }
+
+    public void setEvaluationBy(String evaluationBy) {
+        this.evaluationBy = evaluationBy;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void setRange(ImportRange range) {
+        this.range = range;
+    }
+
+    public void setCurElevationModel(ImportElevationModel curElevationModel) {
+        this.curElevationModel = curElevationModel;
+    }
+
+    public void setOldElevationModel(ImportElevationModel oldElevationModel) {
+        this.oldElevationModel = oldElevationModel;
+    }
+
+    /** Does nothing. */
+    public void setYear(int year) {
+        // do nothing
+    }
+
+    /** Does nothing. */
+    public void setSoundingWidth(int soundingWidth) {
+        // do nothing
+    }
+
+
+    /** Does nothing. */
+    public void setLocationSystem(ImportLocationSystem locationSystem) {
+        // do nothing
+    }
+
+
+    /** Does nothing. */
+    public void setType(ImportBedHeightType type) {
+        // do nothing
+    }
+
+    @Override
+    public void addValue(ImportBedHeightValue value) {
+        values.add((ImportBedHeightEpochValue) value);
+    }
+
+    @Override
+    public void storeDependencies(River river) throws SQLException,
+        ConstraintViolationException {
+        log.info("Store dependencies for epoch: '" + getDescription() + "'");
+
+        BedHeightEpoch peer = getPeer(river);
+
+        if (curElevationModel != null) {
+            curElevationModel.storeDependencies();
+        }
+
+        if (oldElevationModel != null) {
+            oldElevationModel.storeDependencies();
+        }
+
+        if (peer != null) {
+            log.debug("store values now...");
+
+            for (ImportBedHeightEpochValue value : values) {
+                value.storeDependencies(peer);
+            }
+        }
+
+        Session session = ImporterSession.getInstance().getDatabaseSession();
+        session.flush();
+    }
+
+    /**
+     * Asserts all dependent entities (ElevationModel, TimeInterval, Range,
+     * BedHeighEpoch) are in db and returns bound (either newly created or
+     * freshly fetched) BedHeightEpoch.
+     */
+    @Override
+    public BedHeightEpoch getPeer(River river) {
+        if (peer == null) {
+            ElevationModel theCurModel = null;
+            if (curElevationModel != null) {
+                curElevationModel.storeDependencies();
+                theCurModel = curElevationModel.getPeer();
+            }
+
+            if (theCurModel == null) {
+                log.warn("BHE: Skip file - invalid current elevation model.");
+                return null;
+            }
+
+            TimeInterval theTime = null;
+            if (timeInterval != null) {
+                theTime = timeInterval.getPeer();
+            }
+
+            if (theTime == null) {
+                log.warn("BHE: Skip file - invalid time range.");
+                return null;
+            }
+
+            Range theRange = range != null ? range.getPeer(river) : null;
+
+            if (theRange == null) {
+                log.warn("BHE: Skip file - invalid km range.");
+                return null;
+            }
+
+            Session session = ImporterSession.getInstance()
+                .getDatabaseSession();
+
+            Query query = session.createQuery("from BedHeightEpoch where "
+                + "   river=:river and " + "   timeInterval=:timeInterval and "
+                + "   curElevationModel=:curElevationModel and "
+                + "   range=:range and " + "   evaluationBy=:evaluationBy and "
+                + "   description=:description");
+
+            query.setParameter("river", river);
+            query.setParameter("timeInterval", theTime);
+            query.setParameter("curElevationModel", theCurModel);
+            query.setParameter("range", theRange);
+            query.setParameter("evaluationBy", evaluationBy);
+            query.setParameter("description", description);
+
+            List<BedHeightEpoch> bedHeights = query.list();
+
+            if (bedHeights.isEmpty()) {
+                log.info("Create new BedHeightEpoch DB instance.");
+
+                peer = new BedHeightEpoch(river, theTime, theRange,
+                    theCurModel,
+                    oldElevationModel != null ? oldElevationModel.getPeer()
+                        : null, evaluationBy, description);
+
+                session.save(peer);
+            }
+            else {
+                peer = bedHeights.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportBedHeightEpochValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,75 @@
+package de.intevation.flys.importer;
+
+import java.util.List;
+
+import java.math.BigDecimal;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.BedHeightEpoch;
+import de.intevation.flys.model.BedHeightEpochValue;
+
+
+public class ImportBedHeightEpochValue implements ImportBedHeightValue {
+
+    private static final Logger log =
+        Logger.getLogger(ImportBedHeightEpochValue.class);
+
+
+    private BigDecimal station;
+    private BigDecimal height;
+
+    private BedHeightEpochValue peer;
+
+
+    public ImportBedHeightEpochValue() {
+    }
+
+
+    public ImportBedHeightEpochValue(BigDecimal station, BigDecimal height) {
+        this.station = station;
+        this.height  = height;
+    }
+
+
+    public void storeDependencies(BedHeightEpoch bedHeight) {
+        getPeer(bedHeight);
+    }
+
+
+    public BedHeightEpochValue getPeer(BedHeightEpoch bedHeight) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from BedHeightEpochValue where " +
+                "   bedHeight=:bedHeight and " +
+                "   station=:station and " +
+                "   height=:height");
+
+            query.setParameter("bedHeight", bedHeight);
+            query.setParameter("station", station);
+            query.setParameter("height", height);
+
+            List<BedHeightEpochValue> values = query.list();
+
+            if (values.isEmpty()) {
+                peer = new BedHeightEpochValue(
+                    bedHeight,
+                    station,
+                    height
+                );
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportBedHeightSingle.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,191 @@
+package de.intevation.flys.importer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import java.sql.SQLException;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.BedHeightSingle;
+import de.intevation.flys.model.BedHeightType;
+import de.intevation.flys.model.ElevationModel;
+import de.intevation.flys.model.Range;
+import de.intevation.flys.model.River;
+
+
+public class ImportBedHeightSingle implements ImportBedHeight
+{
+    private static Logger log = Logger.getLogger(ImportBedHeightSingle.class);
+
+    protected int year;
+    protected int soundingWidth;
+
+    protected String evaluationBy;
+    protected String description;
+
+    protected ImportRange          range;
+    protected ImportBedHeightType  type;
+    protected ImportLocationSystem locationSystem;
+    protected ImportElevationModel curElevationModel;
+    protected ImportElevationModel oldElevationModel;
+
+    protected List<ImportBedHeightSingleValue> values;
+
+    protected BedHeightSingle peer;
+
+
+    public ImportBedHeightSingle(String description) {
+        this.description = description;
+        this.values      = new ArrayList<ImportBedHeightSingleValue>();
+    }
+
+
+    public String getDescription() {
+        return description;
+    }
+
+    public int getValueCount() {
+        return values.size();
+    }
+
+
+    public void setYear(int year) {
+        this.year = year;
+    }
+
+    public void setTimeInterval(ImportTimeInterval timeInterval) {
+        // do nothing
+    }
+
+    public void setSoundingWidth(int soundingWidth) {
+        this.soundingWidth = soundingWidth;
+    }
+
+    public void setEvaluationBy(String evaluationBy) {
+        this.evaluationBy = evaluationBy;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void setRange(ImportRange range) {
+        this.range = range;
+    }
+
+    public void setType(ImportBedHeightType type) {
+        this.type = type;
+    }
+
+    public void setLocationSystem(ImportLocationSystem locationSystem) {
+        this.locationSystem = locationSystem;
+    }
+
+    public void setCurElevationModel(ImportElevationModel curElevationModel) {
+        this.curElevationModel = curElevationModel;
+    }
+
+    public void setOldElevationModel(ImportElevationModel oldElevationModel) {
+        this.oldElevationModel = oldElevationModel;
+    }
+
+    @Override
+    public void addValue(ImportBedHeightValue value) {
+        values.add((ImportBedHeightSingleValue) value);
+    }
+
+    @Override
+    public void storeDependencies(River river)
+    throws SQLException, ConstraintViolationException
+    {
+        log.info("Store dependencies for single: '" + getDescription() + "'");
+
+        if (type != null) {
+            type.storeDependencies();
+        }
+
+        if (locationSystem != null) {
+            locationSystem.storeDependencies();
+        }
+
+        if (curElevationModel != null) {
+            curElevationModel.storeDependencies();
+        }
+
+        if (oldElevationModel != null) {
+            oldElevationModel.storeDependencies();
+        }
+
+        BedHeightSingle peer = getPeer(river);
+
+        if (peer != null) {
+            for (ImportBedHeightSingleValue value: values) {
+                value.storeDependencies(peer);
+            }
+        }
+
+        Session session = ImporterSession.getInstance().getDatabaseSession();
+        session.flush();
+    }
+
+    @Override
+    public BedHeightSingle getPeer(River river) {
+        if (peer == null) {
+            BedHeightType  theType     = type != null ? type.getPeer() : null;
+            ElevationModel theCurModel = curElevationModel.getPeer();
+            Range          theRange    = range != null ? range.getPeer(river) : null;
+
+            if (theType == null || theCurModel == null || theRange == null) {
+                log.warn("BHS: Skip invalid file '" + description + "'");
+                return null;
+            }
+
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from BedHeightSingle where " +
+                "river=:river and year=:year and soundingWidth=:soundingWidth " +
+                "and type=:type and locationSystem=:locationSystem and " +
+                "curElevationModel=:curElevationModel and range=:range");
+
+            query.setParameter("river", river);
+            query.setParameter("year", year);
+            query.setParameter("soundingWidth", soundingWidth);
+            query.setParameter("type", theType);
+            query.setParameter("locationSystem", locationSystem.getPeer());
+            query.setParameter("curElevationModel", theCurModel);
+            query.setParameter("range", range.getPeer(river));
+
+            List<BedHeightSingle> bedHeights = query.list();
+            if (bedHeights.isEmpty()) {
+                log.info("Create new BedHeightSingle DB instance.");
+
+                peer = new BedHeightSingle(
+                    river,
+                    year,
+                    soundingWidth,
+                    theType,
+                    locationSystem.getPeer(),
+                    theCurModel,
+                    oldElevationModel != null ? oldElevationModel.getPeer() : null,
+                    range.getPeer(river),
+                    evaluationBy,
+                    description
+                );
+
+                session.save(peer);
+            }
+            else {
+                peer = bedHeights.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportBedHeightSingleValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,105 @@
+package de.intevation.flys.importer;
+
+import java.util.List;
+
+import java.math.BigDecimal;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.BedHeightSingle;
+import de.intevation.flys.model.BedHeightSingleValue;
+
+
+public class ImportBedHeightSingleValue implements ImportBedHeightValue {
+
+    private static final Logger log =
+        Logger.getLogger(ImportBedHeightSingleValue.class);
+
+
+    protected ImportBedHeightSingle bedHeight;
+
+    protected BigDecimal station;
+    protected BigDecimal height;
+    protected BigDecimal uncertainty;
+    protected BigDecimal dataGap;
+    protected BigDecimal soundingWidth;
+    protected BigDecimal width;
+
+    protected BedHeightSingleValue peer;
+
+
+    public ImportBedHeightSingleValue(
+        ImportBedHeightSingle bedHeight,
+        BigDecimal station,
+        BigDecimal height,
+        BigDecimal uncertainty,
+        BigDecimal dataGap,
+        BigDecimal soundingWidth,
+        BigDecimal width
+    ) {
+        this.bedHeight     = bedHeight;
+        this.station       = station;
+        this.height        = height;
+        this.uncertainty   = uncertainty;
+        this.dataGap       = dataGap;
+        this.soundingWidth = soundingWidth;
+        this.width         = width;
+    }
+
+
+    public void storeDependencies(BedHeightSingle bedHeight) {
+        getPeer(bedHeight);
+    }
+
+
+    /**
+     * Add this value to database or return database bound Value, assuring
+     * that the BedHeightSingle exists in db already.
+     */
+    public BedHeightSingleValue getPeer(BedHeightSingle bedHeight) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from BedHeightSingleValue where " +
+                "   bedHeight=:bedHeight and " +
+                "   station=:station and " +
+                "   height=:height and " +
+                "   uncertainty=:uncertainty and " +
+                "   dataGap=:dataGap and " +
+                "   soundingWidth=:soundingWidth and " +
+                "   width=:width");
+
+            query.setParameter("bedHeight", bedHeight);
+            query.setParameter("station", station);
+            query.setParameter("height", height);
+            query.setParameter("uncertainty", uncertainty);
+            query.setParameter("dataGap", dataGap);
+            query.setParameter("soundingWidth", soundingWidth);
+            query.setParameter("width", width);
+
+            List<BedHeightSingleValue> values = query.list();
+            if (values.isEmpty()) {
+                peer = new BedHeightSingleValue(
+                    bedHeight,
+                    station,
+                    height,
+                    uncertainty,
+                    dataGap,
+                    soundingWidth,
+                    width
+                );
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportBedHeightType.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,60 @@
+package de.intevation.flys.importer;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.BedHeightType;
+
+
+public class ImportBedHeightType {
+
+    private static final Logger log =
+        Logger.getLogger(ImportBedHeightType.class);
+
+    protected String name;
+    protected String description;
+
+    protected BedHeightType peer;
+
+
+    public ImportBedHeightType(String name, String description) {
+        this.name        = name;
+        this.description = description;
+    }
+
+
+    public void storeDependencies() {
+        BedHeightType type = getPeer();
+    }
+
+
+    public BedHeightType getPeer() {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from BedHeightType where " +
+                "name=:name and description=:description");
+
+            query.setParameter("name", name);
+            query.setParameter("description", description);
+
+            List<BedHeightType> types = query.list();
+
+            if (types.isEmpty()) {
+                peer = new BedHeightType(name, description);
+                session.save(peer);
+            }
+            else {
+                peer = types.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportBedHeightValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,7 @@
+package de.intevation.flys.importer;
+
+
+public interface ImportBedHeightValue {
+
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/importer/ImportCrossSectionLine.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/ImportCrossSectionLine.java	Fri Sep 28 12:15:52 2012 +0200
@@ -7,8 +7,6 @@
 import org.hibernate.Session;
 import org.hibernate.Query;
 
-import java.math.BigDecimal;
-
 import java.util.List;
 import java.util.Comparator;
 import java.util.Map;
@@ -23,7 +21,7 @@
             }
         };
 
-    protected BigDecimal         km;
+    protected Double         km;
     protected ImportCrossSection crossSection;
     protected List<XY>           points;
 
@@ -32,7 +30,7 @@
     public ImportCrossSectionLine() {
     }
 
-    public ImportCrossSectionLine(BigDecimal km, List<XY> points) {
+    public ImportCrossSectionLine(Double km, List<XY> points) {
         this.km     = km;
         this.points = points;
     }
@@ -45,11 +43,11 @@
         this.crossSection = crossSection;
     }
 
-    public BigDecimal getKm() {
+    public Double getKm() {
         return km;
     }
 
-    public void setKm(BigDecimal km) {
+    public void setKm(Double km) {
         this.km = km;
     }
 
@@ -82,12 +80,12 @@
             if (csp == null) { // create new
                 csp = new CrossSectionPoint(
                     csl, key.getColPos(),
-                    new BigDecimal(xy.getX()),
-                    new BigDecimal(xy.getY()));
+                    Double.valueOf(xy.getX()),
+                    Double.valueOf(xy.getY()));
             }
             else { // update old
-                csp.setX(new BigDecimal(xy.getX()));
-                csp.setY(new BigDecimal(xy.getY()));
+                csp.setX(Double.valueOf(xy.getX()));
+                csp.setY(Double.valueOf(xy.getY()));
             }
             session.save(csp);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/ImportDepth.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,75 @@
+package de.intevation.flys.importer;
+
+import java.math.BigDecimal;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.Depth;
+
+
+public class ImportDepth {
+
+    private static Logger log = Logger.getLogger(ImportDepth.class);
+
+
+    protected Depth peer;
+
+    protected BigDecimal lower;
+    protected BigDecimal upper;
+
+    protected ImportUnit unit;
+
+
+    public ImportDepth(BigDecimal lower, BigDecimal upper, ImportUnit unit) {
+        this.lower = lower;
+        this.upper = upper;
+        this.unit  = unit;
+    }
+
+
+    public void storeDependencies() {
+        log.info("store dependencies");
+
+        getPeer();
+    }
+
+
+    public Depth getPeer() {
+        log.info("get peer");
+
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from Depth where " +
+                "   lower=:lower and " +
+                "   upper=:upper and " +
+                "   unit=:unit");
+
+            query.setParameter("lower", lower);
+            query.setParameter("upper", upper);
+            query.setParameter("unit", unit.getPeer());
+
+            List<Depth> depths = query.list();
+
+            if (depths.isEmpty()) {
+                log.debug("Create new Depth DB instance.");
+
+                peer = new Depth(lower, upper, unit.getPeer());
+
+                session.save(peer);
+            }
+            else {
+                peer = depths.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportDischargeZone.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,90 @@
+package de.intevation.flys.importer;
+
+import java.math.BigDecimal;
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.DischargeZone;
+import de.intevation.flys.model.River;
+
+
+public class ImportDischargeZone {
+
+    private static final Logger log =
+        Logger.getLogger(ImportDischargeZone.class);
+
+
+    private String gaugeName;
+
+    private BigDecimal value;
+
+    private String lowerDischarge;
+    private String upperDischarge;
+
+    private DischargeZone peer;
+
+
+    public ImportDischargeZone(
+        String     gaugeName,
+        BigDecimal value,
+        String     lowerDischarge,
+        String     upperDischarge
+    ) {
+        this.gaugeName      = gaugeName;
+        this.value          = value;
+        this.lowerDischarge = lowerDischarge;
+        this.upperDischarge = upperDischarge;
+    }
+
+
+    public void storeDependencies(River river)
+    throws SQLException, ConstraintViolationException
+    {
+        log.debug("store dependencies");
+
+        getPeer(river);
+    }
+
+
+    public DischargeZone getPeer(River river) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from DischargeZone where " +
+                "   river=:river and " +
+                "   gaugeName=:gaugeName and " +
+                "   value=:value"
+            );
+
+            query.setParameter("river", river);
+            query.setParameter("gaugeName", gaugeName);
+            query.setParameter("value", value);
+
+            List<DischargeZone> zone = query.list();
+
+            if (zone.isEmpty()) {
+                peer = new DischargeZone(
+                    river,
+                    gaugeName,
+                    value,
+                    lowerDischarge,
+                    upperDischarge);
+
+                session.save(peer);
+            }
+            else {
+                peer = zone.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportElevationModel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.importer;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.ElevationModel;
+
+
+public class ImportElevationModel {
+
+    private static final Logger log =
+        Logger.getLogger(ImportElevationModel.class);
+
+    protected String name;
+
+    protected ImportUnit unit;
+
+    protected ElevationModel peer;
+
+
+    public ImportElevationModel(String name, ImportUnit unit) {
+        this.name = name;
+        this.unit = unit;
+    }
+
+
+    public void storeDependencies() {
+        ElevationModel model = getPeer();
+    }
+
+    public ElevationModel getPeer() {
+        if (unit == null) {
+            log.warn("No elevation model specified.");
+            return null;
+        }
+
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+            Query query = session.createQuery(
+                "from ElevationModel where " +
+                "name=:name and unit=:unit");
+            query.setParameter("name", name);
+            query.setParameter("unit", unit.getPeer());
+            List<ElevationModel> models = query.list();
+
+            if (models.isEmpty()) {
+                log.info("Create new ElevationModel DB instance.");
+
+                peer = new ElevationModel(name, unit.getPeer());
+                session.save(peer);
+            }
+            else {
+                peer = models.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportFlowVelocityMeasurement.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,85 @@
+package de.intevation.flys.importer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.FlowVelocityMeasurement;
+import de.intevation.flys.model.River;
+
+
+public class ImportFlowVelocityMeasurement {
+
+    private static final Logger log = Logger
+        .getLogger(ImportFlowVelocityMeasurement.class);
+
+    private String description;
+
+    private List<ImportFlowVelocityMeasurementValue> values;
+
+    private FlowVelocityMeasurement peer;
+
+    public ImportFlowVelocityMeasurement() {
+        this(null);
+    }
+
+    public ImportFlowVelocityMeasurement(String description) {
+        this.description = description;
+        this.values = new ArrayList<ImportFlowVelocityMeasurementValue>();
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void addValue(ImportFlowVelocityMeasurementValue value) {
+        this.values.add(value);
+    }
+
+    public void storeDependencies(River river) throws SQLException,
+        ConstraintViolationException {
+        log.debug("store dependencies");
+
+        FlowVelocityMeasurement peer = getPeer(river);
+
+        if (peer != null) {
+            for (ImportFlowVelocityMeasurementValue value : values) {
+                value.storeDependencies(peer);
+            }
+        }
+    }
+
+    public FlowVelocityMeasurement getPeer(River river) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance()
+                .getDatabaseSession();
+
+            Query query = session
+                .createQuery("from FlowVelocityMeasurement where "
+                    + "   river=:river and " + "   description=:description");
+
+            query.setParameter("river", river);
+            query.setParameter("description", description);
+
+            List<FlowVelocityMeasurement> measurement = query.list();
+
+            if (measurement.isEmpty()) {
+                peer = new FlowVelocityMeasurement(river, description);
+
+                session.save(peer);
+            }
+            else {
+                peer = measurement.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportFlowVelocityMeasurementValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,100 @@
+package de.intevation.flys.importer;
+
+import java.math.BigDecimal;
+import java.sql.SQLException;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.FlowVelocityMeasurement;
+import de.intevation.flys.model.FlowVelocityMeasurementValue;
+
+
+public class ImportFlowVelocityMeasurementValue {
+
+    private static final Logger log =
+        Logger.getLogger(ImportFlowVelocityMeasurementValue.class);
+
+
+    private Date datetime;
+
+    private String description;
+
+    private BigDecimal station;
+    private BigDecimal w;
+    private BigDecimal q;
+    private BigDecimal v;
+
+    private FlowVelocityMeasurementValue peer;
+
+
+    public ImportFlowVelocityMeasurementValue(
+        Date       datetime,
+        BigDecimal station,
+        BigDecimal w,
+        BigDecimal q,
+        BigDecimal v,
+        String     description
+    ) {
+        this.datetime    = datetime;
+        this.station     = station;
+        this.w           = w;
+        this.q           = q;
+        this.v           = v;
+        this.description = description;
+    }
+
+
+
+    public void storeDependencies(FlowVelocityMeasurement measurement)
+    throws SQLException, ConstraintViolationException
+    {
+        log.debug("store dependencies");
+
+        getPeer(measurement);
+    }
+
+
+    public FlowVelocityMeasurementValue getPeer(FlowVelocityMeasurement m) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from FlowVelocityMeasurementValue where " +
+                "   measurement=:measurement and " +
+                "   station=:station and " +
+                "   datetime=:datetime"
+            );
+
+            query.setParameter("measurement", m);
+            query.setParameter("station", station);
+            query.setParameter("datetime", datetime);
+
+            List<FlowVelocityMeasurementValue> values = query.list();
+
+            if (values.isEmpty()) {
+                peer = new FlowVelocityMeasurementValue(
+                    m,
+                    datetime,
+                    station,
+                    w,
+                    q,
+                    v,
+                    description);
+
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportFlowVelocityModel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,107 @@
+package de.intevation.flys.importer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.DischargeZone;
+import de.intevation.flys.model.FlowVelocityModel;
+import de.intevation.flys.model.River;
+
+
+public class ImportFlowVelocityModel {
+
+    private static final Logger log = Logger
+        .getLogger(ImportFlowVelocityModel.class);
+
+    private String description;
+
+    private ImportDischargeZone dischargeZone;
+
+    private List<ImportFlowVelocityModelValue> values;
+
+    private FlowVelocityModel peer;
+
+    public ImportFlowVelocityModel() {
+        values = new ArrayList<ImportFlowVelocityModelValue>();
+    }
+
+    public ImportFlowVelocityModel(ImportDischargeZone dischargeZone,
+        String description) {
+        this();
+
+        this.dischargeZone = dischargeZone;
+        this.description = description;
+    }
+
+    public void setDischargeZone(ImportDischargeZone dischargeZone) {
+        this.dischargeZone = dischargeZone;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void addValue(ImportFlowVelocityModelValue value) {
+        this.values.add(value);
+    }
+
+    public void storeDependencies(River river) throws SQLException,
+        ConstraintViolationException {
+        log.debug("store dependencies");
+
+        if (dischargeZone == null) {
+            log.warn("skip flow velocity model: No discharge zone specified.");
+            return;
+        }
+
+        dischargeZone.storeDependencies(river);
+
+        FlowVelocityModel peer = getPeer(river);
+
+        if (peer != null) {
+            int i = 0;
+
+            for (ImportFlowVelocityModelValue value : values) {
+                value.storeDependencies(peer);
+                i++;
+            }
+
+            log.info("stored " + i + " flow velocity model values.");
+        }
+    }
+
+    public FlowVelocityModel getPeer(River river) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance()
+                .getDatabaseSession();
+
+            DischargeZone zone = dischargeZone.getPeer(river);
+
+            Query query = session.createQuery("from FlowVelocityModel where "
+                + "   river=:river and " + "   dischargeZone=:dischargeZone");
+
+            query.setParameter("river", river);
+            query.setParameter("dischargeZone", zone);
+
+            List<FlowVelocityModel> model = query.list();
+
+            if (model.isEmpty()) {
+                peer = new FlowVelocityModel(river, zone);
+                session.save(peer);
+            }
+            else {
+                peer = model.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportFlowVelocityModelValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,77 @@
+package de.intevation.flys.importer;
+
+import java.math.BigDecimal;
+import java.sql.SQLException;
+import java.util.List;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.FlowVelocityModel;
+import de.intevation.flys.model.FlowVelocityModelValue;
+
+
+public class ImportFlowVelocityModelValue {
+
+    private BigDecimal station;
+    private BigDecimal q;
+    private BigDecimal totalChannel;
+    private BigDecimal mainChannel;
+    private BigDecimal shearStress;
+
+    private FlowVelocityModelValue peer;
+
+
+    public ImportFlowVelocityModelValue(
+        BigDecimal station,
+        BigDecimal q,
+        BigDecimal totalChannel,
+        BigDecimal mainChannel,
+        BigDecimal shearStress
+    ) {
+        this.station      = station;
+        this.q            = q;
+        this.totalChannel = totalChannel;
+        this.mainChannel  = mainChannel;
+        this.shearStress  = shearStress;
+    }
+
+
+    public void storeDependencies(FlowVelocityModel model)
+    throws SQLException, ConstraintViolationException
+    {
+        getPeer(model);
+    }
+
+
+    public FlowVelocityModelValue getPeer(FlowVelocityModel model) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from FlowVelocityModelValue where " +
+                "   flowVelocity=:model and " +
+                "   station=:station"
+            );
+
+            query.setParameter("model", model);
+            query.setParameter("station", station);
+
+            List<FlowVelocityModelValue> values = query.list();
+
+            if (values.isEmpty()) {
+                peer = new FlowVelocityModelValue(
+                    model, station, q, totalChannel, mainChannel, shearStress);
+
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportGrainFraction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,89 @@
+package de.intevation.flys.importer;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.GrainFraction;
+import de.intevation.flys.model.Unit;
+
+
+public class ImportGrainFraction {
+
+    private static final Logger log =
+        Logger.getLogger(ImportGrainFraction.class);
+
+    private String name;
+
+    private Double lower;
+    private Double upper;
+
+    private ImportUnit unit;
+
+    private GrainFraction peer;
+
+
+    public ImportGrainFraction(String name) {
+        this.name = name;
+    }
+
+
+    public ImportGrainFraction(
+        String     name,
+        Double     lower,
+        Double     upper,
+        ImportUnit unit
+    ) {
+        this.name  = name;
+        this.lower = lower;
+        this.upper = upper;
+        this.unit  = unit;
+    }
+
+
+    public void storeDependencies() {
+        log.debug("store dependencies");
+
+        getPeer();
+    }
+
+
+    public GrainFraction getPeer() {
+        log.debug("get peer");
+
+        Unit u = unit != null ? unit.getPeer() : null;
+
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+            Query query = session.createQuery(
+                "from GrainFraction where " +
+                "   name=:name and " +
+                "   lower=:lower and " +
+                "   upper=:upper and " +
+                "   unit=:unit"
+            );
+
+            query.setParameter("name", name);
+            query.setParameter("lower", lower);
+            query.setParameter("upper", upper);
+            query.setParameter("unit", u);
+
+            List<GrainFraction> fractions = query.list();
+            if (fractions.isEmpty()) {
+                log.info("create new GrainFraction");
+
+                peer = new GrainFraction(name, lower, upper, u);
+                session.save(peer);
+            }
+            else {
+                peer = fractions.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/importer/ImportHYKFlowZone.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/ImportHYKFlowZone.java	Fri Sep 28 12:15:52 2012 +0200
@@ -68,7 +68,7 @@
             else {
                 peer = zones.get(0);
             }
-            
+
         }
         return peer;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/ImportLocationSystem.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,60 @@
+package de.intevation.flys.importer;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.LocationSystem;
+
+
+public class ImportLocationSystem {
+
+    private static final Logger log =
+        Logger.getLogger(ImportLocationSystem.class);
+
+
+    protected String name;
+    protected String description;
+
+    protected LocationSystem peer;
+
+
+    public ImportLocationSystem(String name, String description) {
+        this.name        = name;
+        this.description = description;
+    }
+
+    public void storeDependencies() {
+        log.info("store LocationSystem '" + name + "'");
+        LocationSystem ls = getPeer();
+
+        Session session = ImporterSession.getInstance().getDatabaseSession();
+        session.flush();
+    }
+
+    public LocationSystem getPeer() {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+            Query query = session.createQuery(
+                "from LocationSystem where " +
+                "name=:name and description=:description");
+            query.setParameter("name", name);
+            query.setParameter("description", description);
+
+            List<LocationSystem> lss = query.list();
+            if (lss.isEmpty()) {
+                peer = new LocationSystem(name, description);
+                session.save(peer);
+            }
+            else {
+                peer = lss.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportMorphWidth.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,83 @@
+package de.intevation.flys.importer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.MorphologicalWidth;
+import de.intevation.flys.model.River;
+
+
+public class ImportMorphWidth {
+
+    private static Logger log = Logger.getLogger(ImportMorphWidth.class);
+
+    protected MorphologicalWidth peer;
+
+    protected ImportUnit unit;
+
+    protected List<ImportMorphWidthValue> values;
+
+    public ImportMorphWidth() {
+        this.values = new ArrayList<ImportMorphWidthValue>();
+    }
+
+    public void addValue(ImportMorphWidthValue value) {
+        this.values.add(value);
+    }
+
+    public void setUnit(ImportUnit unit) {
+        this.unit = unit;
+    }
+
+    public void storeDependencies(River river) throws SQLException,
+        ConstraintViolationException {
+        log.info("store dependencies");
+
+        MorphologicalWidth peer = getPeer(river);
+
+        if (peer != null) {
+            log.info("store morphological width values");
+
+            for (ImportMorphWidthValue value : values) {
+                value.storeDependencies(peer);
+            }
+        }
+    }
+
+    public MorphologicalWidth getPeer(River river) {
+        log.info("get peer");
+
+        if (peer == null) {
+            Session session = ImporterSession.getInstance()
+                .getDatabaseSession();
+
+            Query query = session.createQuery("from MorphologicalWidth where "
+                + "   river=:river and " + "   unit=:unit");
+
+            query.setParameter("river", river);
+            query.setParameter("unit", unit.getPeer());
+
+            List<MorphologicalWidth> widths = query.list();
+
+            if (widths.isEmpty()) {
+                log.debug("Create new MorphologicalWidth DB instance.");
+
+                peer = new MorphologicalWidth(river, unit.getPeer());
+
+                session.save(peer);
+            }
+            else {
+                peer = widths.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportMorphWidthValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,81 @@
+package de.intevation.flys.importer;
+
+import java.math.BigDecimal;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.MorphologicalWidth;
+import de.intevation.flys.model.MorphologicalWidthValue;
+
+
+public class ImportMorphWidthValue {
+
+    private static Logger log = Logger.getLogger(ImportMorphWidthValue.class);
+
+
+    protected MorphologicalWidthValue peer;
+
+    protected BigDecimal station;
+    protected BigDecimal width;
+
+    protected String description;
+
+
+    public ImportMorphWidthValue(
+        BigDecimal station,
+        BigDecimal width,
+        String     description
+    ) {
+        this.station     = station;
+        this.width       = width;
+        this.description = description;
+    }
+
+
+    public void storeDependencies(MorphologicalWidth parent) {
+        getPeer(parent);
+    }
+
+
+    public MorphologicalWidthValue getPeer(MorphologicalWidth parent) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from MorphologicalWidthValue where " +
+                "   morphologicalWidth=:morphologicalWidth and " +
+                "   station=:station and " +
+                "   width=:width and " +
+                "   description=:description");
+
+            query.setParameter("morphologicalWidth", parent);
+            query.setParameter("station", station);
+            query.setParameter("width", width);
+            query.setParameter("description", description);
+
+            List<MorphologicalWidthValue> values = query.list();
+
+            if (values.isEmpty()) {
+                peer = new MorphologicalWidthValue(
+                    parent,
+                    station,
+                    width,
+                    description
+                );
+
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/importer/ImportRiver.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/ImportRiver.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,35 +1,48 @@
 package de.intevation.flys.importer;
 
-import java.math.BigDecimal;
+import de.intevation.artifacts.common.utils.FileTools.HashedFile;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Calendar;
+import de.intevation.artifacts.common.utils.FileTools;
+
+import de.intevation.flys.importer.parsers.AnnotationClassifier;
+import de.intevation.flys.importer.parsers.AnnotationsParser;
+import de.intevation.flys.importer.parsers.BedHeightEpochParser;
+import de.intevation.flys.importer.parsers.BedHeightSingleParser;
+import de.intevation.flys.importer.parsers.FlowVelocityMeasurementParser;
+import de.intevation.flys.importer.parsers.FlowVelocityModelParser;
+import de.intevation.flys.importer.parsers.HYKParser;
+import de.intevation.flys.importer.parsers.MorphologicalWidthParser;
+import de.intevation.flys.importer.parsers.PRFParser;
+import de.intevation.flys.importer.parsers.PegelGltParser;
+import de.intevation.flys.importer.parsers.SedimentDensityParser;
+import de.intevation.flys.importer.parsers.SedimentYieldParser;
+import de.intevation.flys.importer.parsers.SQRelationParser;
+import de.intevation.flys.importer.parsers.WaterlevelDifferencesParser;
+import de.intevation.flys.importer.parsers.WaterlevelParser;
+import de.intevation.flys.importer.parsers.WstParser;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.Unit;
 
 import java.io.File;
 import java.io.IOException;
 
+import java.sql.SQLException;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.log4j.Logger;
 
-import de.intevation.artifacts.common.utils.FileTools;
-import de.intevation.artifacts.common.utils.FileTools.HashedFile;
-
-import de.intevation.flys.model.River;
-import de.intevation.flys.model.Unit;
+import org.hibernate.Query;
+import org.hibernate.Session;
 
-import de.intevation.flys.importer.parsers.PRFParser;
-import de.intevation.flys.importer.parsers.HYKParser;
-import de.intevation.flys.importer.parsers.AnnotationsParser;
-import de.intevation.flys.importer.parsers.AnnotationClassifier;
-import de.intevation.flys.importer.parsers.PegelGltParser;
-import de.intevation.flys.importer.parsers.WstParser;
-
-import org.hibernate.Session;
-import org.hibernate.Query;
+import org.hibernate.exception.ConstraintViolationException;
 
 public class ImportRiver
 {
@@ -54,6 +67,39 @@
     public static final String FLOOD_PROTECTION =
         "HW-Schutzanlagen";
 
+    public static final String MINFO_DIR = "Morphologie";
+
+    public static final String BED_HEIGHT_DIR = "Sohlhoehen";
+
+    public static final String BED_HEIGHT_SINGLE_DIR = "Einzeljahre";
+
+    public static final String BED_HEIGHT_EPOCH_DIR = "Epochen";
+
+    public static final String SEDIMENT_DENSITY_DIR = "Sedimentdichte";
+
+    public static final String MORPHOLOGICAL_WIDTH_DIR = "morphologische_Breite";
+
+    public static final String FLOW_VELOCITY_DIR = "Geschwindigkeit_Schubspannung";
+
+    public static final String FLOW_VELOCITY_MODEL = "Modellrechnungen";
+
+    public static final String FLOW_VELOCITY_MEASUREMENTS = "v-Messungen";
+
+    public static final String SEDIMENT_YIELD_DIR = "Fracht";
+
+    public static final String SEDIMENT_YIELD_SINGLE_DIR = "Einzeljahre";
+
+    public static final String SEDIMENT_YIELD_EPOCH_DIR = "Epochen";
+
+    public static final String MINFO_FIXATIONS_DIR = "Fixierungsanalyse";
+
+    public static final String MINFO_WATERLEVELS_DIR = "Wasserspiegellagen";
+
+    public static final String MINFO_WATERLEVEL_DIFF_DIR = "Wasserspiegeldifferenzen";
+
+    public static final String MINFO_SQ_DIR = "Feststofftransport-Abfluss-Beziehung";
+
+
     protected String name;
 
     protected File   wstFile;
@@ -78,6 +124,26 @@
 
     protected List<ImportWst> floodProtection;
 
+    protected List<ImportBedHeight> bedHeightSingles;
+
+    protected List<ImportBedHeight> bedHeightEpochs;
+
+    protected List<ImportSedimentDensity> sedimentDensities;
+
+    protected List<ImportMorphWidth> morphologicalWidths;
+
+    protected List<ImportFlowVelocityModel> flowVelocityModels;
+
+    protected List<ImportFlowVelocityMeasurement> flowVelocityMeasurements;
+
+    protected List<ImportSedimentYield> sedimentYields;
+
+    protected List<ImportWaterlevel> waterlevels;
+
+    protected List<ImportWaterlevelDifference> waterlevelDiffs;
+
+    protected List<ImportSQRelation> sqRelations;
+
     protected ImportWst wst;
 
     protected ImportUnit wstUnit;
@@ -87,13 +153,21 @@
     protected River peer;
 
     public ImportRiver() {
-        hyks            = new ArrayList<ImportHYK>();
-        crossSections   = new ArrayList<ImportCrossSection>();
-        extraWsts       = new ArrayList<ImportWst>();
-        fixations       = new ArrayList<ImportWst>();
-        officialLines   = new ArrayList<ImportWst>();
-        floodWater      = new ArrayList<ImportWst>();
-        floodProtection = new ArrayList<ImportWst>();
+        hyks                      = new ArrayList<ImportHYK>();
+        crossSections             = new ArrayList<ImportCrossSection>();
+        extraWsts                 = new ArrayList<ImportWst>();
+        fixations                 = new ArrayList<ImportWst>();
+        officialLines             = new ArrayList<ImportWst>();
+        floodWater                = new ArrayList<ImportWst>();
+        floodProtection           = new ArrayList<ImportWst>();
+        sedimentDensities         = new ArrayList<ImportSedimentDensity>();
+        morphologicalWidths       = new ArrayList<ImportMorphWidth>();
+        flowVelocityModels        = new ArrayList<ImportFlowVelocityModel>();
+        flowVelocityMeasurements  = new ArrayList<ImportFlowVelocityMeasurement>();
+        sedimentYields            = new ArrayList<ImportSedimentYield>();
+        waterlevels               = new ArrayList<ImportWaterlevel>();
+        waterlevelDiffs           = new ArrayList<ImportWaterlevelDifference>();
+        sqRelations               = new ArrayList<ImportSQRelation>();
     }
 
     public ImportRiver(
@@ -141,6 +215,11 @@
         this.wst = wst;
     }
 
+    public File getMinfoDir() {
+        File riverDir  = wstFile.getParentFile().getParentFile().getParentFile();
+        return new File(riverDir, MINFO_DIR);
+    }
+
     public void parseDependencies() throws IOException {
         parseGauges();
         parseAnnotations();
@@ -152,6 +231,14 @@
         parseOfficialLines();
         parseFloodWater();
         parseFloodProtection();
+        parseBedHeight();
+        parseSedimentDensity();
+        parseMorphologicalWidth();
+        parseFlowVelocity();
+        parseSedimentYield();
+        parseWaterlevels();
+        parseWaterlevelDifferences();
+        parseSQRelation();
     }
 
     public void parseFloodProtection() throws IOException {
@@ -196,6 +283,321 @@
         }
     }
 
+
+    public void parseBedHeight() throws IOException {
+        File minfoDir     = getMinfoDir();
+        File bedHeightDir = new File(minfoDir, BED_HEIGHT_DIR);
+        File singlesDir   = new File(bedHeightDir, BED_HEIGHT_SINGLE_DIR);
+        File epochDir     = new File(bedHeightDir, BED_HEIGHT_EPOCH_DIR);
+
+        if (Config.INSTANCE.skipBedHeightSingle()) {
+            log.info("skip parsing bed height single.");
+        }
+        else {
+            log.info("Parse bed height single.");
+            parseBedHeightSingles(singlesDir);
+        }
+
+        if (Config.INSTANCE.skipBedHeightEpoch()) {
+            log.info("skip parsing bed height epochs.");
+        }
+        else {
+            log.info("Parse bed height epochs.");
+            parseBedHeightEpochs(epochDir);
+        }
+    }
+
+
+    protected void parseSedimentDensity() throws IOException {
+        if (Config.INSTANCE.skipSedimentDensity()) {
+            log.info("skip parsing sediment density.");
+            return;
+        }
+
+        log.debug("Parse sediment density");
+
+        File minfoDir = getMinfoDir();
+        File sediment = new File(minfoDir, SEDIMENT_DENSITY_DIR);
+
+        File[] files = sediment.listFiles();
+
+        if (files == null) {
+            log.warn("Cannot read directory '" + sediment + "'");
+            return;
+        }
+
+        SedimentDensityParser parser = new SedimentDensityParser();
+
+        for (File file: files) {
+            parser.parse(file);
+        }
+
+        sedimentDensities = parser.getSedimentDensities();
+
+        log.info("Parsed " + sedimentDensities.size() + " sediment densities.");
+    }
+
+
+    protected void parseMorphologicalWidth() throws IOException {
+        if (Config.INSTANCE.skipMorphologicalWidth()) {
+            log.info("skip parsing morphological width.");
+            return;
+        }
+
+        log.debug("Parse morphological width");
+
+        File minfoDir = getMinfoDir();
+        File morphDir = new File(minfoDir, MORPHOLOGICAL_WIDTH_DIR);
+
+        File[] files = morphDir.listFiles();
+
+        if (files == null) {
+            log.warn("Cannot read directory '" + morphDir + "'");
+            return;
+        }
+
+        MorphologicalWidthParser parser = new MorphologicalWidthParser();
+
+        for (File file: files) {
+            parser.parse(file);
+        }
+
+        morphologicalWidths = parser.getMorphologicalWidths();
+
+        log.info("Parsed " + morphologicalWidths.size() + " morph. widths files.");
+    }
+
+
+    protected void parseFlowVelocity() throws IOException {
+        if (Config.INSTANCE.skipFlowVelocity()) {
+            log.info("skip parsing flow velocity");
+            return;
+        }
+
+        log.debug("Parse flow velocity");
+
+        File minfoDir   = getMinfoDir();
+        File flowDir    = new File(minfoDir, FLOW_VELOCITY_DIR);
+        File modelDir   = new File(flowDir, FLOW_VELOCITY_MODEL);
+        File measureDir = new File(flowDir, FLOW_VELOCITY_MEASUREMENTS);
+
+        File[] modelFiles   = modelDir.listFiles();
+        File[] measureFiles = measureDir.listFiles();
+
+        if (modelFiles == null) {
+            log.warn("Cannot read directory '" + modelDir + "'");
+        }
+        else {
+            FlowVelocityModelParser parser = new FlowVelocityModelParser();
+
+            for (File model: modelFiles) {
+                log.debug("Parse file '" + model + "'");
+                parser.parse(model);
+            }
+
+            flowVelocityModels = parser.getModels();
+        }
+
+        if (measureFiles == null) {
+            log.warn("Cannot read directory '" + measureDir + "'");
+        }
+        else {
+            FlowVelocityMeasurementParser parser =
+                new FlowVelocityMeasurementParser();
+
+            for (File measurement: measureFiles) {
+                log.debug("Parse file '" + measurement + "'");
+                parser.parse(measurement);
+            }
+
+            flowVelocityMeasurements = parser.getMeasurements();
+        }
+    }
+
+
+    protected void parseSedimentYield() throws IOException {
+        if (Config.INSTANCE.skipSedimentYield()) {
+            log.info("skip parsing sediment yield data");
+            return;
+        }
+
+        log.debug("Parse sediment yield data");
+
+        File minfoDir         = getMinfoDir();
+        File sedimentYieldDir = new File(minfoDir, SEDIMENT_YIELD_DIR);
+
+        File singleDir = new File(sedimentYieldDir, SEDIMENT_YIELD_SINGLE_DIR);
+        File epochDir  = new File(sedimentYieldDir, SEDIMENT_YIELD_EPOCH_DIR);
+
+        File[] singles = singleDir.listFiles();
+        File[] epochs  = epochDir.listFiles();
+
+        SedimentYieldParser parser = new SedimentYieldParser();
+
+        if (singles == null || singles.length == 0) {
+            log.warn("Cannot read directory '" + singleDir + "'");
+        }
+        else {
+            for (File file: singles) {
+                if (file.isDirectory()) {
+                    for (File child: file.listFiles()) {
+                        parser.parse(child);
+                    }
+                }
+                else {
+                    parser.parse(file);
+                }
+            }
+        }
+
+        if (epochs == null || epochs.length == 0) {
+            log.warn("Cannot read directory '" + epochDir + "'");
+        }
+        else {
+            for (File file: epochs) {
+                if (file.isDirectory()) {
+                    for (File child: file.listFiles()) {
+                        parser.parse(child);
+                    }
+                }
+                else {
+                    parser.parse(file);
+                }
+            }
+        }
+
+        sedimentYields = parser.getSedimentYields();
+    }
+
+
+    protected void parseWaterlevels() throws IOException {
+        if (Config.INSTANCE.skipWaterlevels()) {
+            log.info("skip parsing waterlevels");
+            return;
+        }
+
+        log.info("Parse waterlevels");
+
+        File minfo  = getMinfoDir();
+        File fixDir = new File(minfo, MINFO_FIXATIONS_DIR);
+        File wspDir = new File(fixDir, MINFO_WATERLEVELS_DIR);
+
+        File[] files = wspDir.listFiles();
+
+        if (files == null) {
+            log.warn("Cannot read directory '" + wspDir + "'");
+            return;
+        }
+
+        WaterlevelParser parser = new WaterlevelParser();
+
+        for (File file: files) {
+            parser.parse(file);
+        }
+
+        waterlevels = parser.getWaterlevels();
+    }
+
+
+    protected void parseWaterlevelDifferences() throws IOException {
+        if (Config.INSTANCE.skipWaterlevelDifferences()) {
+            log.info("skip parsing waterlevel differences");
+            return;
+        }
+
+        log.info("Parse waterlevel differences");
+
+        File minfo  = getMinfoDir();
+        File fixDir = new File(minfo, MINFO_FIXATIONS_DIR);
+        File diffDir = new File(fixDir, MINFO_WATERLEVEL_DIFF_DIR);
+
+        File[] files = diffDir.listFiles();
+
+        if (files == null) {
+            log.warn("Cannot read directory '" + diffDir + "'");
+            return;
+        }
+
+        WaterlevelDifferencesParser parser = new WaterlevelDifferencesParser();
+
+        for (File file: files) {
+            parser.parse(file);
+        }
+
+        waterlevelDiffs = parser.getDifferences();
+    }
+
+
+    protected void parseSQRelation() throws IOException {
+        if (Config.INSTANCE.skipSQRelation()) {
+            log.info("skip parsing sq relation");
+            return;
+        }
+
+        log.info("Parse sq relations");
+
+        File minfo = getMinfoDir();
+        File sqDir = new File(minfo, MINFO_SQ_DIR);
+
+        File[] files = sqDir.listFiles();
+
+        if (files == null) {
+            log.warn("Cannot read directory '" + sqDir + "'");
+            return;
+        }
+
+        SQRelationParser parser = new SQRelationParser();
+
+        for (File file: files) {
+            parser.parse(file);
+        }
+
+        sqRelations = parser.getSQRelations();
+
+        log.debug("Parsed " + sqRelations.size() + " SQ relations.");
+    }
+
+
+    protected void parseBedHeightSingles(File dir) throws IOException {
+        log.debug("Parse bed height singles");
+
+        File[] files = dir.listFiles();
+
+        if (files == null) {
+            log.warn("Cannot read directory '" + dir + "'");
+            return;
+        }
+
+        BedHeightSingleParser parser = new BedHeightSingleParser();
+
+        for (File file: files) {
+            parser.parse(file);
+        }
+
+        bedHeightSingles = parser.getBedHeights();
+    }
+
+
+    protected void parseBedHeightEpochs(File dir) throws IOException {
+        log.debug("Parse bed height epochs");
+
+        File[] files = dir.listFiles();
+
+        if (files == null) {
+            log.warn("Cannot read directory '" + dir + "'");
+            return;
+        }
+
+        BedHeightEpochParser parser = new BedHeightEpochParser();
+
+        for (File file: files) {
+            parser.parse(file);
+        }
+
+        bedHeightEpochs = parser.getBedHeights();
+    }
+
+
     public void parseFloodWater() throws IOException {
         if (Config.INSTANCE.skipFloodWater()) {
             log.info("skip parsing flod water");
@@ -489,7 +891,7 @@
                     new ArrayList<ImportCrossSectionLine>();
 
                 for (Map.Entry<Double, List<XY>> entry: parser.getData().entrySet()) {
-                    BigDecimal km     = new BigDecimal(entry.getKey());
+                    Double km         = entry.getKey();
                     List<XY>   points = entry.getValue();
                     lines.add(new ImportCrossSectionLine(km, points));
                 }
@@ -520,6 +922,14 @@
         storeOfficialLines();
         storeFloodWater();
         storeFloodProtection();
+        storeBedHeight();
+        storeSedimentDensity();
+        storeMorphologicalWidth();
+        storeFlowVelocity();
+        storeSedimentYield();
+        storeWaterlevels();
+        storeWaterlevelDifferences();
+        storeSQRelations();
     }
 
     public void storeWstUnit() {
@@ -613,6 +1023,233 @@
         }
     }
 
+
+    public void storeBedHeight() {
+        if (!Config.INSTANCE.skipBedHeightSingle()) {
+            log.info("store bed heights single");
+            storeBedHeightSingle();
+        }
+
+        if (!Config.INSTANCE.skipBedHeightEpoch()) {
+            log.info("store bed height epoch.");
+            storeBedHeightEpoch();
+        }
+    }
+
+
+    private void storeBedHeightSingle() {
+        River river = getPeer();
+
+        if (bedHeightSingles != null) {
+            for (ImportBedHeight tmp: bedHeightSingles) {
+                ImportBedHeightSingle single = (ImportBedHeightSingle) tmp;
+
+                String desc = single.getDescription();
+
+                log.debug("name: " + desc);
+
+                try {
+                    single.storeDependencies(river);
+                }
+                catch (SQLException sqle) {
+                    log.error("File '" + desc + "' is broken!");
+                }
+                catch (ConstraintViolationException cve) {
+                    log.error("File '" + desc + "' is broken!");
+                }
+            }
+        }
+        else {
+            log.info("No single bed heights to store.");
+        }
+    }
+
+
+    private void storeBedHeightEpoch() {
+        River river = getPeer();
+
+        if (bedHeightEpochs != null) {
+            for (ImportBedHeight tmp: bedHeightEpochs) {
+                ImportBedHeightEpoch epoch = (ImportBedHeightEpoch) tmp;
+
+                String desc = epoch.getDescription();
+
+                log.debug("name: " + desc);
+
+                try {
+                    epoch.storeDependencies(river);
+                }
+                catch (SQLException sqle) {
+                    log.error("File '" + desc + "' is broken!");
+                }
+                catch (ConstraintViolationException cve) {
+                    log.error("File '" + desc + "' is broken!");
+                }
+            }
+        }
+        else {
+            log.info("No epoch bed heights to store.");
+        }
+    }
+
+    public void storeSedimentDensity() {
+        if (!Config.INSTANCE.skipSedimentDensity()) {
+            log.info("store sediment density");
+
+            River river = getPeer();
+
+            for (ImportSedimentDensity density: sedimentDensities) {
+                String desc = density.getDescription();
+
+                log.debug("name: " + desc);
+
+                try {
+                    density.storeDependencies(river);
+                }
+                catch (SQLException sqle) {
+                    log.error("File '" + desc + "' is broken!");
+                }
+                catch (ConstraintViolationException cve) {
+                    log.error("File '" + desc + "' is broken!");
+                }
+            }
+        }
+    }
+
+    public void storeMorphologicalWidth() {
+        if (!Config.INSTANCE.skipMorphologicalWidth()) {
+            log.info("store morphological width");
+
+            River river = getPeer();
+
+            for (ImportMorphWidth width: morphologicalWidths) {
+                try {
+                    width.storeDependencies(river);
+                }
+                catch (SQLException sqle) {
+                    log.error("Error while parsing file for morph. width.", sqle);
+                }
+                catch (ConstraintViolationException cve) {
+                    log.error("Error while parsing file for morph. width.", cve);
+                }
+            }
+        }
+    }
+
+    public void storeFlowVelocity() {
+        if (!Config.INSTANCE.skipFlowVelocity()) {
+            log.info("store flow velocity");
+
+            River river = getPeer();
+
+            for (ImportFlowVelocityModel flowVelocityModel: flowVelocityModels){
+                try {
+                    flowVelocityModel.storeDependencies(river);
+                }
+                catch (SQLException sqle) {
+                    log.error("Error while storing flow velocity model.", sqle);
+                }
+                catch (ConstraintViolationException cve) {
+                    log.error("Error while storing flow velocity model.", cve);
+                }
+            }
+
+            for (ImportFlowVelocityMeasurement m: flowVelocityMeasurements) {
+                try {
+                    m.storeDependencies(river);
+                }
+                catch (SQLException sqle) {
+                    log.error("Error while storing flow velocity measurement.", sqle);
+                }
+                catch (ConstraintViolationException cve) {
+                    log.error("Error while storing flow velocity measurement.", cve);
+                }
+            }
+        }
+    }
+
+
+    public void storeSedimentYield() {
+        if (!Config.INSTANCE.skipSedimentYield()) {
+            log.info("store sediment yield data");
+
+            River river = getPeer();
+
+            for (ImportSedimentYield sedimentYield: sedimentYields) {
+                try {
+                    sedimentYield.storeDependencies(river);
+                }
+                catch (SQLException sqle) {
+                    log.error("Error while storing sediment yield.", sqle);
+                }
+                catch (ConstraintViolationException cve) {
+                    log.error("Error while storing sediment yield.", cve);
+                }
+            }
+        }
+    }
+
+
+    public void storeWaterlevels() {
+        if (!Config.INSTANCE.skipWaterlevels()) {
+            log.info("store waterlevels");
+
+            River river = getPeer();
+
+            for (ImportWaterlevel waterlevel: waterlevels) {
+                waterlevel.storeDependencies(river);
+            }
+        }
+    }
+
+
+    public void storeWaterlevelDifferences() {
+        if (!Config.INSTANCE.skipWaterlevelDifferences()) {
+            log.info("store waterlevel differences");
+
+            River river = getPeer();
+
+            for (ImportWaterlevelDifference diff: waterlevelDiffs) {
+                try {
+                    diff.storeDependencies(river);
+                }
+                catch (SQLException sqle) {
+                    log.error("Error while storing waterlevel diff.", sqle);
+                }
+                catch (ConstraintViolationException cve) {
+                    log.error("Error while storing waterlevel diff.", cve);
+                }
+            }
+        }
+    }
+
+
+    public void storeSQRelations() {
+        if (!Config.INSTANCE.skipSQRelation()) {
+            log.info("store sq relations");
+
+            River river = getPeer();
+
+            int count = 0;
+
+            for (ImportSQRelation sqRelation: sqRelations) {
+                try {
+                    sqRelation.storeDependencies(river);
+                    count++;
+                }
+                catch (SQLException sqle) {
+                    log.error("Error while storing sq relation.", sqle);
+                }
+                catch (ConstraintViolationException cve) {
+                    log.error("Error while storing sq relation.", cve);
+                }
+            }
+
+            log.info("stored " + count + " sq relations.");
+        }
+    }
+
+
     public void storeAnnotations() {
         if (!Config.INSTANCE.skipAnnotations()) {
             River river = getPeer();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/ImportSQRelation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,112 @@
+package de.intevation.flys.importer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.SQRelation;
+import de.intevation.flys.model.TimeInterval;
+
+
+public class ImportSQRelation {
+
+    private static Logger log = Logger.getLogger(ImportSQRelation.class);
+
+    private ImportTimeInterval timeInterval;
+
+    private String description;
+
+    private List<ImportSQRelationValue> values;
+
+    private SQRelation peer;
+
+    public ImportSQRelation() {
+        this.values = new ArrayList<ImportSQRelationValue>();
+    }
+
+    public void storeDependencies(River river) throws SQLException,
+        ConstraintViolationException {
+        log.info("store dependencies");
+
+        SQRelation peer = getPeer(river);
+
+        timeInterval.getPeer();
+
+        if (peer != null) {
+            int count = 0;
+
+            for (ImportSQRelationValue value : values) {
+                try {
+                    value.storeDependencies(peer);
+                    count++;
+                }
+                catch (SQLException sqle) {
+                    log.warn("ISQ: Unable to store sq relation value.", sqle);
+                }
+                catch (ConstraintViolationException cve) {
+                    log.warn("ISQ: Unable to store sq relation value.", cve);
+                }
+            }
+
+            log.info("stored " + count + " sq relation values.");
+        }
+    }
+
+    public SQRelation getPeer(River river) {
+        log.debug("getPeer()");
+
+        if (peer == null) {
+            TimeInterval timeInter = timeInterval.getPeer();
+
+            if (timeInter == null) {
+                log.warn("ISQ: Cannot determine sq relation without time interval");
+                return null;
+            }
+
+            Session session = ImporterSession.getInstance()
+                .getDatabaseSession();
+
+            Query query = session
+                .createQuery("FROM SQRelation WHERE river=:river AND timeInterval=:timeInter");
+
+            query.setParameter("river", river);
+            query.setParameter("timeInter", timeInter);
+
+            List<SQRelation> sq = query.list();
+
+            if (sq.isEmpty()) {
+                log.info("create new SQ relation '" + description + "'");
+
+                peer = new SQRelation(river, timeInter, description);
+                session.save(peer);
+            }
+            else {
+                peer = sq.get(0);
+            }
+        }
+
+        return peer;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void setTimeInterval(ImportTimeInterval timeInterval) {
+        this.timeInterval = timeInterval;
+    }
+
+    public void addValue(ImportSQRelationValue value) {
+        if (value != null) {
+            this.values.add(value);
+        }
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportSQRelationValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,97 @@
+package de.intevation.flys.importer;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.SQRelation;
+import de.intevation.flys.model.SQRelationValue;
+
+
+public class ImportSQRelationValue {
+
+    private static Logger log = Logger.getLogger(ImportSQRelationValue.class);
+
+
+    private SQRelationValue peer;
+
+    private String parameter;
+    private String fraction;
+    private String function;
+
+    private double km;
+    private double a;
+    private double b;
+
+
+    public ImportSQRelationValue(
+        String parameter,
+        String fraction,
+        String function,
+        double km,
+        double a,
+        double b
+    ) {
+        this.parameter = parameter;
+        this.fraction  = fraction;
+        this.function  = function;
+        this.km        = km;
+        this.a         = a;
+        this.b         = b;
+    }
+
+
+    public void storeDependencies(SQRelation owner)
+    throws SQLException, ConstraintViolationException
+    {
+        getPeer(owner);
+    }
+
+
+    public SQRelationValue getPeer(SQRelation owner) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from SQRelationValue " +
+                "   where sqRelation=:owner " +
+                "   and parameter=:parameter" +
+                "   and fraction=:fraction" +
+                "   and function=:function" +
+                "   and km=:km");
+
+            query.setParameter("owner", owner);
+            query.setString("parameter", parameter);
+            query.setString("fraction", fraction);
+            query.setString("function", function);
+            query.setDouble("km", km);
+
+            List<SQRelationValue> values = query.list();
+
+            if (values.isEmpty()) {
+                peer = new SQRelationValue(
+                    owner,
+                    parameter,
+                    fraction,
+                    function,
+                    km,
+                    a,
+                    b
+                );
+
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportSedimentDensity.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,114 @@
+package de.intevation.flys.importer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.SedimentDensity;
+
+
+public class ImportSedimentDensity {
+
+    private static Logger log = Logger.getLogger(ImportSedimentDensity.class);
+
+    protected SedimentDensity peer;
+
+    protected ImportDepth depth;
+
+    protected ImportUnit unit;
+
+    protected String description;
+
+    protected List<ImportSedimentDensityValue> values;
+
+    public ImportSedimentDensity(String description) {
+        this.description = description;
+        this.values = new ArrayList<ImportSedimentDensityValue>();
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDepth(ImportDepth depth) {
+        this.depth = depth;
+    }
+
+    public void setUnit(ImportUnit unit) {
+        this.unit = unit;
+    }
+
+    public void addValue(ImportSedimentDensityValue value) {
+        values.add(value);
+    }
+
+    public void storeDependencies(River river) throws SQLException,
+        ConstraintViolationException {
+        log.info("store dependencies");
+
+        if (depth != null) {
+            depth.storeDependencies();
+        }
+
+        SedimentDensity peer = getPeer(river);
+
+        if (peer != null) {
+            log.info("store sediment density values.");
+            for (ImportSedimentDensityValue value : values) {
+                value.storeDependencies(peer);
+            }
+        }
+    }
+
+    public SedimentDensity getPeer(River river) {
+        log.info("get peer");
+
+        if (depth == null) {
+            log.warn("cannot store sediment density '" + description
+                + "': no depth");
+            return null;
+        }
+
+        if (unit == null) {
+            log.warn("cannot store sediment density '" + description
+                + "': no unit");
+            return null;
+        }
+
+        if (peer == null) {
+            Session session = ImporterSession.getInstance()
+                .getDatabaseSession();
+
+            Query query = session.createQuery("from SedimentDensity where "
+                + "   river=:river and " + "   depth=:depth and "
+                + "   unit=:unit");
+
+            query.setParameter("river", river);
+            query.setParameter("depth", depth.getPeer());
+            query.setParameter("unit", unit.getPeer());
+
+            List<SedimentDensity> density = query.list();
+
+            if (density.isEmpty()) {
+                log.debug("Create new SedimentDensity DB instance.");
+
+                peer = new SedimentDensity(river, depth.getPeer(),
+                    unit.getPeer(), description);
+
+                session.save(peer);
+            }
+            else {
+                peer = density.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportSedimentDensityValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,87 @@
+package de.intevation.flys.importer;
+
+import java.math.BigDecimal;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.SedimentDensity;
+import de.intevation.flys.model.SedimentDensityValue;
+
+
+public class ImportSedimentDensityValue {
+
+    private static final Logger log =
+        Logger.getLogger(ImportSedimentDensityValue.class);
+
+
+    protected SedimentDensityValue peer;
+
+    protected BigDecimal station;
+
+    protected BigDecimal density;
+
+    protected String description;
+
+
+    public ImportSedimentDensityValue(
+        BigDecimal station,
+        BigDecimal density,
+        String     description
+    ) {
+        this.station     = station;
+        this.density     = density;
+        this.description = description;
+    }
+
+
+    public void storeDependencies(SedimentDensity sedimentDensity) {
+        log.info("store dependencies");
+
+        getPeer(sedimentDensity);
+    }
+
+
+    public SedimentDensityValue getPeer(SedimentDensity sedimentDensity) {
+        log.info("get peer");
+
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+
+            Query query = session.createQuery(
+                "from SedimentDensityValue where " +
+                "   sedimentDensity=:sedimentDensity and " +
+                "   station=:station and " +
+                "   density=:density and " +
+                "   description=:description");
+
+            query.setParameter("sedimentDensity", sedimentDensity);
+            query.setParameter("station", station);
+            query.setParameter("density", density);
+            query.setParameter("description", description);
+
+            List<SedimentDensityValue> values = query.list();
+            if (values.isEmpty()) {
+                log.debug("Create new SedimentDensityValue DB instance.");
+
+                peer = new SedimentDensityValue(
+                    sedimentDensity,
+                    station,
+                    density,
+                    description);
+
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportSedimentYield.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,124 @@
+package de.intevation.flys.importer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.GrainFraction;
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.SedimentYield;
+import de.intevation.flys.model.TimeInterval;
+import de.intevation.flys.model.Unit;
+
+
+public class ImportSedimentYield {
+
+    private static Logger log = Logger.getLogger(ImportSedimentYield.class);
+
+    private ImportGrainFraction grainFraction;
+
+    private ImportUnit unit;
+
+    private ImportTimeInterval timeInterval;
+
+    private String description;
+
+    private List<ImportSedimentYieldValue> values;
+
+    private SedimentYield peer;
+
+    public ImportSedimentYield(String description) {
+        this.values = new ArrayList<ImportSedimentYieldValue>();
+        this.description = description;
+    }
+
+    public void setTimeInterval(ImportTimeInterval timeInterval) {
+        this.timeInterval = timeInterval;
+    }
+
+    public void setUnit(ImportUnit unit) {
+        this.unit = unit;
+    }
+
+    public void setGrainFraction(ImportGrainFraction grainFraction) {
+        this.grainFraction = grainFraction;
+    }
+
+    public void addValue(ImportSedimentYieldValue value) {
+        this.values.add(value);
+    }
+
+    public void storeDependencies(River river) throws SQLException,
+        ConstraintViolationException {
+        log.debug("store dependencies");
+
+        if (grainFraction != null) {
+            grainFraction.storeDependencies();
+        }
+
+        SedimentYield peer = getPeer(river);
+
+        if (peer != null) {
+            int i = 0;
+
+            for (ImportSedimentYieldValue value : values) {
+                value.storeDependencies(peer);
+                i++;
+            }
+
+            log.info("stored " + i + " sediment yield values.");
+        }
+    }
+
+    public SedimentYield getPeer(River river) {
+        log.debug("get peer");
+
+        GrainFraction gf = grainFraction != null ? grainFraction.getPeer()
+            : null;
+
+        Unit u = unit != null ? unit.getPeer() : null;
+
+        TimeInterval ti = timeInterval != null ? timeInterval.getPeer() : null;
+
+        if (ti == null || u == null) {
+            log.warn("Skip invalid SedimentYield: time interval or unit null!");
+            return null;
+        }
+
+        if (peer == null) {
+            Session session = ImporterSession.getInstance()
+                .getDatabaseSession();
+            Query query = session.createQuery("from SedimentYield where "
+                + "   river=:river and "
+                + "   grainFraction=:grainFraction and " + "   unit=:unit and "
+                + "   timeInterval=:timeInterval and "
+                + "   description=:description");
+
+            query.setParameter("river", river);
+            query.setParameter("grainFraction", gf);
+            query.setParameter("unit", u);
+            query.setParameter("timeInterval", ti);
+            query.setParameter("description", description);
+
+            List<SedimentYield> yields = query.list();
+            if (yields.isEmpty()) {
+                log.debug("create new SedimentYield");
+
+                peer = new SedimentYield(river, u, ti, gf, description);
+                session.save(peer);
+            }
+            else {
+                peer = yields.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportSedimentYieldValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,58 @@
+package de.intevation.flys.importer;
+
+import java.util.List;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.SedimentYield;
+import de.intevation.flys.model.SedimentYieldValue;
+
+
+public class ImportSedimentYieldValue {
+
+    private Double station;
+    private Double value;
+
+    private SedimentYieldValue peer;
+
+
+    public ImportSedimentYieldValue(Double station, Double value) {
+        this.station = station;
+        this.value   = value;
+    }
+
+
+    public void storeDependencies(SedimentYield sedimentYield) {
+        getPeer(sedimentYield);
+    }
+
+
+    public SedimentYieldValue getPeer(SedimentYield sedimentYield) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+            Query query = session.createQuery(
+                "from SedimentYieldValue where " +
+                "   sedimentYield=:sedimentYield and " +
+                "   station=:station and " +
+                "   value=:value"
+            );
+
+            query.setParameter("sedimentYield", sedimentYield);
+            query.setParameter("station", station);
+            query.setParameter("value", value);
+
+            List<SedimentYieldValue> values = query.list();
+            if (values.isEmpty()) {
+                peer = new SedimentYieldValue(sedimentYield, station, value);
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportWaterlevel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,90 @@
+package de.intevation.flys.importer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.Unit;
+import de.intevation.flys.model.Waterlevel;
+
+
+public class ImportWaterlevel {
+
+    private static final Logger log = Logger.getLogger(ImportWaterlevel.class);
+
+    private ImportUnit unit;
+
+    private String description;
+
+    private List<ImportWaterlevelQRange> qRanges;
+
+    private Waterlevel peer;
+
+    public ImportWaterlevel(String description) {
+        this.qRanges = new ArrayList<ImportWaterlevelQRange>();
+
+        this.description = description;
+    }
+
+    public void setUnit(ImportUnit unit) {
+        this.unit = unit;
+    }
+
+    public void addValue(ImportWaterlevelQRange qRange) {
+        this.qRanges.add(qRange);
+    }
+
+    public void storeDependencies(River river) {
+        log.info("store dependencies");
+
+        Waterlevel peer = getPeer(river);
+
+        if (peer != null) {
+            int i = 0;
+
+            for (ImportWaterlevelQRange qRange : qRanges) {
+                qRange.storeDependencies(peer);
+                i++;
+            }
+
+            log.info("stored " + i + " waterlevel q ranges");
+        }
+    }
+
+    public Waterlevel getPeer(River river) {
+        Unit u = unit != null ? unit.getPeer() : null;
+        if (u == null) {
+            log.warn("skip invalid waterlevel - no unit set!");
+            return null;
+        }
+
+        if (peer == null) {
+            Session session = ImporterSession.getInstance()
+                .getDatabaseSession();
+            Query query = session.createQuery("from Waterlevel where "
+                + "   river=:river and " + "   unit=:unit and "
+                + "   description=:description");
+
+            query.setParameter("river", river);
+            query.setParameter("unit", u);
+            query.setParameter("description", description);
+
+            List<Waterlevel> wsts = query.list();
+            if (wsts.isEmpty()) {
+                peer = new Waterlevel(river, u, description);
+                session.save(peer);
+            }
+            else {
+                peer = wsts.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportWaterlevelDifference.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,95 @@
+package de.intevation.flys.importer;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.exception.ConstraintViolationException;
+
+import de.intevation.flys.model.River;
+import de.intevation.flys.model.Unit;
+import de.intevation.flys.model.WaterlevelDifference;
+
+
+public class ImportWaterlevelDifference {
+
+    private static final Logger log = Logger
+        .getLogger(ImportWaterlevelDifference.class);
+
+    private ImportUnit unit;
+
+    private String description;
+
+    private List<ImportWaterlevelDifferenceColumn> columns;
+
+    private WaterlevelDifference peer;
+
+    public ImportWaterlevelDifference(String description) {
+        this.columns = new ArrayList<ImportWaterlevelDifferenceColumn>();
+
+        this.description = description;
+    }
+
+    public void setUnit(ImportUnit unit) {
+        this.unit = unit;
+    }
+
+    public void addValue(ImportWaterlevelDifferenceColumn column) {
+        this.columns.add(column);
+    }
+
+    public void storeDependencies(River river) throws SQLException,
+        ConstraintViolationException {
+        log.info("store dependencies");
+
+        WaterlevelDifference peer = getPeer(river);
+
+        if (peer != null) {
+            int i = 0;
+
+            for (ImportWaterlevelDifferenceColumn column : columns) {
+                column.storeDependencies(peer);
+                i++;
+            }
+
+            log.info("stored " + i + " waterlevel difference columns");
+        }
+    }
+
+    public WaterlevelDifference getPeer(River river) {
+        Unit u = unit != null ? unit.getPeer() : null;
+        if (u == null) {
+            log.warn("IWD: skip invalid waterlevel difference - no unit set!");
+            return null;
+        }
+
+        if (peer == null) {
+            Session session = ImporterSession.getInstance()
+                .getDatabaseSession();
+            Query query = session
+                .createQuery("from WaterlevelDifference where "
+                    + "   river=:river and " + "   unit=:unit and "
+                    + "   description=:description");
+
+            query.setParameter("river", river);
+            query.setParameter("unit", u);
+            query.setParameter("description", description);
+
+            List<WaterlevelDifference> diffs = query.list();
+            if (diffs.isEmpty()) {
+                peer = new WaterlevelDifference(river, u, description);
+                session.save(peer);
+            }
+            else {
+                peer = diffs.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportWaterlevelDifferenceColumn.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,81 @@
+package de.intevation.flys.importer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.WaterlevelDifference;
+import de.intevation.flys.model.WaterlevelDifferenceColumn;
+
+
+public class ImportWaterlevelDifferenceColumn {
+
+    private static final Logger log =
+        Logger.getLogger(ImportWaterlevelDifferenceColumn.class);
+
+
+    private String description;
+
+    private List<ImportWaterlevelDifferenceValue> values;
+
+    private WaterlevelDifferenceColumn peer;
+
+
+    public ImportWaterlevelDifferenceColumn(String description) {
+        this.values = new ArrayList<ImportWaterlevelDifferenceValue>();
+
+        this.description = description;
+    }
+
+
+    public void addValue(ImportWaterlevelDifferenceValue value) {
+        this.values.add(value);
+    }
+
+
+    public void storeDependencies(WaterlevelDifference difference) {
+        log.info("store dependencies");
+
+        WaterlevelDifferenceColumn peer = getPeer(difference);
+
+        int i = 0;
+
+        for (ImportWaterlevelDifferenceValue value: values) {
+            value.storeDependencies(peer);
+            i++;
+        }
+
+        log.info("stored " + i + " waterlevel difference values");
+    }
+
+
+    public WaterlevelDifferenceColumn getPeer(WaterlevelDifference diff) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+            Query query = session.createQuery(
+                "from WaterlevelDifferenceColumn where " +
+                "   difference=:difference and " +
+                "   description=:description"
+            );
+
+            query.setParameter("difference", diff);
+            query.setParameter("description", description);
+
+            List<WaterlevelDifferenceColumn> cols = query.list();
+            if (cols.isEmpty()) {
+                peer = new WaterlevelDifferenceColumn(diff, description);
+                session.save(peer);
+            }
+            else {
+                peer = cols.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportWaterlevelDifferenceValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.importer;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.WaterlevelDifferenceColumn;
+import de.intevation.flys.model.WaterlevelDifferenceValue;
+
+
+public class ImportWaterlevelDifferenceValue {
+
+    private static final Logger log =
+        Logger.getLogger(ImportWaterlevelDifferenceValue.class);
+
+
+    private Double station;
+    private Double value;
+
+    private WaterlevelDifferenceValue peer;
+
+
+    public ImportWaterlevelDifferenceValue(Double station, Double value) {
+        this.station = station;
+        this.value   = value;
+    }
+
+
+    public void storeDependencies(WaterlevelDifferenceColumn column) {
+        getPeer(column);
+    }
+
+
+    public WaterlevelDifferenceValue getPeer(WaterlevelDifferenceColumn column) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+            Query query = session.createQuery(
+                "from WaterlevelDifferenceValue where " +
+                "   column=:column and " +
+                "   station=:station and " +
+                "   value=:value"
+            );
+
+            query.setParameter("column", column);
+            query.setParameter("station", station);
+            query.setParameter("value", value);
+
+            List<WaterlevelDifferenceValue> values = query.list();
+            if (values.isEmpty()) {
+                peer = new WaterlevelDifferenceValue(column, station, value);
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportWaterlevelQRange.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,79 @@
+package de.intevation.flys.importer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.Waterlevel;
+import de.intevation.flys.model.WaterlevelQRange;
+
+
+public class ImportWaterlevelQRange {
+
+    private static final Logger log =
+        Logger.getLogger(ImportWaterlevelQRange.class);
+
+
+    private Double q;
+
+    private List<ImportWaterlevelValue> values;
+
+    private WaterlevelQRange peer;
+
+
+    public ImportWaterlevelQRange(Double q) {
+        this.values = new ArrayList<ImportWaterlevelValue>();
+        this.q      = q;
+    }
+
+    public void addValue(ImportWaterlevelValue value) {
+        this.values.add(value);
+    }
+
+
+    public void storeDependencies(Waterlevel waterlevel) {
+        log.info("store dependencies");
+
+        WaterlevelQRange peer = getPeer(waterlevel);
+
+        int i = 0;
+
+        for (ImportWaterlevelValue value: values) {
+            value.storeDependencies(peer);
+            i++;
+        }
+
+        log.info("stored " + i + " waterlevel values");
+    }
+
+
+    public WaterlevelQRange getPeer(Waterlevel waterlevel) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+            Query query = session.createQuery(
+                "from WaterlevelQRange where " +
+                "   waterlevel=:waterlevel and " +
+                "   q=:q"
+            );
+
+            query.setParameter("waterlevel", waterlevel);
+            query.setParameter("q", q);
+
+            List<WaterlevelQRange> qRanges = query.list();
+            if (qRanges.isEmpty()) {
+                peer = new WaterlevelQRange(waterlevel, q);
+                session.save(peer);
+            }
+            else {
+                peer = qRanges.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/ImportWaterlevelValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,59 @@
+package de.intevation.flys.importer;
+
+import java.util.List;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.model.WaterlevelQRange;
+import de.intevation.flys.model.WaterlevelValue;
+
+
+public class ImportWaterlevelValue {
+
+    private Double station;
+    private Double w;
+
+    private WaterlevelValue peer;
+
+
+    public ImportWaterlevelValue(Double station, Double w) {
+        this.station = station;
+        this.w       = w;
+    }
+
+
+    public void storeDependencies(WaterlevelQRange qRange) {
+        getPeer(qRange);
+    }
+
+
+    public WaterlevelValue getPeer(WaterlevelQRange qRange) {
+        if (peer == null) {
+            Session session = ImporterSession.getInstance().getDatabaseSession();
+            Query query = session.createQuery(
+                "from WaterlevelValue where " +
+                "   qrange=:qrange and " +
+                "   station=:station and " +
+                "   w=:w"
+            );
+
+            query.setParameter("qrange", qRange);
+            query.setParameter("station", station);
+            query.setParameter("w", w);
+
+            List<WaterlevelValue> values = query.list();
+
+            if (values.isEmpty()) {
+                peer = new WaterlevelValue(qRange, station, w);
+                session.save(peer);
+            }
+            else {
+                peer = values.get(0);
+            }
+        }
+
+        return peer;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/importer/Importer.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/Importer.java	Fri Sep 28 12:15:52 2012 +0200
@@ -115,13 +115,26 @@
         InfoGewParser infoGewParser = new InfoGewParser(
             getAnnotationClassifier());
 
+        log.info("Start parsing rivers...");
+
         for (String gew: args) {
             log.info("parsing info gew file: " + gew);
             try {
                 infoGewParser.parse(new File(gew));
             }
             catch (IOException ioe) {
-                log.error("cannot while parsing: " + gew);
+                log.error("error while parsing gew: " + gew);
+            }
+        }
+
+        String gew = Config.INSTANCE.getInfoGewFile();
+        if (gew != null && gew.length() > 0) {
+            log.info("parsing info gew file: " + gew);
+            try {
+                infoGewParser.parse(new File(gew));
+            }
+            catch (IOException ioe) {
+                log.error("error while parsing gew: " + gew);
             }
         }
 
--- a/flys-backend/src/main/java/de/intevation/flys/importer/parsers/AnnotationClassifier.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/AnnotationClassifier.java	Fri Sep 28 12:15:52 2012 +0200
@@ -92,7 +92,7 @@
             Element typeElement = (Element)typeList.item(i);
             String name = typeElement.getAttribute("name");
             if (name.length() == 0) {
-                log.warn("rule has no name");
+                log.warn("ANNCLASS: rule has no name");
                 continue;
             }
 
@@ -155,19 +155,19 @@
         String type    = element.getAttribute("type");
 
         if (pattern.length() == 0) {
-            log.warn("pattern has no 'pattern' attribute.");
+            log.warn("ANNCLASS: pattern has no 'pattern' attribute.");
             return null;
         }
 
         if (type.length() == 0) {
-            log.warn("pattern has no 'type' attribute.");
+            log.warn("ANNCLASS: pattern has no 'type' attribute.");
             return null;
         }
 
         ImportAnnotationType annType = types.get(type);
 
         if (annType == null) {
-            log.warn("pattern has unknown type '" + type + "'");
+            log.warn("ANNCLASS: pattern has unknown type '" + type + "'");
             return null;
         }
 
@@ -178,7 +178,7 @@
                     Pattern.CASE_INSENSITIVE|Pattern.UNICODE_CASE);
         }
         catch (IllegalArgumentException iae) {
-            log.warn("pattern '" + pattern + "' is invalid.", iae);
+            log.warn("ANNCLASS: pattern '" + pattern + "' is invalid.", iae);
             return null;
         }
 
--- a/flys-backend/src/main/java/de/intevation/flys/importer/parsers/AnnotationsParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/AnnotationsParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -32,7 +32,9 @@
 
     public static final String [] TO_SCAN = {
         "Basisdaten",
-        "Streckendaten"
+        "Streckendaten",
+        ".." + File.separator +
+            "Morphologie" + File.separator + "Streckendaten"
     };
 
     protected HashMap<String, ImportAttribute> attributes;
@@ -79,7 +81,7 @@
                 String [] parts = line.split("\\s*;\\s*");
 
                 if (parts.length < 3) {
-                    log.warn("not enough columns in line "
+                    log.warn("ANN: not enough columns in line "
                         + in.getLineNumber());
                     continue;
                 }
@@ -108,7 +110,7 @@
                     }
                 }
                 catch (NumberFormatException nfe) {
-                    log.warn("invalid number in line " + in.getLineNumber());
+                    log.warn("ANN: invalid number in line " + in.getLineNumber());
                     continue;
                 }
 
@@ -121,7 +123,7 @@
                             new BigDecimal(parts[3].trim().replace(',', '.')));
                     }
                     catch (NumberFormatException nfe) {
-                        log.warn("cannot parse 'Unterkante' in line " +
+                        log.warn("ANN: cannot parse 'Unterkante' in line " +
                             in.getLineNumber());
                     }
                 }
@@ -139,7 +141,7 @@
                     }
                     catch (NumberFormatException nfe) {
                         log.warn(
-                            "cannot parse 'Unterkante' or 'Oberkante' in line "
+                            "ANN: cannot parse 'Unterkante' or 'Oberkante' in line "
                             + in.getLineNumber());
                     }
                 }
@@ -154,7 +156,7 @@
                     attribute, position, range, edge, type);
 
                 if (!annotations.add(annotation)) {
-                    log.warn("duplicated annotation '" + parts[0] +
+                    log.warn("ANN: duplicated annotation '" + parts[0] +
                         "' in line " + in.getLineNumber());
                 }
             }
@@ -171,12 +173,12 @@
         for (String toScan: TO_SCAN) {
             File directory = FileTools.repair(new File(root, toScan));
             if (!directory.isDirectory()) {
-                log.warn("'" + directory + "' is not a directory.");
+                log.warn("ANN: '" + directory + "' is not a directory.");
                 continue;
             }
             File [] files = directory.listFiles();
             if (files == null) {
-                log.warn("cannot list directory '" + directory + "'");
+                log.warn("ANN: cannot list directory '" + directory + "'");
                 continue;
             }
 
--- a/flys-backend/src/main/java/de/intevation/flys/importer/parsers/AtFileParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/AtFileParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -132,7 +132,7 @@
             }
         }
         catch (NumberFormatException pe) {
-            logger.warn(pe.getMessage());
+            logger.warn("AT: invalid number " + pe.getMessage());
         }
         finally {
             if (br != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/BedHeightEpochParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,77 @@
+package de.intevation.flys.importer.parsers;
+
+import java.math.BigDecimal;
+
+import java.text.ParseException;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportBedHeight;
+import de.intevation.flys.importer.ImportBedHeightEpoch;
+import de.intevation.flys.importer.ImportBedHeightEpochValue;
+
+
+/** Parses BedHeightEpochs from csv file. */
+public class BedHeightEpochParser extends BedHeightParser {
+
+    /** Our own logger. */
+    private static final Logger log =
+        Logger.getLogger(BedHeightEpochParser.class);
+
+
+    @Override
+    protected ImportBedHeight newImportBedHeight(String description) {
+        return new ImportBedHeightEpoch(description);
+    }
+
+
+    /**
+     * Handle a non-comment, none-Metadata line of csv file, adding
+     * ImportBedHeightEpochValues to the given ImportBedHeight object.
+     */
+    @Override
+    protected void handleDataLine(ImportBedHeight obj, String line) {
+        String[] values = line.split(SEPERATOR_CHAR);
+
+        if (values == null || values.length == 0 || values[0].length() == 0) {
+            // There might be quite some ";" found.
+            //log.warn("Skip invalid data line: " + line);
+            return;
+        }
+
+        BigDecimal km;
+
+        try {
+            km = new BigDecimal(nf.parse(values[0]).doubleValue());
+        }
+        catch (ParseException e) {
+            log.warn("Error while parsing number from data row: " + line);
+            return;
+        }
+
+
+        // Handle "gap" lines like '255,0;'
+        if (values.length < 2) {
+            ImportBedHeightEpochValue value = new ImportBedHeightEpochValue(
+                km,
+                null
+            );
+
+            obj.addValue(value);
+            return;
+        }
+
+        try {
+            ImportBedHeightEpochValue value = new ImportBedHeightEpochValue(
+                km,
+                new BigDecimal(nf.parse(values[1]).doubleValue())
+            );
+
+            obj.addValue(value);
+        }
+        catch (ParseException e) {
+            log.warn("Error while parsing number from data row: " + line);
+        }
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/parsers/BedHeightParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,412 @@
+package de.intevation.flys.importer.parsers;
+
+import java.io.File;
+
+import java.math.BigDecimal;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportBedHeight;
+import de.intevation.flys.importer.ImportBedHeightType;
+import de.intevation.flys.importer.ImportElevationModel;
+import de.intevation.flys.importer.ImportLocationSystem;
+import de.intevation.flys.importer.ImportRange;
+import de.intevation.flys.importer.ImportTimeInterval;
+import de.intevation.flys.importer.ImportUnit;
+import de.intevation.flys.model.BedHeightType;
+
+
+public abstract class BedHeightParser {
+
+    private static final Logger log =
+        Logger.getLogger(BedHeightParser.class);
+
+    public static final String ENCODING = "ISO-8859-1";
+
+    public static final Locale DEFAULT_LOCALE = Locale.GERMAN;
+
+    public static final String START_META_CHAR = "#";
+    public static final String SEPERATOR_CHAR  = ";";
+
+    public static final Pattern META_YEAR =
+        Pattern.compile("^Jahr: [^0-9]*(\\d*).*");
+
+    public static final Pattern META_TIMEINTERVAL =
+        Pattern.compile("^Zeitraum: Epoche (\\d*)-(\\d*).*");
+
+    public static final Pattern META_TYPE =
+        Pattern.compile("^Aufnahmeart: (.*).*");
+
+    public static final Pattern META_LOCATION_SYSTEM =
+        Pattern.compile("^Lagesystem: (.*).*");
+
+    public static final Pattern META_CUR_ELEVATION_SYSTEM =
+        Pattern.compile("^H.hensystem:\\s(\\w++) (.* )??\\[(.*)\\].*");
+
+    public static final Pattern META_OLD_ELEVATION_SYSTEM =
+        Pattern.compile("^urspr.ngliches H.hensystem:\\s(\\w++) (.* )??\\[(.*)\\].*");
+
+    public static final Pattern META_SOUNDING_WIDTH =
+        Pattern.compile("^ausgewertete Peilbreite: (\\d*).*");
+
+    public static final Pattern META_RANGE =
+        Pattern.compile("^Strecke:\\D*(\\d++.\\d*)-(\\d++.\\d*).*");
+
+    public static final Pattern META_EVALUATION_BY =
+        Pattern.compile("^Auswerter: (.*).*");
+
+    public static final Pattern META_COMMENTS =
+        Pattern.compile("^Weitere Bemerkungen: (.*).*");
+
+
+    protected static NumberFormat nf = NumberFormat.getInstance(DEFAULT_LOCALE);
+
+
+    protected List<ImportBedHeight> bedHeights;
+
+
+    protected abstract ImportBedHeight newImportBedHeight(String description);
+
+    /** Handle a line of file that contains data (in contrast to comments, meta). */
+    protected abstract void handleDataLine(
+        ImportBedHeight importBedHeight,
+        String          line
+    );
+
+
+
+    public BedHeightParser() {
+        this.bedHeights = new ArrayList<ImportBedHeight>();
+    }
+
+
+    public List<ImportBedHeight> getBedHeights() {
+        return bedHeights;
+    }
+
+
+    public void parse(File file) throws IOException {
+        log.info("Parsing bed height single file '" + file + "'");
+
+        ImportBedHeight obj = newImportBedHeight(file.getName());
+
+        LineNumberReader in = null;
+        try {
+            in =
+                new LineNumberReader(
+                new InputStreamReader(
+                new FileInputStream(file), ENCODING));
+
+            String line = null;
+            while ((line = in.readLine()) != null) {
+                if ((line = line.trim()).length() == 0) {
+                    continue;
+                }
+
+                if (line.startsWith(START_META_CHAR)) {
+                    handleMetaLine(obj, line);
+                }
+                else {
+                    handleDataLine(obj, line);
+                }
+            }
+
+            log.info("File contained " + obj.getValueCount() + " values.");
+            bedHeights.add(obj);
+        }
+        finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+
+
+    protected static String stripMetaLine(String line) {
+        String tmp = line.substring(1, line.length());
+
+        if (tmp.startsWith(" ")) {
+            return tmp.substring(1, tmp.length());
+        }
+        else {
+            return tmp;
+        }
+    }
+
+
+    public static Date getDateFromYear(int year) {
+        Calendar cal = Calendar.getInstance();
+        cal.set(year, 0, 1);
+
+        return cal.getTime();
+    }
+
+
+    protected void handleMetaLine(ImportBedHeight obj, String line) {
+        String meta = stripMetaLine(line);
+
+        if (handleMetaYear(obj, meta)) {
+            return;
+        }
+        else if (handleMetaTimeInterval(obj, meta)) {
+            return;
+        }
+        else if (handleMetaSoundingWidth(obj, meta)) {
+            return;
+        }
+        else if (handleMetaComment(obj, meta)) {
+            return;
+        }
+        else if (handleMetaEvaluationBy(obj, meta)) {
+            return;
+        }
+        else if (handleMetaRange(obj, meta)) {
+            return;
+        }
+        else if (handleMetaType(obj, meta)) {
+            return;
+        }
+        else if (handleMetaLocationSystem(obj, meta)) {
+            return;
+        }
+        else if (handleMetaCurElevationModel(obj, meta)) {
+            return;
+        }
+        else if (handleMetaOldElevationModel(obj, meta)) {
+            return;
+        }
+        else {
+            log.warn("BHP: Meta line did not match any known type: " + line);
+        }
+    }
+
+
+    protected boolean handleMetaYear(ImportBedHeight obj, String line) {
+        Matcher m = META_YEAR.matcher(line);
+
+        if (m.matches()) {
+            String tmp = m.group(1);
+
+            try {
+                obj.setYear(Integer.valueOf(tmp));
+                return true;
+            }
+            catch (NumberFormatException e) {
+                log.warn("BHP: Error while parsing year!", e);
+            }
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaTimeInterval(ImportBedHeight obj, String line) {
+        Matcher m = META_TIMEINTERVAL.matcher(line);
+
+        if (m.matches()) {
+            String lo = m.group(1);
+            String up = m.group(2);
+
+            log.debug("Found time interval: " + lo + " - " + up);
+
+            try {
+                int lower = Integer.valueOf(lo);
+                int upper = Integer.valueOf(up);
+
+                Date fromYear = getDateFromYear(lower);
+                Date toYear   = getDateFromYear(upper);
+
+                obj.setTimeInterval(new ImportTimeInterval(fromYear, toYear));
+            }
+            catch (NumberFormatException e) {
+                log.warn("BHP: Error while parsing timeinterval!", e);
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaSoundingWidth(ImportBedHeight obj, String line) {
+        Matcher m = META_SOUNDING_WIDTH.matcher(line);
+
+        if (m.matches()) {
+            String tmp = m.group(1);
+
+            try {
+                obj.setSoundingWidth(Integer.valueOf(tmp));
+                return true;
+            }
+            catch (NumberFormatException e) {
+                log.warn("BHP: Error while parsing sounding width: " + line, e);
+                log.warn("-> Set default value '0'");
+            }
+            obj.setSoundingWidth(0);
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaComment(ImportBedHeight obj, String line) {
+        Matcher m = META_COMMENTS.matcher(line);
+
+        if (m.matches()) {
+            String tmp = m.group(1);
+
+            obj.setDescription(tmp);
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaEvaluationBy(
+        ImportBedHeight obj,
+        String                line
+    ) {
+        Matcher m = META_EVALUATION_BY.matcher(line);
+
+        if (m.matches()) {
+            String tmp = m.group(1);
+            tmp = tmp.replace(";", "");
+
+            obj.setEvaluationBy(tmp);
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaRange(ImportBedHeight obj, String line) {
+        Matcher m = META_RANGE.matcher(line);
+
+        if (m.matches() && m.groupCount() >= 2) {
+            String a = m.group(1).replace(";", "");
+            String b = m.group(2).replace(";", "");
+
+            try {
+                BigDecimal lower = new BigDecimal(nf.parse(a).doubleValue());
+                BigDecimal upper = new BigDecimal(nf.parse(b).doubleValue());
+
+                obj.setRange(new ImportRange(lower, upper));
+
+                return true;
+            }
+            catch (ParseException e) {
+                log.warn("BHP: Error while parsing range!", e);
+            }
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaType(ImportBedHeight obj, String line) {
+        Matcher m = META_TYPE.matcher(line);
+
+        if (m.matches()) {
+            String tmp = m.group(1).replace(";", "");
+
+            String name = BedHeightType.getBedHeightName(tmp);
+
+            if (name != null) {
+                obj.setType(new ImportBedHeightType(name, tmp));
+                return true;
+            }
+            else {
+                log.warn("Unknown bed height type: '" + tmp + "'");
+            }
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaLocationSystem(
+        ImportBedHeight obj,
+        String          line
+    ) {
+        Matcher m = META_LOCATION_SYSTEM.matcher(line);
+
+        if (m.matches()) {
+            String tmp = m.group(1).replace(";", "");
+
+            obj.setLocationSystem(new ImportLocationSystem(tmp, tmp));
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaCurElevationModel(
+        ImportBedHeight obj,
+        String          line
+    ) {
+        Matcher m = META_CUR_ELEVATION_SYSTEM.matcher(line);
+
+        if (m.matches()) {
+            String name = m.group(1);
+            String num  = m.group(2);
+            String unit = m.group(3);
+
+            obj.setCurElevationModel(new ImportElevationModel(
+                name + " " + num,
+                new ImportUnit(unit)
+            ));
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaOldElevationModel(
+        ImportBedHeight obj,
+        String          line
+    ) {
+        Matcher m = META_OLD_ELEVATION_SYSTEM.matcher(line);
+
+        if (m.matches()) {
+            String name = m.group(1);
+            String num  = m.group(2);
+            String unit = m.group(3);
+
+            obj.setOldElevationModel(new ImportElevationModel(
+                name + " " + num,
+                new ImportUnit(unit)
+            ));
+
+            return true;
+        }
+
+        return false;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/parsers/BedHeightSingleParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,89 @@
+package de.intevation.flys.importer.parsers;
+
+import java.math.BigDecimal;
+
+import java.text.ParseException;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportBedHeight;
+import de.intevation.flys.importer.ImportBedHeightSingle;
+import de.intevation.flys.importer.ImportBedHeightSingleValue;
+
+
+public class BedHeightSingleParser extends BedHeightParser {
+
+    private static final Logger log =
+        Logger.getLogger(BedHeightSingleParser.class);
+
+
+
+    @Override
+    protected ImportBedHeight newImportBedHeight(String description) {
+        return new ImportBedHeightSingle(description);
+    }
+
+
+
+    /**
+     * Create ImportBedHeightSingleValue from a line of csv file, add
+     * it to the ImportBedHeight.
+     */
+    @Override
+    protected void handleDataLine(ImportBedHeight obj, String line) {
+        String[] values = line.split(SEPERATOR_CHAR);
+
+        if (values == null || (values.length != 1 && values.length < 6)) {
+            //log.warn("BSP: Error while parsing data line: '" + line + "'");
+            return;
+        }
+
+        BigDecimal km;
+
+        try {
+            km = new BigDecimal(nf.parse(values[0]).doubleValue());
+        }
+        catch (ParseException e) {
+            // We expect a lot of ";;;;;;" lines.
+            //log.warn("BSP: Error while parsing km of data row.", e);
+            return;
+        }
+
+        // Handle gaps like "10,0;;;;;".
+        if (values.length == 1) {
+            ImportBedHeightSingleValue value = new ImportBedHeightSingleValue(
+                (ImportBedHeightSingle) obj,
+                km,
+                null, null, null, null, null);
+            obj.addValue(value);
+            return;
+        }
+
+        // Because we cannot enforce consistency of values with complete data
+        // via null constraints in the database (as there are "gap" values),
+        // do this checks manually.
+        if (values[3].length() == 0 || values[4].length() == 0
+            || values[5].length() == 0) {
+            //log.warn("BSP: Error while parsing data row (manual null constraint violated).");
+            return;
+        }
+
+        try {
+            ImportBedHeightSingleValue value = new ImportBedHeightSingleValue(
+                (ImportBedHeightSingle) obj,
+                km,
+                new BigDecimal(nf.parse(values[1]).doubleValue()),
+                new BigDecimal(nf.parse(values[2]).doubleValue()),
+                new BigDecimal(nf.parse(values[3]).doubleValue()),
+                new BigDecimal(nf.parse(values[4]).doubleValue()),
+                new BigDecimal(nf.parse(values[5]).doubleValue())
+            );
+
+            obj.addValue(value);
+        }
+        catch (ParseException e) {
+            log.warn("BSP: Error while parsing data row.", e);
+        }
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/parsers/FlowVelocityMeasurementParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,103 @@
+package de.intevation.flys.importer.parsers;
+
+import de.intevation.flys.importer.ImportFlowVelocityMeasurement;
+import de.intevation.flys.importer.ImportFlowVelocityMeasurementValue;
+
+import java.math.BigDecimal;
+
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+public class FlowVelocityMeasurementParser extends LineParser {
+
+    private static final Logger log =
+        Logger.getLogger(FlowVelocityMeasurementParser.class);
+
+    private static final NumberFormat nf =
+        NumberFormat.getInstance(DEFAULT_LOCALE);
+
+    private static final DateFormat df =
+        new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
+
+
+    private List<ImportFlowVelocityMeasurement> measurements;
+
+    private ImportFlowVelocityMeasurement current;
+
+
+    public FlowVelocityMeasurementParser() {
+        measurements = new ArrayList<ImportFlowVelocityMeasurement>();
+    }
+
+
+    public List<ImportFlowVelocityMeasurement> getMeasurements() {
+        return measurements;
+    }
+
+    @Override
+    protected void reset() {
+        current = new ImportFlowVelocityMeasurement();
+    }
+
+
+    @Override
+    protected void finish() {
+        measurements.add(current);
+    }
+
+
+    @Override
+    protected void handleLine(String line) {
+        if (line.startsWith(START_META_CHAR)) {
+            handleMetaLine(stripMetaLine(line));
+        }
+        else {
+            handleDataLine(line);
+        }
+    }
+
+
+    public void handleMetaLine(String line) {
+        line = line.replace(";", "");
+        current.setDescription(line);
+    }
+
+
+    public void handleDataLine(String line) {
+        String[] cols = line.split(SEPERATOR_CHAR);
+
+        if (cols.length < 8) {
+            log.warn("skip invalid data line: '" + line + "'");
+            return;
+        }
+
+        try {
+            double km     = nf.parse(cols[1]).doubleValue();
+            double w      = nf.parse(cols[5]).doubleValue();
+            double q      = nf.parse(cols[6]).doubleValue();
+            double v      = nf.parse(cols[7]).doubleValue();
+
+            String timestr     = cols[3] + " " + cols[4];
+            String description = cols.length > 8 ? cols[8] : null;
+
+            current.addValue(new ImportFlowVelocityMeasurementValue(
+                df.parse(timestr),
+                new BigDecimal(km),
+                new BigDecimal(w),
+                new BigDecimal(q),
+                new BigDecimal(v),
+                description
+            ));
+        }
+        catch (ParseException pe) {
+            log.warn("Error while parsing flow velocity values.", pe);
+        }
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/parsers/FlowVelocityModelParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,239 @@
+package de.intevation.flys.importer.parsers;
+
+import java.math.BigDecimal;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportDischargeZone;
+import de.intevation.flys.importer.ImportFlowVelocityModel;
+import de.intevation.flys.importer.ImportFlowVelocityModelValue;
+
+
+public class FlowVelocityModelParser extends LineParser {
+
+    private static final Logger log =
+        Logger.getLogger(FlowVelocityModelParser.class);
+
+    private static final Pattern META_REGEX =
+        Pattern.compile(".*Rechnung (.*) \\(Pegel (.*)\\).*");
+
+    private static final Pattern META_GAUGE =
+        Pattern.compile("(.*) Q=(\\w*)m3/s");
+
+    private static final Pattern META_MAINVALUE_A =
+        Pattern.compile("([a-zA-Z]+)+(\\d+)*");
+
+    private static final Pattern META_MAINVALUE_B =
+        Pattern.compile("(([a-zA-Z]+)+(\\d+)*)\\s*-\\s*(([a-zA-Z]+)+(\\d+)*)");
+
+    private static final Pattern META_MAINVALUE_C =
+        Pattern.compile("([0-9]++)\\s?(\\w*)|([0-9]++,[0-9]++)\\s?(\\w*)");
+
+    private static final Pattern META_MAINVALUE_D =
+        Pattern.compile("(([0-9]*)\\s?(\\w*)|([0-9]++,[0-9]++)\\s?(\\w*)) bis (([0-9]*)\\s?(\\w*)|([0-9]++,[0-9]++)\\s?(\\w*))");
+
+    private static final Pattern META_MAINVALUE_E =
+        Pattern.compile("(([a-zA-Z]+)+(\\d+)*) bis (([a-zA-Z]+)+(\\d+)*)");
+
+    private static final NumberFormat nf =
+        NumberFormat.getInstance(DEFAULT_LOCALE);
+
+
+    private List<ImportFlowVelocityModel> models;
+
+    private ImportFlowVelocityModel current;
+
+
+    public FlowVelocityModelParser() {
+        models = new ArrayList<ImportFlowVelocityModel>();
+    }
+
+
+    public List<ImportFlowVelocityModel> getModels() {
+        return models;
+    }
+
+    @Override
+    protected void reset() {
+        current = new ImportFlowVelocityModel();
+    }
+
+
+    @Override
+    protected void finish() {
+        models.add(current);
+    }
+
+
+    @Override
+    protected void handleLine(String line) {
+        if (line.startsWith(START_META_CHAR)) {
+            handleMetaLine(stripMetaLine(line));
+        }
+        else {
+            handleDataLine(line);
+        }
+    }
+
+
+    protected void handleMetaLine(String line) {
+        Matcher m = META_REGEX.matcher(line);
+
+        if (m.matches()) {
+            String mainValueStr = m.group(1);
+            String gaugeStr     = m.group(2);
+
+            Object[] valueData = handleMainValueString(mainValueStr);
+            Object[] gaugeData = handleGaugeString(gaugeStr);
+
+            if (valueData == null || valueData.length < 2) {
+                log.warn("skip invalid MainValue part: '" + line + "'");
+                return;
+            }
+
+            if (gaugeData == null || gaugeData.length < 2) {
+                log.warn("skip invalid gauge part: '" + line + "'");
+                return;
+            }
+
+            if (log.isDebugEnabled()) {
+                log.debug("Found meta information:");
+                log.debug("   Gauge: " + gaugeData[0]);
+                log.debug("   Value: " + gaugeData[1]);
+                log.debug("   Lower: " + valueData[0]);
+                log.debug("   upper: " + valueData[1]);
+            }
+
+            current.setDischargeZone(new ImportDischargeZone(
+                (String) gaugeData[0],
+                (BigDecimal) gaugeData[1],
+                (String) valueData[0],
+                (String) valueData[1]
+            ));
+        }
+    }
+
+
+    protected Object[] handleMainValueString(String mainValueStr) {
+        Matcher mA = META_MAINVALUE_A.matcher(mainValueStr);
+        if (mA.matches()) {
+            String name = mA.group(0);
+
+            return new Object[] { name, name };
+        }
+
+        Matcher mB = META_MAINVALUE_B.matcher(mainValueStr);
+        if (mB.matches()) {
+            String lower = mB.group(1);
+            String upper = mB.group(4);
+
+            return new Object[] { lower, upper };
+        }
+
+        Matcher mC = META_MAINVALUE_C.matcher(mainValueStr);
+        if (mC.matches()) {
+            String facA  = mC.group(1);
+            String nameA = mC.group(2);
+            String facB  = mC.group(3);
+            String nameB = mC.group(4);
+
+            String fac  = facA  != null ? facA  : facB;
+            String name = nameA != null ? nameA : nameB;
+
+            String mainValue = fac + " " + name;
+
+            return new Object[] { mainValue, mainValue };
+        }
+
+        Matcher mD = META_MAINVALUE_D.matcher(mainValueStr);
+        if (mD.matches()) {
+            String loFacA  = mD.group(2);
+            String loNameA = mD.group(3);
+            String loFacB  = mD.group(4);
+            String loNameB = mD.group(5);
+
+            String upFacA  = mD.group(7);
+            String upNameA = mD.group(8);
+            String upFacB  = mD.group(9);
+            String upNameB = mD.group(10);
+
+            String loFac  = loFacA  != null ? loFacA  : loFacB;
+            String loName = loNameA != null ? loNameA : loNameB;
+
+            String upFac  = upFacA  != null ? upFacA  : upFacB;
+            String upName = upNameA != null ? upNameA : upNameB;
+
+            String loMainValue = loFac + " " + loName;
+            String upMainValue = upFac + " " + upName;
+
+            return new Object[] { loMainValue, upMainValue };
+        }
+
+        Matcher mE = META_MAINVALUE_E.matcher(mainValueStr);
+        if (mE.matches()) {
+            String lower = mE.group(1);
+            String upper = mE.group(4);
+
+            return new Object[] { lower, upper };
+        }
+
+        return null;
+    }
+
+
+    protected Object[] handleGaugeString(String gaugeStr) {
+        Matcher m = META_GAUGE.matcher(gaugeStr);
+
+        if (m.matches()) {
+            String name = m.group(1);
+            String qStr = m.group(2);
+
+            try {
+                return new Object[] {
+                    name,
+                    new BigDecimal(nf.parse(qStr).doubleValue()) };
+            }
+            catch (ParseException pe) {
+                log.warn("Error while parsing Q value: '" + qStr + "'");
+            }
+        }
+
+        return null;
+    }
+
+
+    protected void handleDataLine(String line) {
+        String[] cols = line.split(SEPERATOR_CHAR);
+
+        if (cols.length < 5) {
+            log.warn("skip invalid data line: '" + line + "'");
+            return;
+        }
+
+        try {
+            double km     = nf.parse(cols[0]).doubleValue();
+            double q      = nf.parse(cols[1]).doubleValue();
+            double total  = nf.parse(cols[2]).doubleValue();
+            double main   = nf.parse(cols[3]).doubleValue();
+            double stress = nf.parse(cols[4]).doubleValue();
+
+            current.addValue(new ImportFlowVelocityModelValue(
+                new BigDecimal(km),
+                new BigDecimal(q),
+                new BigDecimal(total),
+                new BigDecimal(main),
+                new BigDecimal(stress)
+            ));
+        }
+        catch (ParseException pe) {
+            log.warn("Error while parsing flow velocity values.", pe);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/importer/parsers/HYKParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/HYKParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -124,7 +124,7 @@
                 switch (state) {
                     case LINE_1:
                         if (parts.length < 2) {
-                            log.error("1: not enough elements in line " +
+                            log.error("HYK 1: not enough elements in line " +
                                 in.getLineNumber());
                             return false;
                         }
@@ -163,7 +163,7 @@
 
                     case LINE_2:
                         if (parts.length < 3) {
-                            log.error("2: not enough elements in line " +
+                            log.error("HYK 2: not enough elements in line " +
                                 in.getLineNumber());
                             return false;
                         }
@@ -174,7 +174,7 @@
                         }
                         catch (NumberFormatException nfe) {
                             log.error(
-                                "parsing num zones, bottom or top height " +
+                                "HYK: parsing num zones, bottom or top height " +
                                 "failed in line " + in.getLineNumber());
                             return false;
                         }
@@ -189,7 +189,7 @@
                     case LINE_3:
                         if (parts.length != numZones) {
                             log.error(
-                                "number of flow zones mismatches " +
+                                "HYK: number of flow zones mismatches " +
                                 "in line " + in.getLineNumber());
                             return false;
                         }
@@ -211,7 +211,7 @@
                             }
                         }
                         catch (NumberFormatException nfe) {
-                            log.error("cannot parse number in line " +
+                            log.error("HYK: cannot parse number in line " +
                                 in.getLineNumber());
                             return false;
                         }
@@ -220,12 +220,12 @@
 
                     case LINE_5:
                         if (parts.length + coordPos < coords.length) {
-                            log.error("5: not enough elements in line " +
+                            log.error("HYK 5: not enough elements in line " +
                                 in.getLineNumber());
                             return false;
                         }
                         try {
-                            for (int i = 0; 
+                            for (int i = 0;
                                 i < parts.length && coordPos < coords.length;
                                 ++i, ++coordPos
                             ) {
@@ -233,7 +233,7 @@
                             }
                         }
                         catch (NumberFormatException nfe) {
-                            log.error("cannot parse number in line " + 
+                            log.error("HYK: cannot parse number in line " +
                                 in.getLineNumber());
                             return false;
                         }
@@ -241,7 +241,7 @@
                             BigDecimal a = coords[i];
                             BigDecimal b = coords[i == coords.length-1 ? i : i+1];
                             if (a.compareTo(b) > 0) {
-                                log.warn("zone coordinates swapped in line " + 
+                                log.warn("HYK: zone coordinates swapped in line " +
                                     in.getLineNumber());
                                 BigDecimal c = a; a = b; b = c;
                             }
@@ -254,7 +254,7 @@
 
                     case LINE_6:
                         if (parts.length < 3) {
-                            log.error("6: not enough elements in line " +
+                            log.error("HYK 6: not enough elements in line " +
                                 in.getLineNumber());
                             return false;
                         }
@@ -264,7 +264,7 @@
                             distanceVR = new BigDecimal(parts[2]);
                         }
                         catch (NumberFormatException nfe) {
-                            log.error("cannot parse number in line " +
+                            log.error("HYK: cannot parse number in line " +
                                 in.getLineNumber());
                             return false;
                         }
@@ -281,7 +281,7 @@
             }
         }
         catch (IOException ioe) {
-            log.error(ioe);
+            log.error("HYK: Error reading file.", ioe);
             return false;
         }
         finally {
@@ -290,7 +290,7 @@
                     in.close();
                 }
                 catch (IOException ioe) {
-                    log.error(ioe);
+                    log.error("HYK: Error closing file.", ioe);
                 }
             }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/LineParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,93 @@
+package de.intevation.flys.importer.parsers;
+
+import java.io.File;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+
+import org.apache.log4j.Logger;
+
+
+public abstract class LineParser {
+
+    private static final Logger log = Logger.getLogger(LineParser.class);
+
+    public static final String ENCODING = "ISO-8859-1";
+
+    public static final Locale DEFAULT_LOCALE = Locale.GERMAN;
+
+    public static final String START_META_CHAR = "#";
+    public static final String SEPERATOR_CHAR  = ";";
+
+
+    protected abstract void handleLine(String line);
+
+    protected abstract void reset();
+
+    protected abstract void finish();
+
+
+    /**
+     * This method reads each line of <i>file</i>. At the beginning,
+     * <i>reset()</i> is called; afterwars for each line <i>handleLine()</i> is
+     * called; at the end <i>finish</i> is called.
+     *
+     * @param file The file which should be parsed.
+     */
+    public void parse(File file) throws IOException {
+        log.info("Parsing file '" + file + "'");
+
+        reset();
+
+        LineNumberReader in = null;
+        try {
+            in =
+                new LineNumberReader(
+                new InputStreamReader(
+                new FileInputStream(file), ENCODING));
+
+            String line = null;
+            while ((line = in.readLine()) != null) {
+                if ((line = line.trim()).length() == 0) {
+                    continue;
+                }
+
+                handleLine(line);
+            }
+        }
+        finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+
+        finish();
+    }
+
+
+    protected static String stripMetaLine(String line) {
+        String tmp = line.substring(1, line.length());
+
+        if (tmp.startsWith(" ")) {
+            return tmp.substring(1, tmp.length());
+        }
+        else {
+            return tmp;
+        }
+    }
+
+
+    public static Date getDateFromYear(int year) {
+        Calendar cal = Calendar.getInstance();
+        cal.set(year, 0, 1);
+
+        return cal.getTime();
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/parsers/MorphologicalWidthParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,123 @@
+package de.intevation.flys.importer.parsers;
+
+import java.math.BigDecimal;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportMorphWidth;
+import de.intevation.flys.importer.ImportMorphWidthValue;
+import de.intevation.flys.importer.ImportUnit;
+
+
+public class MorphologicalWidthParser extends LineParser {
+
+    private static final Logger log =
+        Logger.getLogger(MorphologicalWidthParser.class);
+
+
+    public static final NumberFormat nf = NumberFormat.getInstance(DEFAULT_LOCALE);
+
+
+    public static final Pattern META_UNIT =
+        Pattern.compile("^Einheit: \\[(.*)\\].*");
+
+
+    protected List<ImportMorphWidth> morphWidths;
+
+    protected ImportMorphWidth current;
+
+
+    public MorphologicalWidthParser() {
+        morphWidths = new ArrayList<ImportMorphWidth>();
+    }
+
+
+    @Override
+    protected void reset() {
+        current = new ImportMorphWidth();
+    }
+
+
+    @Override
+    protected void finish() {
+        if (current != null) {
+            morphWidths.add(current);
+        }
+    }
+
+
+    @Override
+    protected void handleLine(String line) {
+        if (line.startsWith(START_META_CHAR)) {
+            handleMetaLine(stripMetaLine(line));
+        }
+        else {
+            handleDataLine(line);
+        }
+    }
+
+
+    protected void handleMetaLine(String line) {
+        if (handleMetaUnit(line)) {
+            return;
+        }
+        else {
+            log.warn("MWP: Unknown meta line: '" + line + "'");
+        }
+    }
+
+
+    protected boolean handleMetaUnit(String line) {
+        Matcher m = META_UNIT.matcher(line);
+
+        if (m.matches()) {
+            String unit = m.group(1);
+
+            current.setUnit(new ImportUnit(unit));
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    protected void handleDataLine(String line) {
+        String[] vals = line.split(SEPERATOR_CHAR);
+
+        if (vals == null || vals.length < 2) {
+            log.warn("MWP: skip invalid data line: '" + line + "'");
+            return;
+        }
+
+        try {
+            BigDecimal km    = new BigDecimal(nf.parse(vals[0]).doubleValue());
+            BigDecimal width = new BigDecimal(nf.parse(vals[1]).doubleValue());
+
+            String desc = vals.length > 2 ? vals[2] : null;
+
+            current.addValue(new ImportMorphWidthValue(
+                km,
+                width,
+                desc
+            ));
+        }
+        catch (ParseException pe) {
+            log.warn("MWP: Error while parsing numbers in '" + line + "'");
+        }
+    }
+
+
+    public List<ImportMorphWidth> getMorphologicalWidths() {
+        return morphWidths;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/importer/parsers/PRFParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/PRFParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -94,7 +94,7 @@
                     pos, pos + firstIntegerPlaces);
 
                 String second = line.substring(
-                    pos + firstIntegerPlaces, 
+                    pos + firstIntegerPlaces,
                     Math.min(L, pos+firstIntegerPlaces+secondIntegerPlaces));
 
                 double x, y;
@@ -224,16 +224,23 @@
         return null;
     }
 
+    private static final String removeExtension(String name) {
+        int index = name.lastIndexOf('.');
+        return index == -1
+            ? name
+            : name.substring(0, index);
+    }
+
     public boolean parse(File file) {
 
         if (!(file.isFile() && file.canRead())) {
-            log.warn("cannot open file '" + file + "'");
+            log.warn("PRF: cannot open file '" + file + "'");
             return false;
         }
 
         log.info("parsing PRF file: '" + file + "'");
 
-        description = file.getName();
+        description = removeExtension(file.getName());
 
         year = findYear(file.getName());
 
@@ -260,14 +267,14 @@
             String line = in.readLine();
 
             if (line == null || (line = line.trim()).length() == 0) {
-                log.warn("file is empty.");
+                log.warn("PRF: file is empty.");
                 return false;
             }
 
             Matcher m = DATA_PATTERN.matcher(line);
 
             if (!m.matches()) {
-                log.warn("First line does not look like a PRF data pattern.");
+                log.warn("PRF: First line does not look like a PRF data pattern.");
                 return false;
             }
 
@@ -275,25 +282,25 @@
 
             if ((line = in.readLine()) == null
             || (line = line.trim()).length() == 0) {
-                log.warn("premature EOF. Expected integer in line 2");
+                log.warn("PRF: premature EOF. Expected integer in line 2");
                 return false;
             }
 
             try {
                 if (Integer.parseInt(line) != dataFormat.maxRepetitions) {
-                    log.warn("Expected " +
+                    log.warn("PRF: Expected " +
                         dataFormat.maxRepetitions + " in line 2");
                     return false;
                 }
             }
             catch (NumberFormatException nfe) {
-                log.warn("invalid integer in line 2", nfe);
+                log.warn("PRF: invalid integer in line 2", nfe);
                 return false;
             }
 
             if ((line = in.readLine()) == null) {
                 log.warn(
-                    "premature EOF. Expected pattern for km extraction");
+                    "PRF: premature EOF. Expected pattern for km extraction");
                 return false;
             }
 
@@ -301,7 +308,7 @@
 
             if (!m.matches()) {
                 log.warn(
-                    "line 4 does not look like a PRF km extraction pattern.");
+                    "PRF: line 4 does not look like a PRF km extraction pattern.");
                 return false;
             }
 
@@ -309,7 +316,7 @@
 
             if ((line = in.readLine()) == null
             || (line = line.trim()).length() == 0) {
-                log.warn("premature EOF. Expected skip row count.");
+                log.warn("PRF: premature EOF. Expected skip row count.");
                 return false;
             }
 
@@ -321,7 +328,7 @@
             }
             catch (NumberFormatException nfe) {
                 log.warn(
-                    "line 5 is not an positive integer.");
+                    "PRF: line 5 is not an positive integer.");
                 return false;
             }
 
@@ -337,7 +344,7 @@
                     km = kmFormat.extractKm(line);
                 }
                 catch (NumberFormatException iae) {
-                    log.warn("cannot extract km in line + " + in.getLineNumber());
+                    log.warn("PRF: cannot extract km in line " + in.getLineNumber());
                     return false;
                 }
 
@@ -361,7 +368,7 @@
             sortLists();
         }
         catch (IOException ioe) {
-            log.error(ioe);
+            log.error("Error reading PRF file.", ioe);
             return false;
         }
         finally {
@@ -370,7 +377,7 @@
                     in.close();
                 }
                 catch (IOException ioe) {
-                    log.error(ioe);
+                    log.error("Error closing PRF file.", ioe);
                 }
             }
         }
--- a/flys-backend/src/main/java/de/intevation/flys/importer/parsers/PegelGltParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/PegelGltParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -57,7 +57,7 @@
 
                 int kmPos = line.indexOf(KM);
                 if (kmPos < 0) {
-                    log.warn("no gauge found in line " + in.getLineNumber());
+                    log.warn("GLT: no gauge found in line " + in.getLineNumber());
                     continue;
                 }
 
@@ -68,8 +68,8 @@
 
                 String [] parts = line.split("\\s+");
                 if (parts.length < 4) {
-                    log.warn("line " + in.getLineNumber()
-                        + " has not enough columns");
+                    log.warn("GLT: line " + in.getLineNumber()
+                        + " has not enough columns.");
                     continue;
                 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/SQRelationParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,128 @@
+package de.intevation.flys.importer.parsers;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportSQRelation;
+import de.intevation.flys.importer.ImportSQRelationValue;
+import de.intevation.flys.importer.ImportTimeInterval;
+
+
+public class SQRelationParser extends LineParser {
+
+    private static final Logger log =
+        Logger.getLogger(SQRelationParser.class);
+
+    private static final Pattern TIMERANGE_REGEX =
+        Pattern.compile(".*Zeitraum.*\\s(\\w*)-(\\w*).*");
+
+    private static final NumberFormat nf =
+        NumberFormat.getInstance(DEFAULT_LOCALE);
+
+
+    private List<ImportSQRelation> relations;
+
+    private ImportSQRelation current;
+
+    private String currentDescription;
+
+
+    public SQRelationParser() {
+        relations = new ArrayList<ImportSQRelation>();
+    }
+
+
+    public List<ImportSQRelation> getSQRelations() {
+        return relations;
+    }
+
+    @Override
+    public void parse(File file) throws IOException {
+        this.currentDescription = file.getName();
+        super.parse(file);
+    }
+
+
+    @Override
+    protected void reset() {
+        current = new ImportSQRelation();
+    }
+
+
+    @Override
+    protected void finish() {
+        if (current != null) {
+            current.setDescription(currentDescription);
+            relations.add(current);
+        }
+    }
+
+
+    @Override
+    protected void handleLine(String line) {
+        if (line.startsWith(START_META_CHAR)) {
+            handleMetaLine(stripMetaLine(line));
+        }
+        else {
+            handleDataLine(line);
+        }
+    }
+
+
+    protected void handleMetaLine(String line) {
+        Matcher m = TIMERANGE_REGEX.matcher(line);
+
+        if (m.matches()) {
+            String lo = m.group(1);
+            String hi = m.group(2);
+
+            log.debug("Found timerange " + lo + " - " + hi);
+
+            try {
+                int low  = nf.parse(lo).intValue();
+                int high = nf.parse(hi).intValue();
+
+                current.setTimeInterval(new ImportTimeInterval(
+                    getDateFromYear(low),
+                    getDateFromYear(high)
+                ));
+            }
+            catch (ParseException nfe) {
+                log.warn("Cannot parse time range.", nfe);
+            }
+        }
+    }
+
+
+    protected void handleDataLine(String line) {
+        String[] cols = line.split(SEPERATOR_CHAR);
+
+        if (cols.length < 8) {
+            log.warn("skip invalid data line: '" + line + "'");
+            return;
+        }
+
+        try {
+            current.addValue(new ImportSQRelationValue(
+                cols[1],
+                cols[2],
+                cols[4],
+                nf.parse(cols[3]).doubleValue(),
+                nf.parse(cols[6]).doubleValue(),
+                nf.parse(cols[7]).doubleValue()
+            ));
+        }
+        catch (ParseException pe) {
+            log.warn("Error while parsing sq relation row: '" + line + "'", pe);
+        }
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/parsers/SedimentDensityParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,174 @@
+package de.intevation.flys.importer.parsers;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.math.BigDecimal;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportDepth;
+import de.intevation.flys.importer.ImportSedimentDensity;
+import de.intevation.flys.importer.ImportSedimentDensityValue;
+import de.intevation.flys.importer.ImportUnit;
+
+
+public class SedimentDensityParser extends LineParser {
+
+    private static final Logger log =
+        Logger.getLogger(SedimentDensityParser.class);
+
+
+    public static final NumberFormat nf = NumberFormat.getInstance(DEFAULT_LOCALE);
+
+
+    public static final Pattern META_UNIT =
+        Pattern.compile("^Einheit: \\[(.*)\\].*");
+
+    public static final Pattern META_DEPTH =
+        Pattern.compile("^Tiefe: (\\w++)-(\\w++)( (\\w++))?.*");
+
+
+    protected List<ImportSedimentDensity> sedimentDensities;
+
+    protected ImportSedimentDensity current;
+
+    protected String currentDescription;
+
+
+    public SedimentDensityParser() {
+        sedimentDensities = new ArrayList<ImportSedimentDensity>();
+    }
+
+
+    @Override
+    public void parse(File file) throws IOException {
+        currentDescription = file.getName();
+
+        super.parse(file);
+    }
+
+
+    @Override
+    protected void reset() {
+        current = new ImportSedimentDensity(currentDescription);
+    }
+
+
+    @Override
+    protected void finish() {
+        if (current != null) {
+            sedimentDensities.add(current);
+        }
+    }
+
+
+    @Override
+    protected void handleLine(String line) {
+        if (line.startsWith(START_META_CHAR)) {
+            handleMetaLine(stripMetaLine(line));
+        }
+        else {
+            handleDataLine(line);
+        }
+    }
+
+
+    protected void handleMetaLine(String line) {
+        if (handleMetaUnit(line)) {
+            return;
+        }
+        else if (handleMetaDepth(line)) {
+            return;
+        }
+        else {
+            log.warn("Unknown meta line: '" + line + "'");
+        }
+    }
+
+
+    protected boolean handleMetaUnit(String line) {
+        Matcher m = META_UNIT.matcher(line);
+
+        if (m.matches()) {
+            String unit = m.group(1);
+
+            current.setUnit(new ImportUnit(unit));
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    protected boolean handleMetaDepth(String line) {
+        Matcher m = META_DEPTH.matcher(line);
+
+        if (m.matches()) {
+            String lo   = m.group(1);
+            String up   = m.group(2);
+            String unit = m.group(4);
+
+            log.info("Found sediment density depth: " + lo + " - " + up + " " + unit);
+
+            try {
+                ImportDepth depth = new ImportDepth(
+                    new BigDecimal(nf.parse(lo).doubleValue()),
+                    new BigDecimal(nf.parse(up).doubleValue()),
+                    new ImportUnit(unit)
+                );
+
+                current.setDepth(depth);
+
+                return true;
+            }
+            catch (ParseException pe) {
+                log.warn("Error while parsing numbers in: '" + line + "'");
+            }
+        }
+        else {
+            log.debug("Meta line doesn't contain depth information: " + line);
+        }
+
+        return false;
+    }
+
+
+    protected void handleDataLine(String line) {
+        String[] vals = line.split(SEPERATOR_CHAR);
+
+        if (vals == null || vals.length < 3) {
+            log.warn("skip invalid data line: '" + line + "'");
+            return;
+        }
+
+        try {
+            BigDecimal km      = new BigDecimal(nf.parse(vals[0]).doubleValue());
+            BigDecimal density = new BigDecimal(nf.parse(vals[1]).doubleValue());
+
+            current.addValue(new ImportSedimentDensityValue(
+                km,
+                density,
+                vals[2])
+            );
+        }
+        catch (ParseException pe) {
+            log.warn("Error while parsing numbers in '" + line + "'");
+        }
+    }
+
+
+    public List<ImportSedimentDensity> getSedimentDensities() {
+        return sedimentDensities;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/parsers/SedimentYieldParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,396 @@
+package de.intevation.flys.importer.parsers;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportGrainFraction;
+import de.intevation.flys.importer.ImportSedimentYield;
+import de.intevation.flys.importer.ImportSedimentYieldValue;
+import de.intevation.flys.importer.ImportTimeInterval;
+import de.intevation.flys.importer.ImportUnit;
+import de.intevation.flys.model.GrainFraction;
+
+
+public class SedimentYieldParser extends LineParser {
+
+    private static final Logger log =
+        Logger.getLogger(SedimentYieldParser.class);
+
+
+    public static final NumberFormat nf = NumberFormat.getInstance(DEFAULT_LOCALE);
+
+
+    public static final String FRAKTION_START = "Fraktion:";
+
+    public static final String FRACTION_COARSE_STR =
+        "_Grobkorn.csv";
+
+    public static final String FRACTION_FINE_MIDDLE_STR =
+        "_Fein-Mittel-Kies.csv";
+
+    public static final String FRACTION_SAND =
+        "_Sand.csv";
+
+    public static final String FRACTION_SUSP_SAND =
+        "_susp_Sand.csv";
+
+    public static final String FRACTION_SUSP_SAND_BED =
+        "_susp_Sand_bettbildAnteil.csv";
+
+    public static final String FRACTION_SUSPENDED_SEDIMENT =
+        "_Schwebstoff.csv";
+
+    public static final String FRACTION_TOTAL =
+        "_gesamt.csv";
+
+
+    public static final Pattern TIMEINTERVAL_SINGLE =
+        Pattern.compile("\\D*([0-9]+?)\\D*");
+
+    public static final Pattern TIMEINTERVAL_EPOCH =
+        Pattern.compile("\\D*([0-9]+?)\\s*-\\s*([0-9]+?)\\D*");
+
+    public static final Pattern META_FRACTION =
+        Pattern.compile("^Fraktion: (.*)");
+
+    public static final Pattern META_UNIT =
+        Pattern.compile("^Einheit: \\[(.*)\\].*");
+
+    public static final Pattern META_COLUMN_NAMES =
+        Pattern.compile("^Fluss-km.*");
+
+    public static final Pattern META_GRAIN_FRACTION_A =
+        Pattern.compile("\\D*(([0-9]+?,[0-9]+?)\\s*-|([0-9]++)\\s*-)(([0-9]+?,[0-9]+?)|([0-9]++))\\s*([a-zA-Z]+?)\\W*\\D*");
+
+    public static final Pattern META_GRAIN_FRACTION_B =
+        Pattern.compile("(<|>){1}\\s*(\\w++)\\s*(([0-9]+?,[0-9]+?)\\s*-|([0-9]++)\\s*-)(([0-9]+?,[0-9]+?)|([0-9]++))\\s*([a-zA-Z]+?)");
+
+    public static final Pattern META_GRAIN_FRACTION_C =
+        Pattern.compile("(<|>){1}\\s*((([0-9]+?,[0-9]+?)|([0-9]++))\\s*(\\w+))");
+
+
+    protected List<ImportSedimentYield> sedimentYields;
+
+    protected ImportSedimentYield[] current;
+
+    protected ImportGrainFraction grainFraction;
+
+    protected ImportUnit unit;
+
+    protected String description;
+
+    protected String[] columnNames;
+
+
+    public SedimentYieldParser() {
+        sedimentYields = new ArrayList<ImportSedimentYield>();
+    }
+
+
+    @Override
+    public void parse(File file) throws IOException {
+        description = file.getName();
+
+        super.parse(file);
+    }
+
+
+    @Override
+    protected void reset() {
+        current       = null;
+        grainFraction = null;
+        unit          = null;
+    }
+
+
+    @Override
+    protected void finish() {
+        if (current != null) {
+            for (ImportSedimentYield isy: current) {
+                sedimentYields.add(isy);
+            }
+        }
+
+        description = null;
+    }
+
+
+    @Override
+    protected void handleLine(String line) {
+        if (line.startsWith(START_META_CHAR)) {
+            handleMetaLine(stripMetaLine(line));
+        }
+        else {
+            handleDataLine(line);
+        }
+    }
+
+
+    protected void handleMetaLine(String line) {
+        if (handleMetaUnit(line)) {
+            return;
+        }
+        else if (handleMetaFraction(line)) {
+            return;
+        }
+        else if (handleColumnNames(line)) {
+            return;
+        }
+        else {
+            log.warn("SYP: Unknown meta line: '" + line + "'");
+        }
+    }
+
+
+    protected boolean handleMetaUnit(String line) {
+        Matcher m = META_UNIT.matcher(line);
+
+        if (m.matches()) {
+            unit = new ImportUnit(m.group(1));
+            return true;
+        }
+
+        return false;
+    }
+
+
+    public boolean handleMetaFraction(String line) {
+        Matcher m = META_FRACTION.matcher(line);
+
+        if (m.matches()) {
+            String tmp = m.group(1);
+
+            this.grainFraction = buildGrainFraction(tmp);
+
+            return true;
+        }
+        else if (line.startsWith(FRAKTION_START)) {
+            String newLine = line.replace(FRAKTION_START, "").trim();
+            if (newLine.length() == 0) {
+                log.debug("Found total grain fraction.");
+                this.grainFraction = new ImportGrainFraction(GrainFraction.TOTAL);
+
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+
+    public boolean handleColumnNames(String line) {
+        Matcher m = META_COLUMN_NAMES.matcher(line);
+
+        if (m.matches()) {
+            columnNames = line.split(SEPERATOR_CHAR);
+
+            initializeSedimentYields();
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    protected void handleDataLine(String line) {
+        String[] vals = line.split(SEPERATOR_CHAR);
+
+        if (vals == null || vals.length < columnNames.length-1) {
+            log.warn("SYP: skip invalid data line: '" + line + "'");
+            return;
+        }
+
+        try {
+            Double km = nf.parse(vals[0]).doubleValue();
+
+            for (int i = 1, n = columnNames.length-1; i < n; i++) {
+                String curVal = vals[i];
+
+                if (curVal != null && curVal.length() > 0) {
+                    current[i-1].addValue(new ImportSedimentYieldValue(
+                        km, nf.parse(vals[i]).doubleValue()
+                    ));
+                }
+            }
+        }
+        catch (ParseException pe) {
+            log.warn("SYP: Error while parsing numbers in '" + line + "':", pe);
+        }
+    }
+
+
+    private void initializeSedimentYields() {
+        // skip first column (Fluss-km) and last column (Hinweise)
+        current = new ImportSedimentYield[columnNames.length-2];
+
+        for (int i = 0, n = columnNames.length; i < n-2; i++) {
+            current[i] = new ImportSedimentYield(this.description);
+            current[i].setTimeInterval(getTimeInterval(columnNames[i+1]));
+            current[i].setUnit(unit);
+            current[i].setGrainFraction(grainFraction);
+        }
+    }
+
+
+    private ImportTimeInterval getTimeInterval(String column) {
+        try {
+            Matcher a = TIMEINTERVAL_EPOCH.matcher(column);
+            if (a.matches()) {
+                int yearA = nf.parse(a.group(1)).intValue();
+                int yearB = nf.parse(a.group(2)).intValue();
+
+                return new ImportTimeInterval(
+                    getDateFromYear(yearA),
+                    getDateFromYear(yearB)
+                );
+            }
+
+            Matcher b = TIMEINTERVAL_SINGLE.matcher(column);
+            if (b.matches()) {
+                int year = nf.parse(b.group(1)).intValue();
+
+                return new ImportTimeInterval(getDateFromYear(year));
+            }
+
+            log.warn("SYP: Unknown time interval string: '" + column + "'");
+        }
+        catch (ParseException pe) {
+            log.warn("SYP: Error while parsing years: " + column, pe);
+        }
+
+        return null;
+    }
+
+
+    private ImportGrainFraction buildGrainFraction(String gfStr) {
+        Matcher a = META_GRAIN_FRACTION_A.matcher(gfStr);
+        if (a.matches()) {
+            String lowerA = a.group(2);
+            String lowerB = a.group(3);
+
+            String upperA = a.group(4);
+            String upperB = a.group(5);
+
+            String unitStr = a.group(7);
+            String lower = lowerA != null ? lowerA : lowerB;
+            String upper = upperA != null ? upperA : upperB;
+
+            try {
+                return new ImportGrainFraction(
+                    getGrainFractionTypeName(this.description),
+                    nf.parse(lower).doubleValue(),
+                    nf.parse(upper).doubleValue(),
+                    new ImportUnit(unitStr)
+                );
+            }
+            catch (ParseException pe) {
+                log.warn("SYP: Error while parsing ranges of: '" + gfStr + "'");
+            }
+        }
+
+        Matcher b = META_GRAIN_FRACTION_B.matcher(gfStr);
+        if (b.matches()) {
+            String lowerA  = b.group(4);
+            String lowerB  = b.group(5);
+            String upperA  = b.group(6);
+            String upperB  = b.group(7);
+            String unitStr = b.group(9);
+
+            String lower = lowerA != null ? lowerA : lowerB;
+            String upper = upperA != null ? upperA : upperB;
+
+            try {
+                return new ImportGrainFraction(
+                    getGrainFractionTypeName(this.description),
+                    nf.parse(lower).doubleValue(),
+                    nf.parse(upper).doubleValue(),
+                    new ImportUnit(unitStr)
+                );
+            }
+            catch (ParseException pe) {
+                log.warn("SYP: Error while parsing ranges of: '" + gfStr + "'");
+            }
+        }
+
+        Matcher c = META_GRAIN_FRACTION_C.matcher(gfStr);
+        if (c.matches()) {
+            String oper     = c.group(1);
+            String valueStr = c.group(3);
+            String unitStr  = c.group(6);
+
+            try {
+                Double value = nf.parse(valueStr).doubleValue();
+
+                if (oper.equals(">")) {
+                    return new ImportGrainFraction(
+                        getGrainFractionTypeName(this.description),
+                        value,
+                        null,
+                        new ImportUnit(unitStr)
+                    );
+                }
+                else {
+                    return new ImportGrainFraction(
+                        getGrainFractionTypeName(this.description),
+                        null,
+                        value,
+                        new ImportUnit(unitStr)
+                    );
+                }
+            }
+            catch (ParseException pe) {
+                log.warn("SYP: Error while parsing ranges of: '" + gfStr + "'");
+            }
+        }
+
+        log.warn("SYP: Unknow grain fraction: '" + gfStr + "'");
+
+        return null;
+    }
+
+
+    public static String getGrainFractionTypeName(String filename) {
+        if (filename.endsWith(FRACTION_COARSE_STR)) {
+            return GrainFraction.COARSE;
+        }
+        else if (filename.endsWith(FRACTION_FINE_MIDDLE_STR)) {
+            return GrainFraction.FINE_MIDDLE;
+        }
+        else if (filename.endsWith(FRACTION_SAND)) {
+            return GrainFraction.SAND;
+        }
+        else if (filename.endsWith(FRACTION_SUSP_SAND)) {
+            return GrainFraction.SUSP_SAND;
+        }
+        else if (filename.endsWith(FRACTION_SUSP_SAND_BED)) {
+            return GrainFraction.SUSP_SAND_BED;
+        }
+        else if (filename.endsWith(FRACTION_SUSPENDED_SEDIMENT)) {
+            return GrainFraction.SUSPENDED_SEDIMENT;
+        }
+        else if (filename.endsWith(FRACTION_TOTAL)) {
+            return GrainFraction.TOTAL;
+        }
+        else {
+            log.warn("SYP: Unknown grain fraction '" + filename + "'");
+            return "unknown";
+        }
+    }
+
+
+    public List<ImportSedimentYield> getSedimentYields() {
+        return sedimentYields;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/importer/parsers/StaFileParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/StaFileParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -30,6 +30,9 @@
     public static final String TYPES =
         System.getProperty("flys.backend.main.value.types", "QWTD");
 
+    public static final boolean PARSE_GAUGE_NUMBERS =
+        Boolean.getBoolean("flys.backend.sta.parse.gauge.numbers");
+
     public static final Pattern QWTD_ =
         Pattern.compile("\\s*([^\\s]+)\\s+([^\\s]+)\\s+([" +
             Pattern.quote(TYPES) + "]).*");
@@ -57,19 +60,24 @@
             }
 
             if (line.length() < 37) {
-                log.warn("first line in STA file is too short.");
+                log.warn("First line in STA file is too short.");
                 return false;
             }
-            String gaugeNumberString = line.substring( 0, 16).trim();
-            String gaugeName         = line.substring(16, 37).trim();
+
+            String gaugeName = line.substring(16, 37).trim();
 
             Long gaugeNumber = null;
-            try {
-                gaugeNumber = Long.parseLong(gaugeNumberString);
-            }
-            catch (NumberFormatException nfe) {
-                log.warn("'" + gaugeNumberString +
-                    "' is not a valid long number.");
+
+            if (PARSE_GAUGE_NUMBERS) {
+                String gaugeNumberString = line.substring(0, 16).trim();
+
+                try {
+                    gaugeNumber = Long.parseLong(gaugeNumberString);
+                }
+                catch (NumberFormatException nfe) {
+                    log.warn("STA: '" + gaugeNumberString +
+                        "' is not a valid long number.");
+                }
             }
 
             gauge.setName(gaugeName);
@@ -83,14 +91,14 @@
             String [] values = line.substring(38).trim().split("\\s+", 2);
 
             if (values.length < 2) {
-                log.warn("Not enough columns for aeo and datum");
+                log.warn("STA: Not enough columns for aeo and datum.");
             }
             try {
                 gauge.setAeo(new BigDecimal(values[0].replace(",", ".")));
                 gauge.setDatum(new BigDecimal(values[1].replace(",", ".")));
             }
             catch (NumberFormatException nfe) {
-                log.warn("cannot parse aeo or datum");
+                log.warn("STA: cannot parse aeo or datum.");
                 return false;
             }
 
@@ -102,7 +110,7 @@
             }
 
             if (line.length() < 36) {
-                log.warn("second line is too short");
+                log.warn("STA: second line is too short");
                 return false;
             }
 
@@ -111,7 +119,7 @@
                     new BigDecimal(line.substring(29, 36).trim()));
             }
             catch (NumberFormatException nfe) {
-                log.warn("parsing of the datum of the gauge failed");
+                log.warn("STA: parsing of the datum of the gauge failed");
                 return false;
             }
 
@@ -140,7 +148,7 @@
                         value = new BigDecimal(m.group(2).replace(",", "."));
                     }
                     catch (NumberFormatException nfe) {
-                        log.warn("value not parseable in line "
+                        log.warn("STA: value not parseable in line "
                             + in.getLineNumber());
                         continue;
                     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/WaterlevelDifferencesParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,181 @@
+package de.intevation.flys.importer.parsers;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportUnit;
+import de.intevation.flys.importer.ImportWaterlevelDifference;
+import de.intevation.flys.importer.ImportWaterlevelDifferenceColumn;
+import de.intevation.flys.importer.ImportWaterlevelDifferenceValue;
+
+
+public class WaterlevelDifferencesParser extends LineParser {
+
+    private static final Logger log =
+        Logger.getLogger(WaterlevelDifferencesParser.class);
+
+    private static final NumberFormat nf =
+        NumberFormat.getInstance(DEFAULT_LOCALE);
+
+    public static final Pattern META_UNIT =
+        Pattern.compile("^Einheit: \\[(.*)\\].*");
+
+
+    private List<ImportWaterlevelDifference> differences;
+
+    private ImportWaterlevelDifferenceColumn[] columns;
+
+    private ImportWaterlevelDifference current;
+
+
+    public WaterlevelDifferencesParser() {
+        differences = new ArrayList<ImportWaterlevelDifference>();
+    }
+
+
+    public List<ImportWaterlevelDifference> getDifferences() {
+        return differences;
+    }
+
+
+    @Override
+    public void parse(File file) throws IOException {
+        current = new ImportWaterlevelDifference(file.getName());
+
+        super.parse(file);
+    }
+
+
+    @Override
+    protected void reset() {
+    }
+
+
+    @Override
+    protected void finish() {
+        if (columns != null && current != null) {
+            for (ImportWaterlevelDifferenceColumn col: columns) {
+                current.addValue(col);
+            }
+
+            differences.add(current);
+        }
+
+        current = null;
+        columns = null;
+    }
+
+    @Override
+    protected void handleLine(String line) {
+        if (line.startsWith(START_META_CHAR)) {
+            handleMetaLine(stripMetaLine(line));
+        }
+        else {
+            handleDataLine(line);
+        }
+    }
+
+
+    private void handleMetaLine(String meta) {
+        if (handleMetaUnit(meta)) {
+            return;
+        }
+        else {
+            handleMetaColumnNames(meta);
+        }
+    }
+
+
+    private boolean handleMetaUnit(String meta) {
+        Matcher m = META_UNIT.matcher(meta);
+
+        if (m.matches()) {
+            String unit = m.group(1);
+            log.debug("Found unit: '" + unit + "'");
+
+            current.setUnit(new ImportUnit(unit));
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    private boolean handleMetaColumnNames(String meta) {
+        Pattern META_COLUMN_NAMES = Pattern.compile("Fluss-km;(.*)");
+        Matcher m = META_COLUMN_NAMES.matcher(meta);
+
+        if (m.matches()) {
+            String colStr = m.group(1);
+            String[] cols = colStr.split(SEPERATOR_CHAR);
+
+            log.debug("Found " + cols.length + " columns.");
+
+            initColumns(cols);
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    private void initColumns(String[] cols) {
+        columns = new ImportWaterlevelDifferenceColumn[cols.length];
+
+        for (int i = 0; i < cols.length; i++) {
+            String name = cols[i].replace("\"", "");
+
+            log.debug("Create new column '" + name + "'");
+            columns[i] = new ImportWaterlevelDifferenceColumn(name);
+        }
+    }
+
+
+    private void handleDataLine(String line) {
+        String[] cols = line.split(SEPERATOR_CHAR);
+
+        if (cols == null || cols.length < 2) {
+            log.warn("skip invalid waterlevel line: '" + line + "'");
+            return;
+        }
+
+        try {
+            Double station = nf.parse(cols[0]).doubleValue();
+
+            for (int i = 0; i < columns.length; i++) {
+                int idx = i+1;
+
+                if (idx >= cols.length) {
+                    log.warn("Insufficient column numbers: " + line);
+                    continue;
+                }
+
+                String value = cols[idx];
+
+                try {
+                    columns[i].addValue(new ImportWaterlevelDifferenceValue(
+                        station,
+                        nf.parse(value).doubleValue()
+                    ));
+                }
+                catch (ParseException pe) {
+                    log.warn("Error while parsing value: '" + value + "'");
+                }
+            }
+        }
+        catch (ParseException pe) {
+            log.warn("Error while parsing station: '" + line + "'");
+        }
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/importer/parsers/WaterlevelParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,160 @@
+package de.intevation.flys.importer.parsers;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.importer.ImportUnit;
+import de.intevation.flys.importer.ImportWaterlevel;
+import de.intevation.flys.importer.ImportWaterlevelQRange;
+import de.intevation.flys.importer.ImportWaterlevelValue;
+
+
+public class WaterlevelParser extends LineParser {
+
+    private static final Logger log = Logger.getLogger(WaterlevelParser.class);
+
+    private static final NumberFormat nf =
+        NumberFormat.getInstance(DEFAULT_LOCALE);
+
+    private static final Pattern META_Q_RANGE =
+        Pattern.compile("Abfluss\\s\\[(.*)\\];(.*)");
+
+    public static final Pattern META_UNIT =
+        Pattern.compile("^Einheit: \\[(.*)\\].*");
+
+
+    private List<ImportWaterlevel> waterlevels;
+
+    private ImportWaterlevel current;
+
+    private ImportWaterlevelQRange currentQ;
+
+    private String currentDescription;
+
+
+    public WaterlevelParser() {
+        waterlevels = new ArrayList<ImportWaterlevel>();
+    }
+
+
+    public List<ImportWaterlevel> getWaterlevels() {
+        return waterlevels;
+    }
+
+
+    @Override
+    public void parse(File file) throws IOException {
+        currentDescription = file.getName();
+
+        super.parse(file);
+    }
+
+
+    @Override
+    protected void reset() {
+        currentQ = null;
+        current  = new ImportWaterlevel(currentDescription);
+    }
+
+
+    @Override
+    protected void finish() {
+        if (current != null) {
+            if (currentQ != null) {
+                current.addValue(currentQ);
+            }
+
+            waterlevels.add(current);
+        }
+    }
+
+    @Override
+    protected void handleLine(String line) {
+        if (line.startsWith(START_META_CHAR)) {
+            handleMetaLine(stripMetaLine(line));
+            return;
+        }
+        else if (handleQRange(line)) {
+            return;
+        }
+        else {
+            handleDataLine(line);
+            return;
+        }
+    }
+
+
+    private void handleMetaLine(String meta) {
+        Matcher m = META_UNIT.matcher(meta);
+
+        if (m.matches()) {
+            String unit = m.group(1);
+            log.debug("Found unit: '" + unit + "'");
+
+            current.setUnit(new ImportUnit(unit));
+        }
+    }
+
+
+    private boolean handleQRange(String line) {
+        Matcher m = META_Q_RANGE.matcher(line);
+
+        if (m.matches()) {
+            String unitStr  = m.group(1);
+            String valueStr = m.group(2);
+
+            if (currentQ != null) {
+                if (current != null) {
+                    current.addValue(currentQ);
+                }
+                else {
+                    // this should never happen
+                    log.warn("Try to add Q range without waterlevel!");
+                }
+            }
+
+            try {
+                log.debug("Found new Q range: Q=" + valueStr);
+
+                currentQ = new ImportWaterlevelQRange(
+                    nf.parse(valueStr).doubleValue());
+
+                return true;
+            }
+            catch (ParseException pe) {
+                log.warn("Error while parsing Q range: '" + line + "'");
+            }
+        }
+
+        return false;
+    }
+
+
+    private void handleDataLine(String line) {
+        String[] cols = line.split(SEPERATOR_CHAR);
+
+        if (cols == null || cols.length < 2) {
+            log.warn("skip invalid waterlevel line: '" + line + "'");
+            return;
+        }
+
+        try {
+            Double station = nf.parse(cols[0]).doubleValue();
+            Double value   = nf.parse(cols[1]).doubleValue();
+
+            currentQ.addValue(new ImportWaterlevelValue(station, value));
+        }
+        catch (ParseException pe) {
+            log.warn("Error while parsing number values: '" + line + "'");
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/importer/parsers/WstParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/WstParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -132,7 +132,7 @@
                         lsBezeichner = new String[columnCount];
                     }
                     catch (NumberFormatException nfe) {
-                        log.warn(nfe);
+                        log.warn("WST: invalid number.", nfe);
                         continue;
                     }
                     first = false;
@@ -267,7 +267,7 @@
 
                     if (!kms.add(kaem)) {
                         log.warn(
-                            "km " + kaem +
+                            "WST: km " + kaem +
                             " (line " + in.getLineNumber() +
                             ") found more than once. -> ignored");
                         continue;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/model/BedHeightEpoch.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,211 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "bed_height_epoch")
+public class BedHeightEpoch implements Serializable {
+
+    private Integer id;
+
+    private River river;
+
+    private TimeInterval timeInterval;
+
+    private ElevationModel curElevationModel;
+    private ElevationModel oldElevationModel;
+
+    private Range range;
+
+    private String evaluationBy;
+    private String description;
+
+    private List<BedHeightEpochValue> values;
+
+
+    public BedHeightEpoch() {
+    }
+
+
+    public BedHeightEpoch(
+        River          river,
+        TimeInterval   timeInterval,
+        Range          range,
+        ElevationModel curElevationModel,
+        ElevationModel oldElevationModel,
+        String         evaluationBy,
+        String         description
+    ) {
+        this.river             = river;
+        this.timeInterval      = timeInterval;
+        this.range             = range;
+        this.curElevationModel = curElevationModel;
+        this.oldElevationModel = oldElevationModel;
+        this.evaluationBy      = evaluationBy;
+        this.description       = description;
+        this.values            = new ArrayList<BedHeightEpochValue>();
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_BED_HEIGHT_EPOCH_ID_SEQ",
+        sequenceName   = "BED_HEIGHT_EPOCH_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_BED_HEIGHT_EPOCH_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id" )
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "time_interval_id")
+    public TimeInterval getTimeInterval() {
+        return timeInterval;
+    }
+
+    public void setTimeInterval(TimeInterval timeInterval) {
+        this.timeInterval = timeInterval;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "cur_elevation_model_id")
+    public ElevationModel getCurElevationModel() {
+        return curElevationModel;
+    }
+
+    public void setCurElevationModel(ElevationModel curElevationModel) {
+        this.curElevationModel = curElevationModel;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "old_elevation_model_id")
+    public ElevationModel getOldElevationModel() {
+        return oldElevationModel;
+    }
+
+    public void setOldElevationModel(ElevationModel oldElevationModel) {
+        this.oldElevationModel = oldElevationModel;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "range_id")
+    public Range getRange() {
+        return range;
+    }
+
+    public void setRange(Range range) {
+        this.range = range;
+    }
+
+    @Column(name = "evaluation_by")
+    public String getEvaluationBy() {
+        return evaluationBy;
+    }
+
+    public void setEvaluationBy(String evaluationBy) {
+        this.evaluationBy = evaluationBy;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @OneToMany
+    @JoinColumn(name = "bed_height_epoch_id")
+    public List<BedHeightEpochValue> getValues() {
+        return values;
+    }
+
+    public void setValues(List<BedHeightEpochValue> values) {
+        this.values = values;
+    }
+
+
+    public static List<BedHeightEpoch> getBedHeightEpochs(
+        River  river,
+        double kmLo,
+        double kmHi
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from BedHeightEpoch where river=:river");
+
+        query.setParameter("river", river);
+
+        // TODO Do km range filtering in SQL statement
+
+        List<BedHeightEpoch> epochs = query.list();
+        List<BedHeightEpoch> good   = new ArrayList<BedHeightEpoch>();
+
+        OUTER: for (BedHeightEpoch e: epochs) {
+            for (BedHeightEpochValue value: e.getValues()) {
+                double station = value.getStation().doubleValue();
+
+                if (station >= kmLo && station <= kmHi) {
+                    good.add(e);
+                    continue OUTER;
+                }
+            }
+        }
+
+        return good;
+    }
+
+
+    public static BedHeightEpoch getBedHeightEpochById(int id) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from BedHeightEpoch where id=:id");
+
+        query.setParameter("id", id);
+
+        List<BedHeightEpoch> singles = query.list();
+
+        return singles != null ? singles.get(0) : null;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/BedHeightEpochValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,119 @@
+package de.intevation.flys.model;
+
+import java.util.List;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "bed_height_epoch_values")
+public class BedHeightEpochValue
+implements   Serializable
+{
+    private static Logger logger =
+        Logger.getLogger(BedHeightEpochValue.class);
+
+    private Integer id;
+
+    private BedHeightEpoch bedHeight;
+
+    private BigDecimal station;
+    private BigDecimal height;
+
+
+    public BedHeightEpochValue() {
+    }
+
+    public BedHeightEpochValue(
+        BedHeightEpoch bedHeight,
+        BigDecimal station,
+        BigDecimal height
+    ) {
+        this.bedHeight = bedHeight;
+        this.station   = station;
+        this.height    = height;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_BED_EPOCH_VALUE_ID_SEQ",
+        sequenceName   = "BED_EPOCH_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_BED_EPOCH_VALUE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "bed_height_epoch_id" )
+    public BedHeightEpoch getBedHeight() {
+        return bedHeight;
+    }
+
+    public void setBedHeight(BedHeightEpoch bedHeight) {
+        this.bedHeight = bedHeight;
+    }
+
+    @Column(name = "station")
+    public BigDecimal getStation() {
+        return station;
+    }
+
+    public void setStation(BigDecimal station) {
+        this.station = station;
+    }
+
+    @Column(name = "height")
+    public BigDecimal getHeight() {
+        return height;
+    }
+
+    public void setHeight(BigDecimal height) {
+        this.height = height;
+    }
+
+
+    public static List<BedHeightEpochValue> getBedHeightEpochValues(
+        BedHeightEpoch epoch,
+        double kmLo,
+        double kmHi
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from BedHeightEpochValue where bedHeight=:epoch " +
+            "   and station >= :kmLo and station <= :kmHi");
+
+        query.setParameter("epoch", epoch);
+        query.setParameter("kmLo", new BigDecimal(kmLo));
+        query.setParameter("kmHi", new BigDecimal(kmHi));
+
+        return query.list();
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/BedHeightSingle.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,272 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "bed_height_single")
+public class BedHeightSingle implements Serializable {
+
+    private Integer id;
+    private Integer year;
+    private Integer soundingWidth;
+
+    private String evaluationBy;
+    private String description;
+
+    private River river;
+
+    private BedHeightType  type;
+
+    private LocationSystem locationSystem;
+
+    private ElevationModel curElevationModel;
+
+    private ElevationModel oldElevationModel;
+
+    private Range range;
+
+    private List<BedHeightSingleValue> values;
+
+
+    public BedHeightSingle() {
+    }
+
+
+    public BedHeightSingle(
+        River          river,
+        Integer        year,
+        Integer        soundingWidth,
+        BedHeightType  type,
+        LocationSystem locationSystem,
+        ElevationModel curElevationModel,
+        Range          range
+    ) {
+        this(
+            river,
+            year,
+            soundingWidth,
+            type,
+            locationSystem,
+            curElevationModel,
+            null,
+            range,
+            null,
+            null);
+    }
+
+
+    public BedHeightSingle(
+        River          river,
+        Integer        year,
+        Integer        soundingWidth,
+        BedHeightType  type,
+        LocationSystem locationSystem,
+        ElevationModel curElevationModel,
+        ElevationModel oldElevationModel,
+        Range          range,
+        String         evaluationBy,
+        String         description
+    ) {
+        this.river             = river;
+        this.year              = year;
+        this.soundingWidth     = soundingWidth;
+        this.type              = type;
+        this.locationSystem    = locationSystem;
+        this.curElevationModel = curElevationModel;
+        this.oldElevationModel = oldElevationModel;
+        this.range             = range;
+        this.evaluationBy      = evaluationBy;
+        this.description       = description;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_BED_HEIGHT_SINGLE_ID_SEQ",
+        sequenceName   = "BED_HEIGHT_SINGLE_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_BED_HEIGHT_SINGLE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id" )
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @Column(name = "year")
+    public Integer getYear() {
+        return year;
+    }
+
+    public void setYear(Integer year) {
+        this.year = year;
+    }
+
+    @Column(name = "sounding_width")
+    public Integer getSoundingWidth() {
+        return soundingWidth;
+    }
+
+    public void setSoundingWidth(Integer soundingWidth) {
+        this.soundingWidth = soundingWidth;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "type_id")
+    public BedHeightType getType() {
+        return type;
+    }
+
+    public void setType(BedHeightType type) {
+        this.type = type;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "location_system_id")
+    public LocationSystem getLocationSystem() {
+        return locationSystem;
+    }
+
+    public void setLocationSystem(LocationSystem locationSystem) {
+        this.locationSystem = locationSystem;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "cur_elevation_model_id")
+    public ElevationModel getCurElevationModel() {
+        return curElevationModel;
+    }
+
+    public void setCurElevationModel(ElevationModel curElevationModel) {
+        this.curElevationModel = curElevationModel;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "old_elevation_model_id")
+    public ElevationModel getOldElevationModel() {
+        return oldElevationModel;
+    }
+
+    public void setOldElevationModel(ElevationModel oldElevationModel) {
+        this.oldElevationModel = oldElevationModel;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "range_id")
+    public Range getRange() {
+        return range;
+    }
+
+    public void setRange(Range range) {
+        this.range = range;
+    }
+
+    @Column(name = "evaluation_by")
+    public String getEvaluationBy() {
+        return evaluationBy;
+    }
+
+    public void setEvaluationBy(String evaluationBy) {
+        this.evaluationBy = evaluationBy;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @OneToMany
+    @JoinColumn(name = "bed_height_single_id")
+    public List<BedHeightSingleValue> getValues() {
+        return values;
+    }
+
+    public void setValues(List<BedHeightSingleValue> values) {
+        this.values = values;
+    }
+
+
+    public static List<BedHeightSingle> getBedHeightSingles(
+        River  river,
+        double kmLo,
+        double kmHi
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from BedHeightSingle where river=:river");
+
+        query.setParameter("river", river);
+
+        // TODO Do km range filtering in SQL statement
+
+        List<BedHeightSingle> singles = query.list();
+        List<BedHeightSingle> good    = new ArrayList<BedHeightSingle>();
+
+        for (BedHeightSingle s: singles) {
+            for (BedHeightSingleValue value: s.getValues()) {
+                double station = value.getStation().doubleValue();
+
+                if (station >= kmLo && station <= kmHi) {
+                    good.add(s);
+                    break;
+                }
+            }
+        }
+
+        return good;
+    }
+
+
+    public static BedHeightSingle getBedHeightSingleById(int id) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from BedHeightSingle where id=:id");
+
+        query.setParameter("id", id);
+
+        List<BedHeightSingle> singles = query.list();
+
+        return singles != null ? singles.get(0) : null;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/BedHeightSingleValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,167 @@
+package de.intevation.flys.model;
+
+import java.util.List;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "bed_height_single_values")
+public class BedHeightSingleValue
+implements   Serializable
+{
+    private static Logger logger =
+        Logger.getLogger(BedHeightSingleValue.class);
+
+    private Integer id;
+
+    private BedHeightSingle bedHeight;
+
+    private BigDecimal station;
+    private BigDecimal height;
+    private BigDecimal uncertainty;
+    private BigDecimal dataGap;
+    private BigDecimal soundingWidth;
+    private BigDecimal width;
+
+
+    public BedHeightSingleValue() {
+    }
+
+    public BedHeightSingleValue(
+        BedHeightSingle bedHeight,
+        BigDecimal station,
+        BigDecimal height,
+        BigDecimal uncertainty,
+        BigDecimal dataGap,
+        BigDecimal soundingWidth,
+        BigDecimal width
+    ) {
+        this.bedHeight     = bedHeight;
+        this.station       = station;
+        this.height        = height;
+        this.uncertainty   = uncertainty;
+        this.dataGap       = dataGap;
+        this.soundingWidth = soundingWidth;
+        this.width         = width;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_BED_SINGLE_VALUE_ID_SEQ",
+        sequenceName   = "BED_SINGLE_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_BED_SINGLE_VALUE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "bed_height_single_id" )
+    public BedHeightSingle getBedHeight() {
+        return bedHeight;
+    }
+
+    public void setBedHeight(BedHeightSingle bedHeight) {
+        this.bedHeight = bedHeight;
+    }
+
+    @Column(name = "station")
+    public BigDecimal getStation() {
+        return station;
+    }
+
+    public void setStation(BigDecimal station) {
+        this.station = station;
+    }
+
+    @Column(name = "height")
+    public BigDecimal getHeight() {
+        return height;
+    }
+
+    public void setHeight(BigDecimal height) {
+        this.height = height;
+    }
+
+    @Column(name="uncertainty")
+    public BigDecimal getUncertainty() {
+        return uncertainty;
+    }
+
+    public void setUncertainty(BigDecimal uncertainty) {
+        this.uncertainty = uncertainty;
+    }
+
+    @Column(name="data_gap")
+    public BigDecimal getDataGap() {
+        return dataGap;
+    }
+
+    public void setDataGap(BigDecimal dataGap) {
+        this.dataGap = dataGap;
+    }
+
+    @Column(name="sounding_width")
+    public BigDecimal getSoundingWidth() {
+        return soundingWidth;
+    }
+
+    public void setSoundingWidth(BigDecimal soundingWidth) {
+        this.soundingWidth = soundingWidth;
+    }
+
+    @Column(name="width")
+    public BigDecimal getWidth() {
+        return width;
+    }
+
+    public void setWidth(BigDecimal width) {
+        this.width = width;
+    }
+
+
+    public static List<BedHeightSingleValue> getBedHeightSingleValues(
+        BedHeightSingle single,
+        double kmLo,
+        double kmHi
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from BedHeightSingleValue where bedHeight=:single " +
+            "   and station >= :kmLo and station <= :kmHi");
+
+        query.setParameter("single", single);
+        query.setParameter("kmLo", new BigDecimal(kmLo));
+        query.setParameter("kmHi", new BigDecimal(kmHi));
+
+        return query.list();
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/BedHeightType.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,94 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "bed_height_type")
+public class BedHeightType
+implements   Serializable
+{
+    private static Logger log = Logger.getLogger(BedHeightType.class);
+
+    private Integer id;
+    private String  name;
+    private String  description;
+
+
+    public BedHeightType() {
+    }
+
+    public BedHeightType(String name, String description) {
+        this.name        = name;
+        this.description = description;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_BED_HEIGHT_TYPE_ID_SEQ",
+        sequenceName   = "BED_HEIGHT_TYPE_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_BED_HEIGHT_TYPE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    public static String getBedHeightName(String description) {
+        if (description.equals("Flächenpeilung")) {
+            return "FP";
+        }
+        else if ("Querprofile".equals(description)) {
+            return "QP";
+        }
+        else if ("Querprofil".equals(description)) {
+            return "QP";
+        }
+        else if ("TIN".equals(description)) {
+            return "TIN";
+        }
+        else if ("Flächen- u. Querprofilpeilungen".equals(description)) {
+            return "FP-QP";
+        }
+        else {
+            log.warn("Unknown bed height type: " + description);
+            return null;
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/model/Building.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/Building.java	Fri Sep 28 12:15:52 2012 +0200
@@ -80,12 +80,13 @@
     }
 
 
-    public static List<Building> getBuildings(int riverId) {
+    public static List<Building> getBuildings(int riverId, String name) {
         Session session = SessionHolder.HOLDER.get();
 
         Query query = session.createQuery(
-            "from Building where river.id =:river_id");
+            "from Building where river.id =:river_id and name=:name");
         query.setParameter("river_id", riverId);
+        query.setParameter("name", name);
 
         return query.list();
     }
--- a/flys-backend/src/main/java/de/intevation/flys/model/Catchment.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/Catchment.java	Fri Sep 28 12:15:52 2012 +0200
@@ -15,7 +15,7 @@
 import org.hibernate.Query;
 import org.hibernate.annotations.Type;
 
-import com.vividsolutions.jts.geom.Polygon;
+import com.vividsolutions.jts.geom.Geometry;
 
 import de.intevation.flys.backend.SessionHolder;
 
@@ -29,7 +29,7 @@
     private BigDecimal area;
     private String     name;
     private River      river;
-    private Polygon    geom;
+    private Geometry    geom;
 
     public Catchment() {
     }
@@ -83,22 +83,23 @@
 
     @Column(name = "geom")
     @Type(type = "org.hibernatespatial.GeometryUserType")
-    public Polygon getGeom() {
+    public Geometry getGeom() {
         return geom;
     }
 
 
-    public void setGeom(Polygon geom) {
+    public void setGeom(Geometry geom) {
         this.geom = geom;
     }
 
 
-    public static List<Catchment> getCatchments(int riverId) {
+    public static List<Catchment> getCatchments(int riverId, String name) {
         Session session = SessionHolder.HOLDER.get();
 
         Query query = session.createQuery(
-            "from Catchment where river.id =:river_id");
+            "from Catchment where river.id =:river_id AND name=:name");
         query.setParameter("river_id", riverId);
+        query.setParameter("name", name);
 
         return query.list();
     }
--- a/flys-backend/src/main/java/de/intevation/flys/model/CrossSection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/CrossSection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,6 +3,9 @@
 import java.io.Serializable;
 
 import java.util.List;
+import java.util.ArrayList;
+
+import java.awt.geom.Point2D;
 
 import javax.persistence.Entity;
 import javax.persistence.Id;
@@ -16,11 +19,32 @@
 import javax.persistence.OrderBy;
 import javax.persistence.JoinColumn;
 
+import java.math.MathContext;
+import java.math.BigDecimal;
+
+import org.hibernate.Session;
+import org.hibernate.SQLQuery;
+import org.hibernate.Query;
+
+import org.hibernate.type.StandardBasicTypes;
+
+import de.intevation.flys.backend.SessionHolder;
+
 @Entity
 @Table(name = "cross_sections")
 public class CrossSection
 implements   Serializable
 {
+    public static final MathContext PRECISION = new MathContext(6);
+
+    public static final String SQL_FAST_CROSS_SECTION_LINES =
+        "SELECT km, x, y, csl.id AS csl_id " +
+        "FROM cross_section_lines csl JOIN cross_section_points csp " +
+        "ON csp.cross_section_line_id = csl.id " +
+        "WHERE csl.cross_section_id = :cs_id AND " +
+        "km between :from_km AND :to_km " +
+        "ORDER BY csl.id, csp.col_pos";
+
     private Integer                id;
     private River                  river;
     private TimeInterval           timeInterval;
@@ -96,5 +120,79 @@
     public void setLines(List<CrossSectionLine> lines) {
         this.lines = lines;
     }
+
+    public List<CrossSectionLine> getLines(double startKm, double endKm) {
+        Session session = SessionHolder.HOLDER.get();
+        Query query = session.createQuery(
+            "from CrossSectionLine where crossSection=:crossSection " +
+            "and km between :startKm and :endKm order by km");
+        query.setParameter("crossSection", this);
+        query.setParameter("startKm", new BigDecimal(startKm, PRECISION));
+        query.setParameter("endKm", new BigDecimal(endKm, PRECISION));
+
+        return query.list();
+    }
+
+    public List<FastCrossSectionLine> getFastLines(
+        double startKm,
+        double endKm
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        SQLQuery sqlQuery = session.createSQLQuery(SQL_FAST_CROSS_SECTION_LINES)
+            .addScalar("km",     StandardBasicTypes.DOUBLE)
+            .addScalar("x",      StandardBasicTypes.DOUBLE)
+            .addScalar("y",      StandardBasicTypes.DOUBLE)
+            .addScalar("csl_id", StandardBasicTypes.INTEGER);
+
+        sqlQuery
+            .setInteger("cs_id",  getId())
+            .setDouble("from_km", startKm)
+            .setDouble("to_km",   endKm);
+
+        List<Object []> results = sqlQuery.list();
+
+        ArrayList<Point2D> points = new ArrayList<Point2D>(500);
+        ArrayList<FastCrossSectionLine> lines =
+            new ArrayList<FastCrossSectionLine>();
+
+        Integer lastId = null;
+        Double  lastKm = null;
+
+        for (Object [] result: results) {
+            Double  km = (Double)result[0];
+            Double  x  = (Double)result[1];
+            Double  y  = (Double)result[2];
+            Integer id = (Integer)result[3];
+
+            if (lastId != null && !lastId.equals(id)) {
+                points.trimToSize();
+                FastCrossSectionLine line =
+                    new FastCrossSectionLine(lastKm, points);
+                lines.add(line);
+                points = new ArrayList<Point2D>(500);
+            }
+
+            Point2D p = new Point2D.Double(x, y);
+
+            if (CrossSectionLine.isValid(p)) {
+                points.add(p);
+            }
+
+            lastKm = km;
+            lastId = id;
+        }
+
+        if (lastId != null) {
+            points.trimToSize();
+            FastCrossSectionLine line =
+                new FastCrossSectionLine(lastKm, points);
+            lines.add(line);
+        }
+
+        lines.trimToSize();
+
+        return lines;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/model/CrossSectionLine.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/CrossSectionLine.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,8 +2,6 @@
 
 import java.io.Serializable;
 
-import java.math.BigDecimal;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Collections;
@@ -34,10 +32,10 @@
     public static final double EPSILON   = 1e-4;
 
     public static final double TOO_SMALL = 0.2;
-    public static final double TOO_BIG   = 500;
+    public static final double TOO_BIG   = 2500;
 
     private Integer                 id;
-    private BigDecimal              km;
+    private Double              km;
     private CrossSection            crossSection;
 
     private List<CrossSectionPoint> points;
@@ -60,13 +58,17 @@
     public static final boolean isValid(double x) {
         x = Math.abs(x);
         return x > TOO_SMALL && x < TOO_BIG;
-    }    
+    }
+
+    public static final boolean isValid(Point2D p) {
+        return isValid(p.getX()) && isValid(p.getY());
+    }
 
 
     public CrossSectionLine() {
     }
 
-    public CrossSectionLine(CrossSection crossSection, BigDecimal km) {
+    public CrossSectionLine(CrossSection crossSection, Double km) {
         this.crossSection = crossSection;
         this.km           = km;
     }
@@ -89,11 +91,11 @@
     }
 
     @Column(name = "km")
-    public BigDecimal getKm() {
+    public Double getKm() {
         return km;
     }
 
-    public void setKm(BigDecimal km) {
+    public void setKm(Double km) {
         this.km = km;
     }
 
@@ -119,18 +121,13 @@
 
 
     public List<Point2D> fetchCrossSectionLinesPoints() {
-        List<Point2D> points = new ArrayList<Point2D>();
-
-        List<CrossSectionPoint> linePoints = getPoints();
 
-        if (linePoints.isEmpty()) {
-            logger.info("No points in selected CrossSectionLine.");
-            return points;
-        }
+        List<CrossSectionPoint> linePoints =
+            new ArrayList<CrossSectionPoint>(getPoints());
 
-        linePoints = new ArrayList(linePoints);
         Collections.sort(linePoints, COL_POS_CMP);
 
+        List<Point2D> points = new ArrayList<Point2D>(linePoints.size());
         for (CrossSectionPoint p: linePoints) {
             double x = p.getX().doubleValue();
             double y = p.getY().doubleValue();
@@ -167,7 +164,7 @@
                 }
 
                 xs[i] = x;
-                ys[i] = y; 
+                ys[i] = y;
             }
         }
 
--- a/flys-backend/src/main/java/de/intevation/flys/model/CrossSectionPoint.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/CrossSectionPoint.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,7 +1,5 @@
 package de.intevation.flys.model;
 
-import java.math.BigDecimal;
-
 import java.io.Serializable;
 
 import javax.persistence.Entity;
@@ -22,8 +20,8 @@
     private Integer          id;
     private CrossSectionLine crossSectionLine;
     private Integer          colPos;
-    private BigDecimal       x;
-    private BigDecimal       y;
+    private Double       x;
+    private Double       y;
 
     public CrossSectionPoint() {
     }
@@ -31,8 +29,8 @@
     public CrossSectionPoint(
         CrossSectionLine crossSectionLine,
         Integer          colPos,
-        BigDecimal       x,
-        BigDecimal       y
+        Double       x,
+        Double       y
     ) {
         this.crossSectionLine = crossSectionLine;
         this.colPos           = colPos;
@@ -77,20 +75,20 @@
     }
 
     @Column(name = "x")
-    public BigDecimal getX() {
+    public Double getX() {
         return x;
     }
 
-    public void setX(BigDecimal x) {
+    public void setX(Double x) {
         this.x = x;
     }
 
     @Column(name = "y")
-    public BigDecimal getY() {
+    public Double getY() {
         return y;
     }
 
-    public void setY(BigDecimal y) {
+    public void setY(Double y) {
         this.y = y;
     }
 }
--- a/flys-backend/src/main/java/de/intevation/flys/model/CrossSectionTrack.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/CrossSectionTrack.java	Fri Sep 28 12:15:52 2012 +0200
@@ -27,6 +27,7 @@
 {
     private Integer    id;
     private River      river;
+    private String     name;
     private LineString geom;
     private BigDecimal km;
     private BigDecimal z;
@@ -59,6 +60,17 @@
     }
 
 
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
     @Column(name = "geom")
     @Type(type = "org.hibernatespatial.GeometryUserType")
     public LineString getGeom() {
@@ -106,6 +118,23 @@
     }
 
 
+    public static List<CrossSectionTrack> getCrossSectionTrack(
+        String river,
+        String name
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from CrossSectionTrack as cst " +
+            "    where river.name =:river" +
+            "      and cst.name=:name");
+        query.setParameter("river", river);
+        query.setParameter("name", name);
+
+        return query.list();
+    }
+
+
     /**
      * Returns the nearest CrossSectionTrack of <i>river</i> to a given
      * <i>km</i>.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/model/Depth.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,84 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+
+@Entity
+@Table(name = "depths")
+public class Depth implements Serializable {
+
+    private Integer id;
+
+    private BigDecimal lower;
+    private BigDecimal upper;
+
+    private Unit unit;
+
+
+    public Depth() {
+    }
+
+
+    public Depth(BigDecimal lower, BigDecimal upper, Unit unit) {
+        this.lower = lower;
+        this.upper = upper;
+        this.unit  = unit;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_DEPTHS_ID_SEQ",
+        sequenceName   = "DEPTHS_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_DEPTHS_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @Column(name = "lower")
+    public BigDecimal getLower() {
+        return lower;
+    }
+
+    public void setLower(BigDecimal lower) {
+        this.lower = lower;
+    }
+
+    @Column(name = "upper")
+    public BigDecimal getUpper() {
+        return upper;
+    }
+
+    public void setUpper(BigDecimal upper) {
+        this.upper = upper;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "unit_id")
+    public Unit getUnit() {
+        return unit;
+    }
+
+    public void setUnit(Unit unit) {
+        this.unit = unit;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/model/DischargeTable.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/DischargeTable.java	Fri Sep 28 12:15:52 2012 +0200
@@ -11,6 +11,7 @@
 import javax.persistence.GenerationType;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
+import javax.persistence.OrderBy;
 import javax.persistence.JoinColumn;
 
 import java.util.List;
@@ -105,6 +106,7 @@
 
     @OneToMany
     @JoinColumn(name = "table_id")
+    @OrderBy("q")
     public List<DischargeTableValue> getDischargeTableValues() {
         return dischargeTableValues;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/model/DischargeZone.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,152 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "discharge_zone")
+public class DischargeZone
+implements   Serializable
+{
+    private static Logger logger = Logger.getLogger(DischargeZone.class);
+
+
+    private Integer id;
+
+    private River river;
+
+    private String gaugeName;
+
+    private BigDecimal value;
+
+    private String lowerDischarge;
+    private String upperDischarge;
+
+
+    public DischargeZone() {
+    }
+
+
+    public DischargeZone(
+        River       river,
+        String      gaugeName,
+        BigDecimal  value,
+        String      lowerDischarge,
+        String      upperDischarge
+    ) {
+        this.river          = river;
+        this.gaugeName      = gaugeName;
+        this.value          = value;
+        this.lowerDischarge = lowerDischarge;
+        this.upperDischarge = upperDischarge;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_DISCHARGE_ZONE_ID_SEQ",
+        sequenceName   = "DISCHARGE_ZONE_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_DISCHARGE_ZONE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id" )
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @Column(name = "value")
+    public BigDecimal getValue() {
+        return value;
+    }
+
+    public void setValue(BigDecimal value) {
+        this.value = value;
+    }
+
+    @Column(name = "gauge_name")
+    public String getGaugeName() {
+        return gaugeName;
+    }
+
+    public void setGaugeName(String gaugeName) {
+        this.gaugeName = gaugeName;
+    }
+
+    @Column(name = "lower_discharge")
+    public String getLowerDischarge() {
+        return lowerDischarge;
+    }
+
+    public void setLowerDischarge(String lowerDischarge) {
+        this.lowerDischarge = lowerDischarge;
+    }
+
+    @Column(name = "upper_discharge")
+    public String getUpperDischarge() {
+        return upperDischarge;
+    }
+
+    public void setUpperDischarge(String upperDischarge) {
+        this.upperDischarge = upperDischarge;
+    }
+
+
+    public static List<DischargeZone> getDischargeZones(River river) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from DischargeZone where river=:river");
+
+        query.setParameter("river", river);
+
+        return query.list();
+    }
+
+
+    public static DischargeZone getDischargeZoneById(int id) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from DischargeZone where id=:id");
+
+        query.setParameter("id", id);
+
+        List<DischargeZone> zones = query.list();
+
+        return zones.isEmpty() ? null : zones.get(0);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/ElevationModel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,78 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "elevation_model")
+public class ElevationModel
+implements   Serializable
+{
+    private static Logger logger = Logger.getLogger(ElevationModel.class);
+
+    protected Integer id;
+
+    protected String name;
+
+    protected Unit unit;
+
+
+    public ElevationModel() {
+    }
+
+
+    public ElevationModel(String name, Unit unit) {
+        this.name = name;
+        this.unit = unit;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_ELEVATION_MODE_ID_SEQ",
+        sequenceName   = "ELEVATION_MODEL_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_ELEVATION_MODE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "unit_id")
+    public Unit getUnit() {
+        return unit;
+    }
+
+    public void setUnit(Unit unit) {
+        this.unit = unit;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/FastAnnotations.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,335 @@
+package de.intevation.flys.model;
+
+import java.util.Comparator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import java.io.Serializable;
+
+import org.hibernate.Session;
+import org.hibernate.SQLQuery;
+
+import org.hibernate.type.StandardBasicTypes;
+
+import de.intevation.flys.backend.SessionHolder;
+
+public class FastAnnotations
+implements   Serializable
+{
+    public static final String SQL_BY_RIVER_NAME =
+        "SELECT r.a AS a, r.b AS b, p.value AS position, " +
+                "at.value AS attribute, ant.name AS name, " +
+                "e.top AS top, e.bottom AS bottom " +
+        "FROM annotations an " +
+            "JOIN ranges r " +
+                "ON an.range_id = r.id " +
+            "JOIN attributes at " +
+                "ON an.attribute_id = at.id " +
+            "JOIN positions p " +
+                "ON an.position_id = p.id " +
+            "JOIN rivers riv " +
+                "ON r.river_id = riv.id " +
+            "LEFT JOIN annotation_types ant " +
+                "ON an.type_id = ant.id " +
+            "LEFT JOIN edges e " +
+                "ON an.edge_id = e.id " +
+            "WHERE riv.name = :river_name " +
+                "ORDER BY r.a";
+
+    public static final String SQL_BY_RIVER_ID =
+        "SELECT r.a AS a, r.b AS b, p.value AS position, " +
+                "at.value AS attribute, ant.name AS name, " +
+                "e.top AS top, e.bottom AS bottom " +
+        "FROM annotations an " +
+            "JOIN ranges r " +
+                "ON an.range_id = r.id " +
+            "JOIN attributes at " +
+                "ON an.attribute_id = at.id " +
+            "JOIN positions p " +
+                "ON an.position_id = p.id " +
+            "LEFT JOIN annotation_types ant " +
+                "ON an.type_id = ant.id " +
+            "LEFT JOIN edges e " +
+                "ON an.edge_id = e.id " +
+            "WHERE r.id = :river_id " +
+                "ORDER BY r.a";
+
+    public static final double EPSILON = 1e-5;
+
+    public static final Comparator<Annotation> KM_CMP =
+        new Comparator<Annotation>() {
+            @Override
+            public int compare(Annotation a, Annotation b) {
+                double diff = a.a - b.a;
+                if (diff < -EPSILON) return -1;
+                if (diff > +EPSILON) return +1;
+                return 0;
+            }
+        };
+
+    public static final class Annotation
+    implements                Serializable
+    {
+        private double a;
+        private double b;
+        private String position;
+        private String attribute;
+        private String name;
+        private double top;
+        private double bottom;
+
+        public Annotation() {
+        }
+
+        public Annotation(double a) {
+            this.a = a;
+        }
+
+        public Annotation(
+            double a,
+            double b,
+            String position,
+            String attribute,
+            String name,
+            double top,
+            double bottom
+        ) {
+            this.a         = a;
+            this.b         = b;
+            this.position  = position;
+            this.attribute = attribute;
+            this.name      = name;
+            this.top       = top;
+            this.bottom    = bottom;
+        }
+
+        public double getA() {
+            return a;
+        }
+
+        public double getB() {
+            return b;
+        }
+
+        public String getPosition() {
+            return position;
+        }
+
+        public String getAttribute() {
+            return attribute;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public double getTop() {
+            return top;
+        }
+
+        public double getBottom() {
+            return bottom;
+        }
+
+        @Override
+        public String toString() {
+            return "[a=" + a + ";b=" + b +
+                ";pos=" + position + ";attr=" + attribute +
+                ";name=" + name + ";top=" + top +
+                ";bot=" + bottom + "]";
+        }
+    } // class Annotation
+
+    public interface Filter {
+
+        boolean accept(Annotation annotation);
+
+    } // interface Filter
+
+    public static class NameFilter implements Filter {
+
+        private String name;
+
+        public NameFilter(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public boolean accept(Annotation annotation) {
+            return annotation.getName().contains(name);
+        }
+    } // class NameFilter
+
+    public static final Filter ALL = new Filter() {
+        @Override
+        public boolean accept(Annotation annotation) {
+            return true;
+        }
+    };
+
+    public static final Filter IS_POINT = new Filter() {
+        @Override
+        public boolean accept(Annotation annotation) {
+            return Double.isNaN(annotation.getB());
+        }
+    };
+
+    public static final Filter IS_RANGE = new Filter() {
+        @Override
+        public boolean accept(Annotation annotation) {
+            return !Double.isNaN(annotation.getB());
+        }
+    };
+
+    private Annotation [] annotations;
+
+    public FastAnnotations() {
+    }
+
+    public FastAnnotations(Annotation [] annotations) {
+        this.annotations = annotations;
+    }
+
+    public FastAnnotations(String riverName) {
+        this(loadByRiverName(riverName));
+    }
+
+    public FastAnnotations(int riverId) {
+        this(loadByRiverId(riverId));
+    }
+
+    public FastAnnotations(Iterator<Annotation> iter) {
+        this(toArray(iter));
+    }
+
+    public int size() {
+        return annotations.length;
+    }
+
+    public Iterator<Annotation> filter(final Filter filter) {
+        return new Iterator<Annotation>() {
+
+            private int idx;
+            private Annotation current = findNext();
+
+            @Override
+            public boolean hasNext() {
+                return current != null;
+            }
+
+            @Override
+            public Annotation next() {
+                if (current == null) {
+                    throw new NoSuchElementException();
+                }
+                Annotation result = current;
+                current = findNext();
+                return result;
+            }
+
+            private Annotation findNext() {
+
+                while (idx < annotations.length) {
+                    Annotation annotation = annotations[idx++];
+                    if (filter.accept(annotation)) {
+                        return annotation;
+                    }
+                }
+
+                return null;
+            }
+
+            @Override
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    public static Annotation [] toArray(Iterator<Annotation> iter) {
+
+        ArrayList<Annotation> list = new ArrayList<Annotation>();
+
+        while (iter.hasNext()) {
+            list.add(iter.next());
+        }
+
+        return list.toArray(new Annotation[list.size()]);
+    }
+
+    public Annotation findByKm(double km) {
+        Annotation key = new Annotation(km);
+        int idx = Arrays.binarySearch(annotations, key, KM_CMP);
+        return idx < 0 ? null : annotations[idx];
+    }
+
+    private static SQLQuery createQuery(String query) {
+        Session session = SessionHolder.HOLDER.get();
+
+        return session.createSQLQuery(query)
+            .addScalar("a",         StandardBasicTypes.DOUBLE)
+            .addScalar("b",         StandardBasicTypes.DOUBLE)
+            .addScalar("position",  StandardBasicTypes.STRING)
+            .addScalar("attribute", StandardBasicTypes.STRING)
+            .addScalar("name",      StandardBasicTypes.STRING)
+            .addScalar("top",       StandardBasicTypes.DOUBLE)
+            .addScalar("bottom",    StandardBasicTypes.DOUBLE);
+    }
+
+    private static Annotation [] buildAnnotations(List<Object []> list) {
+        Annotation [] anns = new Annotation[list.size()];
+
+        // Names are likely the same because they are a type
+        // like 'Pegel' or 'Hafen'.
+        HashMap<String, String> names = new HashMap<String, String>();
+
+        for (int i = 0; i < anns.length; ++i) {
+            Object [] data   = list.get(i);
+            double a         = ((Double)data[0]);
+            double b         = data[1] != null ? (Double)data[1] : Double.NaN;
+            String position  = (String)data[2];
+            String attribute = (String)data[3];
+            String name      = (String)data[4];
+            double top       = data[5] != null ? (Double)data[5] : Double.NaN;
+            double bottom    = data[6] != null ? (Double)data[6] : Double.NaN;
+
+            if (name != null) {
+                String old = names.get(name);
+                if (old != null) {
+                    name = old;
+                }
+                else {
+                    names.put(name, name);
+                }
+            }
+
+            anns[i] = new Annotation(
+                a, b, position, attribute, name, top, bottom);
+        }
+
+        return anns;
+    }
+
+    public static Annotation [] loadByRiverName(String riverName) {
+
+        SQLQuery query = createQuery(SQL_BY_RIVER_NAME);
+
+        query.setString("river_name", riverName);
+
+        return buildAnnotations(query.list());
+    }
+
+    public static Annotation [] loadByRiverId(int riverId) {
+
+        SQLQuery query = createQuery(SQL_BY_RIVER_ID);
+
+        query.setInteger("river_id", riverId);
+
+        return buildAnnotations(query.list());
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/FastCrossSectionLine.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,68 @@
+package de.intevation.flys.model;
+
+import java.util.List;
+import java.util.Comparator;
+
+import java.io.Serializable;
+
+import java.awt.geom.Point2D;
+
+public class FastCrossSectionLine
+implements   Serializable
+{
+    public static final double EPSILON = 1e-5;
+
+    public static final Comparator<FastCrossSectionLine> KM_CMP =
+        new Comparator<FastCrossSectionLine>() {
+            public int compare(
+                FastCrossSectionLine a,
+                FastCrossSectionLine b
+            ) {
+                double diff = a.km - b.km;
+                if (diff < -EPSILON) return -1;
+                return diff > +EPSILON ? +1 : 0;
+            }
+        };
+
+    protected double km;
+    protected List<Point2D> points;
+
+    public FastCrossSectionLine() {
+    }
+
+    public FastCrossSectionLine(double km) {
+        this.km = km;
+    }
+
+    public FastCrossSectionLine(double km, List<Point2D> points) {
+        this(km);
+        this.points = points;
+    }
+
+    public FastCrossSectionLine(CrossSectionLine csl) {
+        Double kmBD = csl.getKm();
+        km = kmBD != null ? kmBD.doubleValue() : 0d;
+        points = csl.fetchCrossSectionLinesPoints();
+    }
+
+    public double getKm() {
+        return km;
+    }
+
+    public void setKm(double km) {
+        this.km = km;
+    }
+
+    public List<Point2D> getPoints() {
+        return points;
+    }
+
+    public void setPoints(List<Point2D> points) {
+        this.points = points;
+    }
+
+    public double [][] fetchCrossSectionProfile() {
+        return CrossSectionLine.fetchCrossSectionProfile(points);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/Floodmaps.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,155 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.annotations.Type;
+
+import com.vividsolutions.jts.geom.Geometry;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "floodmaps")
+public class Floodmaps
+implements   Serializable
+{
+    private Integer      id;
+    private River        river;
+    private String       name;
+    private Integer      kind;
+    private Integer      count;
+    private BigDecimal   diff;
+    private BigDecimal   area;
+    private BigDecimal   perimeter;
+    private Geometry     geom;
+
+    public Floodmaps() {
+    }
+
+
+    @Id
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+
+    @OneToOne
+    @JoinColumn(name = "river_id")
+    public River getRiver() {
+        return river;
+    }
+
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name = "kind")
+    public Integer getKind() {
+        return kind;
+    }
+
+
+    public void setKind(Integer kind) {
+        this.kind = kind;
+    }
+
+
+    @Column(name = "count")
+    public Integer getCount() {
+        return count;
+    }
+
+
+    public void setCount(Integer count) {
+        this.count = count;
+    }
+
+
+    @Column(name = "diff")
+    public BigDecimal getDiff() {
+        return diff;
+    }
+
+
+    public void setDiff(BigDecimal diff) {
+        this.diff = diff;
+    }
+
+
+    @Column(name = "area")
+    public BigDecimal getArea() {
+        return area;
+    }
+
+
+    public void setArea(BigDecimal area) {
+        this.area = area;
+    }
+
+
+    @Column(name = "perimeter")
+    public BigDecimal getPerimeter() {
+        return perimeter;
+    }
+
+
+    public void setPerimeter(BigDecimal perimeter) {
+        this.perimeter = perimeter;
+    }
+
+
+    @Column(name = "geom")
+    @Type(type = "org.hibernatespatial.GeometryUserType")
+    public Geometry getGeom() {
+        return geom;
+    }
+
+
+    public void setGeom(Geometry geom) {
+        this.geom = geom;
+    }
+
+
+    public static List<Floodmaps> getFloodmaps(int riverId, String name) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from Floodmaps where river.id =:river_id AND name =:name");
+        query.setParameter("river_id", riverId);
+        query.setParameter("name", name);
+
+        return query.list();
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/FlowVelocityMeasurement.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,97 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "flow_velocity_measurements")
+public class FlowVelocityMeasurement
+implements   Serializable
+{
+    private static Logger logger =
+        Logger.getLogger(FlowVelocityMeasurement.class);
+
+
+    private Integer id;
+
+    private River river;
+
+    private String description;
+
+    private List<FlowVelocityMeasurementValue> values;
+
+
+    public FlowVelocityMeasurement() {
+    }
+
+
+    public FlowVelocityMeasurement(River river, String description) {
+        this.river       = river;
+        this.description = description;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_FV_MEASURE_ID_SEQ",
+        sequenceName   = "FV_MEASURE_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_FV_MEASURE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id" )
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @OneToMany
+    @JoinColumn(name = "measurements_id")
+    public List<FlowVelocityMeasurementValue> getValues() {
+        return values;
+    }
+
+    public void setValues(List<FlowVelocityMeasurementValue> values) {
+        this.values = values;
+    }
+
+    public void addValue(FlowVelocityMeasurementValue value) {
+        this.values.add(value);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/FlowVelocityMeasurementValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,146 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "flow_velocity_measure_values")
+public class FlowVelocityMeasurementValue
+implements   Serializable
+{
+    private static Logger logger =
+        Logger.getLogger(FlowVelocityMeasurementValue.class);
+
+
+    private Integer id;
+
+    private FlowVelocityMeasurement measurement;
+
+    private BigDecimal station;
+    private BigDecimal w;
+    private BigDecimal q;
+    private BigDecimal v;
+
+    private Date datetime;
+
+    private String description;
+
+
+    public FlowVelocityMeasurementValue() {
+    }
+
+
+    public FlowVelocityMeasurementValue(
+        FlowVelocityMeasurement measurement,
+        Date                    datetime,
+        BigDecimal              station,
+        BigDecimal              w,
+        BigDecimal              q,
+        BigDecimal              v,
+        String                  description
+    ) {
+        this.measurement = measurement;
+        this.datetime    = datetime;
+        this.station     = station;
+        this.w           = w;
+        this.q           = q;
+        this.v           = v;
+        this.description = description;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_FV_MEASURE_VALUES_ID_SEQ",
+        sequenceName   = "FV_MEASURE_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_FV_MEASURE_VALUES_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "measurements_id")
+    public FlowVelocityMeasurement getMeasurement() {
+        return measurement;
+    }
+
+    public void setMeasurement(FlowVelocityMeasurement measurement) {
+        this.measurement = measurement;
+    }
+
+    @Column(name = "station")
+    public BigDecimal getStation() {
+        return station;
+    }
+
+    public void setStation(BigDecimal station) {
+        this.station = station;
+    }
+
+    @Column(name = "datetime")
+    public Date getDatetime() {
+        return datetime;
+    }
+
+    public void setDatetime(Date datetime) {
+        this.datetime = datetime;
+    }
+
+    @Column(name = "w")
+    public BigDecimal getW() {
+        return w;
+    }
+
+    public void setW(BigDecimal w) {
+        this.w = w;
+    }
+
+    @Column(name = "q")
+    public BigDecimal getQ() {
+        return q;
+    }
+
+    public void setQ(BigDecimal q) {
+        this.q = q;
+    }
+
+    @Column(name = "v")
+    public BigDecimal getV() {
+        return v;
+    }
+
+    public void setV(BigDecimal v) {
+        this.v = v;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/FlowVelocityModel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,124 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "flow_velocity_model")
+public class FlowVelocityModel
+implements   Serializable
+{
+    private static Logger logger = Logger.getLogger(FlowVelocityModel.class);
+
+
+    private Integer id;
+
+    private River river;
+
+    private DischargeZone dischargeZone;
+
+    private List<FlowVelocityModelValue> values;
+
+    private String description;
+
+
+    public FlowVelocityModel() {
+    }
+
+
+    public FlowVelocityModel(River river, DischargeZone dischargeZone) {
+        this(river, dischargeZone, null);
+    }
+
+
+    public FlowVelocityModel(
+        River         river,
+        DischargeZone dischargeZone,
+        String        description
+    ) {
+        this.river         = river;
+        this.dischargeZone = dischargeZone;
+        this.description   = description;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_FLOW_VELOCITY_MODEL_ID_SEQ",
+        sequenceName   = "FLOW_VELOCITY_MODEL_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_FLOW_VELOCITY_MODEL_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id")
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "discharge_zone_id")
+    public DischargeZone getDischargeZone() {
+        return dischargeZone;
+    }
+
+    public void setDischargeZone(DischargeZone dischargeZone) {
+        this.dischargeZone = dischargeZone;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    public static List<FlowVelocityModel> getModels(
+        River         river,
+        DischargeZone zone
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from FlowVelocityModel where river=:river and dischargeZone=:zone");
+
+        query.setParameter("river", river);
+        query.setParameter("zone", zone);
+
+        return query.list();
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/FlowVelocityModelValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,158 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "flow_velocity_model_values")
+public class FlowVelocityModelValue
+implements   Serializable
+{
+    private static Logger logger =
+        Logger.getLogger(FlowVelocityModelValue.class);
+
+
+    private Integer id;
+
+    private FlowVelocityModel flowVelocity;
+
+    private BigDecimal station;
+    private BigDecimal q;
+    private BigDecimal totalChannel;
+    private BigDecimal mainChannel;
+    private BigDecimal shearStress;
+
+
+    public FlowVelocityModelValue() {
+    }
+
+
+    public FlowVelocityModelValue(
+        FlowVelocityModel flowVelocity,
+        BigDecimal        station,
+        BigDecimal        q,
+        BigDecimal        totalChannel,
+        BigDecimal        mainChannel,
+        BigDecimal        shearStress
+    ) {
+        this.flowVelocity = flowVelocity;
+        this.station      = station;
+        this.q            = q;
+        this.totalChannel = totalChannel;
+        this.mainChannel  = mainChannel;
+        this.shearStress  = shearStress;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_FLOW_VELOCITY_M_VALUES_ID_SEQ",
+        sequenceName   = "FLOW_VELOCITY_M_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_FLOW_VELOCITY_M_VALUES_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "flow_velocity_model_id")
+    public FlowVelocityModel getFlowVelocity() {
+        return flowVelocity;
+    }
+
+    public void setFlowVelocity(FlowVelocityModel flowVelocity) {
+        this.flowVelocity = flowVelocity;
+    }
+
+    @Column(name = "station")
+    public BigDecimal getStation() {
+        return station;
+    }
+
+    public void setStation(BigDecimal station) {
+        this.station = station;
+    }
+
+    @Column(name = "q")
+    public BigDecimal getQ() {
+        return q;
+    }
+
+    public void setQ(BigDecimal q) {
+        this.q = q;
+    }
+
+    @Column(name = "total_channel")
+    public BigDecimal getTotalChannel() {
+        return totalChannel;
+    }
+
+    public void setTotalChannel(BigDecimal totalChannel) {
+        this.totalChannel = totalChannel;
+    }
+
+    @Column(name = "main_channel")
+    public BigDecimal getMainChannel() {
+        return mainChannel;
+    }
+
+    public void setMainChannel(BigDecimal mainChannel) {
+        this.mainChannel = mainChannel;
+    }
+
+    @Column(name = "shear_stress")
+    public BigDecimal getShearStress() {
+        return shearStress;
+    }
+
+    public void setShearStress(BigDecimal shearStress) {
+        this.shearStress = shearStress;
+    }
+
+
+    public static List<FlowVelocityModelValue> getValues(
+        FlowVelocityModel model,
+        double kmLo,
+        double kmHi
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from FlowVelocityModelValue where " +
+            "   flowVelocity=:model and" +
+            "   station >= :kmLo and " +
+            "   station <= :kmHi");
+
+        query.setParameter("model", model);
+        query.setParameter("kmLo", new BigDecimal(kmLo));
+        query.setParameter("kmHi", new BigDecimal(kmHi));
+
+        return query.list();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/model/Gauge.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/Gauge.java	Fri Sep 28 12:15:52 2012 +0200
@@ -21,7 +21,6 @@
 import org.hibernate.Query;
 
 import de.intevation.flys.backend.SessionHolder;
-import de.intevation.flys.model.MainValue;
 
 @Entity
 @Table(name = "gauges")
@@ -30,6 +29,9 @@
 {
     public static final int DEFAULT_SCALE = 100;
 
+    public static final int MASTER_DISCHARGE_TABLE = 0;
+
+
     private Integer    id;
     private String     name;
     private River      river;
@@ -213,6 +215,115 @@
 
     public void setMainValues(List<MainValue> mainValues) {
         this.mainValues = mainValues;
-    } 
+    }
+
+
+    public static Gauge getGaugeByOfficialNumber(long number) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from Gauge where officialNumber=:number");
+
+        query.setParameter("number", number);
+
+        List<Gauge> results = query.list();
+
+        return results.isEmpty() ? null : results.get(0);
+    }
+
+
+    public DischargeTable fetchMasterDischargeTable() {
+        for (DischargeTable dt: dischargeTables) {
+            if (dt.getKind() == MASTER_DISCHARGE_TABLE) {
+                return dt;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns an array of [days, qs] necessary to create duration curves.
+     *
+     * @return a 2dim array of [days, qs] where days is an int[] and qs is
+     * an double[].
+     */
+    public Object[] fetchDurationCurveData() {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "select cast(nmv.name as integer) as days, mv.value as q " +
+            "from MainValue as mv " +
+            "join mv.mainValue as nmv " +
+            "join nmv.type mvt " +
+            "where mvt.name = 'D' and mv.gauge.id = :gauge_id " +
+            "order by days");
+
+        query.setParameter("gauge_id", getId());
+
+        List<Object> results = query.list();
+        int[]        days    = new int[results.size()];
+        double[]     qs      = new double[results.size()];
+
+        int idx = 0;
+
+        for (Object obj: results) {
+            Object[] arr = (Object[]) obj;
+
+            try {
+                int  day = ((Integer)    arr[0]).intValue();
+                double q = ((BigDecimal) arr[1]).doubleValue();
+
+                days[idx] = day;
+                qs[idx++] = q;
+            }
+            catch (NumberFormatException nfe) {
+            }
+        }
+
+        return new Object[] { days, qs };
+    }
+
+    /**
+     * Calculates the maximum and minimum W and Q values
+     *
+     * @return the MaxMinWQ object representing the calculated values
+     */
+    public MinMaxWQ fetchMaxMinWQ() {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "select max(mv.value) as max, min(mv.value) as min " +
+            "from MainValue as mv " +
+            "join mv.mainValue as nmv " +
+            "join nmv.type mvt " +
+            "where mvt.name in ('W', 'Q') " +
+            "and mv.gauge.id = :gauge_id " +
+            "group by mvt.name order by mvt.name"
+            );
+
+        query.setParameter("gauge_id", getId());
+
+        List<Object> results = query.list();
+        if (results.isEmpty()) {
+            // No values found
+            return new MinMaxWQ();
+        }
+
+        Object[] arr = (Object[]) results.get(0);
+        BigDecimal maxw = (BigDecimal)arr[0];
+        BigDecimal minw = (BigDecimal)arr[1];
+        BigDecimal maxq = null;
+        BigDecimal minq = null;
+
+
+        if (results.size() > 1) {
+            arr = (Object[]) results.get(1);
+            maxq = (BigDecimal)arr[0];
+            minq = (BigDecimal)arr[1];
+        }
+
+        return new MinMaxWQ(minw, maxw, minq, maxq);
+    }
 }
 // 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-backend/src/main/java/de/intevation/flys/model/GaugeLocation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,106 @@
+package de.intevation.flys.model;
+
+import com.vividsolutions.jts.geom.Point;
+
+import de.intevation.flys.backend.SessionHolder;
+
+import java.io.Serializable;
+
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+
+import org.hibernate.annotations.Type;
+
+
+@Entity
+@Table(name = "gauge_location")
+public class GaugeLocation
+implements   Serializable
+{
+    private Integer    id;
+    private River      river;
+    private String     name;
+    private Point      geom;
+
+
+    public GaugeLocation() {
+    }
+
+
+    @Id
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+
+    @OneToOne
+    @JoinColumn(name = "river_id")
+    public River getRiver() {
+        return river;
+    }
+
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name = "geom")
+    @Type(type = "org.hibernatespatial.GeometryUserType")
+    public Point getGeom() {
+        return geom;
+    }
+
+
+    public void setGeom(Point geom) {
+        this.geom = geom;
+    }
+
+
+    /**
+     * Returns a list of RiverAxisKm objects for a given river.
+     *
+     * @param riverid The ID of a river in the database.
+     *
+     * @return a list of RiverAxisKm objects.
+     */
+    public static List<GaugeLocation> getGaugeLocations(int riverid, String name) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from GaugeLocation where river.id =:riverid and name=:name");
+        query.setParameter("riverid", riverid);
+        query.setParameter("name", name);
+
+        List<GaugeLocation> list = query.list();
+
+        return list;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/GrainFraction.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,108 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "grain_fraction")
+public class GrainFraction
+implements   Serializable
+{
+    public static final String TOTAL              = "total";
+    public static final String COARSE             = "coarse";
+    public static final String FINE_MIDDLE        = "fine_middle";
+    public static final String SAND               = "sand";
+    public static final String SUSP_SAND          = "susp_sand";
+    public static final String SUSP_SAND_BED      = "susp_sand_bed";
+    public static final String SUSPENDED_SEDIMENT = "suspended_sediment";
+
+
+    private static Logger logger = Logger.getLogger(GrainFraction.class);
+
+    private Integer id;
+
+    private String name;
+
+    private Double lower;
+    private Double upper;
+
+    private Unit unit;
+
+
+    public GrainFraction() {
+    }
+
+    public GrainFraction(String name, Double lower, Double upper, Unit unit) {
+        this.name  = name;
+        this.lower = lower;
+        this.upper = upper;
+        this.unit  = unit;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_GRAIN_FRACTION_ID_SEQ",
+        sequenceName   = "GRAIN_FRACTION_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_GRAIN_FRACTION_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @Column(name = "name" )
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Column(name = "lower")
+    public Double getLower() {
+        return lower;
+    }
+
+    public void setLower(Double lower) {
+        this.lower = lower;
+    }
+
+    @Column(name = "upper")
+    public Double getUpper() {
+        return upper;
+    }
+
+    public void setUpper(Double upper) {
+        this.upper = upper;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "unit_id")
+    public Unit getUnit() {
+        return unit;
+    }
+
+    public void setUnit(Unit unit) {
+        this.unit = unit;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/model/HYKFormation.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/HYKFormation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -38,9 +38,9 @@
     }
 
     public HYKFormation(
-        Integer    formationNum, 
-        HYKEntry   entry, 
-        BigDecimal top, 
+        Integer    formationNum,
+        HYKEntry   entry,
+        BigDecimal top,
         BigDecimal bottom,
         BigDecimal distanceVL,
         BigDecimal distanceHF,
--- a/flys-backend/src/main/java/de/intevation/flys/model/Hws.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/Hws.java	Fri Sep 28 12:15:52 2012 +0200
@@ -92,12 +92,13 @@
     }
 
 
-    public static List<Hws> getHws(int riverId) {
+    public static List<Hws> getHws(int riverId, String name) {
         Session session = SessionHolder.HOLDER.get();
 
         Query query = session.createQuery(
-            "from Hws where river.id =:river_id");
+            "from Hws where river.id =:river_id and name=:name");
         query.setParameter("river_id", riverId);
+        query.setParameter("name", name);
 
         return query.list();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/model/HydrBoundary.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,94 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.annotations.Type;
+
+import com.vividsolutions.jts.geom.LineString;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "hydr_boundaries")
+public class HydrBoundary
+implements   Serializable
+{
+    private Integer    id;
+    private String     name;
+    private River      river;
+    private LineString geom;
+
+    public HydrBoundary() {
+    }
+
+
+    @Id
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+
+    @OneToOne
+    @JoinColumn(name = "river_id")
+    public River getRiver() {
+        return river;
+    }
+
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name = "geom")
+    @Type(type = "org.hibernatespatial.GeometryUserType")
+    public LineString getGeom() {
+        return geom;
+    }
+
+
+    public void setGeom(LineString geom) {
+        this.geom = geom;
+    }
+
+
+    public static List<HydrBoundary> getHydrBoundaries(int riverId, String name) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from HydrBoundary where river.id =:river_id and name=:name");
+        query.setParameter("river_id", riverId);
+        query.setParameter("name", name);
+
+        return query.list();
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/HydrBoundaryPoly.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,94 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.annotations.Type;
+
+import com.vividsolutions.jts.geom.Geometry;
+
+import de.intevation.flys.backend.SessionHolder;
+
+
+@Entity
+@Table(name = "hydr_boundaries_poly")
+public class HydrBoundaryPoly
+implements   Serializable
+{
+    private Integer    id;
+    private String     name;
+    private River      river;
+    private Geometry   geom;
+
+    public HydrBoundaryPoly() {
+    }
+
+
+    @Id
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+
+    @OneToOne
+    @JoinColumn(name = "river_id")
+    public River getRiver() {
+        return river;
+    }
+
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name = "geom")
+    @Type(type = "org.hibernatespatial.GeometryUserType")
+    public Geometry getGeom() {
+        return geom;
+    }
+
+
+    public void setGeom(Geometry geom) {
+        this.geom = geom;
+    }
+
+
+    public static List<HydrBoundaryPoly> getHydrBoundaries(int riverId, String name) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from HydrBoundaryPoly where river.id =:river_id and name=:name");
+        query.setParameter("river_id", riverId);
+        query.setParameter("name", name);
+
+        return query.list();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/model/Line.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/Line.java	Fri Sep 28 12:15:52 2012 +0200
@@ -94,12 +94,13 @@
     }
 
 
-    public static List<Line> getLines(int riverId) {
+    public static List<Line> getLines(int riverId, String name) {
         Session session = SessionHolder.HOLDER.get();
 
         Query query = session.createQuery(
-            "from Line where river.id =:river_id");
+            "from Line where river.id =:river_id and name=:name");
         query.setParameter("river_id", riverId);
+        query.setParameter("name", name);
 
         return query.list();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/model/LocationSystem.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,68 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+
+
+@Entity
+@Table(name = "location_system")
+public class LocationSystem implements Serializable {
+
+    protected Integer id;
+
+    protected String name;
+    protected String description;
+
+
+    public LocationSystem() {
+    }
+
+
+    public LocationSystem(String name, String description) {
+        this.name        = name;
+        this.description = description;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_LOCATION_SYSTEM_ID_SEQ",
+        sequenceName   = "LOCATION_SYSTEM_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_LOCATION_SYSTEM_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/MinMaxWQ.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,58 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * Represents minmimum and maximum values for W and Q
+ */
+public class MinMaxWQ implements Serializable {
+
+    private BigDecimal minw;
+    private BigDecimal maxw;
+    private BigDecimal minq;
+    private BigDecimal maxq;
+
+    /**
+     * Default constuctor to indecate that no min and max w and q values
+     * are available
+     */
+    public MinMaxWQ() {
+    }
+
+    /**
+     * Constructor for a new MinMaxWQ value
+     *
+     * @param minw Mimimim W
+     * @param maxw Maximum W
+     * @param minq Mimimim Q
+     * @param maxq Maximum Q
+     */
+    public MinMaxWQ(
+            BigDecimal minw,
+            BigDecimal maxw,
+            BigDecimal minq,
+            BigDecimal maxq)
+    {
+        this.minw = minw;
+        this.maxw = maxw;
+        this.minq = minq;
+        this.maxq = maxq;
+    }
+
+    public BigDecimal getMinW() {
+        return this.minw;
+    }
+
+    public BigDecimal getMaxW() {
+        return this.maxw;
+    }
+
+    public BigDecimal getMinQ() {
+        return this.minq;
+    }
+
+    public BigDecimal getMaxQ() {
+        return this.maxq;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/model/MorphologicalWidth.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,88 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+
+
+@Entity
+@Table(name = "morphologic_width")
+public class MorphologicalWidth implements Serializable {
+
+    private Integer id;
+
+    private River river;
+
+    private Unit unit;
+
+    private List<MorphologicalWidthValue> values;
+
+
+    public MorphologicalWidth() {
+    }
+
+
+    public MorphologicalWidth(River river, Unit unit) {
+        this.river = river;
+        this.unit  = unit;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_MORPHOLOGIC_WIDTH_ID_SEQ",
+        sequenceName   = "MORPHOLOGIC_WIDTH_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_MORPHOLOGIC_WIDTH_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id")
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "unit_id")
+    public Unit getUnit() {
+        return unit;
+    }
+
+    public void setUnit(Unit unit) {
+        this.unit = unit;
+    }
+
+    @OneToMany
+    @JoinColumn(name = "morphologic_width_id")
+    public List<MorphologicalWidthValue> getValues() {
+        return values;
+    }
+
+    public void setValues(List<MorphologicalWidthValue> values) {
+        this.values = values;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/MorphologicalWidthValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,103 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+
+@Entity
+@Table(name = "morphologic_width_values")
+public class MorphologicalWidthValue implements Serializable {
+
+    private Integer id;
+
+    private MorphologicalWidth morphologicalWidth;
+
+    private BigDecimal station;
+    private BigDecimal width;
+
+    private String description;
+
+
+    public MorphologicalWidthValue() {
+    }
+
+
+    public MorphologicalWidthValue(
+        MorphologicalWidth morphologicalWidth,
+        BigDecimal         station,
+        BigDecimal         width,
+        String             description
+    ) {
+        this.morphologicalWidth = morphologicalWidth;
+        this.station            = station;
+        this.width              = width;
+        this.description        = description;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_MORPH_WIDTH_VALUES_ID_SEQ",
+        sequenceName   = "MORPH_WIDTH_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_MORPH_WIDTH_VALUES_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+
+    @OneToOne
+    @JoinColumn(name = "morphologic_width_id")
+    public MorphologicalWidth getMorphologicalWidth() {
+        return morphologicalWidth;
+    }
+
+    public void setMorphologicalWidth(MorphologicalWidth width) {
+        this.morphologicalWidth = width;
+    }
+
+    @Column(name = "station")
+    public BigDecimal getStation() {
+        return station;
+    }
+
+    public void setStation(BigDecimal station) {
+        this.station = station;
+    }
+
+    @Column(name = "width")
+    public BigDecimal getWidth() {
+        return width;
+    }
+
+    public void setWidth(BigDecimal width) {
+        this.width = width;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/model/River.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/River.java	Fri Sep 28 12:15:52 2012 +0200
@@ -17,6 +17,9 @@
 import javax.persistence.GenerationType;
 
 import java.util.List;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
 
 import org.hibernate.Session;
 import org.hibernate.Query;
@@ -31,8 +34,22 @@
 {
     public static final MathContext PRECISION = new MathContext(6);
 
+    public static final double EPSILON = 1e-5;
+
+    public static final Comparator KM_CMP = new Comparator<Double>() {
+        @Override
+        public int compare(Double a, Double b) {
+            double diff = a - b;
+            if (diff < -EPSILON) return -1;
+            if (diff >  EPSILON) return +1;
+            return 0;
+        }
+    };
+
     private Integer id;
 
+    private Long    officialNumber;
+
     private String  name;
 
     private boolean kmUp;
@@ -58,6 +75,15 @@
         this.id = id;
     }
 
+    @Column(name = "official_number")
+    public Long getOfficialNumber() {
+        return officialNumber;
+    }
+
+    public void setOfficialNumber(Long officialNumber) {
+        this.officialNumber = officialNumber;
+    }
+
     @Column(name = "name")
     public String getName() {
         return name;
@@ -205,6 +231,34 @@
         return gauges.isEmpty() ? null : gauges.get(0);
     }
 
+    public double[] determineMinMaxQ() {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "select min(wqr.q) as min, max(wqr.q) as max " +
+            "from Wst as w " +
+            "join w.columns as wc " +
+            "join wc.columnQRanges as wcqr " +
+            "join wcqr.wstQRange as wqr " +
+            "where w.kind = 0 and river_id = :river");
+
+        query.setParameter("river", getId());
+
+        double minmax[] = new double[] { Double.MAX_VALUE, Double.MIN_VALUE };
+
+        List<Object> results = query.list();
+
+        if (!results.isEmpty()) {
+            Object[] arr = (Object[]) results.get(0);
+            BigDecimal minq = (BigDecimal)arr[0];
+            BigDecimal maxq = (BigDecimal)arr[1];
+            minmax[0] = minq.doubleValue();
+            minmax[1] = maxq.doubleValue();
+        }
+
+        return minmax;
+    }
+
 
     /**
      * This method returns the first gauge that is intersected by <i>a</i> and
@@ -258,5 +312,21 @@
 
         return minmax;
     }
+
+    public Map<Double, Double> queryGaugeDatumsKMs() {
+        List<Gauge> gauges = getGauges();
+        Map result = new TreeMap<Double, Double>(KM_CMP);
+
+        for (Gauge gauge: gauges) {
+            BigDecimal km    = gauge.getStation();
+            BigDecimal datum = gauge.getDatum();
+            if (km != null && datum != null) {
+                result.put(km.doubleValue(), datum.doubleValue());
+            }
+        }
+
+        return result;
+    }
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/model/RiverAxis.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/RiverAxis.java	Fri Sep 28 12:15:52 2012 +0200
@@ -19,6 +19,13 @@
 import de.intevation.flys.backend.SessionHolder;
 
 
+/**
+ * There is a modeling problem with the RiverAxis. The initial idea was, that a
+ * river can have a riveraxis that consist of exact one geometry. Now, it has
+ * turned out, that a single geometry is not enough for a riveraxis (arm of a
+ * river, inflows, ...). As workaround, we now expect, that a river can just
+ * have a single riveraxis.
+ */
 @Entity
 @Table(name = "river_axes")
 public class RiverAxis
@@ -28,6 +35,11 @@
     private Integer    kind;
     private River      river;
     private LineString geom;
+    
+    public static final int DEFAULT_KIND = 0;
+    
+    public static final int KIND_OFFICIAL = 1;
+    public static final int KIND_OUTSOURCED = 2;
 
     public RiverAxis() {
     }
@@ -80,16 +92,21 @@
     }
 
 
-    public static RiverAxis getRiverAxis(String river) {
+    public static List<RiverAxis> getRiverAxis(String river) {
+        return getRiverAxis(river, DEFAULT_KIND);
+    }
+    
+    public static List<RiverAxis> getRiverAxis(String river, int kind) {
         Session session = SessionHolder.HOLDER.get();
 
         Query query = session.createQuery(
-            "from RiverAxis where river.name =:river");
+            "from RiverAxis where river.name =:river AND kind =:kind");
         query.setParameter("river", river);
+        query.setParameter("kind", kind);
 
         List<RiverAxis> list = query.list();
 
-        return list.isEmpty() ? null : list.get(0);
+        return list.isEmpty() ? null : list;
     }
 }
 // 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-backend/src/main/java/de/intevation/flys/model/SQRelation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,105 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.JoinColumn;
+import javax.persistence.GenerationType;
+
+
+@Entity
+@Table(name = "sq_relation")
+public class SQRelation implements Serializable {
+
+    private Integer id;
+
+    private River river;
+
+    private TimeInterval timeInterval;
+
+    private String description;
+
+    private List<SQRelationValue> values;
+
+
+    protected SQRelation() {
+    }
+
+
+    public SQRelation(River river, TimeInterval timeInterval, String desc) {
+        this.river        = river;
+        this.timeInterval = timeInterval;
+        this.description  = desc;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_SQ_ID_SEQ",
+        sequenceName   = "SQ_RELATION_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_SQ_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+
+    @OneToOne
+    @JoinColumn(name = "river_id")
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    @OneToOne
+    @JoinColumn(name = "time_interval_id")
+    public TimeInterval getTimeInterval() {
+        return timeInterval;
+    }
+
+    public void setTimeInterval(TimeInterval timeInterval) {
+        this.timeInterval = timeInterval;
+    }
+
+
+    @OneToMany
+    @JoinColumn(name = "sq_relation_id")
+    public List<SQRelationValue> getValues() {
+        return values;
+    }
+
+    public void setValues(List<SQRelationValue> values) {
+        this.values = values;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/SQRelationValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,144 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.JoinColumn;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.OneToOne;
+import javax.persistence.GenerationType;
+
+
+@Entity
+@Table(name = "sq_relation_value")
+public class SQRelationValue implements Serializable {
+
+    private Integer id;
+
+    private SQRelation sqRelation;
+
+    private String parameter;
+    private String fraction;
+    private String function;
+
+    private double km;
+    private double a;
+    private double b;
+
+
+    protected SQRelationValue() {
+    }
+
+
+    public SQRelationValue(
+        SQRelation sqRelation,
+        String     parameter,
+        String     fraction,
+        String     function,
+        double     km,
+        double     a,
+        double     b
+    ) {
+        this.sqRelation = sqRelation;
+        this.parameter  = parameter;
+        this.fraction   = fraction;
+        this.function   = function;
+        this.km         = km;
+        this.a          = a;
+        this.b          = b;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_SQ_VALUE_ID_SEQ",
+        sequenceName   = "SQ_RELATION_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_SQ_VALUE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+
+    @OneToOne
+    @JoinColumn(name = "sq_relation_id")
+    public SQRelation getSqRelation() {
+        return sqRelation;
+    }
+
+    public void setSqRelation(SQRelation sqRelation) {
+        this.sqRelation = sqRelation;
+    }
+
+
+    @Column(name = "parameter")
+    public String getParameter() {
+        return parameter;
+    }
+
+    public void setParameter(String parameter) {
+        this.parameter = parameter;
+    }
+
+
+    @Column(name = "fraction")
+    public String getFraction() {
+        return fraction;
+    }
+
+    public void setFraction(String fraction) {
+        this.fraction = fraction;
+    }
+
+
+    @Column(name = "function")
+    public String getFunction() {
+        return function;
+    }
+
+    public void setFunction(String function) {
+        this.function = function;
+    }
+
+
+    @Column(name = "km")
+    public double getKm() {
+        return km;
+    }
+
+    public void setKm(double km) {
+        this.km = km;
+    }
+
+
+    @Column(name = "a")
+    public double getA() {
+        return a;
+    }
+
+    public void setA(double a) {
+        this.a = a;
+    }
+
+
+    @Column(name = "b")
+    public double getB() {
+        return b;
+    }
+
+    public void setB(double b) {
+        this.b = b;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/SedimentDensity.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,116 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+
+
+@Entity
+@Table(name = "sediment_density")
+public class SedimentDensity implements Serializable {
+
+    private Integer id;
+
+    private River river;
+
+    private Depth depth;
+
+    private Unit unit;
+
+    private List<SedimentDensityValue> values;
+
+    private String description;
+
+
+    public SedimentDensity() {
+    }
+
+
+    public SedimentDensity(River river, Depth depth, Unit unit, String desc) {
+        this.river       = river;
+        this.depth       = depth;
+        this.unit        = unit;
+        this.description = desc;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_SEDIMENT_DENSITY_ID_SEQ",
+        sequenceName   = "SEDIMENT_DENSITY_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_SEDIMENT_DENSITY_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id" )
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "depth_id")
+    public Depth getDepth() {
+        return depth;
+    }
+
+    public void setDepth(Depth depth) {
+        this.depth = depth;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "unit_id")
+    public Unit getUnit() {
+        return unit;
+    }
+
+    public void setUnit(Unit unit) {
+        this.unit = unit;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @OneToMany
+    @JoinColumn(name="sediment_density_id")
+    public List<SedimentDensityValue> getValues() {
+        return values;
+    }
+
+    public void setValues(List<SedimentDensityValue> values) {
+        this.values = values;
+    }
+
+    public void addValue(SedimentDensityValue value) {
+        this.values.add(value);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/SedimentDensityValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,101 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+
+@Entity
+@Table(name = "sediment_density_values")
+public class SedimentDensityValue implements Serializable {
+
+    private Integer id;
+
+    private SedimentDensity sedimentDensity;
+
+    private BigDecimal station;
+    private BigDecimal density;
+
+    private String description;
+
+
+    public SedimentDensityValue() {
+    }
+
+
+    public SedimentDensityValue(
+        SedimentDensity sedimentDensity,
+        BigDecimal      station,
+        BigDecimal      density,
+        String          desc
+    ) {
+        this.sedimentDensity = sedimentDensity;
+        this.station         = station;
+        this.density         = density;
+        this.description     = desc;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_SEDIMENT_DENSITY_VALUES_ID_SEQ",
+        sequenceName   = "SEDIMENT_DENSITY_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_SEDIMENT_DENSITY_VALUES_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "sediment_density_id")
+    public SedimentDensity getSedimentDensity() {
+        return sedimentDensity;
+    }
+
+    public void setSedimentDensity(SedimentDensity sedimentDensity) {
+        this.sedimentDensity = sedimentDensity;
+    }
+
+    @Column(name = "station")
+    public BigDecimal getStation() {
+        return station;
+    }
+
+    public void setStation(BigDecimal station) {
+        this.station = station;
+    }
+
+    @Column(name = "density")
+    public BigDecimal getDensity() {
+        return density;
+    }
+
+    public void setDensity(BigDecimal density) {
+        this.density = density;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/SedimentYield.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,145 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "sediment_yield")
+public class SedimentYield
+implements   Serializable
+{
+    private static Logger logger = Logger.getLogger(SedimentYield.class);
+
+    private Integer id;
+
+    private River river;
+
+    private GrainFraction grainFraction;
+
+    private Unit unit;
+
+    private TimeInterval timeInterval;
+
+    private String description;
+
+    private List<SedimentYieldValue> values;
+
+
+    public SedimentYield() {
+        this.values = new ArrayList<SedimentYieldValue>();
+    }
+
+    public SedimentYield(River river, Unit unit, TimeInterval timeInterval) {
+        this();
+
+        this.river        = river;
+        this.unit         = unit;
+        this.timeInterval = timeInterval;
+    }
+
+
+    public SedimentYield(
+        River         river,
+        Unit          unit,
+        TimeInterval  timeInterval,
+        GrainFraction grainFraction
+    ) {
+        this(river, unit, timeInterval);
+
+        this.grainFraction = grainFraction;
+    }
+
+
+    public SedimentYield(
+        River         river,
+        Unit          unit,
+        TimeInterval  timeInterval,
+        GrainFraction grainFraction,
+        String        description
+    ) {
+        this(river, unit, timeInterval, grainFraction);
+
+        this.description = description;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_SEDIMENT_YIELD_ID_SEQ",
+        sequenceName   = "SEDIMENT_YIELD_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_SEDIMENT_YIELD_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id")
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @OneToOne
+    @JoinColumn(name="grain_fraction_id")
+    public GrainFraction getGrainFraction() {
+        return grainFraction;
+    }
+
+    public void setGrainFraction(GrainFraction grainFraction) {
+        this.grainFraction = grainFraction;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "unit_id")
+    public Unit getUnit() {
+        return unit;
+    }
+
+    public void setUnit(Unit unit) {
+        this.unit = unit;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "time_interval_id")
+    public TimeInterval getTimeInterval() {
+        return timeInterval;
+    }
+
+    public void setTimeInterval(TimeInterval timeInterval) {
+        this.timeInterval = timeInterval;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/SedimentYieldValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,93 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "sediment_yield_values")
+public class SedimentYieldValue
+implements   Serializable
+{
+    private static Logger logger = Logger.getLogger(SedimentYieldValue.class);
+
+    private Integer id;
+
+    private SedimentYield sedimentYield;
+
+    private Double station;
+    private Double value;
+
+    private Unit unit;
+
+
+    public SedimentYieldValue() {
+    }
+
+    public SedimentYieldValue(
+        SedimentYield sedimentYield,
+        Double        station,
+        Double        value
+    ) {
+        this.sedimentYield = sedimentYield;
+        this.station       = station;
+        this.value         = value;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_SEDIMENT_YIELD_VALuES_ID_SEQ",
+        sequenceName   = "SEDIMENT_YIELD_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_SEDIMENT_YIELD_VALuES_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "sediment_yield_id" )
+    public SedimentYield getSedimentYield() {
+        return sedimentYield;
+    }
+
+    public void setSedimentYield(SedimentYield sedimentYield) {
+        this.sedimentYield = sedimentYield;
+    }
+
+    @Column(name="station")
+    public Double getStation() {
+        return station;
+    }
+
+    public void setStation(Double station) {
+        this.station = station;
+    }
+
+    @Column(name = "value")
+    public Double getValue() {
+        return value;
+    }
+
+    public void setValue(Double value) {
+        this.value = value;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/Waterlevel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,113 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+
+import org.apache.log4j.Logger;
+
+
+
+
+@Entity
+@Table(name = "waterlevel")
+public class Waterlevel
+implements   Serializable
+{
+    private static Logger logger = Logger.getLogger(Waterlevel.class);
+
+    private Integer id;
+
+    private River river;
+
+    private Unit unit;
+
+    private String  description;
+
+    private List<WaterlevelQRange> qRanges;
+
+
+    public Waterlevel() {
+    }
+
+    public Waterlevel(River river, Unit unit) {
+        this.river = river;
+        this.unit  = unit;
+    }
+
+    public Waterlevel(River river, Unit unit, String description) {
+        this(river, unit);
+        this.description = description;
+    }
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_WATERLEVEL_ID_SEQ",
+        sequenceName   = "WATERLEVEL_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_WATERLEVEL_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id" )
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "unit_id")
+    public Unit getUnit() {
+        return unit;
+    }
+
+    public void setUnit(Unit unit) {
+        this.unit = unit;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @OneToMany
+    @JoinColumn(name="waterlevel_id")
+    public List<WaterlevelQRange> getQRanges() {
+        return qRanges;
+    }
+
+    public void setQRanges(List<WaterlevelQRange> qRanges) {
+        this.qRanges = qRanges;
+    }
+
+    public void addQRange(WaterlevelQRange qRange) {
+        qRanges.add(qRange);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/WaterlevelDifference.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,119 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "waterlevel_difference")
+public class WaterlevelDifference
+implements   Serializable
+{
+    private static Logger logger = Logger.getLogger(WaterlevelDifference.class);
+
+    private Integer id;
+
+    private River river;
+
+    private Unit unit;
+
+    private List<WaterlevelDifferenceColumn> columns;
+
+    private String description;
+
+
+    public WaterlevelDifference() {
+        columns = new ArrayList<WaterlevelDifferenceColumn>();
+    }
+
+
+    public WaterlevelDifference(River river, Unit unit) {
+        this();
+
+        this.river = river;
+        this.unit  = unit;
+    }
+
+
+    public WaterlevelDifference(River river, Unit unit, String description) {
+        this(river, unit);
+
+        this.description = description;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_WATERLEVEL_DIFFERENCE_ID_SEQ",
+        sequenceName   = "WATERLEVEL_DIFFERENCE_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_WATERLEVEL_DIFFERENCE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "river_id" )
+    public River getRiver() {
+        return river;
+    }
+
+    public void setRiver(River river) {
+        this.river = river;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "unit_id")
+    public Unit getUnit() {
+        return unit;
+    }
+
+    public void setUnit(Unit unit) {
+        this.unit = unit;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @OneToMany
+    @JoinColumn(name = "difference_id")
+    public List<WaterlevelDifferenceColumn> getColumns() {
+        return columns;
+    }
+
+    public void setColumns(List<WaterlevelDifferenceColumn> columns) {
+        this.columns = columns;
+    }
+
+    public void addColumn(WaterlevelDifferenceColumn column) {
+        this.columns.add(column);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/WaterlevelDifferenceColumn.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,104 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "waterlevel_difference_column")
+public class WaterlevelDifferenceColumn
+implements   Serializable
+{
+    private static Logger logger =
+        Logger.getLogger(WaterlevelDifferenceColumn.class);
+
+
+    private Integer id;
+
+    private WaterlevelDifference difference;
+
+    private List<WaterlevelDifferenceValue> values;
+
+    private String description;
+
+
+    public WaterlevelDifferenceColumn() {
+        values = new ArrayList<WaterlevelDifferenceValue>();
+    }
+
+    public WaterlevelDifferenceColumn(
+        WaterlevelDifference difference,
+        String               description
+    ) {
+        this();
+
+        this.difference = difference;
+        this.description = description;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_WATERLEVEL_DIFF_COLUMN_ID_SEQ",
+        sequenceName   = "WATERLEVEL_DIFF_COLUMN_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_WATERLEVEL_DIFF_COLUMN_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "difference_id" )
+    public WaterlevelDifference getDifference() {
+        return difference;
+    }
+
+    public void setDifference(WaterlevelDifference difference) {
+        this.difference = difference;
+    }
+
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @OneToMany
+    @JoinColumn(name = "column_id")
+    public List<WaterlevelDifferenceValue> getValues() {
+        return values;
+    }
+
+    public void setValues(List<WaterlevelDifferenceValue> values) {
+        this.values = values;
+    }
+
+    public void addValue(WaterlevelDifferenceValue value) {
+        this.values.add(value);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/WaterlevelDifferenceValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,94 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.apache.log4j.Logger;
+
+
+@Entity
+@Table(name = "waterlevel_difference_values")
+public class WaterlevelDifferenceValue
+implements   Serializable
+{
+    private static Logger logger =
+        Logger.getLogger(WaterlevelDifferenceValue.class);
+
+
+    private Integer id;
+
+    private WaterlevelDifferenceColumn column;
+
+    private Double station;
+    private Double value;
+
+
+    public WaterlevelDifferenceValue() {
+    }
+
+    public WaterlevelDifferenceValue(
+        WaterlevelDifferenceColumn column,
+        Double                     station,
+        Double                     value
+    ) {
+        this.column  = column;
+        this.station = station;
+        this.value   = value;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_WATERLEVEL_DIFF_VALUES_ID_SEQ",
+        sequenceName   = "WATERLEVEL_DIFF_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_WATERLEVEL_DIFF_VALUES_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "column_id" )
+    public WaterlevelDifferenceColumn getColumn() {
+        return column;
+    }
+
+    public void setColumn(WaterlevelDifferenceColumn column) {
+        this.column = column;
+    }
+
+    @Column(name = "station")
+    public Double getStation() {
+        return station;
+    }
+
+    public void setStation(Double station) {
+        this.station = station;
+    }
+
+    @Column(name = "value")
+    public Double getValue() {
+        return value;
+    }
+
+    public void setValue(Double value) {
+        this.value = value;
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/WaterlevelQRange.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,100 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.OneToMany;
+
+import org.apache.log4j.Logger;
+
+
+
+
+@Entity
+@Table(name = "waterlevel_q_range")
+public class WaterlevelQRange
+implements   Serializable
+{
+    private static Logger logger = Logger.getLogger(WaterlevelQRange.class);
+
+    private Integer id;
+
+    private Waterlevel waterlevel;
+
+    private Double q;
+
+    private List<WaterlevelValue> values;
+
+
+    public WaterlevelQRange() {
+        this.values = new ArrayList<WaterlevelValue>();
+    }
+
+    public WaterlevelQRange(Waterlevel waterlevel, Double q) {
+        this();
+        this.q          = q;
+        this.waterlevel = waterlevel;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_WATERLEVEL_Q_RANGE_ID_SEQ",
+        sequenceName   = "WATERLEVEL_Q_RANGES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_WATERLEVEL_Q_RANGE_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "waterlevel_id" )
+    public Waterlevel getWaterlevel() {
+        return waterlevel;
+    }
+
+    public void setWaterlevel(Waterlevel waterlevel) {
+        this.waterlevel = waterlevel;
+    }
+
+    @Column(name = "q")
+    public Double getQ() {
+        return q;
+    }
+
+    public void setQ(Double q) {
+        this.q = q;
+    }
+
+    @OneToMany
+    @Column(name = "waterlevel_q_range_id")
+    public List<WaterlevelValue> getValues() {
+        return values;
+    }
+
+    public void setValues(List<WaterlevelValue> values) {
+        this.values = values;
+    }
+
+    public void addValue(WaterlevelValue value) {
+        values.add(value);
+    }
+}
+// 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-backend/src/main/java/de/intevation/flys/model/WaterlevelValue.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,90 @@
+package de.intevation.flys.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.GenerationType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+import org.apache.log4j.Logger;
+
+
+
+
+@Entity
+@Table(name = "waterlevel_values")
+public class WaterlevelValue
+implements   Serializable
+{
+    private static Logger logger = Logger.getLogger(WaterlevelValue.class);
+
+    private Integer id;
+
+    private WaterlevelQRange qrange;
+
+    private Double station;
+    private Double w;
+
+
+    public WaterlevelValue() {
+    }
+
+    public WaterlevelValue(WaterlevelQRange qrange, Double station, Double w) {
+        this.qrange  = qrange;
+        this.station = station;
+        this.w       = w;
+    }
+
+
+    @Id
+    @SequenceGenerator(
+        name           = "SEQUENCE_WATERLEVEL_VALUES_ID_SEQ",
+        sequenceName   = "WATERLEVEL_VALUES_ID_SEQ",
+        allocationSize = 1)
+    @GeneratedValue(
+        strategy  = GenerationType.SEQUENCE,
+        generator = "SEQUENCE_WATERLEVEL_VALUES_ID_SEQ")
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @OneToOne
+    @JoinColumn(name = "waterlevel_q_range_id" )
+    public WaterlevelQRange getQrange() {
+        return qrange;
+    }
+
+    public void setQrange(WaterlevelQRange qrange) {
+        this.qrange = qrange;
+    }
+
+    @Column(name = "station")
+    public Double getStation() {
+        return station;
+    }
+
+    public void setStation(Double station) {
+        this.station = station;
+    }
+
+    @Column(name = "w")
+    public Double getW() {
+        return w;
+    }
+
+    public void setW(Double w) {
+        this.w = w;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-backend/src/main/java/de/intevation/flys/model/Wst.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/model/Wst.java	Fri Sep 28 12:15:52 2012 +0200
@@ -42,7 +42,7 @@
 
     public static final String SQL_SELECT_MINMAX =
         "select min(q) as minQ, max(q) as maxQ from wst_q_values " +
-        "where wst_id = :wst and  not (a > :km or b < :km)";
+        "where wst_id = :wst and not (a > :km or b < :km)";
 
     public Wst() {
     }
@@ -197,12 +197,18 @@
 
         List<Object[]> minmaxQ = sqlQuery.list();
 
+
         if (minmaxQ.isEmpty()) {
             return null;
         }
 
         Object[] mm = minmaxQ.get(0);
 
+        if (mm[0] == null || mm[1] == null) {
+            logger.warn ("No min/max Q for km " + km + " found.");
+            return null;
+        }
+
         return new double[] { (Double) mm[0], (Double) mm[1] };
     }
 }
--- a/flys-backend/src/main/java/de/intevation/flys/utils/DBCPConnectionProvider.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/utils/DBCPConnectionProvider.java	Fri Sep 28 12:15:52 2012 +0200
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.hibernate.connection;
+package de.intevation.flys.utils;
 
 import java.sql.Connection;
 import java.sql.SQLException;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/flys/utils/DgmSqlConverter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,483 @@
+package de.intevation.flys.utils;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import au.com.bytecode.opencsv.CSVReader;
+
+
+/**
+ * A converter for CSV files with DGM information. The result of a conversion
+ * is an SQL file with "INSERT INTO dem ..." statements.
+ * <br>
+ * To start the converter, at least the following three system properties are
+ * required:
+ * <br>
+ * <ul>
+ * <ol><b>gew.dir</b>: This property must point to the directory where all
+ * rivers are stored.</ol>
+ * <ol><b>csv</b>: This property must point to the CSV file that contains the
+ * DGM information.</ol>
+ * <ol><b>sql</b>: This property must point to a (not yet existing) file that
+ * will be generated by this converter.</ol>
+ * </ul>
+ * <br>
+ * In addiation, the following properties are accepted to modify log messages,
+ * etc.
+ * <ul>
+ * <ol><b>verbose</b>: Accepts integer values (0, 1, 2, 3) to modify the log
+ * messages. The higher the value the more log messages are printed to STDOUT.
+ * </ol>
+ * <ol><b>full</b>: Accepts true|false values. If true is set, all rivers
+ * included in the CSV file are taken into account while parsing. Otherwise,
+ * the converter reads information for 'Saar', 'Mosel' and 'Eble' only.</ol>
+ * </ul>
+ *
+ * @author Ingo Weinzierl <a href="mailto:ingo.weinzierl@intevation.de">
+ * ingo.weinzierl@intevation.de</a>
+ *
+ */
+public class DgmSqlConverter {
+
+    public static final String SQL_INSERT = "INSERT INTO dem (river_id, name, lower, upper, year_from, year_to,"
+        + "projection, elevation_state, format, border_break, resolution, description, path) VALUES ("
+        + "%s, '%s', %s, %s, %s, %s, '%s', '%s', '%s', %s, '%s', '%s', '%s');";
+
+    public static final String SQL_SELECT_RIVER = "(SELECT id from rivers WHERE name = '%s')";
+
+    public static final char DEFAULT_SEPERATOR = ',';
+    public static final char DEFAULT_QUOTE = '"';
+    public static final int DEFAULT_LOG_LEVEL = 2;
+
+    public static final boolean FULL_MODE = Boolean.getBoolean("full");
+    public static final String GEW_DIR = System.getProperty("gew.dir", null);
+    public static final String CSV_FILE = System.getProperty("csv");
+    public static final String SQL_FILE = System.getProperty("sql");
+    public static final int LOG_LEVEL = Integer.getInteger("verbose",
+        DEFAULT_LOG_LEVEL);
+
+    public static final int MIN_COLUMN_COUNT = 15;
+
+    public static final int IDX_RIVERNAME = 0;
+    public static final int IDX_NAME = 12;
+    public static final int IDX_LOWER = 1;
+    public static final int IDX_UPPER = 2;
+    public static final int IDX_YEAR_FROM = 3;
+    public static final int IDX_YEAR_TO = 4;
+    public static final int IDX_PROJECTION = 7;
+    public static final int IDX_ELEVATION_STATE = 8;
+    public static final int IDX_FORMAT = 9;
+    public static final int IDX_BORDER_BREAK = 10;
+    public static final int IDX_RESOLUTION = 11;
+    public static final int IDX_DESCRIPTION = 14;
+    public static final int IDX_FILE_NAME = 5;
+    public static final int IDX_FILE_PATH = 6;
+
+    private class DGM {
+
+        public String river;
+        public String name;
+        public String projection;
+        public String elevationState;
+        public String format;
+        public String resolution;
+        public String description;
+        public String path;
+
+        public double lower;
+        public double upper;
+        public Integer yearFrom;
+        public Integer yearTo;
+
+        public boolean borderBreak;
+
+        public DGM() {
+            borderBreak = false;
+        }
+
+        public String toSQL() {
+            String riverId = String.format(SQL_SELECT_RIVER, river);
+            String lower = String.valueOf(this.lower);
+            String upper = String.valueOf(this.upper);
+            String yearFrom = this.yearFrom != null ? String
+                .valueOf(this.yearFrom) : "";
+            String yearTo = this.yearTo != null ? String.valueOf(this.yearTo)
+                : "";
+
+            return String.format(SQL_INSERT, riverId, name, lower, upper,
+                yearFrom, yearTo, projection, elevationState, format,
+                borderBreak, resolution, description, path);
+        }
+    }
+
+    private File riverDir;
+    private File csv;
+    private File sql;
+
+    private List<DGM> dgms;
+
+    public static void debug(String msg) {
+        if (LOG_LEVEL >= 3) {
+            System.out.println("DEBUG: " + msg);
+        }
+    }
+
+    public static void info(String msg) {
+        if (LOG_LEVEL >= 2) {
+            System.out.println("INFO: " + msg);
+        }
+    }
+
+    public static void warn(String msg) {
+        if (LOG_LEVEL >= 1) {
+            System.out.println("WARN: " + msg);
+        }
+    }
+
+    public static void error(String msg) {
+        System.out.println("ERROR: " + msg);
+    }
+
+    public static File getRiverDir(String[] args) {
+        if (GEW_DIR != null && GEW_DIR.length() > 0) {
+            return new File(GEW_DIR);
+        }
+        else if (args != null && args.length > 0) {
+            return new File(args[0]);
+        }
+
+        return null;
+    }
+
+    public static File getCSVFile(String[] args) {
+        if (CSV_FILE != null && CSV_FILE.length() > 0) {
+            return new File(CSV_FILE);
+        }
+        else if (args != null && args.length > 1) {
+            return new File(args[1]);
+        }
+
+        return null;
+    }
+
+    public static File getSQLFile(String[] args) {
+        if (SQL_FILE != null && SQL_FILE.length() > 0) {
+            return new File(SQL_FILE);
+        }
+        else if (args != null && args.length > 2) {
+            return new File(args[2]);
+        }
+
+        return null;
+    }
+
+    public static void main(String[] args) {
+        info("Start convering CSV -> SQL statements");
+
+        if (!FULL_MODE) {
+            info("You are running in DEMO mode; other rivers than 'Saar', 'Mosel' and 'Elbe' are ignored.");
+        }
+
+        File riverDir = getRiverDir(args);
+
+        if (riverDir == null) {
+            warn("No rivers directory specified!");
+            return;
+        }
+        else if (!riverDir.isDirectory()) {
+            warn("Specified rivers directory is not a directory!");
+            return;
+        }
+        else if (!riverDir.canRead()) {
+            warn("Unable to read '" + riverDir.toString() + "'");
+            return;
+        }
+
+        File csv = getCSVFile(args);
+
+        if (csv == null) {
+            warn("No CSV file specified!");
+            return;
+        }
+        else if (csv.isDirectory()) {
+            warn("Specified CSV file is a directory!");
+            return;
+        }
+        else if (!csv.canRead()) {
+            warn("Unable to read '" + csv.toString() + "'");
+            return;
+        }
+
+        File sql = getSQLFile(args);
+
+        if (sql == null) {
+            warn("No destination file specified!");
+            return;
+        }
+        else if (sql.isDirectory()) {
+            warn("Specified destination file is a directory!");
+            return;
+        }
+        else if (sql.exists() && !sql.canWrite()) {
+            warn("Unable to write to '" + sql.toString() + "'");
+            return;
+        }
+        else if (!sql.exists()) {
+            try {
+                sql.createNewFile();
+            }
+            catch (IOException ioe) {
+                warn("Unable to write to '" + sql.toString() + "'");
+                return;
+            }
+        }
+
+        info("Start parsing CSV file '" + csv.toString() + "'");
+
+        try {
+            DgmSqlConverter parser = new DgmSqlConverter(riverDir, csv, sql);
+            parser.read();
+            parser.write();
+        }
+        catch (Exception e) {
+            error("Unexpected error: " + e.getMessage());
+            e.printStackTrace();
+        }
+
+        info("Finished converting CSV -> SQL regularly.");
+    }
+
+    public DgmSqlConverter(File riverDir, File csv, File sql) {
+        this.riverDir = riverDir;
+        this.csv = csv;
+        this.sql = sql;
+        this.dgms = new ArrayList<DGM>();
+    }
+
+    public void read() {
+        info("Read DGM information from CSV file: " + csv.getAbsolutePath());
+
+        InputStream in = null;
+
+        try {
+            in = new BufferedInputStream(new FileInputStream(csv));
+        }
+        catch (FileNotFoundException e) {
+            error("File not found: " + e.getMessage());
+            return;
+        }
+
+        Reader reader = new InputStreamReader(in);
+        CSVReader csvReader = new CSVReader(reader, DEFAULT_SEPERATOR,
+            DEFAULT_QUOTE);
+
+        List<String[]> rows = new ArrayList<String[]>();
+
+        int success = 0;
+
+        try {
+            rows = csvReader.readAll();
+
+            for (int idx = 0; idx < rows.size(); idx++) {
+                String[] row = rows.get(idx);
+                if (readRow(row)) {
+                    success++;
+                }
+                else {
+                    warn("Unable to parse row " + (idx + 1));
+                }
+            }
+        }
+        catch (IOException e) {
+            error("Error while parsing CSV: " + e.getMessage());
+            return;
+        }
+
+        info("Parsed CSV file: " + rows.size() + " lines.");
+        info("Parsed " + success + " line successful");
+    }
+
+    private boolean readRow(String[] row) {
+        if (row == null) {
+            warn("Row is null!");
+            return false;
+        }
+
+        if (row.length < MIN_COLUMN_COUNT) {
+            warn("invalid column count: " + row.length);
+            return false;
+        }
+
+        StringBuffer rowBuffer = new StringBuffer();
+        for (String col : row) {
+            rowBuffer.append(col);
+            rowBuffer.append(" | ");
+        }
+        debug(rowBuffer.toString());
+
+        try {
+            DGM dgm = new DGM();
+            dgm.river = readRiver(row[IDX_RIVERNAME]);
+            dgm.name = row[IDX_NAME];
+            dgm.projection = row[IDX_PROJECTION];
+            dgm.elevationState = row[IDX_ELEVATION_STATE];
+            dgm.format = row[IDX_FORMAT];
+            dgm.resolution = row[IDX_RESOLUTION];
+            dgm.description = row[IDX_DESCRIPTION];
+            dgm.lower = readLower(row[IDX_LOWER]);
+            dgm.upper = readUpper(row[IDX_UPPER]);
+            dgm.yearFrom = readFromYear(row[IDX_YEAR_FROM]);
+            dgm.yearTo = readToYear(row[IDX_YEAR_TO]);
+            dgm.borderBreak = readBorderBreak(row[IDX_BORDER_BREAK]);
+            dgm.path = readPath(dgm.river, row[IDX_FILE_PATH],
+                row[IDX_FILE_NAME]);
+
+            dgms.add(dgm);
+
+            return true;
+        }
+        catch (IllegalArgumentException iae) {
+            warn(iae.getMessage());
+        }
+
+        return false;
+    }
+
+    private String readRiver(String rivername) throws IllegalArgumentException {
+        if (rivername == null || rivername.length() == 0) {
+            throw new IllegalAccessError("Invalid rivername: " + rivername);
+        }
+
+        if (!FULL_MODE
+            && !(rivername.equals("Saar") || rivername.equals("Mosel") || rivername
+                .equals("Elbe"))) {
+            throw new IllegalArgumentException("In DEMO mode; skip river: "
+                + rivername);
+        }
+
+        return rivername;
+    }
+
+    private Double readLower(String lower) throws IllegalArgumentException {
+        try {
+            return Double.valueOf(lower);
+        }
+        catch (NumberFormatException nfe) {
+        }
+
+        throw new IllegalArgumentException("Attribute 'lower' invalid: "
+            + lower);
+    }
+
+    private Double readUpper(String upper) throws IllegalArgumentException {
+        try {
+            return Double.valueOf(upper);
+        }
+        catch (NumberFormatException nfe) {
+        }
+
+        throw new IllegalArgumentException("Attribute 'upper' invalid: "
+            + upper);
+    }
+
+    private Integer readFromYear(String from) throws IllegalArgumentException {
+        try {
+            return Integer.valueOf(from);
+        }
+        catch (NumberFormatException nfe) {
+        }
+
+        return null;
+    }
+
+    private Integer readToYear(String to) throws IllegalArgumentException {
+        try {
+            return Integer.valueOf(to);
+        }
+        catch (NumberFormatException nfe) {
+        }
+
+        return null;
+    }
+
+    private String readPath(String rivername, String dir, String filename)
+        throws IllegalArgumentException {
+        File riverDir = new File(this.riverDir, rivername);
+        File dgmDir = new File(riverDir, dir);
+        File dgmFile = new File(dgmDir, filename);
+
+        try {
+            debug("Path of DGM = " + dgmFile.getAbsolutePath());
+
+            if (dgmFile == null || !dgmFile.exists()) {
+                throw new IllegalAccessError(
+                    "Specified DGM file does not exist: "
+                        + dgmFile.getAbsolutePath());
+            }
+
+            if (!dgmFile.isFile()) {
+                throw new IllegalArgumentException(
+                    "Specified DGM file is no file: "
+                        + dgmFile.getAbsolutePath());
+            }
+        }
+        catch (IllegalAccessError iae) {
+            throw new IllegalArgumentException("Cannot find DGM file (river="
+                + rivername + " | directory=" + dir + " | filename=" + filename
+                + ")");
+        }
+
+        return dgmFile.getAbsolutePath();
+    }
+
+    private boolean readBorderBreak(String borderBreak) {
+        if (borderBreak == null || borderBreak.length() == 0) {
+            return true;
+        }
+        else if (borderBreak.toLowerCase().equals("ja")) {
+            return true;
+        }
+        else if (borderBreak.toLowerCase().equals("nein")) {
+            return false;
+        }
+        else {
+            return true;
+        }
+    }
+
+    public void write() {
+        info("Write DEM information to SQL file: " + sql.getAbsolutePath());
+
+        BufferedWriter bufferedWriter = null;
+        try {
+            bufferedWriter = new BufferedWriter(new FileWriter(sql));
+
+            for (DGM dgm : dgms) {
+                bufferedWriter.write(dgm.toSQL());
+                bufferedWriter.newLine();
+            }
+        }
+        catch (IOException ioe) {
+            error(ioe.getMessage());
+        }
+        finally {
+            if (bufferedWriter != null) {
+                try {
+                    bufferedWriter.close();
+                }
+                catch (IOException ioe) {
+                }
+            }
+        }
+    }
+}
--- a/flys-backend/src/main/java/de/intevation/flys/utils/StringUtil.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-backend/src/main/java/de/intevation/flys/utils/StringUtil.java	Fri Sep 28 12:15:52 2012 +0200
@@ -517,7 +517,7 @@
     }
 
     /**
-     * Gibt den Dateinamen in S ohne Dateiendung zurück.
+     * Returns the file name without extension.
      */
     public static final String cutExtension(String s) {
         if (s == null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/hibernate/MapResultTransformer.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,26 @@
+package de.intevation.hibernate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.transform.BasicTransformerAdapter;
+
+public class MapResultTransformer
+extends      BasicTransformerAdapter
+{
+    public static final MapResultTransformer INSTANCE =
+        new MapResultTransformer();
+
+    public MapResultTransformer() {
+    }
+
+    @Override
+    public Object transformTuple(Object [] tuple, String [] aliases) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        for (int i = 0; i < tuple.length; ++i) {
+            map.put(aliases[i], tuple[i]);
+        }
+        return map;
+    }
+}
+// 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-backend/src/main/java/de/intevation/seddb/model/Bezugspegel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,286 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * Bezugspegel generated by hbm2java
+ */
+@Entity
+@Table(name="BEZUGSPEGEL"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames={"GEWAESSERID", "NAME"})
+)
+public class Bezugspegel  implements java.io.Serializable {
+
+
+     private long bezugspegelid;
+     private Gewaesser gewaesser;
+     private BigDecimal km;
+     private String name;
+     private BigDecimal nullpunkt;
+     private String kennung;
+     private BigDecimal einzugsgebiet;
+     private Date inbetrieb;
+     private String fliesscharakter;
+     private BigDecimal laufentwicklung;
+     private BigDecimal mnq;
+     private BigDecimal mq;
+     private BigDecimal mhq;
+     private BigDecimal nnq;
+     private BigDecimal hhq;
+     private Date nnqdatum;
+     private Date hhqdatum;
+     private String jahresreihe;
+     private String bemerkung;
+     private Set<Station> stations = new HashSet<Station>(0);
+
+    public Bezugspegel() {
+    }
+
+    public Bezugspegel(long bezugspegelid, Gewaesser gewaesser, BigDecimal km, String name, BigDecimal nullpunkt) {
+        this.bezugspegelid = bezugspegelid;
+        this.gewaesser = gewaesser;
+        this.km = km;
+        this.name = name;
+        this.nullpunkt = nullpunkt;
+    }
+    public Bezugspegel(long bezugspegelid, Gewaesser gewaesser, BigDecimal km, String name, BigDecimal nullpunkt, String kennung, BigDecimal einzugsgebiet, Date inbetrieb, String fliesscharakter, BigDecimal laufentwicklung, BigDecimal mnq, BigDecimal mq, BigDecimal mhq, BigDecimal nnq, BigDecimal hhq, Date nnqdatum, Date hhqdatum, String jahresreihe, String bemerkung, Set<Station> stations) {
+       this.bezugspegelid = bezugspegelid;
+       this.gewaesser = gewaesser;
+       this.km = km;
+       this.name = name;
+       this.nullpunkt = nullpunkt;
+       this.kennung = kennung;
+       this.einzugsgebiet = einzugsgebiet;
+       this.inbetrieb = inbetrieb;
+       this.fliesscharakter = fliesscharakter;
+       this.laufentwicklung = laufentwicklung;
+       this.mnq = mnq;
+       this.mq = mq;
+       this.mhq = mhq;
+       this.nnq = nnq;
+       this.hhq = hhq;
+       this.nnqdatum = nnqdatum;
+       this.hhqdatum = hhqdatum;
+       this.jahresreihe = jahresreihe;
+       this.bemerkung = bemerkung;
+       this.stations = stations;
+    }
+
+     @Id
+
+
+    @Column(name="BEZUGSPEGELID", unique=true, nullable=false, precision=11, scale=0)
+    public long getBezugspegelid() {
+        return this.bezugspegelid;
+    }
+
+    public void setBezugspegelid(long bezugspegelid) {
+        this.bezugspegelid = bezugspegelid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="GEWAESSERID", nullable=false)
+    public Gewaesser getGewaesser() {
+        return this.gewaesser;
+    }
+
+    public void setGewaesser(Gewaesser gewaesser) {
+        this.gewaesser = gewaesser;
+    }
+
+
+    @Column(name="KM", nullable=false, precision=8, scale=3)
+    public BigDecimal getKm() {
+        return this.km;
+    }
+
+    public void setKm(BigDecimal km) {
+        this.km = km;
+    }
+
+
+    @Column(name="NAME", nullable=false, length=50)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="NULLPUNKT", nullable=false, precision=8, scale=3)
+    public BigDecimal getNullpunkt() {
+        return this.nullpunkt;
+    }
+
+    public void setNullpunkt(BigDecimal nullpunkt) {
+        this.nullpunkt = nullpunkt;
+    }
+
+
+    @Column(name="KENNUNG", length=16)
+    public String getKennung() {
+        return this.kennung;
+    }
+
+    public void setKennung(String kennung) {
+        this.kennung = kennung;
+    }
+
+
+    @Column(name="EINZUGSGEBIET", precision=10)
+    public BigDecimal getEinzugsgebiet() {
+        return this.einzugsgebiet;
+    }
+
+    public void setEinzugsgebiet(BigDecimal einzugsgebiet) {
+        this.einzugsgebiet = einzugsgebiet;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="INBETRIEB", length=7)
+    public Date getInbetrieb() {
+        return this.inbetrieb;
+    }
+
+    public void setInbetrieb(Date inbetrieb) {
+        this.inbetrieb = inbetrieb;
+    }
+
+
+    @Column(name="FLIESSCHARAKTER", length=3)
+    public String getFliesscharakter() {
+        return this.fliesscharakter;
+    }
+
+    public void setFliesscharakter(String fliesscharakter) {
+        this.fliesscharakter = fliesscharakter;
+    }
+
+
+    @Column(name="LAUFENTWICKLUNG", precision=7, scale=3)
+    public BigDecimal getLaufentwicklung() {
+        return this.laufentwicklung;
+    }
+
+    public void setLaufentwicklung(BigDecimal laufentwicklung) {
+        this.laufentwicklung = laufentwicklung;
+    }
+
+
+    @Column(name="MNQ", precision=8, scale=3)
+    public BigDecimal getMnq() {
+        return this.mnq;
+    }
+
+    public void setMnq(BigDecimal mnq) {
+        this.mnq = mnq;
+    }
+
+
+    @Column(name="MQ", precision=8, scale=3)
+    public BigDecimal getMq() {
+        return this.mq;
+    }
+
+    public void setMq(BigDecimal mq) {
+        this.mq = mq;
+    }
+
+
+    @Column(name="MHQ", precision=8, scale=3)
+    public BigDecimal getMhq() {
+        return this.mhq;
+    }
+
+    public void setMhq(BigDecimal mhq) {
+        this.mhq = mhq;
+    }
+
+
+    @Column(name="NNQ", precision=8, scale=3)
+    public BigDecimal getNnq() {
+        return this.nnq;
+    }
+
+    public void setNnq(BigDecimal nnq) {
+        this.nnq = nnq;
+    }
+
+
+    @Column(name="HHQ", precision=8, scale=3)
+    public BigDecimal getHhq() {
+        return this.hhq;
+    }
+
+    public void setHhq(BigDecimal hhq) {
+        this.hhq = hhq;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="NNQDATUM", length=7)
+    public Date getNnqdatum() {
+        return this.nnqdatum;
+    }
+
+    public void setNnqdatum(Date nnqdatum) {
+        this.nnqdatum = nnqdatum;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="HHQDATUM", length=7)
+    public Date getHhqdatum() {
+        return this.hhqdatum;
+    }
+
+    public void setHhqdatum(Date hhqdatum) {
+        this.hhqdatum = hhqdatum;
+    }
+
+
+    @Column(name="JAHRESREIHE", length=12)
+    public String getJahresreihe() {
+        return this.jahresreihe;
+    }
+
+    public void setJahresreihe(String jahresreihe) {
+        this.jahresreihe = jahresreihe;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="bezugspegel")
+    public Set<Station> getStations() {
+        return this.stations;
+    }
+
+    public void setStations(Set<Station> stations) {
+        this.stations = stations;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Bezugspegelgew.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,61 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Bezugspegelgew generated by hbm2java
+ */
+@Entity
+@Table(name="BEZUGSPEGELGEW"
+    ,schema="SEDDB"
+)
+public class Bezugspegelgew  implements java.io.Serializable {
+
+
+     private BezugspegelgewId id;
+
+    public Bezugspegelgew() {
+    }
+
+    public Bezugspegelgew(BezugspegelgewId id) {
+       this.id = id;
+    }
+
+     @EmbeddedId
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="bezugspegelid", column=@Column(name="BEZUGSPEGELID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="gewaesserid", column=@Column(name="GEWAESSERID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="km", column=@Column(name="KM", nullable=false, precision=8, scale=3) ),
+        @AttributeOverride(name="name", column=@Column(name="NAME", nullable=false, length=50) ),
+        @AttributeOverride(name="nullpunkt", column=@Column(name="NULLPUNKT", nullable=false, precision=8, scale=3) ),
+        @AttributeOverride(name="kennung", column=@Column(name="KENNUNG", length=16) ),
+        @AttributeOverride(name="einzugsgebiet", column=@Column(name="EINZUGSGEBIET", precision=10) ),
+        @AttributeOverride(name="inbetrieb", column=@Column(name="INBETRIEB", length=7) ),
+        @AttributeOverride(name="fliesscharakter", column=@Column(name="FLIESSCHARAKTER", length=3) ),
+        @AttributeOverride(name="laufentwicklung", column=@Column(name="LAUFENTWICKLUNG", precision=7, scale=3) ),
+        @AttributeOverride(name="mnq", column=@Column(name="MNQ", precision=8, scale=3) ),
+        @AttributeOverride(name="mq", column=@Column(name="MQ", precision=8, scale=3) ),
+        @AttributeOverride(name="mhq", column=@Column(name="MHQ", precision=8, scale=3) ),
+        @AttributeOverride(name="nnq", column=@Column(name="NNQ", precision=8, scale=3) ),
+        @AttributeOverride(name="hhq", column=@Column(name="HHQ", precision=8, scale=3) ),
+        @AttributeOverride(name="nnqdatum", column=@Column(name="NNQDATUM", length=7) ),
+        @AttributeOverride(name="hhqdatum", column=@Column(name="HHQDATUM", length=7) ),
+        @AttributeOverride(name="jahresreihe", column=@Column(name="JAHRESREIHE", length=12) ),
+        @AttributeOverride(name="bemerkung", column=@Column(name="BEMERKUNG", length=240) ),
+        @AttributeOverride(name="gewname", column=@Column(name="GEWNAME", nullable=false, length=20) ) } )
+    public BezugspegelgewId getId() {
+        return this.id;
+    }
+
+    public void setId(BezugspegelgewId id) {
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/BezugspegelgewId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,327 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.Date;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * BezugspegelgewId generated by hbm2java
+ */
+@Embeddable
+public class BezugspegelgewId  implements java.io.Serializable {
+
+
+     private long bezugspegelid;
+     private long gewaesserid;
+     private BigDecimal km;
+     private String name;
+     private BigDecimal nullpunkt;
+     private String kennung;
+     private BigDecimal einzugsgebiet;
+     private Date inbetrieb;
+     private String fliesscharakter;
+     private BigDecimal laufentwicklung;
+     private BigDecimal mnq;
+     private BigDecimal mq;
+     private BigDecimal mhq;
+     private BigDecimal nnq;
+     private BigDecimal hhq;
+     private Date nnqdatum;
+     private Date hhqdatum;
+     private String jahresreihe;
+     private String bemerkung;
+     private String gewname;
+
+    public BezugspegelgewId() {
+    }
+
+    public BezugspegelgewId(long bezugspegelid, long gewaesserid, BigDecimal km, String name, BigDecimal nullpunkt, String gewname) {
+        this.bezugspegelid = bezugspegelid;
+        this.gewaesserid = gewaesserid;
+        this.km = km;
+        this.name = name;
+        this.nullpunkt = nullpunkt;
+        this.gewname = gewname;
+    }
+    public BezugspegelgewId(long bezugspegelid, long gewaesserid, BigDecimal km, String name, BigDecimal nullpunkt, String kennung, BigDecimal einzugsgebiet, Date inbetrieb, String fliesscharakter, BigDecimal laufentwicklung, BigDecimal mnq, BigDecimal mq, BigDecimal mhq, BigDecimal nnq, BigDecimal hhq, Date nnqdatum, Date hhqdatum, String jahresreihe, String bemerkung, String gewname) {
+       this.bezugspegelid = bezugspegelid;
+       this.gewaesserid = gewaesserid;
+       this.km = km;
+       this.name = name;
+       this.nullpunkt = nullpunkt;
+       this.kennung = kennung;
+       this.einzugsgebiet = einzugsgebiet;
+       this.inbetrieb = inbetrieb;
+       this.fliesscharakter = fliesscharakter;
+       this.laufentwicklung = laufentwicklung;
+       this.mnq = mnq;
+       this.mq = mq;
+       this.mhq = mhq;
+       this.nnq = nnq;
+       this.hhq = hhq;
+       this.nnqdatum = nnqdatum;
+       this.hhqdatum = hhqdatum;
+       this.jahresreihe = jahresreihe;
+       this.bemerkung = bemerkung;
+       this.gewname = gewname;
+    }
+
+
+
+    @Column(name="BEZUGSPEGELID", nullable=false, precision=11, scale=0)
+    public long getBezugspegelid() {
+        return this.bezugspegelid;
+    }
+
+    public void setBezugspegelid(long bezugspegelid) {
+        this.bezugspegelid = bezugspegelid;
+    }
+
+
+    @Column(name="GEWAESSERID", nullable=false, precision=11, scale=0)
+    public long getGewaesserid() {
+        return this.gewaesserid;
+    }
+
+    public void setGewaesserid(long gewaesserid) {
+        this.gewaesserid = gewaesserid;
+    }
+
+
+    @Column(name="KM", nullable=false, precision=8, scale=3)
+    public BigDecimal getKm() {
+        return this.km;
+    }
+
+    public void setKm(BigDecimal km) {
+        this.km = km;
+    }
+
+
+    @Column(name="NAME", nullable=false, length=50)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="NULLPUNKT", nullable=false, precision=8, scale=3)
+    public BigDecimal getNullpunkt() {
+        return this.nullpunkt;
+    }
+
+    public void setNullpunkt(BigDecimal nullpunkt) {
+        this.nullpunkt = nullpunkt;
+    }
+
+
+    @Column(name="KENNUNG", length=16)
+    public String getKennung() {
+        return this.kennung;
+    }
+
+    public void setKennung(String kennung) {
+        this.kennung = kennung;
+    }
+
+
+    @Column(name="EINZUGSGEBIET", precision=10)
+    public BigDecimal getEinzugsgebiet() {
+        return this.einzugsgebiet;
+    }
+
+    public void setEinzugsgebiet(BigDecimal einzugsgebiet) {
+        this.einzugsgebiet = einzugsgebiet;
+    }
+
+
+    @Column(name="INBETRIEB", length=7)
+    public Date getInbetrieb() {
+        return this.inbetrieb;
+    }
+
+    public void setInbetrieb(Date inbetrieb) {
+        this.inbetrieb = inbetrieb;
+    }
+
+
+    @Column(name="FLIESSCHARAKTER", length=3)
+    public String getFliesscharakter() {
+        return this.fliesscharakter;
+    }
+
+    public void setFliesscharakter(String fliesscharakter) {
+        this.fliesscharakter = fliesscharakter;
+    }
+
+
+    @Column(name="LAUFENTWICKLUNG", precision=7, scale=3)
+    public BigDecimal getLaufentwicklung() {
+        return this.laufentwicklung;
+    }
+
+    public void setLaufentwicklung(BigDecimal laufentwicklung) {
+        this.laufentwicklung = laufentwicklung;
+    }
+
+
+    @Column(name="MNQ", precision=8, scale=3)
+    public BigDecimal getMnq() {
+        return this.mnq;
+    }
+
+    public void setMnq(BigDecimal mnq) {
+        this.mnq = mnq;
+    }
+
+
+    @Column(name="MQ", precision=8, scale=3)
+    public BigDecimal getMq() {
+        return this.mq;
+    }
+
+    public void setMq(BigDecimal mq) {
+        this.mq = mq;
+    }
+
+
+    @Column(name="MHQ", precision=8, scale=3)
+    public BigDecimal getMhq() {
+        return this.mhq;
+    }
+
+    public void setMhq(BigDecimal mhq) {
+        this.mhq = mhq;
+    }
+
+
+    @Column(name="NNQ", precision=8, scale=3)
+    public BigDecimal getNnq() {
+        return this.nnq;
+    }
+
+    public void setNnq(BigDecimal nnq) {
+        this.nnq = nnq;
+    }
+
+
+    @Column(name="HHQ", precision=8, scale=3)
+    public BigDecimal getHhq() {
+        return this.hhq;
+    }
+
+    public void setHhq(BigDecimal hhq) {
+        this.hhq = hhq;
+    }
+
+
+    @Column(name="NNQDATUM", length=7)
+    public Date getNnqdatum() {
+        return this.nnqdatum;
+    }
+
+    public void setNnqdatum(Date nnqdatum) {
+        this.nnqdatum = nnqdatum;
+    }
+
+
+    @Column(name="HHQDATUM", length=7)
+    public Date getHhqdatum() {
+        return this.hhqdatum;
+    }
+
+    public void setHhqdatum(Date hhqdatum) {
+        this.hhqdatum = hhqdatum;
+    }
+
+
+    @Column(name="JAHRESREIHE", length=12)
+    public String getJahresreihe() {
+        return this.jahresreihe;
+    }
+
+    public void setJahresreihe(String jahresreihe) {
+        this.jahresreihe = jahresreihe;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="GEWNAME", nullable=false, length=20)
+    public String getGewname() {
+        return this.gewname;
+    }
+
+    public void setGewname(String gewname) {
+        this.gewname = gewname;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof BezugspegelgewId) ) return false;
+         BezugspegelgewId castOther = ( BezugspegelgewId ) other;
+
+         return (this.getBezugspegelid()==castOther.getBezugspegelid())
+ && (this.getGewaesserid()==castOther.getGewaesserid())
+ && ( (this.getKm()==castOther.getKm()) || ( this.getKm()!=null && castOther.getKm()!=null && this.getKm().equals(castOther.getKm()) ) )
+ && ( (this.getName()==castOther.getName()) || ( this.getName()!=null && castOther.getName()!=null && this.getName().equals(castOther.getName()) ) )
+ && ( (this.getNullpunkt()==castOther.getNullpunkt()) || ( this.getNullpunkt()!=null && castOther.getNullpunkt()!=null && this.getNullpunkt().equals(castOther.getNullpunkt()) ) )
+ && ( (this.getKennung()==castOther.getKennung()) || ( this.getKennung()!=null && castOther.getKennung()!=null && this.getKennung().equals(castOther.getKennung()) ) )
+ && ( (this.getEinzugsgebiet()==castOther.getEinzugsgebiet()) || ( this.getEinzugsgebiet()!=null && castOther.getEinzugsgebiet()!=null && this.getEinzugsgebiet().equals(castOther.getEinzugsgebiet()) ) )
+ && ( (this.getInbetrieb()==castOther.getInbetrieb()) || ( this.getInbetrieb()!=null && castOther.getInbetrieb()!=null && this.getInbetrieb().equals(castOther.getInbetrieb()) ) )
+ && ( (this.getFliesscharakter()==castOther.getFliesscharakter()) || ( this.getFliesscharakter()!=null && castOther.getFliesscharakter()!=null && this.getFliesscharakter().equals(castOther.getFliesscharakter()) ) )
+ && ( (this.getLaufentwicklung()==castOther.getLaufentwicklung()) || ( this.getLaufentwicklung()!=null && castOther.getLaufentwicklung()!=null && this.getLaufentwicklung().equals(castOther.getLaufentwicklung()) ) )
+ && ( (this.getMnq()==castOther.getMnq()) || ( this.getMnq()!=null && castOther.getMnq()!=null && this.getMnq().equals(castOther.getMnq()) ) )
+ && ( (this.getMq()==castOther.getMq()) || ( this.getMq()!=null && castOther.getMq()!=null && this.getMq().equals(castOther.getMq()) ) )
+ && ( (this.getMhq()==castOther.getMhq()) || ( this.getMhq()!=null && castOther.getMhq()!=null && this.getMhq().equals(castOther.getMhq()) ) )
+ && ( (this.getNnq()==castOther.getNnq()) || ( this.getNnq()!=null && castOther.getNnq()!=null && this.getNnq().equals(castOther.getNnq()) ) )
+ && ( (this.getHhq()==castOther.getHhq()) || ( this.getHhq()!=null && castOther.getHhq()!=null && this.getHhq().equals(castOther.getHhq()) ) )
+ && ( (this.getNnqdatum()==castOther.getNnqdatum()) || ( this.getNnqdatum()!=null && castOther.getNnqdatum()!=null && this.getNnqdatum().equals(castOther.getNnqdatum()) ) )
+ && ( (this.getHhqdatum()==castOther.getHhqdatum()) || ( this.getHhqdatum()!=null && castOther.getHhqdatum()!=null && this.getHhqdatum().equals(castOther.getHhqdatum()) ) )
+ && ( (this.getJahresreihe()==castOther.getJahresreihe()) || ( this.getJahresreihe()!=null && castOther.getJahresreihe()!=null && this.getJahresreihe().equals(castOther.getJahresreihe()) ) )
+ && ( (this.getBemerkung()==castOther.getBemerkung()) || ( this.getBemerkung()!=null && castOther.getBemerkung()!=null && this.getBemerkung().equals(castOther.getBemerkung()) ) )
+ && ( (this.getGewname()==castOther.getGewname()) || ( this.getGewname()!=null && castOther.getGewname()!=null && this.getGewname().equals(castOther.getGewname()) ) );
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getBezugspegelid();
+         result = 37 * result + (int) this.getGewaesserid();
+         result = 37 * result + ( getKm() == null ? 0 : this.getKm().hashCode() );
+         result = 37 * result + ( getName() == null ? 0 : this.getName().hashCode() );
+         result = 37 * result + ( getNullpunkt() == null ? 0 : this.getNullpunkt().hashCode() );
+         result = 37 * result + ( getKennung() == null ? 0 : this.getKennung().hashCode() );
+         result = 37 * result + ( getEinzugsgebiet() == null ? 0 : this.getEinzugsgebiet().hashCode() );
+         result = 37 * result + ( getInbetrieb() == null ? 0 : this.getInbetrieb().hashCode() );
+         result = 37 * result + ( getFliesscharakter() == null ? 0 : this.getFliesscharakter().hashCode() );
+         result = 37 * result + ( getLaufentwicklung() == null ? 0 : this.getLaufentwicklung().hashCode() );
+         result = 37 * result + ( getMnq() == null ? 0 : this.getMnq().hashCode() );
+         result = 37 * result + ( getMq() == null ? 0 : this.getMq().hashCode() );
+         result = 37 * result + ( getMhq() == null ? 0 : this.getMhq().hashCode() );
+         result = 37 * result + ( getNnq() == null ? 0 : this.getNnq().hashCode() );
+         result = 37 * result + ( getHhq() == null ? 0 : this.getHhq().hashCode() );
+         result = 37 * result + ( getNnqdatum() == null ? 0 : this.getNnqdatum().hashCode() );
+         result = 37 * result + ( getHhqdatum() == null ? 0 : this.getHhqdatum().hashCode() );
+         result = 37 * result + ( getJahresreihe() == null ? 0 : this.getJahresreihe().hashCode() );
+         result = 37 * result + ( getBemerkung() == null ? 0 : this.getBemerkung().hashCode() );
+         result = 37 * result + ( getGewname() == null ? 0 : this.getGewname().hashCode() );
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Bild.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,194 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+/**
+ * Bild generated by hbm2java
+ */
+@Entity
+@Table(name="BILD"
+    ,schema="SEDDB"
+)
+public class Bild  implements java.io.Serializable {
+
+
+     private long bildid;
+     private Zzthema zzthema;
+     private Sohltest sohltest;
+     private int lfdnr;
+     private boolean istdigital;
+     private String pfad;
+     private String standort;
+     private String medium;
+     private String medpfad;
+     private String bemerkung;
+     private String typklein;
+     private String typmittel;
+     private String typgross;
+
+    public Bild() {
+    }
+
+    public Bild(long bildid, Zzthema zzthema, Sohltest sohltest, int lfdnr, boolean istdigital) {
+        this.bildid = bildid;
+        this.zzthema = zzthema;
+        this.sohltest = sohltest;
+        this.lfdnr = lfdnr;
+        this.istdigital = istdigital;
+    }
+    public Bild(long bildid, Zzthema zzthema, Sohltest sohltest, int lfdnr, boolean istdigital, String pfad, String standort, String medium, String medpfad, String bemerkung, String typklein, String typmittel, String typgross) {
+       this.bildid = bildid;
+       this.zzthema = zzthema;
+       this.sohltest = sohltest;
+       this.lfdnr = lfdnr;
+       this.istdigital = istdigital;
+       this.pfad = pfad;
+       this.standort = standort;
+       this.medium = medium;
+       this.medpfad = medpfad;
+       this.bemerkung = bemerkung;
+       this.typklein = typklein;
+       this.typmittel = typmittel;
+       this.typgross = typgross;
+    }
+
+     @Id
+
+
+    @Column(name="BILDID", unique=true, nullable=false, precision=11, scale=0)
+    public long getBildid() {
+        return this.bildid;
+    }
+
+    public void setBildid(long bildid) {
+        this.bildid = bildid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="THEMAID", nullable=false)
+    public Zzthema getZzthema() {
+        return this.zzthema;
+    }
+
+    public void setZzthema(Zzthema zzthema) {
+        this.zzthema = zzthema;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="SOHLTESTID", nullable=false)
+    public Sohltest getSohltest() {
+        return this.sohltest;
+    }
+
+    public void setSohltest(Sohltest sohltest) {
+        this.sohltest = sohltest;
+    }
+
+
+    @Column(name="LFDNR", nullable=false, precision=5, scale=0)
+    public int getLfdnr() {
+        return this.lfdnr;
+    }
+
+    public void setLfdnr(int lfdnr) {
+        this.lfdnr = lfdnr;
+    }
+
+
+    @Column(name="ISTDIGITAL", nullable=false, precision=1, scale=0)
+    public boolean isIstdigital() {
+        return this.istdigital;
+    }
+
+    public void setIstdigital(boolean istdigital) {
+        this.istdigital = istdigital;
+    }
+
+
+    @Column(name="PFAD", length=512)
+    public String getPfad() {
+        return this.pfad;
+    }
+
+    public void setPfad(String pfad) {
+        this.pfad = pfad;
+    }
+
+
+    @Column(name="STANDORT", length=50)
+    public String getStandort() {
+        return this.standort;
+    }
+
+    public void setStandort(String standort) {
+        this.standort = standort;
+    }
+
+
+    @Column(name="MEDIUM", length=50)
+    public String getMedium() {
+        return this.medium;
+    }
+
+    public void setMedium(String medium) {
+        this.medium = medium;
+    }
+
+
+    @Column(name="MEDPFAD", length=50)
+    public String getMedpfad() {
+        return this.medpfad;
+    }
+
+    public void setMedpfad(String medpfad) {
+        this.medpfad = medpfad;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="TYPKLEIN", length=8)
+    public String getTypklein() {
+        return this.typklein;
+    }
+
+    public void setTypklein(String typklein) {
+        this.typklein = typklein;
+    }
+
+
+    @Column(name="TYPMITTEL", length=8)
+    public String getTypmittel() {
+        return this.typmittel;
+    }
+
+    public void setTypmittel(String typmittel) {
+        this.typmittel = typmittel;
+    }
+
+
+    @Column(name="TYPGROSS", length=8)
+    public String getTypgross() {
+        return this.typgross;
+    }
+
+    public void setTypgross(String typgross) {
+        this.typgross = typgross;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Gewaesser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,139 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * Gewaesser generated by hbm2java
+ */
+@Entity
+@Table(name="GEWAESSER"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames="NAME")
+)
+public class Gewaesser  implements java.io.Serializable {
+
+
+     private long gewaesserid;
+     private String name;
+     private String kennung;
+     private BigDecimal laenge;
+     private BigDecimal einzugsgebiet;
+     private String bemerkung;
+     private Set<Bezugspegel> bezugspegels = new HashSet<Bezugspegel>(0);
+     private Set<Station> stations = new HashSet<Station>(0);
+
+    public Gewaesser() {
+    }
+
+    public Gewaesser(long gewaesserid, String name) {
+        this.gewaesserid = gewaesserid;
+        this.name = name;
+    }
+    public Gewaesser(long gewaesserid, String name, String kennung, BigDecimal laenge, BigDecimal einzugsgebiet, String bemerkung, Set<Bezugspegel> bezugspegels, Set<Station> stations) {
+       this.gewaesserid = gewaesserid;
+       this.name = name;
+       this.kennung = kennung;
+       this.laenge = laenge;
+       this.einzugsgebiet = einzugsgebiet;
+       this.bemerkung = bemerkung;
+       this.bezugspegels = bezugspegels;
+       this.stations = stations;
+    }
+
+     @Id
+
+
+    @Column(name="GEWAESSERID", unique=true, nullable=false, precision=11, scale=0)
+    public long getGewaesserid() {
+        return this.gewaesserid;
+    }
+
+    public void setGewaesserid(long gewaesserid) {
+        this.gewaesserid = gewaesserid;
+    }
+
+
+    @Column(name="NAME", unique=true, nullable=false, length=20)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="KENNUNG", length=11)
+    public String getKennung() {
+        return this.kennung;
+    }
+
+    public void setKennung(String kennung) {
+        this.kennung = kennung;
+    }
+
+
+    @Column(name="LAENGE", precision=7, scale=3)
+    public BigDecimal getLaenge() {
+        return this.laenge;
+    }
+
+    public void setLaenge(BigDecimal laenge) {
+        this.laenge = laenge;
+    }
+
+
+    @Column(name="EINZUGSGEBIET", precision=10)
+    public BigDecimal getEinzugsgebiet() {
+        return this.einzugsgebiet;
+    }
+
+    public void setEinzugsgebiet(BigDecimal einzugsgebiet) {
+        this.einzugsgebiet = einzugsgebiet;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="gewaesser")
+    public Set<Bezugspegel> getBezugspegels() {
+        return this.bezugspegels;
+    }
+
+    public void setBezugspegels(Set<Bezugspegel> bezugspegels) {
+        this.bezugspegels = bezugspegels;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="gewaesser")
+    public Set<Station> getStations() {
+        return this.stations;
+    }
+
+    public void setStations(Set<Station> stations) {
+        this.stations = stations;
+    }
+
+
+
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Gfaenger.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,125 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * Gfaenger generated by hbm2java
+ */
+@Entity
+@Table(name="GFAENGER"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames="NAME")
+)
+public class Gfaenger  implements java.io.Serializable {
+
+
+     private long gfaengerid;
+     private boolean istaktiv;
+     private String name;
+     private BigDecimal breite;
+     private BigDecimal maschenweite;
+     private String bemerkung;
+     private Set<Messung> messungs = new HashSet<Messung>(0);
+
+    public Gfaenger() {
+    }
+
+    public Gfaenger(long gfaengerid, boolean istaktiv, String name, BigDecimal breite, BigDecimal maschenweite) {
+        this.gfaengerid = gfaengerid;
+        this.istaktiv = istaktiv;
+        this.name = name;
+        this.breite = breite;
+        this.maschenweite = maschenweite;
+    }
+    public Gfaenger(long gfaengerid, boolean istaktiv, String name, BigDecimal breite, BigDecimal maschenweite, String bemerkung, Set<Messung> messungs) {
+       this.gfaengerid = gfaengerid;
+       this.istaktiv = istaktiv;
+       this.name = name;
+       this.breite = breite;
+       this.maschenweite = maschenweite;
+       this.bemerkung = bemerkung;
+       this.messungs = messungs;
+    }
+
+     @Id
+
+
+    @Column(name="GFAENGERID", unique=true, nullable=false, precision=11, scale=0)
+    public long getGfaengerid() {
+        return this.gfaengerid;
+    }
+
+    public void setGfaengerid(long gfaengerid) {
+        this.gfaengerid = gfaengerid;
+    }
+
+
+    @Column(name="ISTAKTIV", nullable=false, precision=1, scale=0)
+    public boolean isIstaktiv() {
+        return this.istaktiv;
+    }
+
+    public void setIstaktiv(boolean istaktiv) {
+        this.istaktiv = istaktiv;
+    }
+
+
+    @Column(name="NAME", unique=true, nullable=false, length=30)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="BREITE", nullable=false, precision=6, scale=3)
+    public BigDecimal getBreite() {
+        return this.breite;
+    }
+
+    public void setBreite(BigDecimal breite) {
+        this.breite = breite;
+    }
+
+
+    @Column(name="MASCHENWEITE", nullable=false, precision=7, scale=4)
+    public BigDecimal getMaschenweite() {
+        return this.maschenweite;
+    }
+
+    public void setMaschenweite(BigDecimal maschenweite) {
+        this.maschenweite = maschenweite;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="gfaenger")
+    public Set<Messung> getMessungs() {
+        return this.messungs;
+    }
+
+    public void setMessungs(Set<Messung> messungs) {
+        this.messungs = messungs;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Glotlinks.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,72 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Glotlinks generated by hbm2java
+ */
+@Entity
+@Table(name="GLOTLINKS"
+    ,schema="SEDDB"
+)
+public class Glotlinks  implements java.io.Serializable {
+
+
+     private GlotlinksId id;
+
+    public Glotlinks() {
+    }
+
+    public Glotlinks(GlotlinksId id) {
+       this.id = id;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="glotrechteid", column=@Column(name="GLOTRECHTEID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="messungid", column=@Column(name="MESSUNGID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="uferabst", column=@Column(name="UFERABST", nullable=false, precision=8, scale=3) ),
+        @AttributeOverride(name="tgeschiebe", column=@Column(name="TGESCHIEBE", precision=8, scale=3) ),
+        @AttributeOverride(name="dm", column=@Column(name="DM", precision=7, scale=4) ),
+        @AttributeOverride(name="sk", column=@Column(name="SK", precision=8, scale=3) ),
+        @AttributeOverride(name="so", column=@Column(name="SO", precision=8, scale=3) ),
+        @AttributeOverride(name="u", column=@Column(name="U", precision=8, scale=3) ),
+        @AttributeOverride(name="d90", column=@Column(name="D90", precision=7, scale=4) ),
+        @AttributeOverride(name="d84", column=@Column(name="D84", precision=7, scale=4) ),
+        @AttributeOverride(name="d80", column=@Column(name="D80", precision=7, scale=4) ),
+        @AttributeOverride(name="d75", column=@Column(name="D75", precision=7, scale=4) ),
+        @AttributeOverride(name="d70", column=@Column(name="D70", precision=7, scale=4) ),
+        @AttributeOverride(name="d60", column=@Column(name="D60", precision=7, scale=4) ),
+        @AttributeOverride(name="d50", column=@Column(name="D50", precision=7, scale=4) ),
+        @AttributeOverride(name="d40", column=@Column(name="D40", precision=7, scale=4) ),
+        @AttributeOverride(name="d30", column=@Column(name="D30", precision=7, scale=4) ),
+        @AttributeOverride(name="d25", column=@Column(name="D25", precision=7, scale=4) ),
+        @AttributeOverride(name="d20", column=@Column(name="D20", precision=7, scale=4) ),
+        @AttributeOverride(name="d16", column=@Column(name="D16", precision=7, scale=4) ),
+        @AttributeOverride(name="d10", column=@Column(name="D10", precision=7, scale=4) ),
+        @AttributeOverride(name="dmin", column=@Column(name="DMIN", precision=7, scale=4) ),
+        @AttributeOverride(name="durchdmin", column=@Column(name="DURCHDMIN", precision=6, scale=3) ),
+        @AttributeOverride(name="dmax", column=@Column(name="DMAX", precision=7, scale=4) ),
+        @AttributeOverride(name="durchdmax", column=@Column(name="DURCHDMAX", precision=6, scale=3) ),
+        @AttributeOverride(name="stdabw", column=@Column(name="STDABW", precision=8, scale=3) ),
+        @AttributeOverride(name="stdfehler", column=@Column(name="STDFEHLER", precision=8, scale=3) ),
+        @AttributeOverride(name="bemerkung", column=@Column(name="BEMERKUNG", length=240) ),
+        @AttributeOverride(name="uferablinks", column=@Column(name="UFERABLINKS", precision=8, scale=3) ),
+        @AttributeOverride(name="linksabst", column=@Column(name="LINKSABST", precision=22, scale=0) ) } )
+    public GlotlinksId getId() {
+        return this.id;
+    }
+
+    public void setId(GlotlinksId id) {
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/GlotlinksId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,464 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * GlotlinksId generated by hbm2java
+ */
+@Embeddable
+public class GlotlinksId  implements java.io.Serializable {
+
+
+     private long glotrechteid;
+     private long messungid;
+     private BigDecimal uferabst;
+     private BigDecimal tgeschiebe;
+     private BigDecimal dm;
+     private BigDecimal sk;
+     private BigDecimal so;
+     private BigDecimal u;
+     private BigDecimal d90;
+     private BigDecimal d84;
+     private BigDecimal d80;
+     private BigDecimal d75;
+     private BigDecimal d70;
+     private BigDecimal d60;
+     private BigDecimal d50;
+     private BigDecimal d40;
+     private BigDecimal d30;
+     private BigDecimal d25;
+     private BigDecimal d20;
+     private BigDecimal d16;
+     private BigDecimal d10;
+     private BigDecimal dmin;
+     private BigDecimal durchdmin;
+     private BigDecimal dmax;
+     private BigDecimal durchdmax;
+     private BigDecimal stdabw;
+     private BigDecimal stdfehler;
+     private String bemerkung;
+     private BigDecimal uferablinks;
+     private BigDecimal linksabst;
+
+    public GlotlinksId() {
+    }
+
+
+    public GlotlinksId(long glotrechteid, long messungid, BigDecimal uferabst) {
+        this.glotrechteid = glotrechteid;
+        this.messungid = messungid;
+        this.uferabst = uferabst;
+    }
+    public GlotlinksId(long glotrechteid, long messungid, BigDecimal uferabst, BigDecimal tgeschiebe, BigDecimal dm, BigDecimal sk, BigDecimal so, BigDecimal u, BigDecimal d90, BigDecimal d84, BigDecimal d80, BigDecimal d75, BigDecimal d70, BigDecimal d60, BigDecimal d50, BigDecimal d40, BigDecimal d30, BigDecimal d25, BigDecimal d20, BigDecimal d16, BigDecimal d10, BigDecimal dmin, BigDecimal durchdmin, BigDecimal dmax, BigDecimal durchdmax, BigDecimal stdabw, BigDecimal stdfehler, String bemerkung, BigDecimal uferablinks, BigDecimal linksabst) {
+       this.glotrechteid = glotrechteid;
+       this.messungid = messungid;
+       this.uferabst = uferabst;
+       this.tgeschiebe = tgeschiebe;
+       this.dm = dm;
+       this.sk = sk;
+       this.so = so;
+       this.u = u;
+       this.d90 = d90;
+       this.d84 = d84;
+       this.d80 = d80;
+       this.d75 = d75;
+       this.d70 = d70;
+       this.d60 = d60;
+       this.d50 = d50;
+       this.d40 = d40;
+       this.d30 = d30;
+       this.d25 = d25;
+       this.d20 = d20;
+       this.d16 = d16;
+       this.d10 = d10;
+       this.dmin = dmin;
+       this.durchdmin = durchdmin;
+       this.dmax = dmax;
+       this.durchdmax = durchdmax;
+       this.stdabw = stdabw;
+       this.stdfehler = stdfehler;
+       this.bemerkung = bemerkung;
+       this.uferablinks = uferablinks;
+       this.linksabst = linksabst;
+    }
+
+
+
+    @Column(name="GLOTRECHTEID", nullable=false, precision=11, scale=0)
+    public long getGlotrechteid() {
+        return this.glotrechteid;
+    }
+
+    public void setGlotrechteid(long glotrechteid) {
+        this.glotrechteid = glotrechteid;
+    }
+
+
+    @Column(name="MESSUNGID", nullable=false, precision=11, scale=0)
+    public long getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(long messungid) {
+        this.messungid = messungid;
+    }
+
+
+    @Column(name="UFERABST", nullable=false, precision=8, scale=3)
+    public BigDecimal getUferabst() {
+        return this.uferabst;
+    }
+
+    public void setUferabst(BigDecimal uferabst) {
+        this.uferabst = uferabst;
+    }
+
+
+    @Column(name="TGESCHIEBE", precision=8, scale=3)
+    public BigDecimal getTgeschiebe() {
+        return this.tgeschiebe;
+    }
+
+    public void setTgeschiebe(BigDecimal tgeschiebe) {
+        this.tgeschiebe = tgeschiebe;
+    }
+
+
+    @Column(name="DM", precision=7, scale=4)
+    public BigDecimal getDm() {
+        return this.dm;
+    }
+
+    public void setDm(BigDecimal dm) {
+        this.dm = dm;
+    }
+
+
+    @Column(name="SK", precision=8, scale=3)
+    public BigDecimal getSk() {
+        return this.sk;
+    }
+
+    public void setSk(BigDecimal sk) {
+        this.sk = sk;
+    }
+
+
+    @Column(name="SO", precision=8, scale=3)
+    public BigDecimal getSo() {
+        return this.so;
+    }
+
+    public void setSo(BigDecimal so) {
+        this.so = so;
+    }
+
+
+    @Column(name="U", precision=8, scale=3)
+    public BigDecimal getU() {
+        return this.u;
+    }
+
+    public void setU(BigDecimal u) {
+        this.u = u;
+    }
+
+
+    @Column(name="D90", precision=7, scale=4)
+    public BigDecimal getD90() {
+        return this.d90;
+    }
+
+    public void setD90(BigDecimal d90) {
+        this.d90 = d90;
+    }
+
+
+    @Column(name="D84", precision=7, scale=4)
+    public BigDecimal getD84() {
+        return this.d84;
+    }
+
+    public void setD84(BigDecimal d84) {
+        this.d84 = d84;
+    }
+
+
+    @Column(name="D80", precision=7, scale=4)
+    public BigDecimal getD80() {
+        return this.d80;
+    }
+
+    public void setD80(BigDecimal d80) {
+        this.d80 = d80;
+    }
+
+
+    @Column(name="D75", precision=7, scale=4)
+    public BigDecimal getD75() {
+        return this.d75;
+    }
+
+    public void setD75(BigDecimal d75) {
+        this.d75 = d75;
+    }
+
+
+    @Column(name="D70", precision=7, scale=4)
+    public BigDecimal getD70() {
+        return this.d70;
+    }
+
+    public void setD70(BigDecimal d70) {
+        this.d70 = d70;
+    }
+
+
+    @Column(name="D60", precision=7, scale=4)
+    public BigDecimal getD60() {
+        return this.d60;
+    }
+
+    public void setD60(BigDecimal d60) {
+        this.d60 = d60;
+    }
+
+
+    @Column(name="D50", precision=7, scale=4)
+    public BigDecimal getD50() {
+        return this.d50;
+    }
+
+    public void setD50(BigDecimal d50) {
+        this.d50 = d50;
+    }
+
+
+    @Column(name="D40", precision=7, scale=4)
+    public BigDecimal getD40() {
+        return this.d40;
+    }
+
+    public void setD40(BigDecimal d40) {
+        this.d40 = d40;
+    }
+
+
+    @Column(name="D30", precision=7, scale=4)
+    public BigDecimal getD30() {
+        return this.d30;
+    }
+
+    public void setD30(BigDecimal d30) {
+        this.d30 = d30;
+    }
+
+
+    @Column(name="D25", precision=7, scale=4)
+    public BigDecimal getD25() {
+        return this.d25;
+    }
+
+    public void setD25(BigDecimal d25) {
+        this.d25 = d25;
+    }
+
+
+    @Column(name="D20", precision=7, scale=4)
+    public BigDecimal getD20() {
+        return this.d20;
+    }
+
+    public void setD20(BigDecimal d20) {
+        this.d20 = d20;
+    }
+
+
+    @Column(name="D16", precision=7, scale=4)
+    public BigDecimal getD16() {
+        return this.d16;
+    }
+
+    public void setD16(BigDecimal d16) {
+        this.d16 = d16;
+    }
+
+
+    @Column(name="D10", precision=7, scale=4)
+    public BigDecimal getD10() {
+        return this.d10;
+    }
+
+    public void setD10(BigDecimal d10) {
+        this.d10 = d10;
+    }
+
+
+    @Column(name="DMIN", precision=7, scale=4)
+    public BigDecimal getDmin() {
+        return this.dmin;
+    }
+
+    public void setDmin(BigDecimal dmin) {
+        this.dmin = dmin;
+    }
+
+
+    @Column(name="DURCHDMIN", precision=6, scale=3)
+    public BigDecimal getDurchdmin() {
+        return this.durchdmin;
+    }
+
+    public void setDurchdmin(BigDecimal durchdmin) {
+        this.durchdmin = durchdmin;
+    }
+
+
+    @Column(name="DMAX", precision=7, scale=4)
+    public BigDecimal getDmax() {
+        return this.dmax;
+    }
+
+    public void setDmax(BigDecimal dmax) {
+        this.dmax = dmax;
+    }
+
+
+    @Column(name="DURCHDMAX", precision=6, scale=3)
+    public BigDecimal getDurchdmax() {
+        return this.durchdmax;
+    }
+
+    public void setDurchdmax(BigDecimal durchdmax) {
+        this.durchdmax = durchdmax;
+    }
+
+
+    @Column(name="STDABW", precision=8, scale=3)
+    public BigDecimal getStdabw() {
+        return this.stdabw;
+    }
+
+    public void setStdabw(BigDecimal stdabw) {
+        this.stdabw = stdabw;
+    }
+
+
+    @Column(name="STDFEHLER", precision=8, scale=3)
+    public BigDecimal getStdfehler() {
+        return this.stdfehler;
+    }
+
+    public void setStdfehler(BigDecimal stdfehler) {
+        this.stdfehler = stdfehler;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="UFERABLINKS", precision=8, scale=3)
+    public BigDecimal getUferablinks() {
+        return this.uferablinks;
+    }
+
+    public void setUferablinks(BigDecimal uferablinks) {
+        this.uferablinks = uferablinks;
+    }
+
+
+    @Column(name="LINKSABST", precision=22, scale=0)
+    public BigDecimal getLinksabst() {
+        return this.linksabst;
+    }
+
+    public void setLinksabst(BigDecimal linksabst) {
+        this.linksabst = linksabst;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof GlotlinksId) ) return false;
+         GlotlinksId castOther = ( GlotlinksId ) other;
+
+         return (this.getGlotrechteid()==castOther.getGlotrechteid())
+ && (this.getMessungid()==castOther.getMessungid())
+ && ( (this.getUferabst()==castOther.getUferabst()) || ( this.getUferabst()!=null && castOther.getUferabst()!=null && this.getUferabst().equals(castOther.getUferabst()) ) )
+ && ( (this.getTgeschiebe()==castOther.getTgeschiebe()) || ( this.getTgeschiebe()!=null && castOther.getTgeschiebe()!=null && this.getTgeschiebe().equals(castOther.getTgeschiebe()) ) )
+ && ( (this.getDm()==castOther.getDm()) || ( this.getDm()!=null && castOther.getDm()!=null && this.getDm().equals(castOther.getDm()) ) )
+ && ( (this.getSk()==castOther.getSk()) || ( this.getSk()!=null && castOther.getSk()!=null && this.getSk().equals(castOther.getSk()) ) )
+ && ( (this.getSo()==castOther.getSo()) || ( this.getSo()!=null && castOther.getSo()!=null && this.getSo().equals(castOther.getSo()) ) )
+ && ( (this.getU()==castOther.getU()) || ( this.getU()!=null && castOther.getU()!=null && this.getU().equals(castOther.getU()) ) )
+ && ( (this.getD90()==castOther.getD90()) || ( this.getD90()!=null && castOther.getD90()!=null && this.getD90().equals(castOther.getD90()) ) )
+ && ( (this.getD84()==castOther.getD84()) || ( this.getD84()!=null && castOther.getD84()!=null && this.getD84().equals(castOther.getD84()) ) )
+ && ( (this.getD80()==castOther.getD80()) || ( this.getD80()!=null && castOther.getD80()!=null && this.getD80().equals(castOther.getD80()) ) )
+ && ( (this.getD75()==castOther.getD75()) || ( this.getD75()!=null && castOther.getD75()!=null && this.getD75().equals(castOther.getD75()) ) )
+ && ( (this.getD70()==castOther.getD70()) || ( this.getD70()!=null && castOther.getD70()!=null && this.getD70().equals(castOther.getD70()) ) )
+ && ( (this.getD60()==castOther.getD60()) || ( this.getD60()!=null && castOther.getD60()!=null && this.getD60().equals(castOther.getD60()) ) )
+ && ( (this.getD50()==castOther.getD50()) || ( this.getD50()!=null && castOther.getD50()!=null && this.getD50().equals(castOther.getD50()) ) )
+ && ( (this.getD40()==castOther.getD40()) || ( this.getD40()!=null && castOther.getD40()!=null && this.getD40().equals(castOther.getD40()) ) )
+ && ( (this.getD30()==castOther.getD30()) || ( this.getD30()!=null && castOther.getD30()!=null && this.getD30().equals(castOther.getD30()) ) )
+ && ( (this.getD25()==castOther.getD25()) || ( this.getD25()!=null && castOther.getD25()!=null && this.getD25().equals(castOther.getD25()) ) )
+ && ( (this.getD20()==castOther.getD20()) || ( this.getD20()!=null && castOther.getD20()!=null && this.getD20().equals(castOther.getD20()) ) )
+ && ( (this.getD16()==castOther.getD16()) || ( this.getD16()!=null && castOther.getD16()!=null && this.getD16().equals(castOther.getD16()) ) )
+ && ( (this.getD10()==castOther.getD10()) || ( this.getD10()!=null && castOther.getD10()!=null && this.getD10().equals(castOther.getD10()) ) )
+ && ( (this.getDmin()==castOther.getDmin()) || ( this.getDmin()!=null && castOther.getDmin()!=null && this.getDmin().equals(castOther.getDmin()) ) )
+ && ( (this.getDurchdmin()==castOther.getDurchdmin()) || ( this.getDurchdmin()!=null && castOther.getDurchdmin()!=null && this.getDurchdmin().equals(castOther.getDurchdmin()) ) )
+ && ( (this.getDmax()==castOther.getDmax()) || ( this.getDmax()!=null && castOther.getDmax()!=null && this.getDmax().equals(castOther.getDmax()) ) )
+ && ( (this.getDurchdmax()==castOther.getDurchdmax()) || ( this.getDurchdmax()!=null && castOther.getDurchdmax()!=null && this.getDurchdmax().equals(castOther.getDurchdmax()) ) )
+ && ( (this.getStdabw()==castOther.getStdabw()) || ( this.getStdabw()!=null && castOther.getStdabw()!=null && this.getStdabw().equals(castOther.getStdabw()) ) )
+ && ( (this.getStdfehler()==castOther.getStdfehler()) || ( this.getStdfehler()!=null && castOther.getStdfehler()!=null && this.getStdfehler().equals(castOther.getStdfehler()) ) )
+ && ( (this.getBemerkung()==castOther.getBemerkung()) || ( this.getBemerkung()!=null && castOther.getBemerkung()!=null && this.getBemerkung().equals(castOther.getBemerkung()) ) )
+ && ( (this.getUferablinks()==castOther.getUferablinks()) || ( this.getUferablinks()!=null && castOther.getUferablinks()!=null && this.getUferablinks().equals(castOther.getUferablinks()) ) )
+ && ( (this.getLinksabst()==castOther.getLinksabst()) || ( this.getLinksabst()!=null && castOther.getLinksabst()!=null && this.getLinksabst().equals(castOther.getLinksabst()) ) );
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getGlotrechteid();
+         result = 37 * result + (int) this.getMessungid();
+         result = 37 * result + ( getUferabst() == null ? 0 : this.getUferabst().hashCode() );
+         result = 37 * result + ( getTgeschiebe() == null ? 0 : this.getTgeschiebe().hashCode() );
+         result = 37 * result + ( getDm() == null ? 0 : this.getDm().hashCode() );
+         result = 37 * result + ( getSk() == null ? 0 : this.getSk().hashCode() );
+         result = 37 * result + ( getSo() == null ? 0 : this.getSo().hashCode() );
+         result = 37 * result + ( getU() == null ? 0 : this.getU().hashCode() );
+         result = 37 * result + ( getD90() == null ? 0 : this.getD90().hashCode() );
+         result = 37 * result + ( getD84() == null ? 0 : this.getD84().hashCode() );
+         result = 37 * result + ( getD80() == null ? 0 : this.getD80().hashCode() );
+         result = 37 * result + ( getD75() == null ? 0 : this.getD75().hashCode() );
+         result = 37 * result + ( getD70() == null ? 0 : this.getD70().hashCode() );
+         result = 37 * result + ( getD60() == null ? 0 : this.getD60().hashCode() );
+         result = 37 * result + ( getD50() == null ? 0 : this.getD50().hashCode() );
+         result = 37 * result + ( getD40() == null ? 0 : this.getD40().hashCode() );
+         result = 37 * result + ( getD30() == null ? 0 : this.getD30().hashCode() );
+         result = 37 * result + ( getD25() == null ? 0 : this.getD25().hashCode() );
+         result = 37 * result + ( getD20() == null ? 0 : this.getD20().hashCode() );
+         result = 37 * result + ( getD16() == null ? 0 : this.getD16().hashCode() );
+         result = 37 * result + ( getD10() == null ? 0 : this.getD10().hashCode() );
+         result = 37 * result + ( getDmin() == null ? 0 : this.getDmin().hashCode() );
+         result = 37 * result + ( getDurchdmin() == null ? 0 : this.getDurchdmin().hashCode() );
+         result = 37 * result + ( getDmax() == null ? 0 : this.getDmax().hashCode() );
+         result = 37 * result + ( getDurchdmax() == null ? 0 : this.getDurchdmax().hashCode() );
+         result = 37 * result + ( getStdabw() == null ? 0 : this.getStdabw().hashCode() );
+         result = 37 * result + ( getStdfehler() == null ? 0 : this.getStdfehler().hashCode() );
+         result = 37 * result + ( getBemerkung() == null ? 0 : this.getBemerkung().hashCode() );
+         result = 37 * result + ( getUferablinks() == null ? 0 : this.getUferablinks().hashCode() );
+         result = 37 * result + ( getLinksabst() == null ? 0 : this.getLinksabst().hashCode() );
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Glotrechte.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,412 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+/**
+ * Glotrechte generated by hbm2java
+ */
+@Entity
+@Table(name="GLOTRECHTE"
+    ,schema="SEDDB"
+)
+public class Glotrechte  implements java.io.Serializable {
+
+
+     private long glotrechteid;
+     private Messung messung;
+     private BigDecimal uferabst;
+     private BigDecimal tgeschiebe;
+     private BigDecimal dm;
+     private BigDecimal sk;
+     private BigDecimal so;
+     private BigDecimal u;
+     private BigDecimal d90;
+     private BigDecimal d84;
+     private BigDecimal d80;
+     private BigDecimal d75;
+     private BigDecimal d70;
+     private BigDecimal d60;
+     private BigDecimal d50;
+     private BigDecimal d40;
+     private BigDecimal d30;
+     private BigDecimal d25;
+     private BigDecimal d20;
+     private BigDecimal d16;
+     private BigDecimal d10;
+     private BigDecimal dmin;
+     private BigDecimal durchdmin;
+     private BigDecimal dmax;
+     private BigDecimal durchdmax;
+     private BigDecimal stdabw;
+     private BigDecimal stdfehler;
+     private String bemerkung;
+     private BigDecimal uferablinks;
+     private Gsiebung gsiebung;
+     private Set<Gprobe> gprobes = new HashSet<Gprobe>(0);
+
+    public Glotrechte() {
+    }
+
+
+    public Glotrechte(long glotrechteid, Messung messung, BigDecimal uferabst) {
+        this.glotrechteid = glotrechteid;
+        this.messung = messung;
+        this.uferabst = uferabst;
+    }
+    public Glotrechte(long glotrechteid, Messung messung, BigDecimal uferabst, BigDecimal tgeschiebe, BigDecimal dm, BigDecimal sk, BigDecimal so, BigDecimal u, BigDecimal d90, BigDecimal d84, BigDecimal d80, BigDecimal d75, BigDecimal d70, BigDecimal d60, BigDecimal d50, BigDecimal d40, BigDecimal d30, BigDecimal d25, BigDecimal d20, BigDecimal d16, BigDecimal d10, BigDecimal dmin, BigDecimal durchdmin, BigDecimal dmax, BigDecimal durchdmax, BigDecimal stdabw, BigDecimal stdfehler, String bemerkung, BigDecimal uferablinks, Gsiebung gsiebung, Set<Gprobe> gprobes) {
+       this.glotrechteid = glotrechteid;
+       this.messung = messung;
+       this.uferabst = uferabst;
+       this.tgeschiebe = tgeschiebe;
+       this.dm = dm;
+       this.sk = sk;
+       this.so = so;
+       this.u = u;
+       this.d90 = d90;
+       this.d84 = d84;
+       this.d80 = d80;
+       this.d75 = d75;
+       this.d70 = d70;
+       this.d60 = d60;
+       this.d50 = d50;
+       this.d40 = d40;
+       this.d30 = d30;
+       this.d25 = d25;
+       this.d20 = d20;
+       this.d16 = d16;
+       this.d10 = d10;
+       this.dmin = dmin;
+       this.durchdmin = durchdmin;
+       this.dmax = dmax;
+       this.durchdmax = durchdmax;
+       this.stdabw = stdabw;
+       this.stdfehler = stdfehler;
+       this.bemerkung = bemerkung;
+       this.uferablinks = uferablinks;
+       this.gsiebung = gsiebung;
+       this.gprobes = gprobes;
+    }
+
+     @Id
+
+
+    @Column(name="GLOTRECHTEID", unique=true, nullable=false, precision=11, scale=0)
+    public long getGlotrechteid() {
+        return this.glotrechteid;
+    }
+
+    public void setGlotrechteid(long glotrechteid) {
+        this.glotrechteid = glotrechteid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="MESSUNGID", nullable=false)
+    public Messung getMessung() {
+        return this.messung;
+    }
+
+    public void setMessung(Messung messung) {
+        this.messung = messung;
+    }
+
+
+    @Column(name="UFERABST", nullable=false, precision=8, scale=3)
+    public BigDecimal getUferabst() {
+        return this.uferabst;
+    }
+
+    public void setUferabst(BigDecimal uferabst) {
+        this.uferabst = uferabst;
+    }
+
+
+    @Column(name="TGESCHIEBE", precision=8, scale=3)
+    public BigDecimal getTgeschiebe() {
+        return this.tgeschiebe;
+    }
+
+    public void setTgeschiebe(BigDecimal tgeschiebe) {
+        this.tgeschiebe = tgeschiebe;
+    }
+
+
+    @Column(name="DM", precision=7, scale=4)
+    public BigDecimal getDm() {
+        return this.dm;
+    }
+
+    public void setDm(BigDecimal dm) {
+        this.dm = dm;
+    }
+
+
+    @Column(name="SK", precision=8, scale=3)
+    public BigDecimal getSk() {
+        return this.sk;
+    }
+
+    public void setSk(BigDecimal sk) {
+        this.sk = sk;
+    }
+
+
+    @Column(name="SO", precision=8, scale=3)
+    public BigDecimal getSo() {
+        return this.so;
+    }
+
+    public void setSo(BigDecimal so) {
+        this.so = so;
+    }
+
+
+    @Column(name="U", precision=8, scale=3)
+    public BigDecimal getU() {
+        return this.u;
+    }
+
+    public void setU(BigDecimal u) {
+        this.u = u;
+    }
+
+
+    @Column(name="D90", precision=7, scale=4)
+    public BigDecimal getD90() {
+        return this.d90;
+    }
+
+    public void setD90(BigDecimal d90) {
+        this.d90 = d90;
+    }
+
+
+    @Column(name="D84", precision=7, scale=4)
+    public BigDecimal getD84() {
+        return this.d84;
+    }
+
+    public void setD84(BigDecimal d84) {
+        this.d84 = d84;
+    }
+
+
+    @Column(name="D80", precision=7, scale=4)
+    public BigDecimal getD80() {
+        return this.d80;
+    }
+
+    public void setD80(BigDecimal d80) {
+        this.d80 = d80;
+    }
+
+
+    @Column(name="D75", precision=7, scale=4)
+    public BigDecimal getD75() {
+        return this.d75;
+    }
+
+    public void setD75(BigDecimal d75) {
+        this.d75 = d75;
+    }
+
+
+    @Column(name="D70", precision=7, scale=4)
+    public BigDecimal getD70() {
+        return this.d70;
+    }
+
+    public void setD70(BigDecimal d70) {
+        this.d70 = d70;
+    }
+
+
+    @Column(name="D60", precision=7, scale=4)
+    public BigDecimal getD60() {
+        return this.d60;
+    }
+
+    public void setD60(BigDecimal d60) {
+        this.d60 = d60;
+    }
+
+
+    @Column(name="D50", precision=7, scale=4)
+    public BigDecimal getD50() {
+        return this.d50;
+    }
+
+    public void setD50(BigDecimal d50) {
+        this.d50 = d50;
+    }
+
+
+    @Column(name="D40", precision=7, scale=4)
+    public BigDecimal getD40() {
+        return this.d40;
+    }
+
+    public void setD40(BigDecimal d40) {
+        this.d40 = d40;
+    }
+
+
+    @Column(name="D30", precision=7, scale=4)
+    public BigDecimal getD30() {
+        return this.d30;
+    }
+
+    public void setD30(BigDecimal d30) {
+        this.d30 = d30;
+    }
+
+
+    @Column(name="D25", precision=7, scale=4)
+    public BigDecimal getD25() {
+        return this.d25;
+    }
+
+    public void setD25(BigDecimal d25) {
+        this.d25 = d25;
+    }
+
+
+    @Column(name="D20", precision=7, scale=4)
+    public BigDecimal getD20() {
+        return this.d20;
+    }
+
+    public void setD20(BigDecimal d20) {
+        this.d20 = d20;
+    }
+
+
+    @Column(name="D16", precision=7, scale=4)
+    public BigDecimal getD16() {
+        return this.d16;
+    }
+
+    public void setD16(BigDecimal d16) {
+        this.d16 = d16;
+    }
+
+
+    @Column(name="D10", precision=7, scale=4)
+    public BigDecimal getD10() {
+        return this.d10;
+    }
+
+    public void setD10(BigDecimal d10) {
+        this.d10 = d10;
+    }
+
+
+    @Column(name="DMIN", precision=7, scale=4)
+    public BigDecimal getDmin() {
+        return this.dmin;
+    }
+
+    public void setDmin(BigDecimal dmin) {
+        this.dmin = dmin;
+    }
+
+
+    @Column(name="DURCHDMIN", precision=6, scale=3)
+    public BigDecimal getDurchdmin() {
+        return this.durchdmin;
+    }
+
+    public void setDurchdmin(BigDecimal durchdmin) {
+        this.durchdmin = durchdmin;
+    }
+
+
+    @Column(name="DMAX", precision=7, scale=4)
+    public BigDecimal getDmax() {
+        return this.dmax;
+    }
+
+    public void setDmax(BigDecimal dmax) {
+        this.dmax = dmax;
+    }
+
+
+    @Column(name="DURCHDMAX", precision=6, scale=3)
+    public BigDecimal getDurchdmax() {
+        return this.durchdmax;
+    }
+
+    public void setDurchdmax(BigDecimal durchdmax) {
+        this.durchdmax = durchdmax;
+    }
+
+
+    @Column(name="STDABW", precision=8, scale=3)
+    public BigDecimal getStdabw() {
+        return this.stdabw;
+    }
+
+    public void setStdabw(BigDecimal stdabw) {
+        this.stdabw = stdabw;
+    }
+
+
+    @Column(name="STDFEHLER", precision=8, scale=3)
+    public BigDecimal getStdfehler() {
+        return this.stdfehler;
+    }
+
+    public void setStdfehler(BigDecimal stdfehler) {
+        this.stdfehler = stdfehler;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="UFERABLINKS", precision=8, scale=3)
+    public BigDecimal getUferablinks() {
+        return this.uferablinks;
+    }
+
+    public void setUferablinks(BigDecimal uferablinks) {
+        this.uferablinks = uferablinks;
+    }
+
+@OneToOne(fetch=FetchType.LAZY, mappedBy="glotrechte")
+    public Gsiebung getGsiebung() {
+        return this.gsiebung;
+    }
+
+    public void setGsiebung(Gsiebung gsiebung) {
+        this.gsiebung = gsiebung;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="glotrechte")
+    public Set<Gprobe> getGprobes() {
+        return this.gprobes;
+    }
+
+    public void setGprobes(Set<Gprobe> gprobes) {
+        this.gprobes = gprobes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Gprobe.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,138 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+/**
+ * Gprobe generated by hbm2java
+ */
+@Entity
+@Table(name="GPROBE"
+    ,schema="SEDDB"
+)
+public class Gprobe  implements java.io.Serializable {
+
+
+     private GprobeId id;
+     private Glotrechte glotrechte;
+     private int messdauer;
+     private BigDecimal menge;
+     private BigDecimal gtrieb;
+     private BigDecimal faktor;
+     private BigDecimal mengeF;
+     private BigDecimal gtriebF;
+
+    public Gprobe() {
+    }
+
+    public Gprobe(GprobeId id, Glotrechte glotrechte, int messdauer, BigDecimal menge) {
+        this.id = id;
+        this.glotrechte = glotrechte;
+        this.messdauer = messdauer;
+        this.menge = menge;
+    }
+    public Gprobe(GprobeId id, Glotrechte glotrechte, int messdauer, BigDecimal menge, BigDecimal gtrieb, BigDecimal faktor, BigDecimal mengeF, BigDecimal gtriebF) {
+       this.id = id;
+       this.glotrechte = glotrechte;
+       this.messdauer = messdauer;
+       this.menge = menge;
+       this.gtrieb = gtrieb;
+       this.faktor = faktor;
+       this.mengeF = mengeF;
+       this.gtriebF = gtriebF;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="glotrechteid", column=@Column(name="GLOTRECHTEID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="lfdnr", column=@Column(name="LFDNR", nullable=false, precision=5, scale=0) ) } )
+    public GprobeId getId() {
+        return this.id;
+    }
+
+    public void setId(GprobeId id) {
+        this.id = id;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="GLOTRECHTEID", nullable=false, insertable=false, updatable=false)
+    public Glotrechte getGlotrechte() {
+        return this.glotrechte;
+    }
+
+    public void setGlotrechte(Glotrechte glotrechte) {
+        this.glotrechte = glotrechte;
+    }
+
+
+    @Column(name="MESSDAUER", nullable=false, precision=5, scale=0)
+    public int getMessdauer() {
+        return this.messdauer;
+    }
+
+    public void setMessdauer(int messdauer) {
+        this.messdauer = messdauer;
+    }
+
+
+    @Column(name="MENGE", nullable=false, precision=9, scale=3)
+    public BigDecimal getMenge() {
+        return this.menge;
+    }
+
+    public void setMenge(BigDecimal menge) {
+        this.menge = menge;
+    }
+
+
+    @Column(name="GTRIEB", precision=8, scale=3)
+    public BigDecimal getGtrieb() {
+        return this.gtrieb;
+    }
+
+    public void setGtrieb(BigDecimal gtrieb) {
+        this.gtrieb = gtrieb;
+    }
+
+
+    @Column(name="FAKTOR", precision=4, scale=3)
+    public BigDecimal getFaktor() {
+        return this.faktor;
+    }
+
+    public void setFaktor(BigDecimal faktor) {
+        this.faktor = faktor;
+    }
+
+
+    @Column(name="MENGE_F", precision=9, scale=3)
+    public BigDecimal getMengeF() {
+        return this.mengeF;
+    }
+
+    public void setMengeF(BigDecimal mengeF) {
+        this.mengeF = mengeF;
+    }
+
+
+    @Column(name="GTRIEB_F", precision=8, scale=3)
+    public BigDecimal getGtriebF() {
+        return this.gtriebF;
+    }
+
+    public void setGtriebF(BigDecimal gtriebF) {
+        this.gtriebF = gtriebF;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/GprobeId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,65 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * GprobeId generated by hbm2java
+ */
+@Embeddable
+public class GprobeId  implements java.io.Serializable {
+
+
+     private long glotrechteid;
+     private int lfdnr;
+
+    public GprobeId() {
+    }
+
+    public GprobeId(long glotrechteid, int lfdnr) {
+       this.glotrechteid = glotrechteid;
+       this.lfdnr = lfdnr;
+    }
+
+
+
+    @Column(name="GLOTRECHTEID", nullable=false, precision=11, scale=0)
+    public long getGlotrechteid() {
+        return this.glotrechteid;
+    }
+
+    public void setGlotrechteid(long glotrechteid) {
+        this.glotrechteid = glotrechteid;
+    }
+
+
+    @Column(name="LFDNR", nullable=false, precision=5, scale=0)
+    public int getLfdnr() {
+        return this.lfdnr;
+    }
+
+    public void setLfdnr(int lfdnr) {
+        this.lfdnr = lfdnr;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof GprobeId) ) return false;
+         GprobeId castOther = ( GprobeId ) other;
+
+         return (this.getGlotrechteid()==castOther.getGlotrechteid())
+ && (this.getLfdnr()==castOther.getLfdnr());
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getGlotrechteid();
+         result = 37 * result + this.getLfdnr();
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Gsiebsatz.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,363 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * Gsiebsatz generated by hbm2java
+ */
+@Entity
+@Table(name="GSIEBSATZ"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames="NAME")
+)
+public class Gsiebsatz  implements java.io.Serializable {
+
+
+     private long gsiebsatzid;
+     private String name;
+     private boolean istaktiv;
+     private BigDecimal sieb01;
+     private BigDecimal sieb02;
+     private BigDecimal sieb03;
+     private BigDecimal sieb04;
+     private BigDecimal sieb05;
+     private BigDecimal sieb06;
+     private BigDecimal sieb07;
+     private BigDecimal sieb08;
+     private BigDecimal sieb09;
+     private BigDecimal sieb10;
+     private BigDecimal sieb11;
+     private BigDecimal sieb12;
+     private BigDecimal sieb13;
+     private BigDecimal sieb14;
+     private BigDecimal sieb15;
+     private BigDecimal sieb16;
+     private BigDecimal sieb17;
+     private BigDecimal sieb18;
+     private BigDecimal sieb19;
+     private BigDecimal sieb20;
+     private BigDecimal sieb21;
+     private String bemerkung;
+     private Set<Ssiebung> ssiebungs = new HashSet<Ssiebung>(0);
+     private Set<Messung> messungs = new HashSet<Messung>(0);
+
+    public Gsiebsatz() {
+    }
+
+
+    public Gsiebsatz(long gsiebsatzid, String name, boolean istaktiv) {
+        this.gsiebsatzid = gsiebsatzid;
+        this.name = name;
+        this.istaktiv = istaktiv;
+    }
+    public Gsiebsatz(long gsiebsatzid, String name, boolean istaktiv, BigDecimal sieb01, BigDecimal sieb02, BigDecimal sieb03, BigDecimal sieb04, BigDecimal sieb05, BigDecimal sieb06, BigDecimal sieb07, BigDecimal sieb08, BigDecimal sieb09, BigDecimal sieb10, BigDecimal sieb11, BigDecimal sieb12, BigDecimal sieb13, BigDecimal sieb14, BigDecimal sieb15, BigDecimal sieb16, BigDecimal sieb17, BigDecimal sieb18, BigDecimal sieb19, BigDecimal sieb20, BigDecimal sieb21, String bemerkung, Set<Ssiebung> ssiebungs, Set<Messung> messungs) {
+       this.gsiebsatzid = gsiebsatzid;
+       this.name = name;
+       this.istaktiv = istaktiv;
+       this.sieb01 = sieb01;
+       this.sieb02 = sieb02;
+       this.sieb03 = sieb03;
+       this.sieb04 = sieb04;
+       this.sieb05 = sieb05;
+       this.sieb06 = sieb06;
+       this.sieb07 = sieb07;
+       this.sieb08 = sieb08;
+       this.sieb09 = sieb09;
+       this.sieb10 = sieb10;
+       this.sieb11 = sieb11;
+       this.sieb12 = sieb12;
+       this.sieb13 = sieb13;
+       this.sieb14 = sieb14;
+       this.sieb15 = sieb15;
+       this.sieb16 = sieb16;
+       this.sieb17 = sieb17;
+       this.sieb18 = sieb18;
+       this.sieb19 = sieb19;
+       this.sieb20 = sieb20;
+       this.sieb21 = sieb21;
+       this.bemerkung = bemerkung;
+       this.ssiebungs = ssiebungs;
+       this.messungs = messungs;
+    }
+
+     @Id
+
+
+    @Column(name="GSIEBSATZID", unique=true, nullable=false, precision=11, scale=0)
+    public long getGsiebsatzid() {
+        return this.gsiebsatzid;
+    }
+
+    public void setGsiebsatzid(long gsiebsatzid) {
+        this.gsiebsatzid = gsiebsatzid;
+    }
+
+
+    @Column(name="NAME", unique=true, nullable=false, length=20)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="ISTAKTIV", nullable=false, precision=1, scale=0)
+    public boolean isIstaktiv() {
+        return this.istaktiv;
+    }
+
+    public void setIstaktiv(boolean istaktiv) {
+        this.istaktiv = istaktiv;
+    }
+
+
+    @Column(name="SIEB01", precision=7, scale=4)
+    public BigDecimal getSieb01() {
+        return this.sieb01;
+    }
+
+    public void setSieb01(BigDecimal sieb01) {
+        this.sieb01 = sieb01;
+    }
+
+
+    @Column(name="SIEB02", precision=7, scale=4)
+    public BigDecimal getSieb02() {
+        return this.sieb02;
+    }
+
+    public void setSieb02(BigDecimal sieb02) {
+        this.sieb02 = sieb02;
+    }
+
+
+    @Column(name="SIEB03", precision=7, scale=4)
+    public BigDecimal getSieb03() {
+        return this.sieb03;
+    }
+
+    public void setSieb03(BigDecimal sieb03) {
+        this.sieb03 = sieb03;
+    }
+
+
+    @Column(name="SIEB04", precision=7, scale=4)
+    public BigDecimal getSieb04() {
+        return this.sieb04;
+    }
+
+    public void setSieb04(BigDecimal sieb04) {
+        this.sieb04 = sieb04;
+    }
+
+
+    @Column(name="SIEB05", precision=7, scale=4)
+    public BigDecimal getSieb05() {
+        return this.sieb05;
+    }
+
+    public void setSieb05(BigDecimal sieb05) {
+        this.sieb05 = sieb05;
+    }
+
+
+    @Column(name="SIEB06", precision=7, scale=4)
+    public BigDecimal getSieb06() {
+        return this.sieb06;
+    }
+
+    public void setSieb06(BigDecimal sieb06) {
+        this.sieb06 = sieb06;
+    }
+
+
+    @Column(name="SIEB07", precision=7, scale=4)
+    public BigDecimal getSieb07() {
+        return this.sieb07;
+    }
+
+    public void setSieb07(BigDecimal sieb07) {
+        this.sieb07 = sieb07;
+    }
+
+
+    @Column(name="SIEB08", precision=7, scale=4)
+    public BigDecimal getSieb08() {
+        return this.sieb08;
+    }
+
+    public void setSieb08(BigDecimal sieb08) {
+        this.sieb08 = sieb08;
+    }
+
+
+    @Column(name="SIEB09", precision=7, scale=4)
+    public BigDecimal getSieb09() {
+        return this.sieb09;
+    }
+
+    public void setSieb09(BigDecimal sieb09) {
+        this.sieb09 = sieb09;
+    }
+
+
+    @Column(name="SIEB10", precision=7, scale=4)
+    public BigDecimal getSieb10() {
+        return this.sieb10;
+    }
+
+    public void setSieb10(BigDecimal sieb10) {
+        this.sieb10 = sieb10;
+    }
+
+
+    @Column(name="SIEB11", precision=7, scale=4)
+    public BigDecimal getSieb11() {
+        return this.sieb11;
+    }
+
+    public void setSieb11(BigDecimal sieb11) {
+        this.sieb11 = sieb11;
+    }
+
+
+    @Column(name="SIEB12", precision=7, scale=4)
+    public BigDecimal getSieb12() {
+        return this.sieb12;
+    }
+
+    public void setSieb12(BigDecimal sieb12) {
+        this.sieb12 = sieb12;
+    }
+
+
+    @Column(name="SIEB13", precision=7, scale=4)
+    public BigDecimal getSieb13() {
+        return this.sieb13;
+    }
+
+    public void setSieb13(BigDecimal sieb13) {
+        this.sieb13 = sieb13;
+    }
+
+
+    @Column(name="SIEB14", precision=7, scale=4)
+    public BigDecimal getSieb14() {
+        return this.sieb14;
+    }
+
+    public void setSieb14(BigDecimal sieb14) {
+        this.sieb14 = sieb14;
+    }
+
+
+    @Column(name="SIEB15", precision=7, scale=4)
+    public BigDecimal getSieb15() {
+        return this.sieb15;
+    }
+
+    public void setSieb15(BigDecimal sieb15) {
+        this.sieb15 = sieb15;
+    }
+
+
+    @Column(name="SIEB16", precision=7, scale=4)
+    public BigDecimal getSieb16() {
+        return this.sieb16;
+    }
+
+    public void setSieb16(BigDecimal sieb16) {
+        this.sieb16 = sieb16;
+    }
+
+
+    @Column(name="SIEB17", precision=7, scale=4)
+    public BigDecimal getSieb17() {
+        return this.sieb17;
+    }
+
+    public void setSieb17(BigDecimal sieb17) {
+        this.sieb17 = sieb17;
+    }
+
+
+    @Column(name="SIEB18", precision=7, scale=4)
+    public BigDecimal getSieb18() {
+        return this.sieb18;
+    }
+
+    public void setSieb18(BigDecimal sieb18) {
+        this.sieb18 = sieb18;
+    }
+
+
+    @Column(name="SIEB19", precision=7, scale=4)
+    public BigDecimal getSieb19() {
+        return this.sieb19;
+    }
+
+    public void setSieb19(BigDecimal sieb19) {
+        this.sieb19 = sieb19;
+    }
+
+
+    @Column(name="SIEB20", precision=7, scale=4)
+    public BigDecimal getSieb20() {
+        return this.sieb20;
+    }
+
+    public void setSieb20(BigDecimal sieb20) {
+        this.sieb20 = sieb20;
+    }
+
+
+    @Column(name="SIEB21", precision=7, scale=4)
+    public BigDecimal getSieb21() {
+        return this.sieb21;
+    }
+
+    public void setSieb21(BigDecimal sieb21) {
+        this.sieb21 = sieb21;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="gsiebsatz")
+    public Set<Ssiebung> getSsiebungs() {
+        return this.ssiebungs;
+    }
+
+    public void setSsiebungs(Set<Ssiebung> ssiebungs) {
+        this.ssiebungs = ssiebungs;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="gsiebsatz")
+    public Set<Messung> getMessungs() {
+        return this.messungs;
+    }
+
+    public void setMessungs(Set<Messung> messungs) {
+        this.messungs = messungs;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Gsiebung.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,348 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.Table;
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Parameter;
+
+/**
+ * Gsiebung generated by hbm2java
+ */
+@Entity
+@Table(name="GSIEBUNG"
+    ,schema="SEDDB"
+)
+public class Gsiebung  implements java.io.Serializable {
+
+
+     private long glotrechteid;
+     private Glotrechte glotrechte;
+     private BigDecimal gmasse;
+     private BigDecimal rsieb01;
+     private BigDecimal rsieb02;
+     private BigDecimal rsieb03;
+     private BigDecimal rsieb04;
+     private BigDecimal rsieb05;
+     private BigDecimal rsieb06;
+     private BigDecimal rsieb07;
+     private BigDecimal rsieb08;
+     private BigDecimal rsieb09;
+     private BigDecimal rsieb10;
+     private BigDecimal rsieb11;
+     private BigDecimal rsieb12;
+     private BigDecimal rsieb13;
+     private BigDecimal rsieb14;
+     private BigDecimal rsieb15;
+     private BigDecimal rsieb16;
+     private BigDecimal rsieb17;
+     private BigDecimal rsieb18;
+     private BigDecimal rsieb19;
+     private BigDecimal rsieb20;
+     private BigDecimal rsieb21;
+     private BigDecimal rest;
+     private String bemerkung;
+
+    public Gsiebung() {
+    }
+
+    public Gsiebung(Glotrechte glotrechte) {
+        this.glotrechte = glotrechte;
+    }
+    public Gsiebung(Glotrechte glotrechte, BigDecimal gmasse, BigDecimal rsieb01, BigDecimal rsieb02, BigDecimal rsieb03, BigDecimal rsieb04, BigDecimal rsieb05, BigDecimal rsieb06, BigDecimal rsieb07, BigDecimal rsieb08, BigDecimal rsieb09, BigDecimal rsieb10, BigDecimal rsieb11, BigDecimal rsieb12, BigDecimal rsieb13, BigDecimal rsieb14, BigDecimal rsieb15, BigDecimal rsieb16, BigDecimal rsieb17, BigDecimal rsieb18, BigDecimal rsieb19, BigDecimal rsieb20, BigDecimal rsieb21, BigDecimal rest, String bemerkung) {
+       this.glotrechte = glotrechte;
+       this.gmasse = gmasse;
+       this.rsieb01 = rsieb01;
+       this.rsieb02 = rsieb02;
+       this.rsieb03 = rsieb03;
+       this.rsieb04 = rsieb04;
+       this.rsieb05 = rsieb05;
+       this.rsieb06 = rsieb06;
+       this.rsieb07 = rsieb07;
+       this.rsieb08 = rsieb08;
+       this.rsieb09 = rsieb09;
+       this.rsieb10 = rsieb10;
+       this.rsieb11 = rsieb11;
+       this.rsieb12 = rsieb12;
+       this.rsieb13 = rsieb13;
+       this.rsieb14 = rsieb14;
+       this.rsieb15 = rsieb15;
+       this.rsieb16 = rsieb16;
+       this.rsieb17 = rsieb17;
+       this.rsieb18 = rsieb18;
+       this.rsieb19 = rsieb19;
+       this.rsieb20 = rsieb20;
+       this.rsieb21 = rsieb21;
+       this.rest = rest;
+       this.bemerkung = bemerkung;
+    }
+
+     @GenericGenerator(name="generator", strategy="foreign", parameters=@Parameter(name="property", value="glotrechte"))@Id @GeneratedValue(generator="generator")
+
+
+    @Column(name="GLOTRECHTEID", unique=true, nullable=false, precision=11, scale=0)
+    public long getGlotrechteid() {
+        return this.glotrechteid;
+    }
+
+    public void setGlotrechteid(long glotrechteid) {
+        this.glotrechteid = glotrechteid;
+    }
+
+@OneToOne(fetch=FetchType.LAZY)@PrimaryKeyJoinColumn
+    public Glotrechte getGlotrechte() {
+        return this.glotrechte;
+    }
+
+    public void setGlotrechte(Glotrechte glotrechte) {
+        this.glotrechte = glotrechte;
+    }
+
+
+    @Column(name="GMASSE", precision=9, scale=3)
+    public BigDecimal getGmasse() {
+        return this.gmasse;
+    }
+
+    public void setGmasse(BigDecimal gmasse) {
+        this.gmasse = gmasse;
+    }
+
+
+    @Column(name="RSIEB01", precision=9, scale=3)
+    public BigDecimal getRsieb01() {
+        return this.rsieb01;
+    }
+
+    public void setRsieb01(BigDecimal rsieb01) {
+        this.rsieb01 = rsieb01;
+    }
+
+
+    @Column(name="RSIEB02", precision=9, scale=3)
+    public BigDecimal getRsieb02() {
+        return this.rsieb02;
+    }
+
+    public void setRsieb02(BigDecimal rsieb02) {
+        this.rsieb02 = rsieb02;
+    }
+
+
+    @Column(name="RSIEB03", precision=9, scale=3)
+    public BigDecimal getRsieb03() {
+        return this.rsieb03;
+    }
+
+    public void setRsieb03(BigDecimal rsieb03) {
+        this.rsieb03 = rsieb03;
+    }
+
+
+    @Column(name="RSIEB04", precision=9, scale=3)
+    public BigDecimal getRsieb04() {
+        return this.rsieb04;
+    }
+
+    public void setRsieb04(BigDecimal rsieb04) {
+        this.rsieb04 = rsieb04;
+    }
+
+
+    @Column(name="RSIEB05", precision=9, scale=3)
+    public BigDecimal getRsieb05() {
+        return this.rsieb05;
+    }
+
+    public void setRsieb05(BigDecimal rsieb05) {
+        this.rsieb05 = rsieb05;
+    }
+
+
+    @Column(name="RSIEB06", precision=9, scale=3)
+    public BigDecimal getRsieb06() {
+        return this.rsieb06;
+    }
+
+    public void setRsieb06(BigDecimal rsieb06) {
+        this.rsieb06 = rsieb06;
+    }
+
+
+    @Column(name="RSIEB07", precision=9, scale=3)
+    public BigDecimal getRsieb07() {
+        return this.rsieb07;
+    }
+
+    public void setRsieb07(BigDecimal rsieb07) {
+        this.rsieb07 = rsieb07;
+    }
+
+
+    @Column(name="RSIEB08", precision=9, scale=3)
+    public BigDecimal getRsieb08() {
+        return this.rsieb08;
+    }
+
+    public void setRsieb08(BigDecimal rsieb08) {
+        this.rsieb08 = rsieb08;
+    }
+
+
+    @Column(name="RSIEB09", precision=9, scale=3)
+    public BigDecimal getRsieb09() {
+        return this.rsieb09;
+    }
+
+    public void setRsieb09(BigDecimal rsieb09) {
+        this.rsieb09 = rsieb09;
+    }
+
+
+    @Column(name="RSIEB10", precision=9, scale=3)
+    public BigDecimal getRsieb10() {
+        return this.rsieb10;
+    }
+
+    public void setRsieb10(BigDecimal rsieb10) {
+        this.rsieb10 = rsieb10;
+    }
+
+
+    @Column(name="RSIEB11", precision=9, scale=3)
+    public BigDecimal getRsieb11() {
+        return this.rsieb11;
+    }
+
+    public void setRsieb11(BigDecimal rsieb11) {
+        this.rsieb11 = rsieb11;
+    }
+
+
+    @Column(name="RSIEB12", precision=9, scale=3)
+    public BigDecimal getRsieb12() {
+        return this.rsieb12;
+    }
+
+    public void setRsieb12(BigDecimal rsieb12) {
+        this.rsieb12 = rsieb12;
+    }
+
+
+    @Column(name="RSIEB13", precision=9, scale=3)
+    public BigDecimal getRsieb13() {
+        return this.rsieb13;
+    }
+
+    public void setRsieb13(BigDecimal rsieb13) {
+        this.rsieb13 = rsieb13;
+    }
+
+
+    @Column(name="RSIEB14", precision=9, scale=3)
+    public BigDecimal getRsieb14() {
+        return this.rsieb14;
+    }
+
+    public void setRsieb14(BigDecimal rsieb14) {
+        this.rsieb14 = rsieb14;
+    }
+
+
+    @Column(name="RSIEB15", precision=9, scale=3)
+    public BigDecimal getRsieb15() {
+        return this.rsieb15;
+    }
+
+    public void setRsieb15(BigDecimal rsieb15) {
+        this.rsieb15 = rsieb15;
+    }
+
+
+    @Column(name="RSIEB16", precision=9, scale=3)
+    public BigDecimal getRsieb16() {
+        return this.rsieb16;
+    }
+
+    public void setRsieb16(BigDecimal rsieb16) {
+        this.rsieb16 = rsieb16;
+    }
+
+
+    @Column(name="RSIEB17", precision=9, scale=3)
+    public BigDecimal getRsieb17() {
+        return this.rsieb17;
+    }
+
+    public void setRsieb17(BigDecimal rsieb17) {
+        this.rsieb17 = rsieb17;
+    }
+
+
+    @Column(name="RSIEB18", precision=9, scale=3)
+    public BigDecimal getRsieb18() {
+        return this.rsieb18;
+    }
+
+    public void setRsieb18(BigDecimal rsieb18) {
+        this.rsieb18 = rsieb18;
+    }
+
+
+    @Column(name="RSIEB19", precision=9, scale=3)
+    public BigDecimal getRsieb19() {
+        return this.rsieb19;
+    }
+
+    public void setRsieb19(BigDecimal rsieb19) {
+        this.rsieb19 = rsieb19;
+    }
+
+
+    @Column(name="RSIEB20", precision=9, scale=3)
+    public BigDecimal getRsieb20() {
+        return this.rsieb20;
+    }
+
+    public void setRsieb20(BigDecimal rsieb20) {
+        this.rsieb20 = rsieb20;
+    }
+
+
+    @Column(name="RSIEB21", precision=9, scale=3)
+    public BigDecimal getRsieb21() {
+        return this.rsieb21;
+    }
+
+    public void setRsieb21(BigDecimal rsieb21) {
+        this.rsieb21 = rsieb21;
+    }
+
+
+    @Column(name="REST", precision=9, scale=3)
+    public BigDecimal getRest() {
+        return this.rest;
+    }
+
+    public void setRest(BigDecimal rest) {
+        this.rest = rest;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Gsiebungsieb.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,88 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Gsiebungsieb generated by hbm2java
+ */
+@Entity
+@Table(name="GSIEBUNGSIEB"
+    ,schema="SEDDB"
+)
+public class Gsiebungsieb  implements java.io.Serializable {
+
+
+     private GsiebungsiebId id;
+
+    public Gsiebungsieb() {
+    }
+
+    public Gsiebungsieb(GsiebungsiebId id) {
+       this.id = id;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="glotrechteid", column=@Column(name="GLOTRECHTEID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="gsiebsatzid", column=@Column(name="GSIEBSATZID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="gmasse", column=@Column(name="GMASSE", precision=9, scale=3) ),
+        @AttributeOverride(name="masche01", column=@Column(name="MASCHE01", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck01", column=@Column(name="RUECK01", precision=9, scale=3) ),
+        @AttributeOverride(name="masche02", column=@Column(name="MASCHE02", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck02", column=@Column(name="RUECK02", precision=9, scale=3) ),
+        @AttributeOverride(name="masche03", column=@Column(name="MASCHE03", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck03", column=@Column(name="RUECK03", precision=9, scale=3) ),
+        @AttributeOverride(name="masche04", column=@Column(name="MASCHE04", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck04", column=@Column(name="RUECK04", precision=9, scale=3) ),
+        @AttributeOverride(name="masche05", column=@Column(name="MASCHE05", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck05", column=@Column(name="RUECK05", precision=9, scale=3) ),
+        @AttributeOverride(name="masche06", column=@Column(name="MASCHE06", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck06", column=@Column(name="RUECK06", precision=9, scale=3) ),
+        @AttributeOverride(name="masche07", column=@Column(name="MASCHE07", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck07", column=@Column(name="RUECK07", precision=9, scale=3) ),
+        @AttributeOverride(name="masche08", column=@Column(name="MASCHE08", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck08", column=@Column(name="RUECK08", precision=9, scale=3) ),
+        @AttributeOverride(name="masche09", column=@Column(name="MASCHE09", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck09", column=@Column(name="RUECK09", precision=9, scale=3) ),
+        @AttributeOverride(name="masche10", column=@Column(name="MASCHE10", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck10", column=@Column(name="RUECK10", precision=9, scale=3) ),
+        @AttributeOverride(name="masche11", column=@Column(name="MASCHE11", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck11", column=@Column(name="RUECK11", precision=9, scale=3) ),
+        @AttributeOverride(name="masche12", column=@Column(name="MASCHE12", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck12", column=@Column(name="RUECK12", precision=9, scale=3) ),
+        @AttributeOverride(name="masche13", column=@Column(name="MASCHE13", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck13", column=@Column(name="RUECK13", precision=9, scale=3) ),
+        @AttributeOverride(name="masche14", column=@Column(name="MASCHE14", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck14", column=@Column(name="RUECK14", precision=9, scale=3) ),
+        @AttributeOverride(name="masche15", column=@Column(name="MASCHE15", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck15", column=@Column(name="RUECK15", precision=9, scale=3) ),
+        @AttributeOverride(name="masche16", column=@Column(name="MASCHE16", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck16", column=@Column(name="RUECK16", precision=9, scale=3) ),
+        @AttributeOverride(name="masche17", column=@Column(name="MASCHE17", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck17", column=@Column(name="RUECK17", precision=9, scale=3) ),
+        @AttributeOverride(name="masche18", column=@Column(name="MASCHE18", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck18", column=@Column(name="RUECK18", precision=9, scale=3) ),
+        @AttributeOverride(name="masche19", column=@Column(name="MASCHE19", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck19", column=@Column(name="RUECK19", precision=9, scale=3) ),
+        @AttributeOverride(name="masche20", column=@Column(name="MASCHE20", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck20", column=@Column(name="RUECK20", precision=9, scale=3) ),
+        @AttributeOverride(name="masche21", column=@Column(name="MASCHE21", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck21", column=@Column(name="RUECK21", precision=9, scale=3) ),
+        @AttributeOverride(name="rest", column=@Column(name="REST", precision=9, scale=3) ) } )
+    public GsiebungsiebId getId() {
+        return this.id;
+    }
+
+    public void setId(GsiebungsiebId id) {
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/GsiebungsiebId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,687 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * GsiebungsiebId generated by hbm2java
+ */
+@Embeddable
+public class GsiebungsiebId  implements java.io.Serializable {
+
+
+     private long glotrechteid;
+     private long gsiebsatzid;
+     private BigDecimal gmasse;
+     private BigDecimal masche01;
+     private BigDecimal rueck01;
+     private BigDecimal masche02;
+     private BigDecimal rueck02;
+     private BigDecimal masche03;
+     private BigDecimal rueck03;
+     private BigDecimal masche04;
+     private BigDecimal rueck04;
+     private BigDecimal masche05;
+     private BigDecimal rueck05;
+     private BigDecimal masche06;
+     private BigDecimal rueck06;
+     private BigDecimal masche07;
+     private BigDecimal rueck07;
+     private BigDecimal masche08;
+     private BigDecimal rueck08;
+     private BigDecimal masche09;
+     private BigDecimal rueck09;
+     private BigDecimal masche10;
+     private BigDecimal rueck10;
+     private BigDecimal masche11;
+     private BigDecimal rueck11;
+     private BigDecimal masche12;
+     private BigDecimal rueck12;
+     private BigDecimal masche13;
+     private BigDecimal rueck13;
+     private BigDecimal masche14;
+     private BigDecimal rueck14;
+     private BigDecimal masche15;
+     private BigDecimal rueck15;
+     private BigDecimal masche16;
+     private BigDecimal rueck16;
+     private BigDecimal masche17;
+     private BigDecimal rueck17;
+     private BigDecimal masche18;
+     private BigDecimal rueck18;
+     private BigDecimal masche19;
+     private BigDecimal rueck19;
+     private BigDecimal masche20;
+     private BigDecimal rueck20;
+     private BigDecimal masche21;
+     private BigDecimal rueck21;
+     private BigDecimal rest;
+
+    public GsiebungsiebId() {
+    }
+
+
+    public GsiebungsiebId(long glotrechteid, long gsiebsatzid) {
+        this.glotrechteid = glotrechteid;
+        this.gsiebsatzid = gsiebsatzid;
+    }
+    public GsiebungsiebId(long glotrechteid, long gsiebsatzid, BigDecimal gmasse, BigDecimal masche01, BigDecimal rueck01, BigDecimal masche02, BigDecimal rueck02, BigDecimal masche03, BigDecimal rueck03, BigDecimal masche04, BigDecimal rueck04, BigDecimal masche05, BigDecimal rueck05, BigDecimal masche06, BigDecimal rueck06, BigDecimal masche07, BigDecimal rueck07, BigDecimal masche08, BigDecimal rueck08, BigDecimal masche09, BigDecimal rueck09, BigDecimal masche10, BigDecimal rueck10, BigDecimal masche11, BigDecimal rueck11, BigDecimal masche12, BigDecimal rueck12, BigDecimal masche13, BigDecimal rueck13, BigDecimal masche14, BigDecimal rueck14, BigDecimal masche15, BigDecimal rueck15, BigDecimal masche16, BigDecimal rueck16, BigDecimal masche17, BigDecimal rueck17, BigDecimal masche18, BigDecimal rueck18, BigDecimal masche19, BigDecimal rueck19, BigDecimal masche20, BigDecimal rueck20, BigDecimal masche21, BigDecimal rueck21, BigDecimal rest) {
+       this.glotrechteid = glotrechteid;
+       this.gsiebsatzid = gsiebsatzid;
+       this.gmasse = gmasse;
+       this.masche01 = masche01;
+       this.rueck01 = rueck01;
+       this.masche02 = masche02;
+       this.rueck02 = rueck02;
+       this.masche03 = masche03;
+       this.rueck03 = rueck03;
+       this.masche04 = masche04;
+       this.rueck04 = rueck04;
+       this.masche05 = masche05;
+       this.rueck05 = rueck05;
+       this.masche06 = masche06;
+       this.rueck06 = rueck06;
+       this.masche07 = masche07;
+       this.rueck07 = rueck07;
+       this.masche08 = masche08;
+       this.rueck08 = rueck08;
+       this.masche09 = masche09;
+       this.rueck09 = rueck09;
+       this.masche10 = masche10;
+       this.rueck10 = rueck10;
+       this.masche11 = masche11;
+       this.rueck11 = rueck11;
+       this.masche12 = masche12;
+       this.rueck12 = rueck12;
+       this.masche13 = masche13;
+       this.rueck13 = rueck13;
+       this.masche14 = masche14;
+       this.rueck14 = rueck14;
+       this.masche15 = masche15;
+       this.rueck15 = rueck15;
+       this.masche16 = masche16;
+       this.rueck16 = rueck16;
+       this.masche17 = masche17;
+       this.rueck17 = rueck17;
+       this.masche18 = masche18;
+       this.rueck18 = rueck18;
+       this.masche19 = masche19;
+       this.rueck19 = rueck19;
+       this.masche20 = masche20;
+       this.rueck20 = rueck20;
+       this.masche21 = masche21;
+       this.rueck21 = rueck21;
+       this.rest = rest;
+    }
+
+
+
+    @Column(name="GLOTRECHTEID", nullable=false, precision=11, scale=0)
+    public long getGlotrechteid() {
+        return this.glotrechteid;
+    }
+
+    public void setGlotrechteid(long glotrechteid) {
+        this.glotrechteid = glotrechteid;
+    }
+
+
+    @Column(name="GSIEBSATZID", nullable=false, precision=11, scale=0)
+    public long getGsiebsatzid() {
+        return this.gsiebsatzid;
+    }
+
+    public void setGsiebsatzid(long gsiebsatzid) {
+        this.gsiebsatzid = gsiebsatzid;
+    }
+
+
+    @Column(name="GMASSE", precision=9, scale=3)
+    public BigDecimal getGmasse() {
+        return this.gmasse;
+    }
+
+    public void setGmasse(BigDecimal gmasse) {
+        this.gmasse = gmasse;
+    }
+
+
+    @Column(name="MASCHE01", precision=7, scale=4)
+    public BigDecimal getMasche01() {
+        return this.masche01;
+    }
+
+    public void setMasche01(BigDecimal masche01) {
+        this.masche01 = masche01;
+    }
+
+
+    @Column(name="RUECK01", precision=9, scale=3)
+    public BigDecimal getRueck01() {
+        return this.rueck01;
+    }
+
+    public void setRueck01(BigDecimal rueck01) {
+        this.rueck01 = rueck01;
+    }
+
+
+    @Column(name="MASCHE02", precision=7, scale=4)
+    public BigDecimal getMasche02() {
+        return this.masche02;
+    }
+
+    public void setMasche02(BigDecimal masche02) {
+        this.masche02 = masche02;
+    }
+
+
+    @Column(name="RUECK02", precision=9, scale=3)
+    public BigDecimal getRueck02() {
+        return this.rueck02;
+    }
+
+    public void setRueck02(BigDecimal rueck02) {
+        this.rueck02 = rueck02;
+    }
+
+
+    @Column(name="MASCHE03", precision=7, scale=4)
+    public BigDecimal getMasche03() {
+        return this.masche03;
+    }
+
+    public void setMasche03(BigDecimal masche03) {
+        this.masche03 = masche03;
+    }
+
+
+    @Column(name="RUECK03", precision=9, scale=3)
+    public BigDecimal getRueck03() {
+        return this.rueck03;
+    }
+
+    public void setRueck03(BigDecimal rueck03) {
+        this.rueck03 = rueck03;
+    }
+
+
+    @Column(name="MASCHE04", precision=7, scale=4)
+    public BigDecimal getMasche04() {
+        return this.masche04;
+    }
+
+    public void setMasche04(BigDecimal masche04) {
+        this.masche04 = masche04;
+    }
+
+
+    @Column(name="RUECK04", precision=9, scale=3)
+    public BigDecimal getRueck04() {
+        return this.rueck04;
+    }
+
+    public void setRueck04(BigDecimal rueck04) {
+        this.rueck04 = rueck04;
+    }
+
+
+    @Column(name="MASCHE05", precision=7, scale=4)
+    public BigDecimal getMasche05() {
+        return this.masche05;
+    }
+
+    public void setMasche05(BigDecimal masche05) {
+        this.masche05 = masche05;
+    }
+
+
+    @Column(name="RUECK05", precision=9, scale=3)
+    public BigDecimal getRueck05() {
+        return this.rueck05;
+    }
+
+    public void setRueck05(BigDecimal rueck05) {
+        this.rueck05 = rueck05;
+    }
+
+
+    @Column(name="MASCHE06", precision=7, scale=4)
+    public BigDecimal getMasche06() {
+        return this.masche06;
+    }
+
+    public void setMasche06(BigDecimal masche06) {
+        this.masche06 = masche06;
+    }
+
+
+    @Column(name="RUECK06", precision=9, scale=3)
+    public BigDecimal getRueck06() {
+        return this.rueck06;
+    }
+
+    public void setRueck06(BigDecimal rueck06) {
+        this.rueck06 = rueck06;
+    }
+
+
+    @Column(name="MASCHE07", precision=7, scale=4)
+    public BigDecimal getMasche07() {
+        return this.masche07;
+    }
+
+    public void setMasche07(BigDecimal masche07) {
+        this.masche07 = masche07;
+    }
+
+
+    @Column(name="RUECK07", precision=9, scale=3)
+    public BigDecimal getRueck07() {
+        return this.rueck07;
+    }
+
+    public void setRueck07(BigDecimal rueck07) {
+        this.rueck07 = rueck07;
+    }
+
+
+    @Column(name="MASCHE08", precision=7, scale=4)
+    public BigDecimal getMasche08() {
+        return this.masche08;
+    }
+
+    public void setMasche08(BigDecimal masche08) {
+        this.masche08 = masche08;
+    }
+
+
+    @Column(name="RUECK08", precision=9, scale=3)
+    public BigDecimal getRueck08() {
+        return this.rueck08;
+    }
+
+    public void setRueck08(BigDecimal rueck08) {
+        this.rueck08 = rueck08;
+    }
+
+
+    @Column(name="MASCHE09", precision=7, scale=4)
+    public BigDecimal getMasche09() {
+        return this.masche09;
+    }
+
+    public void setMasche09(BigDecimal masche09) {
+        this.masche09 = masche09;
+    }
+
+
+    @Column(name="RUECK09", precision=9, scale=3)
+    public BigDecimal getRueck09() {
+        return this.rueck09;
+    }
+
+    public void setRueck09(BigDecimal rueck09) {
+        this.rueck09 = rueck09;
+    }
+
+
+    @Column(name="MASCHE10", precision=7, scale=4)
+    public BigDecimal getMasche10() {
+        return this.masche10;
+    }
+
+    public void setMasche10(BigDecimal masche10) {
+        this.masche10 = masche10;
+    }
+
+
+    @Column(name="RUECK10", precision=9, scale=3)
+    public BigDecimal getRueck10() {
+        return this.rueck10;
+    }
+
+    public void setRueck10(BigDecimal rueck10) {
+        this.rueck10 = rueck10;
+    }
+
+
+    @Column(name="MASCHE11", precision=7, scale=4)
+    public BigDecimal getMasche11() {
+        return this.masche11;
+    }
+
+    public void setMasche11(BigDecimal masche11) {
+        this.masche11 = masche11;
+    }
+
+
+    @Column(name="RUECK11", precision=9, scale=3)
+    public BigDecimal getRueck11() {
+        return this.rueck11;
+    }
+
+    public void setRueck11(BigDecimal rueck11) {
+        this.rueck11 = rueck11;
+    }
+
+
+    @Column(name="MASCHE12", precision=7, scale=4)
+    public BigDecimal getMasche12() {
+        return this.masche12;
+    }
+
+    public void setMasche12(BigDecimal masche12) {
+        this.masche12 = masche12;
+    }
+
+
+    @Column(name="RUECK12", precision=9, scale=3)
+    public BigDecimal getRueck12() {
+        return this.rueck12;
+    }
+
+    public void setRueck12(BigDecimal rueck12) {
+        this.rueck12 = rueck12;
+    }
+
+
+    @Column(name="MASCHE13", precision=7, scale=4)
+    public BigDecimal getMasche13() {
+        return this.masche13;
+    }
+
+    public void setMasche13(BigDecimal masche13) {
+        this.masche13 = masche13;
+    }
+
+
+    @Column(name="RUECK13", precision=9, scale=3)
+    public BigDecimal getRueck13() {
+        return this.rueck13;
+    }
+
+    public void setRueck13(BigDecimal rueck13) {
+        this.rueck13 = rueck13;
+    }
+
+
+    @Column(name="MASCHE14", precision=7, scale=4)
+    public BigDecimal getMasche14() {
+        return this.masche14;
+    }
+
+    public void setMasche14(BigDecimal masche14) {
+        this.masche14 = masche14;
+    }
+
+
+    @Column(name="RUECK14", precision=9, scale=3)
+    public BigDecimal getRueck14() {
+        return this.rueck14;
+    }
+
+    public void setRueck14(BigDecimal rueck14) {
+        this.rueck14 = rueck14;
+    }
+
+
+    @Column(name="MASCHE15", precision=7, scale=4)
+    public BigDecimal getMasche15() {
+        return this.masche15;
+    }
+
+    public void setMasche15(BigDecimal masche15) {
+        this.masche15 = masche15;
+    }
+
+
+    @Column(name="RUECK15", precision=9, scale=3)
+    public BigDecimal getRueck15() {
+        return this.rueck15;
+    }
+
+    public void setRueck15(BigDecimal rueck15) {
+        this.rueck15 = rueck15;
+    }
+
+
+    @Column(name="MASCHE16", precision=7, scale=4)
+    public BigDecimal getMasche16() {
+        return this.masche16;
+    }
+
+    public void setMasche16(BigDecimal masche16) {
+        this.masche16 = masche16;
+    }
+
+
+    @Column(name="RUECK16", precision=9, scale=3)
+    public BigDecimal getRueck16() {
+        return this.rueck16;
+    }
+
+    public void setRueck16(BigDecimal rueck16) {
+        this.rueck16 = rueck16;
+    }
+
+
+    @Column(name="MASCHE17", precision=7, scale=4)
+    public BigDecimal getMasche17() {
+        return this.masche17;
+    }
+
+    public void setMasche17(BigDecimal masche17) {
+        this.masche17 = masche17;
+    }
+
+
+    @Column(name="RUECK17", precision=9, scale=3)
+    public BigDecimal getRueck17() {
+        return this.rueck17;
+    }
+
+    public void setRueck17(BigDecimal rueck17) {
+        this.rueck17 = rueck17;
+    }
+
+
+    @Column(name="MASCHE18", precision=7, scale=4)
+    public BigDecimal getMasche18() {
+        return this.masche18;
+    }
+
+    public void setMasche18(BigDecimal masche18) {
+        this.masche18 = masche18;
+    }
+
+
+    @Column(name="RUECK18", precision=9, scale=3)
+    public BigDecimal getRueck18() {
+        return this.rueck18;
+    }
+
+    public void setRueck18(BigDecimal rueck18) {
+        this.rueck18 = rueck18;
+    }
+
+
+    @Column(name="MASCHE19", precision=7, scale=4)
+    public BigDecimal getMasche19() {
+        return this.masche19;
+    }
+
+    public void setMasche19(BigDecimal masche19) {
+        this.masche19 = masche19;
+    }
+
+
+    @Column(name="RUECK19", precision=9, scale=3)
+    public BigDecimal getRueck19() {
+        return this.rueck19;
+    }
+
+    public void setRueck19(BigDecimal rueck19) {
+        this.rueck19 = rueck19;
+    }
+
+
+    @Column(name="MASCHE20", precision=7, scale=4)
+    public BigDecimal getMasche20() {
+        return this.masche20;
+    }
+
+    public void setMasche20(BigDecimal masche20) {
+        this.masche20 = masche20;
+    }
+
+
+    @Column(name="RUECK20", precision=9, scale=3)
+    public BigDecimal getRueck20() {
+        return this.rueck20;
+    }
+
+    public void setRueck20(BigDecimal rueck20) {
+        this.rueck20 = rueck20;
+    }
+
+
+    @Column(name="MASCHE21", precision=7, scale=4)
+    public BigDecimal getMasche21() {
+        return this.masche21;
+    }
+
+    public void setMasche21(BigDecimal masche21) {
+        this.masche21 = masche21;
+    }
+
+
+    @Column(name="RUECK21", precision=9, scale=3)
+    public BigDecimal getRueck21() {
+        return this.rueck21;
+    }
+
+    public void setRueck21(BigDecimal rueck21) {
+        this.rueck21 = rueck21;
+    }
+
+
+    @Column(name="REST", precision=9, scale=3)
+    public BigDecimal getRest() {
+        return this.rest;
+    }
+
+    public void setRest(BigDecimal rest) {
+        this.rest = rest;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof GsiebungsiebId) ) return false;
+         GsiebungsiebId castOther = ( GsiebungsiebId ) other;
+
+         return (this.getGlotrechteid()==castOther.getGlotrechteid())
+ && (this.getGsiebsatzid()==castOther.getGsiebsatzid())
+ && ( (this.getGmasse()==castOther.getGmasse()) || ( this.getGmasse()!=null && castOther.getGmasse()!=null && this.getGmasse().equals(castOther.getGmasse()) ) )
+ && ( (this.getMasche01()==castOther.getMasche01()) || ( this.getMasche01()!=null && castOther.getMasche01()!=null && this.getMasche01().equals(castOther.getMasche01()) ) )
+ && ( (this.getRueck01()==castOther.getRueck01()) || ( this.getRueck01()!=null && castOther.getRueck01()!=null && this.getRueck01().equals(castOther.getRueck01()) ) )
+ && ( (this.getMasche02()==castOther.getMasche02()) || ( this.getMasche02()!=null && castOther.getMasche02()!=null && this.getMasche02().equals(castOther.getMasche02()) ) )
+ && ( (this.getRueck02()==castOther.getRueck02()) || ( this.getRueck02()!=null && castOther.getRueck02()!=null && this.getRueck02().equals(castOther.getRueck02()) ) )
+ && ( (this.getMasche03()==castOther.getMasche03()) || ( this.getMasche03()!=null && castOther.getMasche03()!=null && this.getMasche03().equals(castOther.getMasche03()) ) )
+ && ( (this.getRueck03()==castOther.getRueck03()) || ( this.getRueck03()!=null && castOther.getRueck03()!=null && this.getRueck03().equals(castOther.getRueck03()) ) )
+ && ( (this.getMasche04()==castOther.getMasche04()) || ( this.getMasche04()!=null && castOther.getMasche04()!=null && this.getMasche04().equals(castOther.getMasche04()) ) )
+ && ( (this.getRueck04()==castOther.getRueck04()) || ( this.getRueck04()!=null && castOther.getRueck04()!=null && this.getRueck04().equals(castOther.getRueck04()) ) )
+ && ( (this.getMasche05()==castOther.getMasche05()) || ( this.getMasche05()!=null && castOther.getMasche05()!=null && this.getMasche05().equals(castOther.getMasche05()) ) )
+ && ( (this.getRueck05()==castOther.getRueck05()) || ( this.getRueck05()!=null && castOther.getRueck05()!=null && this.getRueck05().equals(castOther.getRueck05()) ) )
+ && ( (this.getMasche06()==castOther.getMasche06()) || ( this.getMasche06()!=null && castOther.getMasche06()!=null && this.getMasche06().equals(castOther.getMasche06()) ) )
+ && ( (this.getRueck06()==castOther.getRueck06()) || ( this.getRueck06()!=null && castOther.getRueck06()!=null && this.getRueck06().equals(castOther.getRueck06()) ) )
+ && ( (this.getMasche07()==castOther.getMasche07()) || ( this.getMasche07()!=null && castOther.getMasche07()!=null && this.getMasche07().equals(castOther.getMasche07()) ) )
+ && ( (this.getRueck07()==castOther.getRueck07()) || ( this.getRueck07()!=null && castOther.getRueck07()!=null && this.getRueck07().equals(castOther.getRueck07()) ) )
+ && ( (this.getMasche08()==castOther.getMasche08()) || ( this.getMasche08()!=null && castOther.getMasche08()!=null && this.getMasche08().equals(castOther.getMasche08()) ) )
+ && ( (this.getRueck08()==castOther.getRueck08()) || ( this.getRueck08()!=null && castOther.getRueck08()!=null && this.getRueck08().equals(castOther.getRueck08()) ) )
+ && ( (this.getMasche09()==castOther.getMasche09()) || ( this.getMasche09()!=null && castOther.getMasche09()!=null && this.getMasche09().equals(castOther.getMasche09()) ) )
+ && ( (this.getRueck09()==castOther.getRueck09()) || ( this.getRueck09()!=null && castOther.getRueck09()!=null && this.getRueck09().equals(castOther.getRueck09()) ) )
+ && ( (this.getMasche10()==castOther.getMasche10()) || ( this.getMasche10()!=null && castOther.getMasche10()!=null && this.getMasche10().equals(castOther.getMasche10()) ) )
+ && ( (this.getRueck10()==castOther.getRueck10()) || ( this.getRueck10()!=null && castOther.getRueck10()!=null && this.getRueck10().equals(castOther.getRueck10()) ) )
+ && ( (this.getMasche11()==castOther.getMasche11()) || ( this.getMasche11()!=null && castOther.getMasche11()!=null && this.getMasche11().equals(castOther.getMasche11()) ) )
+ && ( (this.getRueck11()==castOther.getRueck11()) || ( this.getRueck11()!=null && castOther.getRueck11()!=null && this.getRueck11().equals(castOther.getRueck11()) ) )
+ && ( (this.getMasche12()==castOther.getMasche12()) || ( this.getMasche12()!=null && castOther.getMasche12()!=null && this.getMasche12().equals(castOther.getMasche12()) ) )
+ && ( (this.getRueck12()==castOther.getRueck12()) || ( this.getRueck12()!=null && castOther.getRueck12()!=null && this.getRueck12().equals(castOther.getRueck12()) ) )
+ && ( (this.getMasche13()==castOther.getMasche13()) || ( this.getMasche13()!=null && castOther.getMasche13()!=null && this.getMasche13().equals(castOther.getMasche13()) ) )
+ && ( (this.getRueck13()==castOther.getRueck13()) || ( this.getRueck13()!=null && castOther.getRueck13()!=null && this.getRueck13().equals(castOther.getRueck13()) ) )
+ && ( (this.getMasche14()==castOther.getMasche14()) || ( this.getMasche14()!=null && castOther.getMasche14()!=null && this.getMasche14().equals(castOther.getMasche14()) ) )
+ && ( (this.getRueck14()==castOther.getRueck14()) || ( this.getRueck14()!=null && castOther.getRueck14()!=null && this.getRueck14().equals(castOther.getRueck14()) ) )
+ && ( (this.getMasche15()==castOther.getMasche15()) || ( this.getMasche15()!=null && castOther.getMasche15()!=null && this.getMasche15().equals(castOther.getMasche15()) ) )
+ && ( (this.getRueck15()==castOther.getRueck15()) || ( this.getRueck15()!=null && castOther.getRueck15()!=null && this.getRueck15().equals(castOther.getRueck15()) ) )
+ && ( (this.getMasche16()==castOther.getMasche16()) || ( this.getMasche16()!=null && castOther.getMasche16()!=null && this.getMasche16().equals(castOther.getMasche16()) ) )
+ && ( (this.getRueck16()==castOther.getRueck16()) || ( this.getRueck16()!=null && castOther.getRueck16()!=null && this.getRueck16().equals(castOther.getRueck16()) ) )
+ && ( (this.getMasche17()==castOther.getMasche17()) || ( this.getMasche17()!=null && castOther.getMasche17()!=null && this.getMasche17().equals(castOther.getMasche17()) ) )
+ && ( (this.getRueck17()==castOther.getRueck17()) || ( this.getRueck17()!=null && castOther.getRueck17()!=null && this.getRueck17().equals(castOther.getRueck17()) ) )
+ && ( (this.getMasche18()==castOther.getMasche18()) || ( this.getMasche18()!=null && castOther.getMasche18()!=null && this.getMasche18().equals(castOther.getMasche18()) ) )
+ && ( (this.getRueck18()==castOther.getRueck18()) || ( this.getRueck18()!=null && castOther.getRueck18()!=null && this.getRueck18().equals(castOther.getRueck18()) ) )
+ && ( (this.getMasche19()==castOther.getMasche19()) || ( this.getMasche19()!=null && castOther.getMasche19()!=null && this.getMasche19().equals(castOther.getMasche19()) ) )
+ && ( (this.getRueck19()==castOther.getRueck19()) || ( this.getRueck19()!=null && castOther.getRueck19()!=null && this.getRueck19().equals(castOther.getRueck19()) ) )
+ && ( (this.getMasche20()==castOther.getMasche20()) || ( this.getMasche20()!=null && castOther.getMasche20()!=null && this.getMasche20().equals(castOther.getMasche20()) ) )
+ && ( (this.getRueck20()==castOther.getRueck20()) || ( this.getRueck20()!=null && castOther.getRueck20()!=null && this.getRueck20().equals(castOther.getRueck20()) ) )
+ && ( (this.getMasche21()==castOther.getMasche21()) || ( this.getMasche21()!=null && castOther.getMasche21()!=null && this.getMasche21().equals(castOther.getMasche21()) ) )
+ && ( (this.getRueck21()==castOther.getRueck21()) || ( this.getRueck21()!=null && castOther.getRueck21()!=null && this.getRueck21().equals(castOther.getRueck21()) ) )
+ && ( (this.getRest()==castOther.getRest()) || ( this.getRest()!=null && castOther.getRest()!=null && this.getRest().equals(castOther.getRest()) ) );
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getGlotrechteid();
+         result = 37 * result + (int) this.getGsiebsatzid();
+         result = 37 * result + ( getGmasse() == null ? 0 : this.getGmasse().hashCode() );
+         result = 37 * result + ( getMasche01() == null ? 0 : this.getMasche01().hashCode() );
+         result = 37 * result + ( getRueck01() == null ? 0 : this.getRueck01().hashCode() );
+         result = 37 * result + ( getMasche02() == null ? 0 : this.getMasche02().hashCode() );
+         result = 37 * result + ( getRueck02() == null ? 0 : this.getRueck02().hashCode() );
+         result = 37 * result + ( getMasche03() == null ? 0 : this.getMasche03().hashCode() );
+         result = 37 * result + ( getRueck03() == null ? 0 : this.getRueck03().hashCode() );
+         result = 37 * result + ( getMasche04() == null ? 0 : this.getMasche04().hashCode() );
+         result = 37 * result + ( getRueck04() == null ? 0 : this.getRueck04().hashCode() );
+         result = 37 * result + ( getMasche05() == null ? 0 : this.getMasche05().hashCode() );
+         result = 37 * result + ( getRueck05() == null ? 0 : this.getRueck05().hashCode() );
+         result = 37 * result + ( getMasche06() == null ? 0 : this.getMasche06().hashCode() );
+         result = 37 * result + ( getRueck06() == null ? 0 : this.getRueck06().hashCode() );
+         result = 37 * result + ( getMasche07() == null ? 0 : this.getMasche07().hashCode() );
+         result = 37 * result + ( getRueck07() == null ? 0 : this.getRueck07().hashCode() );
+         result = 37 * result + ( getMasche08() == null ? 0 : this.getMasche08().hashCode() );
+         result = 37 * result + ( getRueck08() == null ? 0 : this.getRueck08().hashCode() );
+         result = 37 * result + ( getMasche09() == null ? 0 : this.getMasche09().hashCode() );
+         result = 37 * result + ( getRueck09() == null ? 0 : this.getRueck09().hashCode() );
+         result = 37 * result + ( getMasche10() == null ? 0 : this.getMasche10().hashCode() );
+         result = 37 * result + ( getRueck10() == null ? 0 : this.getRueck10().hashCode() );
+         result = 37 * result + ( getMasche11() == null ? 0 : this.getMasche11().hashCode() );
+         result = 37 * result + ( getRueck11() == null ? 0 : this.getRueck11().hashCode() );
+         result = 37 * result + ( getMasche12() == null ? 0 : this.getMasche12().hashCode() );
+         result = 37 * result + ( getRueck12() == null ? 0 : this.getRueck12().hashCode() );
+         result = 37 * result + ( getMasche13() == null ? 0 : this.getMasche13().hashCode() );
+         result = 37 * result + ( getRueck13() == null ? 0 : this.getRueck13().hashCode() );
+         result = 37 * result + ( getMasche14() == null ? 0 : this.getMasche14().hashCode() );
+         result = 37 * result + ( getRueck14() == null ? 0 : this.getRueck14().hashCode() );
+         result = 37 * result + ( getMasche15() == null ? 0 : this.getMasche15().hashCode() );
+         result = 37 * result + ( getRueck15() == null ? 0 : this.getRueck15().hashCode() );
+         result = 37 * result + ( getMasche16() == null ? 0 : this.getMasche16().hashCode() );
+         result = 37 * result + ( getRueck16() == null ? 0 : this.getRueck16().hashCode() );
+         result = 37 * result + ( getMasche17() == null ? 0 : this.getMasche17().hashCode() );
+         result = 37 * result + ( getRueck17() == null ? 0 : this.getRueck17().hashCode() );
+         result = 37 * result + ( getMasche18() == null ? 0 : this.getMasche18().hashCode() );
+         result = 37 * result + ( getRueck18() == null ? 0 : this.getRueck18().hashCode() );
+         result = 37 * result + ( getMasche19() == null ? 0 : this.getMasche19().hashCode() );
+         result = 37 * result + ( getRueck19() == null ? 0 : this.getRueck19().hashCode() );
+         result = 37 * result + ( getMasche20() == null ? 0 : this.getMasche20().hashCode() );
+         result = 37 * result + ( getRueck20() == null ? 0 : this.getRueck20().hashCode() );
+         result = 37 * result + ( getMasche21() == null ? 0 : this.getMasche21().hashCode() );
+         result = 37 * result + ( getRueck21() == null ? 0 : this.getRueck21().hashCode() );
+         result = 37 * result + ( getRest() == null ? 0 : this.getRest().hashCode() );
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Hpeilpunkt.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,84 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+/**
+ * Hpeilpunkt generated by hbm2java
+ */
+@Entity
+@Table(name="HPEILPUNKT"
+    ,schema="SEDDB"
+)
+public class Hpeilpunkt  implements java.io.Serializable {
+
+
+     private HpeilpunktId id;
+     private Hpeilung hpeilung;
+     private BigDecimal y;
+     private BigDecimal z;
+
+    public Hpeilpunkt() {
+    }
+
+    public Hpeilpunkt(HpeilpunktId id, Hpeilung hpeilung, BigDecimal y, BigDecimal z) {
+       this.id = id;
+       this.hpeilung = hpeilung;
+       this.y = y;
+       this.z = z;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="hpeilungid", column=@Column(name="HPEILUNGID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="punktnr", column=@Column(name="PUNKTNR", nullable=false, precision=5, scale=0) ) } )
+    public HpeilpunktId getId() {
+        return this.id;
+    }
+
+    public void setId(HpeilpunktId id) {
+        this.id = id;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="HPEILUNGID", nullable=false, insertable=false, updatable=false)
+    public Hpeilung getHpeilung() {
+        return this.hpeilung;
+    }
+
+    public void setHpeilung(Hpeilung hpeilung) {
+        this.hpeilung = hpeilung;
+    }
+
+
+    @Column(name="Y", nullable=false, precision=8, scale=3)
+    public BigDecimal getY() {
+        return this.y;
+    }
+
+    public void setY(BigDecimal y) {
+        this.y = y;
+    }
+
+
+    @Column(name="Z", nullable=false, precision=8, scale=3)
+    public BigDecimal getZ() {
+        return this.z;
+    }
+
+    public void setZ(BigDecimal z) {
+        this.z = z;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/HpeilpunktId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,65 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * HpeilpunktId generated by hbm2java
+ */
+@Embeddable
+public class HpeilpunktId  implements java.io.Serializable {
+
+
+     private long hpeilungid;
+     private int punktnr;
+
+    public HpeilpunktId() {
+    }
+
+    public HpeilpunktId(long hpeilungid, int punktnr) {
+       this.hpeilungid = hpeilungid;
+       this.punktnr = punktnr;
+    }
+
+
+
+    @Column(name="HPEILUNGID", nullable=false, precision=11, scale=0)
+    public long getHpeilungid() {
+        return this.hpeilungid;
+    }
+
+    public void setHpeilungid(long hpeilungid) {
+        this.hpeilungid = hpeilungid;
+    }
+
+
+    @Column(name="PUNKTNR", nullable=false, precision=5, scale=0)
+    public int getPunktnr() {
+        return this.punktnr;
+    }
+
+    public void setPunktnr(int punktnr) {
+        this.punktnr = punktnr;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof HpeilpunktId) ) return false;
+         HpeilpunktId castOther = ( HpeilpunktId ) other;
+
+         return (this.getHpeilungid()==castOther.getHpeilungid())
+ && (this.getPunktnr()==castOther.getPunktnr());
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getHpeilungid();
+         result = 37 * result + this.getPunktnr();
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Hpeilung.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,463 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+/**
+ * Hpeilung generated by hbm2java
+ */
+@Entity
+@Table(name="HPEILUNG"
+    ,schema="SEDDB"
+)
+public class Hpeilung  implements java.io.Serializable {
+
+
+     private long hpeilungid;
+     private Station station;
+     private BigDecimal km;
+     private Date datum;
+     private String glwname;
+     private BigDecimal glwhoehe;
+     private BigDecimal buliabst;
+     private BigDecimal bulihoehe;
+     private BigDecimal bulifuss;
+     private BigDecimal buliruecken;
+     private BigDecimal bureabst;
+     private BigDecimal burehoehe;
+     private BigDecimal burefuss;
+     private BigDecimal bureruecken;
+     private BigDecimal fahrliabst;
+     private BigDecimal fahrreabst;
+     private BigDecimal fahrtief;
+     private BigDecimal ausbliabst;
+     private BigDecimal ausbreabst;
+     private BigDecimal achseabst;
+     private BigDecimal teilvonabst;
+     private BigDecimal teilbisabst;
+     private BigDecimal hmabst;
+     private BigDecimal lgkrechts;
+     private BigDecimal lgkhoch;
+     private BigDecimal lgkhoehe;
+     private BigDecimal rgkrechts;
+     private BigDecimal rgkhoch;
+     private BigDecimal rgkhoehe;
+     private String bemerkung;
+     private Date lastupdated;
+     private Long oldprfid;
+     private BigDecimal mitteabst;
+     private Set<Hpeilpunkt> hpeilpunkts = new HashSet<Hpeilpunkt>(0);
+     private Set<Messung> messungs = new HashSet<Messung>(0);
+
+    public Hpeilung() {
+    }
+
+    public Hpeilung(long hpeilungid, Station station, BigDecimal km, Date datum, Date lastupdated) {
+        this.hpeilungid = hpeilungid;
+        this.station = station;
+        this.km = km;
+        this.datum = datum;
+        this.lastupdated = lastupdated;
+    }
+    public Hpeilung(long hpeilungid, Station station, BigDecimal km, Date datum, String glwname, BigDecimal glwhoehe, BigDecimal buliabst, BigDecimal bulihoehe, BigDecimal bulifuss, BigDecimal buliruecken, BigDecimal bureabst, BigDecimal burehoehe, BigDecimal burefuss, BigDecimal bureruecken, BigDecimal fahrliabst, BigDecimal fahrreabst, BigDecimal fahrtief, BigDecimal ausbliabst, BigDecimal ausbreabst, BigDecimal achseabst, BigDecimal teilvonabst, BigDecimal teilbisabst, BigDecimal hmabst, BigDecimal lgkrechts, BigDecimal lgkhoch, BigDecimal lgkhoehe, BigDecimal rgkrechts, BigDecimal rgkhoch, BigDecimal rgkhoehe, String bemerkung, Date lastupdated, Long oldprfid, BigDecimal mitteabst, Set<Hpeilpunkt> hpeilpunkts, Set<Messung> messungs) {
+       this.hpeilungid = hpeilungid;
+       this.station = station;
+       this.km = km;
+       this.datum = datum;
+       this.glwname = glwname;
+       this.glwhoehe = glwhoehe;
+       this.buliabst = buliabst;
+       this.bulihoehe = bulihoehe;
+       this.bulifuss = bulifuss;
+       this.buliruecken = buliruecken;
+       this.bureabst = bureabst;
+       this.burehoehe = burehoehe;
+       this.burefuss = burefuss;
+       this.bureruecken = bureruecken;
+       this.fahrliabst = fahrliabst;
+       this.fahrreabst = fahrreabst;
+       this.fahrtief = fahrtief;
+       this.ausbliabst = ausbliabst;
+       this.ausbreabst = ausbreabst;
+       this.achseabst = achseabst;
+       this.teilvonabst = teilvonabst;
+       this.teilbisabst = teilbisabst;
+       this.hmabst = hmabst;
+       this.lgkrechts = lgkrechts;
+       this.lgkhoch = lgkhoch;
+       this.lgkhoehe = lgkhoehe;
+       this.rgkrechts = rgkrechts;
+       this.rgkhoch = rgkhoch;
+       this.rgkhoehe = rgkhoehe;
+       this.bemerkung = bemerkung;
+       this.lastupdated = lastupdated;
+       this.oldprfid = oldprfid;
+       this.mitteabst = mitteabst;
+       this.hpeilpunkts = hpeilpunkts;
+       this.messungs = messungs;
+    }
+
+     @Id
+
+
+    @Column(name="HPEILUNGID", unique=true, nullable=false, precision=11, scale=0)
+    public long getHpeilungid() {
+        return this.hpeilungid;
+    }
+
+    public void setHpeilungid(long hpeilungid) {
+        this.hpeilungid = hpeilungid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="STATIONID", nullable=false)
+    public Station getStation() {
+        return this.station;
+    }
+
+    public void setStation(Station station) {
+        this.station = station;
+    }
+
+
+    @Column(name="KM", nullable=false, precision=8, scale=3)
+    public BigDecimal getKm() {
+        return this.km;
+    }
+
+    public void setKm(BigDecimal km) {
+        this.km = km;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="DATUM", nullable=false, length=7)
+    public Date getDatum() {
+        return this.datum;
+    }
+
+    public void setDatum(Date datum) {
+        this.datum = datum;
+    }
+
+
+    @Column(name="GLWNAME", length=8)
+    public String getGlwname() {
+        return this.glwname;
+    }
+
+    public void setGlwname(String glwname) {
+        this.glwname = glwname;
+    }
+
+
+    @Column(name="GLWHOEHE", precision=8, scale=3)
+    public BigDecimal getGlwhoehe() {
+        return this.glwhoehe;
+    }
+
+    public void setGlwhoehe(BigDecimal glwhoehe) {
+        this.glwhoehe = glwhoehe;
+    }
+
+
+    @Column(name="BULIABST", precision=8, scale=3)
+    public BigDecimal getBuliabst() {
+        return this.buliabst;
+    }
+
+    public void setBuliabst(BigDecimal buliabst) {
+        this.buliabst = buliabst;
+    }
+
+
+    @Column(name="BULIHOEHE", precision=8, scale=3)
+    public BigDecimal getBulihoehe() {
+        return this.bulihoehe;
+    }
+
+    public void setBulihoehe(BigDecimal bulihoehe) {
+        this.bulihoehe = bulihoehe;
+    }
+
+
+    @Column(name="BULIFUSS", precision=8, scale=3)
+    public BigDecimal getBulifuss() {
+        return this.bulifuss;
+    }
+
+    public void setBulifuss(BigDecimal bulifuss) {
+        this.bulifuss = bulifuss;
+    }
+
+
+    @Column(name="BULIRUECKEN", precision=8, scale=3)
+    public BigDecimal getBuliruecken() {
+        return this.buliruecken;
+    }
+
+    public void setBuliruecken(BigDecimal buliruecken) {
+        this.buliruecken = buliruecken;
+    }
+
+
+    @Column(name="BUREABST", precision=8, scale=3)
+    public BigDecimal getBureabst() {
+        return this.bureabst;
+    }
+
+    public void setBureabst(BigDecimal bureabst) {
+        this.bureabst = bureabst;
+    }
+
+
+    @Column(name="BUREHOEHE", precision=8, scale=3)
+    public BigDecimal getBurehoehe() {
+        return this.burehoehe;
+    }
+
+    public void setBurehoehe(BigDecimal burehoehe) {
+        this.burehoehe = burehoehe;
+    }
+
+
+    @Column(name="BUREFUSS", precision=8, scale=3)
+    public BigDecimal getBurefuss() {
+        return this.burefuss;
+    }
+
+    public void setBurefuss(BigDecimal burefuss) {
+        this.burefuss = burefuss;
+    }
+
+
+    @Column(name="BURERUECKEN", precision=8, scale=3)
+    public BigDecimal getBureruecken() {
+        return this.bureruecken;
+    }
+
+    public void setBureruecken(BigDecimal bureruecken) {
+        this.bureruecken = bureruecken;
+    }
+
+
+    @Column(name="FAHRLIABST", precision=8, scale=3)
+    public BigDecimal getFahrliabst() {
+        return this.fahrliabst;
+    }
+
+    public void setFahrliabst(BigDecimal fahrliabst) {
+        this.fahrliabst = fahrliabst;
+    }
+
+
+    @Column(name="FAHRREABST", precision=8, scale=3)
+    public BigDecimal getFahrreabst() {
+        return this.fahrreabst;
+    }
+
+    public void setFahrreabst(BigDecimal fahrreabst) {
+        this.fahrreabst = fahrreabst;
+    }
+
+
+    @Column(name="FAHRTIEF", precision=8, scale=3)
+    public BigDecimal getFahrtief() {
+        return this.fahrtief;
+    }
+
+    public void setFahrtief(BigDecimal fahrtief) {
+        this.fahrtief = fahrtief;
+    }
+
+
+    @Column(name="AUSBLIABST", precision=8, scale=3)
+    public BigDecimal getAusbliabst() {
+        return this.ausbliabst;
+    }
+
+    public void setAusbliabst(BigDecimal ausbliabst) {
+        this.ausbliabst = ausbliabst;
+    }
+
+
+    @Column(name="AUSBREABST", precision=8, scale=3)
+    public BigDecimal getAusbreabst() {
+        return this.ausbreabst;
+    }
+
+    public void setAusbreabst(BigDecimal ausbreabst) {
+        this.ausbreabst = ausbreabst;
+    }
+
+
+    @Column(name="ACHSEABST", precision=8, scale=3)
+    public BigDecimal getAchseabst() {
+        return this.achseabst;
+    }
+
+    public void setAchseabst(BigDecimal achseabst) {
+        this.achseabst = achseabst;
+    }
+
+
+    @Column(name="TEILVONABST", precision=8, scale=3)
+    public BigDecimal getTeilvonabst() {
+        return this.teilvonabst;
+    }
+
+    public void setTeilvonabst(BigDecimal teilvonabst) {
+        this.teilvonabst = teilvonabst;
+    }
+
+
+    @Column(name="TEILBISABST", precision=8, scale=3)
+    public BigDecimal getTeilbisabst() {
+        return this.teilbisabst;
+    }
+
+    public void setTeilbisabst(BigDecimal teilbisabst) {
+        this.teilbisabst = teilbisabst;
+    }
+
+
+    @Column(name="HMABST", precision=8, scale=3)
+    public BigDecimal getHmabst() {
+        return this.hmabst;
+    }
+
+    public void setHmabst(BigDecimal hmabst) {
+        this.hmabst = hmabst;
+    }
+
+
+    @Column(name="LGKRECHTS", precision=11, scale=3)
+    public BigDecimal getLgkrechts() {
+        return this.lgkrechts;
+    }
+
+    public void setLgkrechts(BigDecimal lgkrechts) {
+        this.lgkrechts = lgkrechts;
+    }
+
+
+    @Column(name="LGKHOCH", precision=11, scale=3)
+    public BigDecimal getLgkhoch() {
+        return this.lgkhoch;
+    }
+
+    public void setLgkhoch(BigDecimal lgkhoch) {
+        this.lgkhoch = lgkhoch;
+    }
+
+
+    @Column(name="LGKHOEHE", precision=8, scale=3)
+    public BigDecimal getLgkhoehe() {
+        return this.lgkhoehe;
+    }
+
+    public void setLgkhoehe(BigDecimal lgkhoehe) {
+        this.lgkhoehe = lgkhoehe;
+    }
+
+
+    @Column(name="RGKRECHTS", precision=11, scale=3)
+    public BigDecimal getRgkrechts() {
+        return this.rgkrechts;
+    }
+
+    public void setRgkrechts(BigDecimal rgkrechts) {
+        this.rgkrechts = rgkrechts;
+    }
+
+
+    @Column(name="RGKHOCH", precision=11, scale=3)
+    public BigDecimal getRgkhoch() {
+        return this.rgkhoch;
+    }
+
+    public void setRgkhoch(BigDecimal rgkhoch) {
+        this.rgkhoch = rgkhoch;
+    }
+
+
+    @Column(name="RGKHOEHE", precision=8, scale=3)
+    public BigDecimal getRgkhoehe() {
+        return this.rgkhoehe;
+    }
+
+    public void setRgkhoehe(BigDecimal rgkhoehe) {
+        this.rgkhoehe = rgkhoehe;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="LASTUPDATED", nullable=false, length=7)
+    public Date getLastupdated() {
+        return this.lastupdated;
+    }
+
+    public void setLastupdated(Date lastupdated) {
+        this.lastupdated = lastupdated;
+    }
+
+
+    @Column(name="OLDPRFID", precision=11, scale=0)
+    public Long getOldprfid() {
+        return this.oldprfid;
+    }
+
+    public void setOldprfid(Long oldprfid) {
+        this.oldprfid = oldprfid;
+    }
+
+
+    @Column(name="MITTEABST", precision=8, scale=3)
+    public BigDecimal getMitteabst() {
+        return this.mitteabst;
+    }
+
+    public void setMitteabst(BigDecimal mitteabst) {
+        this.mitteabst = mitteabst;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="hpeilung")
+    public Set<Hpeilpunkt> getHpeilpunkts() {
+        return this.hpeilpunkts;
+    }
+
+    public void setHpeilpunkts(Set<Hpeilpunkt> hpeilpunkts) {
+        this.hpeilpunkts = hpeilpunkts;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="hpeilung")
+    public Set<Messung> getMessungs() {
+        return this.messungs;
+    }
+
+    public void setMessungs(Set<Messung> messungs) {
+        this.messungs = messungs;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Messung.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,995 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+/**
+ * Messung generated by hbm2java
+ */
+@Entity
+@Table(name="MESSUNG"
+    ,schema="SEDDB"
+)
+public class Messung  implements java.io.Serializable {
+
+     private long messungid;
+     private Station station;
+     private Gsiebsatz gsiebsatz;
+     private Gfaenger gfaenger;
+     private Hpeilung hpeilung;
+     private Date datum;
+     private Long mpeilungid;
+     private int messnr;
+     private String fgue;
+     private Date uhrvon;
+     private Date uhrbis;
+     private BigDecimal wspcm;
+     private BigDecimal QBpegel;
+     private BigDecimal wspnn;
+     private BigDecimal ie;
+     private BigDecimal wtemp;
+     private BigDecimal gbreite;
+     private BigDecimal gbreitevon;
+     private BigDecimal gbreitebis;
+     private BigDecimal tgeschiebe;
+     private BigDecimal tsand;
+     private BigDecimal tschweb;
+     private BigDecimal cschweb;
+     private BigDecimal uferliabst;
+     private BigDecimal uferreabst;
+     private BigDecimal q;
+     private BigDecimal AHpeil;
+     private BigDecimal AMpeil;
+     private BigDecimal b;
+     private BigDecimal hm;
+     private BigDecimal vm;
+     private BigDecimal vsohle;
+     private BigDecimal tau;
+     private BigDecimal tauv;
+     private BigDecimal teilQ;
+     private BigDecimal teilAHpeil;
+     private BigDecimal teilAMpeil;
+     private BigDecimal teilB;
+     private BigDecimal teilHm;
+     private BigDecimal teilVm;
+     private BigDecimal teilVsohle;
+     private BigDecimal teilTau;
+     private BigDecimal teilTauv;
+     private Boolean mitteltyp;
+     private BigDecimal dm;
+     private BigDecimal sk;
+     private BigDecimal so;
+     private BigDecimal u;
+     private BigDecimal d90;
+     private BigDecimal d84;
+     private BigDecimal d80;
+     private BigDecimal d75;
+     private BigDecimal d70;
+     private BigDecimal d60;
+     private BigDecimal d50;
+     private BigDecimal d40;
+     private BigDecimal d30;
+     private BigDecimal d25;
+     private BigDecimal d20;
+     private BigDecimal d16;
+     private BigDecimal d10;
+     private BigDecimal dmin;
+     private BigDecimal durchdmin;
+     private BigDecimal dmax;
+     private BigDecimal durchdmax;
+     private int NGeschieb;
+     private int NVielpkt;
+     private Date sysDate;
+     private String bemerkung;
+     private Date lastupdated;
+     private BigDecimal km;
+     private BigDecimal glotabstoffset;
+     private BigDecimal slotabstoffset;
+     private BigDecimal gbreitevonlinks;
+     private BigDecimal gbreitebislinks;
+     private Boolean glotuferabstistvonlinks;
+     private Boolean slotuferabstistvonlinks;
+     private Set<Glotrechte> glotrechtes = new HashSet<Glotrechte>(0);
+     private Set<Slotrechte> slotrechtes = new HashSet<Slotrechte>(0);
+
+    public Messung() {
+    }
+
+
+    public Messung(long messungid, Station station, Date datum, int messnr, int NGeschieb, int NVielpkt, Date lastupdated, BigDecimal glotabstoffset, BigDecimal slotabstoffset) {
+        this.messungid = messungid;
+        this.station = station;
+        this.datum = datum;
+        this.messnr = messnr;
+        this.NGeschieb = NGeschieb;
+        this.NVielpkt = NVielpkt;
+        this.lastupdated = lastupdated;
+        this.glotabstoffset = glotabstoffset;
+        this.slotabstoffset = slotabstoffset;
+    }
+    public Messung(long messungid, Station station, Gsiebsatz gsiebsatz, Gfaenger gfaenger, Hpeilung hpeilung, Date datum, Long mpeilungid, int messnr, String fgue, Date uhrvon, Date uhrbis, BigDecimal wspcm, BigDecimal QBpegel, BigDecimal wspnn, BigDecimal ie, BigDecimal wtemp, BigDecimal gbreite, BigDecimal gbreitevon, BigDecimal gbreitebis, BigDecimal tgeschiebe, BigDecimal tsand, BigDecimal tschweb, BigDecimal cschweb, BigDecimal uferliabst, BigDecimal uferreabst, BigDecimal q, BigDecimal AHpeil, BigDecimal AMpeil, BigDecimal b, BigDecimal hm, BigDecimal vm, BigDecimal vsohle, BigDecimal tau, BigDecimal tauv, BigDecimal teilQ, BigDecimal teilAHpeil, BigDecimal teilAMpeil, BigDecimal teilB, BigDecimal teilHm, BigDecimal teilVm, BigDecimal teilVsohle, BigDecimal teilTau, BigDecimal teilTauv, Boolean mitteltyp, BigDecimal dm, BigDecimal sk, BigDecimal so, BigDecimal u, BigDecimal d90, BigDecimal d84, BigDecimal d80, BigDecimal d75, BigDecimal d70, BigDecimal d60, BigDecimal d50, BigDecimal d40, BigDecimal d30, BigDecimal d25, BigDecimal d20, BigDecimal d16, BigDecimal d10, BigDecimal dmin, BigDecimal durchdmin, BigDecimal dmax, BigDecimal durchdmax, int NGeschieb, int NVielpkt, Date sysDate, String bemerkung, Date lastupdated, BigDecimal km, BigDecimal glotabstoffset, BigDecimal slotabstoffset, BigDecimal gbreitevonlinks, BigDecimal gbreitebislinks, Boolean glotuferabstistvonlinks, Boolean slotuferabstistvonlinks, Set<Glotrechte> glotrechtes, Set<Slotrechte> slotrechtes) {
+       this.messungid = messungid;
+       this.station = station;
+       this.gsiebsatz = gsiebsatz;
+       this.gfaenger = gfaenger;
+       this.hpeilung = hpeilung;
+       this.datum = datum;
+       this.mpeilungid = mpeilungid;
+       this.messnr = messnr;
+       this.fgue = fgue;
+       this.uhrvon = uhrvon;
+       this.uhrbis = uhrbis;
+       this.wspcm = wspcm;
+       this.QBpegel = QBpegel;
+       this.wspnn = wspnn;
+       this.ie = ie;
+       this.wtemp = wtemp;
+       this.gbreite = gbreite;
+       this.gbreitevon = gbreitevon;
+       this.gbreitebis = gbreitebis;
+       this.tgeschiebe = tgeschiebe;
+       this.tsand = tsand;
+       this.tschweb = tschweb;
+       this.cschweb = cschweb;
+       this.uferliabst = uferliabst;
+       this.uferreabst = uferreabst;
+       this.q = q;
+       this.AHpeil = AHpeil;
+       this.AMpeil = AMpeil;
+       this.b = b;
+       this.hm = hm;
+       this.vm = vm;
+       this.vsohle = vsohle;
+       this.tau = tau;
+       this.tauv = tauv;
+       this.teilQ = teilQ;
+       this.teilAHpeil = teilAHpeil;
+       this.teilAMpeil = teilAMpeil;
+       this.teilB = teilB;
+       this.teilHm = teilHm;
+       this.teilVm = teilVm;
+       this.teilVsohle = teilVsohle;
+       this.teilTau = teilTau;
+       this.teilTauv = teilTauv;
+       this.mitteltyp = mitteltyp;
+       this.dm = dm;
+       this.sk = sk;
+       this.so = so;
+       this.u = u;
+       this.d90 = d90;
+       this.d84 = d84;
+       this.d80 = d80;
+       this.d75 = d75;
+       this.d70 = d70;
+       this.d60 = d60;
+       this.d50 = d50;
+       this.d40 = d40;
+       this.d30 = d30;
+       this.d25 = d25;
+       this.d20 = d20;
+       this.d16 = d16;
+       this.d10 = d10;
+       this.dmin = dmin;
+       this.durchdmin = durchdmin;
+       this.dmax = dmax;
+       this.durchdmax = durchdmax;
+       this.NGeschieb = NGeschieb;
+       this.NVielpkt = NVielpkt;
+       this.sysDate = sysDate;
+       this.bemerkung = bemerkung;
+       this.lastupdated = lastupdated;
+       this.km = km;
+       this.glotabstoffset = glotabstoffset;
+       this.slotabstoffset = slotabstoffset;
+       this.gbreitevonlinks = gbreitevonlinks;
+       this.gbreitebislinks = gbreitebislinks;
+       this.glotuferabstistvonlinks = glotuferabstistvonlinks;
+       this.slotuferabstistvonlinks = slotuferabstistvonlinks;
+       this.glotrechtes = glotrechtes;
+       this.slotrechtes = slotrechtes;
+    }
+
+     @Id
+
+
+    @Column(name="MESSUNGID", unique=true, nullable=false, precision=11, scale=0)
+    public long getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(long messungid) {
+        this.messungid = messungid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="STATIONID", nullable=false)
+    public Station getStation() {
+        return this.station;
+    }
+
+    public void setStation(Station station) {
+        this.station = station;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="GSIEBSATZID")
+    public Gsiebsatz getGsiebsatz() {
+        return this.gsiebsatz;
+    }
+
+    public void setGsiebsatz(Gsiebsatz gsiebsatz) {
+        this.gsiebsatz = gsiebsatz;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="GFAENGERID")
+    public Gfaenger getGfaenger() {
+        return this.gfaenger;
+    }
+
+    public void setGfaenger(Gfaenger gfaenger) {
+        this.gfaenger = gfaenger;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="HPEILUNGID")
+    public Hpeilung getHpeilung() {
+        return this.hpeilung;
+    }
+
+    public void setHpeilung(Hpeilung hpeilung) {
+        this.hpeilung = hpeilung;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="DATUM", nullable=false, length=7)
+    public Date getDatum() {
+        return this.datum;
+    }
+
+    public void setDatum(Date datum) {
+        this.datum = datum;
+    }
+
+
+    @Column(name="MPEILUNGID", precision=11, scale=0)
+    public Long getMpeilungid() {
+        return this.mpeilungid;
+    }
+
+    public void setMpeilungid(Long mpeilungid) {
+        this.mpeilungid = mpeilungid;
+    }
+
+
+    @Column(name="MESSNR", nullable=false, precision=5, scale=0)
+    public int getMessnr() {
+        return this.messnr;
+    }
+
+    public void setMessnr(int messnr) {
+        this.messnr = messnr;
+    }
+
+
+    @Column(name="FGUE", length=10)
+    public String getFgue() {
+        return this.fgue;
+    }
+
+    public void setFgue(String fgue) {
+        this.fgue = fgue;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="UHRVON", length=7)
+    public Date getUhrvon() {
+        return this.uhrvon;
+    }
+
+    public void setUhrvon(Date uhrvon) {
+        this.uhrvon = uhrvon;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="UHRBIS", length=7)
+    public Date getUhrbis() {
+        return this.uhrbis;
+    }
+
+    public void setUhrbis(Date uhrbis) {
+        this.uhrbis = uhrbis;
+    }
+
+
+    @Column(name="WSPCM", precision=8, scale=1)
+    public BigDecimal getWspcm() {
+        return this.wspcm;
+    }
+
+    public void setWspcm(BigDecimal wspcm) {
+        this.wspcm = wspcm;
+    }
+
+
+    @Column(name="Q_BPEGEL", precision=8, scale=3)
+    public BigDecimal getQBpegel() {
+        return this.QBpegel;
+    }
+
+    public void setQBpegel(BigDecimal QBpegel) {
+        this.QBpegel = QBpegel;
+    }
+
+
+    @Column(name="WSPNN", precision=8, scale=3)
+    public BigDecimal getWspnn() {
+        return this.wspnn;
+    }
+
+    public void setWspnn(BigDecimal wspnn) {
+        this.wspnn = wspnn;
+    }
+
+
+    @Column(name="IE", precision=6, scale=3)
+    public BigDecimal getIe() {
+        return this.ie;
+    }
+
+    public void setIe(BigDecimal ie) {
+        this.ie = ie;
+    }
+
+
+    @Column(name="WTEMP", precision=4, scale=1)
+    public BigDecimal getWtemp() {
+        return this.wtemp;
+    }
+
+    public void setWtemp(BigDecimal wtemp) {
+        this.wtemp = wtemp;
+    }
+
+
+    @Column(name="GBREITE", precision=8, scale=3)
+    public BigDecimal getGbreite() {
+        return this.gbreite;
+    }
+
+    public void setGbreite(BigDecimal gbreite) {
+        this.gbreite = gbreite;
+    }
+
+
+    @Column(name="GBREITEVON", precision=8, scale=3)
+    public BigDecimal getGbreitevon() {
+        return this.gbreitevon;
+    }
+
+    public void setGbreitevon(BigDecimal gbreitevon) {
+        this.gbreitevon = gbreitevon;
+    }
+
+
+    @Column(name="GBREITEBIS", precision=8, scale=3)
+    public BigDecimal getGbreitebis() {
+        return this.gbreitebis;
+    }
+
+    public void setGbreitebis(BigDecimal gbreitebis) {
+        this.gbreitebis = gbreitebis;
+    }
+
+
+    @Column(name="TGESCHIEBE", precision=9, scale=3)
+    public BigDecimal getTgeschiebe() {
+        return this.tgeschiebe;
+    }
+
+    public void setTgeschiebe(BigDecimal tgeschiebe) {
+        this.tgeschiebe = tgeschiebe;
+    }
+
+
+    @Column(name="TSAND", precision=9, scale=3)
+    public BigDecimal getTsand() {
+        return this.tsand;
+    }
+
+    public void setTsand(BigDecimal tsand) {
+        this.tsand = tsand;
+    }
+
+
+    @Column(name="TSCHWEB", precision=9, scale=3)
+    public BigDecimal getTschweb() {
+        return this.tschweb;
+    }
+
+    public void setTschweb(BigDecimal tschweb) {
+        this.tschweb = tschweb;
+    }
+
+
+    @Column(name="CSCHWEB", precision=8, scale=3)
+    public BigDecimal getCschweb() {
+        return this.cschweb;
+    }
+
+    public void setCschweb(BigDecimal cschweb) {
+        this.cschweb = cschweb;
+    }
+
+
+    @Column(name="UFERLIABST", precision=8, scale=3)
+    public BigDecimal getUferliabst() {
+        return this.uferliabst;
+    }
+
+    public void setUferliabst(BigDecimal uferliabst) {
+        this.uferliabst = uferliabst;
+    }
+
+
+    @Column(name="UFERREABST", precision=8, scale=3)
+    public BigDecimal getUferreabst() {
+        return this.uferreabst;
+    }
+
+    public void setUferreabst(BigDecimal uferreabst) {
+        this.uferreabst = uferreabst;
+    }
+
+
+    @Column(name="Q", precision=8, scale=3)
+    public BigDecimal getQ() {
+        return this.q;
+    }
+
+    public void setQ(BigDecimal q) {
+        this.q = q;
+    }
+
+
+    @Column(name="A_HPEIL", precision=6, scale=1)
+    public BigDecimal getAHpeil() {
+        return this.AHpeil;
+    }
+
+    public void setAHpeil(BigDecimal AHpeil) {
+        this.AHpeil = AHpeil;
+    }
+
+
+    @Column(name="A_MPEIL", precision=6, scale=1)
+    public BigDecimal getAMpeil() {
+        return this.AMpeil;
+    }
+
+    public void setAMpeil(BigDecimal AMpeil) {
+        this.AMpeil = AMpeil;
+    }
+
+
+    @Column(name="B", precision=8, scale=3)
+    public BigDecimal getB() {
+        return this.b;
+    }
+
+    public void setB(BigDecimal b) {
+        this.b = b;
+    }
+
+
+    @Column(name="HM", precision=8, scale=3)
+    public BigDecimal getHm() {
+        return this.hm;
+    }
+
+    public void setHm(BigDecimal hm) {
+        this.hm = hm;
+    }
+
+
+    @Column(name="VM", precision=6, scale=4)
+    public BigDecimal getVm() {
+        return this.vm;
+    }
+
+    public void setVm(BigDecimal vm) {
+        this.vm = vm;
+    }
+
+
+    @Column(name="VSOHLE", precision=6, scale=4)
+    public BigDecimal getVsohle() {
+        return this.vsohle;
+    }
+
+    public void setVsohle(BigDecimal vsohle) {
+        this.vsohle = vsohle;
+    }
+
+
+    @Column(name="TAU", precision=9, scale=4)
+    public BigDecimal getTau() {
+        return this.tau;
+    }
+
+    public void setTau(BigDecimal tau) {
+        this.tau = tau;
+    }
+
+
+    @Column(name="TAUV", precision=9, scale=6)
+    public BigDecimal getTauv() {
+        return this.tauv;
+    }
+
+    public void setTauv(BigDecimal tauv) {
+        this.tauv = tauv;
+    }
+
+
+    @Column(name="TEIL_Q", precision=8, scale=3)
+    public BigDecimal getTeilQ() {
+        return this.teilQ;
+    }
+
+    public void setTeilQ(BigDecimal teilQ) {
+        this.teilQ = teilQ;
+    }
+
+
+    @Column(name="TEIL_A_HPEIL", precision=6, scale=1)
+    public BigDecimal getTeilAHpeil() {
+        return this.teilAHpeil;
+    }
+
+    public void setTeilAHpeil(BigDecimal teilAHpeil) {
+        this.teilAHpeil = teilAHpeil;
+    }
+
+
+    @Column(name="TEIL_A_MPEIL", precision=6, scale=1)
+    public BigDecimal getTeilAMpeil() {
+        return this.teilAMpeil;
+    }
+
+    public void setTeilAMpeil(BigDecimal teilAMpeil) {
+        this.teilAMpeil = teilAMpeil;
+    }
+
+
+    @Column(name="TEIL_B", precision=8, scale=3)
+    public BigDecimal getTeilB() {
+        return this.teilB;
+    }
+
+    public void setTeilB(BigDecimal teilB) {
+        this.teilB = teilB;
+    }
+
+
+    @Column(name="TEIL_HM", precision=8, scale=3)
+    public BigDecimal getTeilHm() {
+        return this.teilHm;
+    }
+
+    public void setTeilHm(BigDecimal teilHm) {
+        this.teilHm = teilHm;
+    }
+
+
+    @Column(name="TEIL_VM", precision=6, scale=4)
+    public BigDecimal getTeilVm() {
+        return this.teilVm;
+    }
+
+    public void setTeilVm(BigDecimal teilVm) {
+        this.teilVm = teilVm;
+    }
+
+
+    @Column(name="TEIL_VSOHLE", precision=6, scale=4)
+    public BigDecimal getTeilVsohle() {
+        return this.teilVsohle;
+    }
+
+    public void setTeilVsohle(BigDecimal teilVsohle) {
+        this.teilVsohle = teilVsohle;
+    }
+
+
+    @Column(name="TEIL_TAU", precision=9, scale=4)
+    public BigDecimal getTeilTau() {
+        return this.teilTau;
+    }
+
+    public void setTeilTau(BigDecimal teilTau) {
+        this.teilTau = teilTau;
+    }
+
+
+    @Column(name="TEIL_TAUV", precision=9, scale=6)
+    public BigDecimal getTeilTauv() {
+        return this.teilTauv;
+    }
+
+    public void setTeilTauv(BigDecimal teilTauv) {
+        this.teilTauv = teilTauv;
+    }
+
+
+    @Column(name="MITTELTYP", precision=1, scale=0)
+    public Boolean getMitteltyp() {
+        return this.mitteltyp;
+    }
+
+    public void setMitteltyp(Boolean mitteltyp) {
+        this.mitteltyp = mitteltyp;
+    }
+
+
+    @Column(name="DM", precision=7, scale=3)
+    public BigDecimal getDm() {
+        return this.dm;
+    }
+
+    public void setDm(BigDecimal dm) {
+        this.dm = dm;
+    }
+
+
+    @Column(name="SK", precision=8, scale=3)
+    public BigDecimal getSk() {
+        return this.sk;
+    }
+
+    public void setSk(BigDecimal sk) {
+        this.sk = sk;
+    }
+
+
+    @Column(name="SO", precision=8, scale=3)
+    public BigDecimal getSo() {
+        return this.so;
+    }
+
+    public void setSo(BigDecimal so) {
+        this.so = so;
+    }
+
+
+    @Column(name="U", precision=8, scale=3)
+    public BigDecimal getU() {
+        return this.u;
+    }
+
+    public void setU(BigDecimal u) {
+        this.u = u;
+    }
+
+
+    @Column(name="D90", precision=7, scale=4)
+    public BigDecimal getD90() {
+        return this.d90;
+    }
+
+    public void setD90(BigDecimal d90) {
+        this.d90 = d90;
+    }
+
+
+    @Column(name="D84", precision=7, scale=4)
+    public BigDecimal getD84() {
+        return this.d84;
+    }
+
+    public void setD84(BigDecimal d84) {
+        this.d84 = d84;
+    }
+
+
+    @Column(name="D80", precision=7, scale=4)
+    public BigDecimal getD80() {
+        return this.d80;
+    }
+
+    public void setD80(BigDecimal d80) {
+        this.d80 = d80;
+    }
+
+
+    @Column(name="D75", precision=7, scale=4)
+    public BigDecimal getD75() {
+        return this.d75;
+    }
+
+    public void setD75(BigDecimal d75) {
+        this.d75 = d75;
+    }
+
+
+    @Column(name="D70", precision=7, scale=4)
+    public BigDecimal getD70() {
+        return this.d70;
+    }
+
+    public void setD70(BigDecimal d70) {
+        this.d70 = d70;
+    }
+
+
+    @Column(name="D60", precision=7, scale=4)
+    public BigDecimal getD60() {
+        return this.d60;
+    }
+
+    public void setD60(BigDecimal d60) {
+        this.d60 = d60;
+    }
+
+
+    @Column(name="D50", precision=7, scale=4)
+    public BigDecimal getD50() {
+        return this.d50;
+    }
+
+    public void setD50(BigDecimal d50) {
+        this.d50 = d50;
+    }
+
+
+    @Column(name="D40", precision=7, scale=4)
+    public BigDecimal getD40() {
+        return this.d40;
+    }
+
+    public void setD40(BigDecimal d40) {
+        this.d40 = d40;
+    }
+
+
+    @Column(name="D30", precision=7, scale=4)
+    public BigDecimal getD30() {
+        return this.d30;
+    }
+
+    public void setD30(BigDecimal d30) {
+        this.d30 = d30;
+    }
+
+
+    @Column(name="D25", precision=7, scale=4)
+    public BigDecimal getD25() {
+        return this.d25;
+    }
+
+    public void setD25(BigDecimal d25) {
+        this.d25 = d25;
+    }
+
+
+    @Column(name="D20", precision=7, scale=4)
+    public BigDecimal getD20() {
+        return this.d20;
+    }
+
+    public void setD20(BigDecimal d20) {
+        this.d20 = d20;
+    }
+
+
+    @Column(name="D16", precision=7, scale=4)
+    public BigDecimal getD16() {
+        return this.d16;
+    }
+
+    public void setD16(BigDecimal d16) {
+        this.d16 = d16;
+    }
+
+
+    @Column(name="D10", precision=7, scale=4)
+    public BigDecimal getD10() {
+        return this.d10;
+    }
+
+    public void setD10(BigDecimal d10) {
+        this.d10 = d10;
+    }
+
+
+    @Column(name="DMIN", precision=7, scale=4)
+    public BigDecimal getDmin() {
+        return this.dmin;
+    }
+
+    public void setDmin(BigDecimal dmin) {
+        this.dmin = dmin;
+    }
+
+
+    @Column(name="DURCHDMIN", precision=6, scale=3)
+    public BigDecimal getDurchdmin() {
+        return this.durchdmin;
+    }
+
+    public void setDurchdmin(BigDecimal durchdmin) {
+        this.durchdmin = durchdmin;
+    }
+
+
+    @Column(name="DMAX", precision=7, scale=3)
+    public BigDecimal getDmax() {
+        return this.dmax;
+    }
+
+    public void setDmax(BigDecimal dmax) {
+        this.dmax = dmax;
+    }
+
+
+    @Column(name="DURCHDMAX", precision=6, scale=3)
+    public BigDecimal getDurchdmax() {
+        return this.durchdmax;
+    }
+
+    public void setDurchdmax(BigDecimal durchdmax) {
+        this.durchdmax = durchdmax;
+    }
+
+
+    @Column(name="N_GESCHIEB", nullable=false, precision=5, scale=0)
+    public int getNGeschieb() {
+        return this.NGeschieb;
+    }
+
+    public void setNGeschieb(int NGeschieb) {
+        this.NGeschieb = NGeschieb;
+    }
+
+
+    @Column(name="N_VIELPKT", nullable=false, precision=5, scale=0)
+    public int getNVielpkt() {
+        return this.NVielpkt;
+    }
+
+    public void setNVielpkt(int NVielpkt) {
+        this.NVielpkt = NVielpkt;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="SYS_DATE", length=7)
+    public Date getSysDate() {
+        return this.sysDate;
+    }
+
+    public void setSysDate(Date sysDate) {
+        this.sysDate = sysDate;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="LASTUPDATED", nullable=false, length=7)
+    public Date getLastupdated() {
+        return this.lastupdated;
+    }
+
+    public void setLastupdated(Date lastupdated) {
+        this.lastupdated = lastupdated;
+    }
+
+
+    @Column(name="KM", precision=8, scale=3)
+    public BigDecimal getKm() {
+        return this.km;
+    }
+
+    public void setKm(BigDecimal km) {
+        this.km = km;
+    }
+
+
+    @Column(name="GLOTABSTOFFSET", nullable=false, precision=8, scale=3)
+    public BigDecimal getGlotabstoffset() {
+        return this.glotabstoffset;
+    }
+
+    public void setGlotabstoffset(BigDecimal glotabstoffset) {
+        this.glotabstoffset = glotabstoffset;
+    }
+
+
+    @Column(name="SLOTABSTOFFSET", nullable=false, precision=8, scale=3)
+    public BigDecimal getSlotabstoffset() {
+        return this.slotabstoffset;
+    }
+
+    public void setSlotabstoffset(BigDecimal slotabstoffset) {
+        this.slotabstoffset = slotabstoffset;
+    }
+
+
+    @Column(name="GBREITEVONLINKS", precision=8, scale=3)
+    public BigDecimal getGbreitevonlinks() {
+        return this.gbreitevonlinks;
+    }
+
+    public void setGbreitevonlinks(BigDecimal gbreitevonlinks) {
+        this.gbreitevonlinks = gbreitevonlinks;
+    }
+
+
+    @Column(name="GBREITEBISLINKS", precision=8, scale=3)
+    public BigDecimal getGbreitebislinks() {
+        return this.gbreitebislinks;
+    }
+
+    public void setGbreitebislinks(BigDecimal gbreitebislinks) {
+        this.gbreitebislinks = gbreitebislinks;
+    }
+
+
+    @Column(name="GLOTUFERABSTISTVONLINKS", precision=1, scale=0)
+    public Boolean getGlotuferabstistvonlinks() {
+        return this.glotuferabstistvonlinks;
+    }
+
+    public void setGlotuferabstistvonlinks(Boolean glotuferabstistvonlinks) {
+        this.glotuferabstistvonlinks = glotuferabstistvonlinks;
+    }
+
+
+    @Column(name="SLOTUFERABSTISTVONLINKS", precision=1, scale=0)
+    public Boolean getSlotuferabstistvonlinks() {
+        return this.slotuferabstistvonlinks;
+    }
+
+    public void setSlotuferabstistvonlinks(Boolean slotuferabstistvonlinks) {
+        this.slotuferabstistvonlinks = slotuferabstistvonlinks;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="messung")
+    public Set<Glotrechte> getGlotrechtes() {
+        return this.glotrechtes;
+    }
+
+    public void setGlotrechtes(Set<Glotrechte> glotrechtes) {
+        this.glotrechtes = glotrechtes;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="messung")
+    public Set<Slotrechte> getSlotrechtes() {
+        return this.slotrechtes;
+    }
+
+    public void setSlotrechtes(Set<Slotrechte> slotrechtes) {
+        this.slotrechtes = slotrechtes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Messunglotcount.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,45 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Messunglotcount generated by hbm2java
+ */
+@Entity
+@Table(name="MESSUNGLOTCOUNT"
+    ,schema="SEDDB"
+)
+public class Messunglotcount  implements java.io.Serializable {
+
+
+     private MessunglotcountId id;
+
+    public Messunglotcount() {
+    }
+
+    public Messunglotcount(MessunglotcountId id) {
+       this.id = id;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="messungid", column=@Column(name="MESSUNGID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="glotcount", column=@Column(name="GLOTCOUNT", precision=22, scale=0) ),
+        @AttributeOverride(name="slotcount", column=@Column(name="SLOTCOUNT", precision=22, scale=0) ) } )
+    public MessunglotcountId getId() {
+        return this.id;
+    }
+
+    public void setId(MessunglotcountId id) {
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/MessunglotcountId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,84 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * MessunglotcountId generated by hbm2java
+ */
+@Embeddable
+public class MessunglotcountId  implements java.io.Serializable {
+
+
+     private long messungid;
+     private BigDecimal glotcount;
+     private BigDecimal slotcount;
+
+    public MessunglotcountId() {
+    }
+
+
+    public MessunglotcountId(long messungid) {
+        this.messungid = messungid;
+    }
+    public MessunglotcountId(long messungid, BigDecimal glotcount, BigDecimal slotcount) {
+       this.messungid = messungid;
+       this.glotcount = glotcount;
+       this.slotcount = slotcount;
+    }
+
+
+
+    @Column(name="MESSUNGID", nullable=false, precision=11, scale=0)
+    public long getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(long messungid) {
+        this.messungid = messungid;
+    }
+
+
+    @Column(name="GLOTCOUNT", precision=22, scale=0)
+    public BigDecimal getGlotcount() {
+        return this.glotcount;
+    }
+
+    public void setGlotcount(BigDecimal glotcount) {
+        this.glotcount = glotcount;
+    }
+
+
+    @Column(name="SLOTCOUNT", precision=22, scale=0)
+    public BigDecimal getSlotcount() {
+        return this.slotcount;
+    }
+
+    public void setSlotcount(BigDecimal slotcount) {
+        this.slotcount = slotcount;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof MessunglotcountId) ) return false;
+         MessunglotcountId castOther = ( MessunglotcountId ) other;
+
+         return (this.getMessungid()==castOther.getMessungid())
+ && ( (this.getGlotcount()==castOther.getGlotcount()) || ( this.getGlotcount()!=null && castOther.getGlotcount()!=null && this.getGlotcount().equals(castOther.getGlotcount()) ) )
+ && ( (this.getSlotcount()==castOther.getSlotcount()) || ( this.getSlotcount()!=null && castOther.getSlotcount()!=null && this.getSlotcount().equals(castOther.getSlotcount()) ) );
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getMessungid();
+         result = 37 * result + ( getGlotcount() == null ? 0 : this.getGlotcount().hashCode() );
+         result = 37 * result + ( getSlotcount() == null ? 0 : this.getSlotcount().hashCode() );
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Messungsta.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,122 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Messungsta generated by hbm2java
+ */
+@Entity
+@Table(name="MESSUNGSTA"
+    ,schema="SEDDB"
+)
+public class Messungsta  implements java.io.Serializable {
+
+
+     private MessungstaId id;
+
+    public Messungsta() {
+    }
+
+    public Messungsta(MessungstaId id) {
+       this.id = id;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="messungid", column=@Column(name="MESSUNGID") ),
+        @AttributeOverride(name="stationid", column=@Column(name="STATIONID") ),
+        @AttributeOverride(name="datum", column=@Column(name="DATUM") ),
+        @AttributeOverride(name="hpeilungid", column=@Column(name="HPEILUNGID") ),
+        @AttributeOverride(name="mpeilungid", column=@Column(name="MPEILUNGID") ),
+        @AttributeOverride(name="gfaengerid", column=@Column(name="GFAENGERID") ),
+        @AttributeOverride(name="gsiebsatzid", column=@Column(name="GSIEBSATZID") ),
+        @AttributeOverride(name="messnr", column=@Column(name="MESSNR") ),
+        @AttributeOverride(name="fgue", column=@Column(name="FGUE") ),
+        @AttributeOverride(name="uhrvon", column=@Column(name="UHRVON") ),
+        @AttributeOverride(name="uhrbis", column=@Column(name="UHRBIS") ),
+        @AttributeOverride(name="wspcm", column=@Column(name="WSPCM") ),
+        @AttributeOverride(name="QBpegel", column=@Column(name="Q_BPEGEL") ),
+        @AttributeOverride(name="wspnn", column=@Column(name="WSPNN") ),
+        @AttributeOverride(name="ie", column=@Column(name="IE") ),
+        @AttributeOverride(name="wtemp", column=@Column(name="WTEMP") ),
+        @AttributeOverride(name="gbreite", column=@Column(name="GBREITE") ),
+        @AttributeOverride(name="gbreitevon", column=@Column(name="GBREITEVON") ),
+        @AttributeOverride(name="gbreitebis", column=@Column(name="GBREITEBIS") ),
+        @AttributeOverride(name="tgeschiebe", column=@Column(name="TGESCHIEBE") ),
+        @AttributeOverride(name="tsand", column=@Column(name="TSAND") ),
+        @AttributeOverride(name="tschweb", column=@Column(name="TSCHWEB") ),
+        @AttributeOverride(name="cschweb", column=@Column(name="CSCHWEB") ),
+        @AttributeOverride(name="uferliabst", column=@Column(name="UFERLIABST") ),
+        @AttributeOverride(name="uferreabst", column=@Column(name="UFERREABST") ),
+        @AttributeOverride(name="q", column=@Column(name="Q") ),
+        @AttributeOverride(name="AHpeil", column=@Column(name="A_HPEIL") ),
+        @AttributeOverride(name="AMpeil", column=@Column(name="A_MPEIL") ),
+        @AttributeOverride(name="b", column=@Column(name="B") ),
+        @AttributeOverride(name="hm", column=@Column(name="HM") ),
+        @AttributeOverride(name="vm", column=@Column(name="VM") ),
+        @AttributeOverride(name="vsohle", column=@Column(name="VSOHLE") ),
+        @AttributeOverride(name="tau", column=@Column(name="TAU") ),
+        @AttributeOverride(name="tauv", column=@Column(name="TAUV") ),
+        @AttributeOverride(name="teilQ", column=@Column(name="TEIL_Q") ),
+        @AttributeOverride(name="teilAHpeil", column=@Column(name="TEIL_A_HPEIL") ),
+        @AttributeOverride(name="teilAMpeil", column=@Column(name="TEIL_A_MPEIL") ),
+        @AttributeOverride(name="teilB", column=@Column(name="TEIL_B") ),
+        @AttributeOverride(name="teilHm", column=@Column(name="TEIL_HM") ),
+        @AttributeOverride(name="teilVm", column=@Column(name="TEIL_VM") ),
+        @AttributeOverride(name="teilVsohle", column=@Column(name="TEIL_VSOHLE") ),
+        @AttributeOverride(name="teilTau", column=@Column(name="TEIL_TAU") ),
+        @AttributeOverride(name="teilTauv", column=@Column(name="TEIL_TAUV") ),
+        @AttributeOverride(name="mitteltyp", column=@Column(name="MITTELTYP") ),
+        @AttributeOverride(name="dm", column=@Column(name="DM") ),
+        @AttributeOverride(name="sk", column=@Column(name="SK") ),
+        @AttributeOverride(name="so", column=@Column(name="SO") ),
+        @AttributeOverride(name="u", column=@Column(name="U") ),
+        @AttributeOverride(name="d90", column=@Column(name="D90") ),
+        @AttributeOverride(name="d84", column=@Column(name="D84") ),
+        @AttributeOverride(name="d80", column=@Column(name="D80") ),
+        @AttributeOverride(name="d75", column=@Column(name="D75") ),
+        @AttributeOverride(name="d70", column=@Column(name="D70") ),
+        @AttributeOverride(name="d60", column=@Column(name="D60") ),
+        @AttributeOverride(name="d50", column=@Column(name="D50") ),
+        @AttributeOverride(name="d40", column=@Column(name="D40") ),
+        @AttributeOverride(name="d30", column=@Column(name="D30") ),
+        @AttributeOverride(name="d25", column=@Column(name="D25") ),
+        @AttributeOverride(name="d20", column=@Column(name="D20") ),
+        @AttributeOverride(name="d16", column=@Column(name="D16") ),
+        @AttributeOverride(name="d10", column=@Column(name="D10") ),
+        @AttributeOverride(name="dmin", column=@Column(name="DMIN") ),
+        @AttributeOverride(name="durchdmin", column=@Column(name="DURCHDMIN") ),
+        @AttributeOverride(name="dmax", column=@Column(name="DMAX") ),
+        @AttributeOverride(name="durchdmax", column=@Column(name="DURCHDMAX") ),
+        @AttributeOverride(name="NGeschieb", column=@Column(name="N_GESCHIEB") ),
+        @AttributeOverride(name="NVielpkt", column=@Column(name="N_VIELPKT") ),
+        @AttributeOverride(name="sysDate", column=@Column(name="SYS_DATE") ),
+        @AttributeOverride(name="bemerkung", column=@Column(name="BEMERKUNG") ),
+        @AttributeOverride(name="lastupdated", column=@Column(name="LASTUPDATED") ),
+        @AttributeOverride(name="km", column=@Column(name="KM") ),
+        @AttributeOverride(name="glotabstoffset", column=@Column(name="GLOTABSTOFFSET") ),
+        @AttributeOverride(name="slotabstoffset", column=@Column(name="SLOTABSTOFFSET") ),
+        @AttributeOverride(name="gbreitevonlinks", column=@Column(name="GBREITEVONLINKS") ),
+        @AttributeOverride(name="gbreitebislinks", column=@Column(name="GBREITEBISLINKS") ),
+        @AttributeOverride(name="staname", column=@Column(name="STANAME") ),
+        @AttributeOverride(name="stakm", column=@Column(name="STAKM") ),
+        @AttributeOverride(name="gewaesserid", column=@Column(name="GEWAESSERID") ),
+        @AttributeOverride(name="gewname", column=@Column(name="GEWNAME") ),
+        @AttributeOverride(name="bezugspegelid", column=@Column(name="BEZUGSPEGELID") ) } )
+    public MessungstaId getId() {
+        return this.id;
+    }
+
+    public void setId(MessungstaId id) {
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/MessungstaId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,1158 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.io.Serializable;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * MessungstaId generated by hbm2java
+ */
+@Embeddable
+public class MessungstaId  implements java.io.Serializable {
+
+
+     private Serializable messungid;
+     private Serializable stationid;
+     private Serializable datum;
+     private Serializable hpeilungid;
+     private Serializable mpeilungid;
+     private Serializable gfaengerid;
+     private Serializable gsiebsatzid;
+     private Serializable messnr;
+     private Serializable fgue;
+     private Serializable uhrvon;
+     private Serializable uhrbis;
+     private Serializable wspcm;
+     private Serializable QBpegel;
+     private Serializable wspnn;
+     private Serializable ie;
+     private Serializable wtemp;
+     private Serializable gbreite;
+     private Serializable gbreitevon;
+     private Serializable gbreitebis;
+     private Serializable tgeschiebe;
+     private Serializable tsand;
+     private Serializable tschweb;
+     private Serializable cschweb;
+     private Serializable uferliabst;
+     private Serializable uferreabst;
+     private Serializable q;
+     private Serializable AHpeil;
+     private Serializable AMpeil;
+     private Serializable b;
+     private Serializable hm;
+     private Serializable vm;
+     private Serializable vsohle;
+     private Serializable tau;
+     private Serializable tauv;
+     private Serializable teilQ;
+     private Serializable teilAHpeil;
+     private Serializable teilAMpeil;
+     private Serializable teilB;
+     private Serializable teilHm;
+     private Serializable teilVm;
+     private Serializable teilVsohle;
+     private Serializable teilTau;
+     private Serializable teilTauv;
+     private Serializable mitteltyp;
+     private Serializable dm;
+     private Serializable sk;
+     private Serializable so;
+     private Serializable u;
+     private Serializable d90;
+     private Serializable d84;
+     private Serializable d80;
+     private Serializable d75;
+     private Serializable d70;
+     private Serializable d60;
+     private Serializable d50;
+     private Serializable d40;
+     private Serializable d30;
+     private Serializable d25;
+     private Serializable d20;
+     private Serializable d16;
+     private Serializable d10;
+     private Serializable dmin;
+     private Serializable durchdmin;
+     private Serializable dmax;
+     private Serializable durchdmax;
+     private Serializable NGeschieb;
+     private Serializable NVielpkt;
+     private Serializable sysDate;
+     private Serializable bemerkung;
+     private Serializable lastupdated;
+     private Serializable km;
+     private Serializable glotabstoffset;
+     private Serializable slotabstoffset;
+     private Serializable gbreitevonlinks;
+     private Serializable gbreitebislinks;
+     private Serializable staname;
+     private Serializable stakm;
+     private Serializable gewaesserid;
+     private Serializable gewname;
+     private Serializable bezugspegelid;
+
+    public MessungstaId() {
+    }
+
+    public MessungstaId(Serializable messungid, Serializable stationid, Serializable datum, Serializable hpeilungid, Serializable mpeilungid, Serializable gfaengerid, Serializable gsiebsatzid, Serializable messnr, Serializable fgue, Serializable uhrvon, Serializable uhrbis, Serializable wspcm, Serializable QBpegel, Serializable wspnn, Serializable ie, Serializable wtemp, Serializable gbreite, Serializable gbreitevon, Serializable gbreitebis, Serializable tgeschiebe, Serializable tsand, Serializable tschweb, Serializable cschweb, Serializable uferliabst, Serializable uferreabst, Serializable q, Serializable AHpeil, Serializable AMpeil, Serializable b, Serializable hm, Serializable vm, Serializable vsohle, Serializable tau, Serializable tauv, Serializable teilQ, Serializable teilAHpeil, Serializable teilAMpeil, Serializable teilB, Serializable teilHm, Serializable teilVm, Serializable teilVsohle, Serializable teilTau, Serializable teilTauv, Serializable mitteltyp, Serializable dm, Serializable sk, Serializable so, Serializable u, Serializable d90, Serializable d84, Serializable d80, Serializable d75, Serializable d70, Serializable d60, Serializable d50, Serializable d40, Serializable d30, Serializable d25, Serializable d20, Serializable d16, Serializable d10, Serializable dmin, Serializable durchdmin, Serializable dmax, Serializable durchdmax, Serializable NGeschieb, Serializable NVielpkt, Serializable sysDate, Serializable bemerkung, Serializable lastupdated, Serializable km, Serializable glotabstoffset, Serializable slotabstoffset, Serializable gbreitevonlinks, Serializable gbreitebislinks, Serializable staname, Serializable stakm, Serializable gewaesserid, Serializable gewname, Serializable bezugspegelid) {
+       this.messungid = messungid;
+       this.stationid = stationid;
+       this.datum = datum;
+       this.hpeilungid = hpeilungid;
+       this.mpeilungid = mpeilungid;
+       this.gfaengerid = gfaengerid;
+       this.gsiebsatzid = gsiebsatzid;
+       this.messnr = messnr;
+       this.fgue = fgue;
+       this.uhrvon = uhrvon;
+       this.uhrbis = uhrbis;
+       this.wspcm = wspcm;
+       this.QBpegel = QBpegel;
+       this.wspnn = wspnn;
+       this.ie = ie;
+       this.wtemp = wtemp;
+       this.gbreite = gbreite;
+       this.gbreitevon = gbreitevon;
+       this.gbreitebis = gbreitebis;
+       this.tgeschiebe = tgeschiebe;
+       this.tsand = tsand;
+       this.tschweb = tschweb;
+       this.cschweb = cschweb;
+       this.uferliabst = uferliabst;
+       this.uferreabst = uferreabst;
+       this.q = q;
+       this.AHpeil = AHpeil;
+       this.AMpeil = AMpeil;
+       this.b = b;
+       this.hm = hm;
+       this.vm = vm;
+       this.vsohle = vsohle;
+       this.tau = tau;
+       this.tauv = tauv;
+       this.teilQ = teilQ;
+       this.teilAHpeil = teilAHpeil;
+       this.teilAMpeil = teilAMpeil;
+       this.teilB = teilB;
+       this.teilHm = teilHm;
+       this.teilVm = teilVm;
+       this.teilVsohle = teilVsohle;
+       this.teilTau = teilTau;
+       this.teilTauv = teilTauv;
+       this.mitteltyp = mitteltyp;
+       this.dm = dm;
+       this.sk = sk;
+       this.so = so;
+       this.u = u;
+       this.d90 = d90;
+       this.d84 = d84;
+       this.d80 = d80;
+       this.d75 = d75;
+       this.d70 = d70;
+       this.d60 = d60;
+       this.d50 = d50;
+       this.d40 = d40;
+       this.d30 = d30;
+       this.d25 = d25;
+       this.d20 = d20;
+       this.d16 = d16;
+       this.d10 = d10;
+       this.dmin = dmin;
+       this.durchdmin = durchdmin;
+       this.dmax = dmax;
+       this.durchdmax = durchdmax;
+       this.NGeschieb = NGeschieb;
+       this.NVielpkt = NVielpkt;
+       this.sysDate = sysDate;
+       this.bemerkung = bemerkung;
+       this.lastupdated = lastupdated;
+       this.km = km;
+       this.glotabstoffset = glotabstoffset;
+       this.slotabstoffset = slotabstoffset;
+       this.gbreitevonlinks = gbreitevonlinks;
+       this.gbreitebislinks = gbreitebislinks;
+       this.staname = staname;
+       this.stakm = stakm;
+       this.gewaesserid = gewaesserid;
+       this.gewname = gewname;
+       this.bezugspegelid = bezugspegelid;
+    }
+
+
+
+    @Column(name="MESSUNGID")
+    public Serializable getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(Serializable messungid) {
+        this.messungid = messungid;
+    }
+
+
+    @Column(name="STATIONID")
+    public Serializable getStationid() {
+        return this.stationid;
+    }
+
+    public void setStationid(Serializable stationid) {
+        this.stationid = stationid;
+    }
+
+
+    @Column(name="DATUM")
+    public Serializable getDatum() {
+        return this.datum;
+    }
+
+    public void setDatum(Serializable datum) {
+        this.datum = datum;
+    }
+
+
+    @Column(name="HPEILUNGID")
+    public Serializable getHpeilungid() {
+        return this.hpeilungid;
+    }
+
+    public void setHpeilungid(Serializable hpeilungid) {
+        this.hpeilungid = hpeilungid;
+    }
+
+
+    @Column(name="MPEILUNGID")
+    public Serializable getMpeilungid() {
+        return this.mpeilungid;
+    }
+
+    public void setMpeilungid(Serializable mpeilungid) {
+        this.mpeilungid = mpeilungid;
+    }
+
+
+    @Column(name="GFAENGERID")
+    public Serializable getGfaengerid() {
+        return this.gfaengerid;
+    }
+
+    public void setGfaengerid(Serializable gfaengerid) {
+        this.gfaengerid = gfaengerid;
+    }
+
+
+    @Column(name="GSIEBSATZID")
+    public Serializable getGsiebsatzid() {
+        return this.gsiebsatzid;
+    }
+
+    public void setGsiebsatzid(Serializable gsiebsatzid) {
+        this.gsiebsatzid = gsiebsatzid;
+    }
+
+
+    @Column(name="MESSNR")
+    public Serializable getMessnr() {
+        return this.messnr;
+    }
+
+    public void setMessnr(Serializable messnr) {
+        this.messnr = messnr;
+    }
+
+
+    @Column(name="FGUE")
+    public Serializable getFgue() {
+        return this.fgue;
+    }
+
+    public void setFgue(Serializable fgue) {
+        this.fgue = fgue;
+    }
+
+
+    @Column(name="UHRVON")
+    public Serializable getUhrvon() {
+        return this.uhrvon;
+    }
+
+    public void setUhrvon(Serializable uhrvon) {
+        this.uhrvon = uhrvon;
+    }
+
+
+    @Column(name="UHRBIS")
+    public Serializable getUhrbis() {
+        return this.uhrbis;
+    }
+
+    public void setUhrbis(Serializable uhrbis) {
+        this.uhrbis = uhrbis;
+    }
+
+
+    @Column(name="WSPCM")
+    public Serializable getWspcm() {
+        return this.wspcm;
+    }
+
+    public void setWspcm(Serializable wspcm) {
+        this.wspcm = wspcm;
+    }
+
+
+    @Column(name="Q_BPEGEL")
+    public Serializable getQBpegel() {
+        return this.QBpegel;
+    }
+
+    public void setQBpegel(Serializable QBpegel) {
+        this.QBpegel = QBpegel;
+    }
+
+
+    @Column(name="WSPNN")
+    public Serializable getWspnn() {
+        return this.wspnn;
+    }
+
+    public void setWspnn(Serializable wspnn) {
+        this.wspnn = wspnn;
+    }
+
+
+    @Column(name="IE")
+    public Serializable getIe() {
+        return this.ie;
+    }
+
+    public void setIe(Serializable ie) {
+        this.ie = ie;
+    }
+
+
+    @Column(name="WTEMP")
+    public Serializable getWtemp() {
+        return this.wtemp;
+    }
+
+    public void setWtemp(Serializable wtemp) {
+        this.wtemp = wtemp;
+    }
+
+
+    @Column(name="GBREITE")
+    public Serializable getGbreite() {
+        return this.gbreite;
+    }
+
+    public void setGbreite(Serializable gbreite) {
+        this.gbreite = gbreite;
+    }
+
+
+    @Column(name="GBREITEVON")
+    public Serializable getGbreitevon() {
+        return this.gbreitevon;
+    }
+
+    public void setGbreitevon(Serializable gbreitevon) {
+        this.gbreitevon = gbreitevon;
+    }
+
+
+    @Column(name="GBREITEBIS")
+    public Serializable getGbreitebis() {
+        return this.gbreitebis;
+    }
+
+    public void setGbreitebis(Serializable gbreitebis) {
+        this.gbreitebis = gbreitebis;
+    }
+
+
+    @Column(name="TGESCHIEBE")
+    public Serializable getTgeschiebe() {
+        return this.tgeschiebe;
+    }
+
+    public void setTgeschiebe(Serializable tgeschiebe) {
+        this.tgeschiebe = tgeschiebe;
+    }
+
+
+    @Column(name="TSAND")
+    public Serializable getTsand() {
+        return this.tsand;
+    }
+
+    public void setTsand(Serializable tsand) {
+        this.tsand = tsand;
+    }
+
+
+    @Column(name="TSCHWEB")
+    public Serializable getTschweb() {
+        return this.tschweb;
+    }
+
+    public void setTschweb(Serializable tschweb) {
+        this.tschweb = tschweb;
+    }
+
+
+    @Column(name="CSCHWEB")
+    public Serializable getCschweb() {
+        return this.cschweb;
+    }
+
+    public void setCschweb(Serializable cschweb) {
+        this.cschweb = cschweb;
+    }
+
+
+    @Column(name="UFERLIABST")
+    public Serializable getUferliabst() {
+        return this.uferliabst;
+    }
+
+    public void setUferliabst(Serializable uferliabst) {
+        this.uferliabst = uferliabst;
+    }
+
+
+    @Column(name="UFERREABST")
+    public Serializable getUferreabst() {
+        return this.uferreabst;
+    }
+
+    public void setUferreabst(Serializable uferreabst) {
+        this.uferreabst = uferreabst;
+    }
+
+
+    @Column(name="Q")
+    public Serializable getQ() {
+        return this.q;
+    }
+
+    public void setQ(Serializable q) {
+        this.q = q;
+    }
+
+
+    @Column(name="A_HPEIL")
+    public Serializable getAHpeil() {
+        return this.AHpeil;
+    }
+
+    public void setAHpeil(Serializable AHpeil) {
+        this.AHpeil = AHpeil;
+    }
+
+
+    @Column(name="A_MPEIL")
+    public Serializable getAMpeil() {
+        return this.AMpeil;
+    }
+
+    public void setAMpeil(Serializable AMpeil) {
+        this.AMpeil = AMpeil;
+    }
+
+
+    @Column(name="B")
+    public Serializable getB() {
+        return this.b;
+    }
+
+    public void setB(Serializable b) {
+        this.b = b;
+    }
+
+
+    @Column(name="HM")
+    public Serializable getHm() {
+        return this.hm;
+    }
+
+    public void setHm(Serializable hm) {
+        this.hm = hm;
+    }
+
+
+    @Column(name="VM")
+    public Serializable getVm() {
+        return this.vm;
+    }
+
+    public void setVm(Serializable vm) {
+        this.vm = vm;
+    }
+
+
+    @Column(name="VSOHLE")
+    public Serializable getVsohle() {
+        return this.vsohle;
+    }
+
+    public void setVsohle(Serializable vsohle) {
+        this.vsohle = vsohle;
+    }
+
+
+    @Column(name="TAU")
+    public Serializable getTau() {
+        return this.tau;
+    }
+
+    public void setTau(Serializable tau) {
+        this.tau = tau;
+    }
+
+
+    @Column(name="TAUV")
+    public Serializable getTauv() {
+        return this.tauv;
+    }
+
+    public void setTauv(Serializable tauv) {
+        this.tauv = tauv;
+    }
+
+
+    @Column(name="TEIL_Q")
+    public Serializable getTeilQ() {
+        return this.teilQ;
+    }
+
+    public void setTeilQ(Serializable teilQ) {
+        this.teilQ = teilQ;
+    }
+
+
+    @Column(name="TEIL_A_HPEIL")
+    public Serializable getTeilAHpeil() {
+        return this.teilAHpeil;
+    }
+
+    public void setTeilAHpeil(Serializable teilAHpeil) {
+        this.teilAHpeil = teilAHpeil;
+    }
+
+
+    @Column(name="TEIL_A_MPEIL")
+    public Serializable getTeilAMpeil() {
+        return this.teilAMpeil;
+    }
+
+    public void setTeilAMpeil(Serializable teilAMpeil) {
+        this.teilAMpeil = teilAMpeil;
+    }
+
+
+    @Column(name="TEIL_B")
+    public Serializable getTeilB() {
+        return this.teilB;
+    }
+
+    public void setTeilB(Serializable teilB) {
+        this.teilB = teilB;
+    }
+
+
+    @Column(name="TEIL_HM")
+    public Serializable getTeilHm() {
+        return this.teilHm;
+    }
+
+    public void setTeilHm(Serializable teilHm) {
+        this.teilHm = teilHm;
+    }
+
+
+    @Column(name="TEIL_VM")
+    public Serializable getTeilVm() {
+        return this.teilVm;
+    }
+
+    public void setTeilVm(Serializable teilVm) {
+        this.teilVm = teilVm;
+    }
+
+
+    @Column(name="TEIL_VSOHLE")
+    public Serializable getTeilVsohle() {
+        return this.teilVsohle;
+    }
+
+    public void setTeilVsohle(Serializable teilVsohle) {
+        this.teilVsohle = teilVsohle;
+    }
+
+
+    @Column(name="TEIL_TAU")
+    public Serializable getTeilTau() {
+        return this.teilTau;
+    }
+
+    public void setTeilTau(Serializable teilTau) {
+        this.teilTau = teilTau;
+    }
+
+
+    @Column(name="TEIL_TAUV")
+    public Serializable getTeilTauv() {
+        return this.teilTauv;
+    }
+
+    public void setTeilTauv(Serializable teilTauv) {
+        this.teilTauv = teilTauv;
+    }
+
+
+    @Column(name="MITTELTYP")
+    public Serializable getMitteltyp() {
+        return this.mitteltyp;
+    }
+
+    public void setMitteltyp(Serializable mitteltyp) {
+        this.mitteltyp = mitteltyp;
+    }
+
+
+    @Column(name="DM")
+    public Serializable getDm() {
+        return this.dm;
+    }
+
+    public void setDm(Serializable dm) {
+        this.dm = dm;
+    }
+
+
+    @Column(name="SK")
+    public Serializable getSk() {
+        return this.sk;
+    }
+
+    public void setSk(Serializable sk) {
+        this.sk = sk;
+    }
+
+
+    @Column(name="SO")
+    public Serializable getSo() {
+        return this.so;
+    }
+
+    public void setSo(Serializable so) {
+        this.so = so;
+    }
+
+
+    @Column(name="U")
+    public Serializable getU() {
+        return this.u;
+    }
+
+    public void setU(Serializable u) {
+        this.u = u;
+    }
+
+
+    @Column(name="D90")
+    public Serializable getD90() {
+        return this.d90;
+    }
+
+    public void setD90(Serializable d90) {
+        this.d90 = d90;
+    }
+
+
+    @Column(name="D84")
+    public Serializable getD84() {
+        return this.d84;
+    }
+
+    public void setD84(Serializable d84) {
+        this.d84 = d84;
+    }
+
+
+    @Column(name="D80")
+    public Serializable getD80() {
+        return this.d80;
+    }
+
+    public void setD80(Serializable d80) {
+        this.d80 = d80;
+    }
+
+
+    @Column(name="D75")
+    public Serializable getD75() {
+        return this.d75;
+    }
+
+    public void setD75(Serializable d75) {
+        this.d75 = d75;
+    }
+
+
+    @Column(name="D70")
+    public Serializable getD70() {
+        return this.d70;
+    }
+
+    public void setD70(Serializable d70) {
+        this.d70 = d70;
+    }
+
+
+    @Column(name="D60")
+    public Serializable getD60() {
+        return this.d60;
+    }
+
+    public void setD60(Serializable d60) {
+        this.d60 = d60;
+    }
+
+
+    @Column(name="D50")
+    public Serializable getD50() {
+        return this.d50;
+    }
+
+    public void setD50(Serializable d50) {
+        this.d50 = d50;
+    }
+
+
+    @Column(name="D40")
+    public Serializable getD40() {
+        return this.d40;
+    }
+
+    public void setD40(Serializable d40) {
+        this.d40 = d40;
+    }
+
+
+    @Column(name="D30")
+    public Serializable getD30() {
+        return this.d30;
+    }
+
+    public void setD30(Serializable d30) {
+        this.d30 = d30;
+    }
+
+
+    @Column(name="D25")
+    public Serializable getD25() {
+        return this.d25;
+    }
+
+    public void setD25(Serializable d25) {
+        this.d25 = d25;
+    }
+
+
+    @Column(name="D20")
+    public Serializable getD20() {
+        return this.d20;
+    }
+
+    public void setD20(Serializable d20) {
+        this.d20 = d20;
+    }
+
+
+    @Column(name="D16")
+    public Serializable getD16() {
+        return this.d16;
+    }
+
+    public void setD16(Serializable d16) {
+        this.d16 = d16;
+    }
+
+
+    @Column(name="D10")
+    public Serializable getD10() {
+        return this.d10;
+    }
+
+    public void setD10(Serializable d10) {
+        this.d10 = d10;
+    }
+
+
+    @Column(name="DMIN")
+    public Serializable getDmin() {
+        return this.dmin;
+    }
+
+    public void setDmin(Serializable dmin) {
+        this.dmin = dmin;
+    }
+
+
+    @Column(name="DURCHDMIN")
+    public Serializable getDurchdmin() {
+        return this.durchdmin;
+    }
+
+    public void setDurchdmin(Serializable durchdmin) {
+        this.durchdmin = durchdmin;
+    }
+
+
+    @Column(name="DMAX")
+    public Serializable getDmax() {
+        return this.dmax;
+    }
+
+    public void setDmax(Serializable dmax) {
+        this.dmax = dmax;
+    }
+
+
+    @Column(name="DURCHDMAX")
+    public Serializable getDurchdmax() {
+        return this.durchdmax;
+    }
+
+    public void setDurchdmax(Serializable durchdmax) {
+        this.durchdmax = durchdmax;
+    }
+
+
+    @Column(name="N_GESCHIEB")
+    public Serializable getNGeschieb() {
+        return this.NGeschieb;
+    }
+
+    public void setNGeschieb(Serializable NGeschieb) {
+        this.NGeschieb = NGeschieb;
+    }
+
+
+    @Column(name="N_VIELPKT")
+    public Serializable getNVielpkt() {
+        return this.NVielpkt;
+    }
+
+    public void setNVielpkt(Serializable NVielpkt) {
+        this.NVielpkt = NVielpkt;
+    }
+
+
+    @Column(name="SYS_DATE")
+    public Serializable getSysDate() {
+        return this.sysDate;
+    }
+
+    public void setSysDate(Serializable sysDate) {
+        this.sysDate = sysDate;
+    }
+
+
+    @Column(name="BEMERKUNG")
+    public Serializable getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(Serializable bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="LASTUPDATED")
+    public Serializable getLastupdated() {
+        return this.lastupdated;
+    }
+
+    public void setLastupdated(Serializable lastupdated) {
+        this.lastupdated = lastupdated;
+    }
+
+
+    @Column(name="KM")
+    public Serializable getKm() {
+        return this.km;
+    }
+
+    public void setKm(Serializable km) {
+        this.km = km;
+    }
+
+
+    @Column(name="GLOTABSTOFFSET")
+    public Serializable getGlotabstoffset() {
+        return this.glotabstoffset;
+    }
+
+    public void setGlotabstoffset(Serializable glotabstoffset) {
+        this.glotabstoffset = glotabstoffset;
+    }
+
+
+    @Column(name="SLOTABSTOFFSET")
+    public Serializable getSlotabstoffset() {
+        return this.slotabstoffset;
+    }
+
+    public void setSlotabstoffset(Serializable slotabstoffset) {
+        this.slotabstoffset = slotabstoffset;
+    }
+
+
+    @Column(name="GBREITEVONLINKS")
+    public Serializable getGbreitevonlinks() {
+        return this.gbreitevonlinks;
+    }
+
+    public void setGbreitevonlinks(Serializable gbreitevonlinks) {
+        this.gbreitevonlinks = gbreitevonlinks;
+    }
+
+
+    @Column(name="GBREITEBISLINKS")
+    public Serializable getGbreitebislinks() {
+        return this.gbreitebislinks;
+    }
+
+    public void setGbreitebislinks(Serializable gbreitebislinks) {
+        this.gbreitebislinks = gbreitebislinks;
+    }
+
+
+    @Column(name="STANAME")
+    public Serializable getStaname() {
+        return this.staname;
+    }
+
+    public void setStaname(Serializable staname) {
+        this.staname = staname;
+    }
+
+
+    @Column(name="STAKM")
+    public Serializable getStakm() {
+        return this.stakm;
+    }
+
+    public void setStakm(Serializable stakm) {
+        this.stakm = stakm;
+    }
+
+
+    @Column(name="GEWAESSERID")
+    public Serializable getGewaesserid() {
+        return this.gewaesserid;
+    }
+
+    public void setGewaesserid(Serializable gewaesserid) {
+        this.gewaesserid = gewaesserid;
+    }
+
+
+    @Column(name="GEWNAME")
+    public Serializable getGewname() {
+        return this.gewname;
+    }
+
+    public void setGewname(Serializable gewname) {
+        this.gewname = gewname;
+    }
+
+
+    @Column(name="BEZUGSPEGELID")
+    public Serializable getBezugspegelid() {
+        return this.bezugspegelid;
+    }
+
+    public void setBezugspegelid(Serializable bezugspegelid) {
+        this.bezugspegelid = bezugspegelid;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof MessungstaId) ) return false;
+         MessungstaId castOther = ( MessungstaId ) other;
+
+         return ( (this.getMessungid()==castOther.getMessungid()) || ( this.getMessungid()!=null && castOther.getMessungid()!=null && this.getMessungid().equals(castOther.getMessungid()) ) )
+ && ( (this.getStationid()==castOther.getStationid()) || ( this.getStationid()!=null && castOther.getStationid()!=null && this.getStationid().equals(castOther.getStationid()) ) )
+ && ( (this.getDatum()==castOther.getDatum()) || ( this.getDatum()!=null && castOther.getDatum()!=null && this.getDatum().equals(castOther.getDatum()) ) )
+ && ( (this.getHpeilungid()==castOther.getHpeilungid()) || ( this.getHpeilungid()!=null && castOther.getHpeilungid()!=null && this.getHpeilungid().equals(castOther.getHpeilungid()) ) )
+ && ( (this.getMpeilungid()==castOther.getMpeilungid()) || ( this.getMpeilungid()!=null && castOther.getMpeilungid()!=null && this.getMpeilungid().equals(castOther.getMpeilungid()) ) )
+ && ( (this.getGfaengerid()==castOther.getGfaengerid()) || ( this.getGfaengerid()!=null && castOther.getGfaengerid()!=null && this.getGfaengerid().equals(castOther.getGfaengerid()) ) )
+ && ( (this.getGsiebsatzid()==castOther.getGsiebsatzid()) || ( this.getGsiebsatzid()!=null && castOther.getGsiebsatzid()!=null && this.getGsiebsatzid().equals(castOther.getGsiebsatzid()) ) )
+ && ( (this.getMessnr()==castOther.getMessnr()) || ( this.getMessnr()!=null && castOther.getMessnr()!=null && this.getMessnr().equals(castOther.getMessnr()) ) )
+ && ( (this.getFgue()==castOther.getFgue()) || ( this.getFgue()!=null && castOther.getFgue()!=null && this.getFgue().equals(castOther.getFgue()) ) )
+ && ( (this.getUhrvon()==castOther.getUhrvon()) || ( this.getUhrvon()!=null && castOther.getUhrvon()!=null && this.getUhrvon().equals(castOther.getUhrvon()) ) )
+ && ( (this.getUhrbis()==castOther.getUhrbis()) || ( this.getUhrbis()!=null && castOther.getUhrbis()!=null && this.getUhrbis().equals(castOther.getUhrbis()) ) )
+ && ( (this.getWspcm()==castOther.getWspcm()) || ( this.getWspcm()!=null && castOther.getWspcm()!=null && this.getWspcm().equals(castOther.getWspcm()) ) )
+ && ( (this.getQBpegel()==castOther.getQBpegel()) || ( this.getQBpegel()!=null && castOther.getQBpegel()!=null && this.getQBpegel().equals(castOther.getQBpegel()) ) )
+ && ( (this.getWspnn()==castOther.getWspnn()) || ( this.getWspnn()!=null && castOther.getWspnn()!=null && this.getWspnn().equals(castOther.getWspnn()) ) )
+ && ( (this.getIe()==castOther.getIe()) || ( this.getIe()!=null && castOther.getIe()!=null && this.getIe().equals(castOther.getIe()) ) )
+ && ( (this.getWtemp()==castOther.getWtemp()) || ( this.getWtemp()!=null && castOther.getWtemp()!=null && this.getWtemp().equals(castOther.getWtemp()) ) )
+ && ( (this.getGbreite()==castOther.getGbreite()) || ( this.getGbreite()!=null && castOther.getGbreite()!=null && this.getGbreite().equals(castOther.getGbreite()) ) )
+ && ( (this.getGbreitevon()==castOther.getGbreitevon()) || ( this.getGbreitevon()!=null && castOther.getGbreitevon()!=null && this.getGbreitevon().equals(castOther.getGbreitevon()) ) )
+ && ( (this.getGbreitebis()==castOther.getGbreitebis()) || ( this.getGbreitebis()!=null && castOther.getGbreitebis()!=null && this.getGbreitebis().equals(castOther.getGbreitebis()) ) )
+ && ( (this.getTgeschiebe()==castOther.getTgeschiebe()) || ( this.getTgeschiebe()!=null && castOther.getTgeschiebe()!=null && this.getTgeschiebe().equals(castOther.getTgeschiebe()) ) )
+ && ( (this.getTsand()==castOther.getTsand()) || ( this.getTsand()!=null && castOther.getTsand()!=null && this.getTsand().equals(castOther.getTsand()) ) )
+ && ( (this.getTschweb()==castOther.getTschweb()) || ( this.getTschweb()!=null && castOther.getTschweb()!=null && this.getTschweb().equals(castOther.getTschweb()) ) )
+ && ( (this.getCschweb()==castOther.getCschweb()) || ( this.getCschweb()!=null && castOther.getCschweb()!=null && this.getCschweb().equals(castOther.getCschweb()) ) )
+ && ( (this.getUferliabst()==castOther.getUferliabst()) || ( this.getUferliabst()!=null && castOther.getUferliabst()!=null && this.getUferliabst().equals(castOther.getUferliabst()) ) )
+ && ( (this.getUferreabst()==castOther.getUferreabst()) || ( this.getUferreabst()!=null && castOther.getUferreabst()!=null && this.getUferreabst().equals(castOther.getUferreabst()) ) )
+ && ( (this.getQ()==castOther.getQ()) || ( this.getQ()!=null && castOther.getQ()!=null && this.getQ().equals(castOther.getQ()) ) )
+ && ( (this.getAHpeil()==castOther.getAHpeil()) || ( this.getAHpeil()!=null && castOther.getAHpeil()!=null && this.getAHpeil().equals(castOther.getAHpeil()) ) )
+ && ( (this.getAMpeil()==castOther.getAMpeil()) || ( this.getAMpeil()!=null && castOther.getAMpeil()!=null && this.getAMpeil().equals(castOther.getAMpeil()) ) )
+ && ( (this.getB()==castOther.getB()) || ( this.getB()!=null && castOther.getB()!=null && this.getB().equals(castOther.getB()) ) )
+ && ( (this.getHm()==castOther.getHm()) || ( this.getHm()!=null && castOther.getHm()!=null && this.getHm().equals(castOther.getHm()) ) )
+ && ( (this.getVm()==castOther.getVm()) || ( this.getVm()!=null && castOther.getVm()!=null && this.getVm().equals(castOther.getVm()) ) )
+ && ( (this.getVsohle()==castOther.getVsohle()) || ( this.getVsohle()!=null && castOther.getVsohle()!=null && this.getVsohle().equals(castOther.getVsohle()) ) )
+ && ( (this.getTau()==castOther.getTau()) || ( this.getTau()!=null && castOther.getTau()!=null && this.getTau().equals(castOther.getTau()) ) )
+ && ( (this.getTauv()==castOther.getTauv()) || ( this.getTauv()!=null && castOther.getTauv()!=null && this.getTauv().equals(castOther.getTauv()) ) )
+ && ( (this.getTeilQ()==castOther.getTeilQ()) || ( this.getTeilQ()!=null && castOther.getTeilQ()!=null && this.getTeilQ().equals(castOther.getTeilQ()) ) )
+ && ( (this.getTeilAHpeil()==castOther.getTeilAHpeil()) || ( this.getTeilAHpeil()!=null && castOther.getTeilAHpeil()!=null && this.getTeilAHpeil().equals(castOther.getTeilAHpeil()) ) )
+ && ( (this.getTeilAMpeil()==castOther.getTeilAMpeil()) || ( this.getTeilAMpeil()!=null && castOther.getTeilAMpeil()!=null && this.getTeilAMpeil().equals(castOther.getTeilAMpeil()) ) )
+ && ( (this.getTeilB()==castOther.getTeilB()) || ( this.getTeilB()!=null && castOther.getTeilB()!=null && this.getTeilB().equals(castOther.getTeilB()) ) )
+ && ( (this.getTeilHm()==castOther.getTeilHm()) || ( this.getTeilHm()!=null && castOther.getTeilHm()!=null && this.getTeilHm().equals(castOther.getTeilHm()) ) )
+ && ( (this.getTeilVm()==castOther.getTeilVm()) || ( this.getTeilVm()!=null && castOther.getTeilVm()!=null && this.getTeilVm().equals(castOther.getTeilVm()) ) )
+ && ( (this.getTeilVsohle()==castOther.getTeilVsohle()) || ( this.getTeilVsohle()!=null && castOther.getTeilVsohle()!=null && this.getTeilVsohle().equals(castOther.getTeilVsohle()) ) )
+ && ( (this.getTeilTau()==castOther.getTeilTau()) || ( this.getTeilTau()!=null && castOther.getTeilTau()!=null && this.getTeilTau().equals(castOther.getTeilTau()) ) )
+ && ( (this.getTeilTauv()==castOther.getTeilTauv()) || ( this.getTeilTauv()!=null && castOther.getTeilTauv()!=null && this.getTeilTauv().equals(castOther.getTeilTauv()) ) )
+ && ( (this.getMitteltyp()==castOther.getMitteltyp()) || ( this.getMitteltyp()!=null && castOther.getMitteltyp()!=null && this.getMitteltyp().equals(castOther.getMitteltyp()) ) )
+ && ( (this.getDm()==castOther.getDm()) || ( this.getDm()!=null && castOther.getDm()!=null && this.getDm().equals(castOther.getDm()) ) )
+ && ( (this.getSk()==castOther.getSk()) || ( this.getSk()!=null && castOther.getSk()!=null && this.getSk().equals(castOther.getSk()) ) )
+ && ( (this.getSo()==castOther.getSo()) || ( this.getSo()!=null && castOther.getSo()!=null && this.getSo().equals(castOther.getSo()) ) )
+ && ( (this.getU()==castOther.getU()) || ( this.getU()!=null && castOther.getU()!=null && this.getU().equals(castOther.getU()) ) )
+ && ( (this.getD90()==castOther.getD90()) || ( this.getD90()!=null && castOther.getD90()!=null && this.getD90().equals(castOther.getD90()) ) )
+ && ( (this.getD84()==castOther.getD84()) || ( this.getD84()!=null && castOther.getD84()!=null && this.getD84().equals(castOther.getD84()) ) )
+ && ( (this.getD80()==castOther.getD80()) || ( this.getD80()!=null && castOther.getD80()!=null && this.getD80().equals(castOther.getD80()) ) )
+ && ( (this.getD75()==castOther.getD75()) || ( this.getD75()!=null && castOther.getD75()!=null && this.getD75().equals(castOther.getD75()) ) )
+ && ( (this.getD70()==castOther.getD70()) || ( this.getD70()!=null && castOther.getD70()!=null && this.getD70().equals(castOther.getD70()) ) )
+ && ( (this.getD60()==castOther.getD60()) || ( this.getD60()!=null && castOther.getD60()!=null && this.getD60().equals(castOther.getD60()) ) )
+ && ( (this.getD50()==castOther.getD50()) || ( this.getD50()!=null && castOther.getD50()!=null && this.getD50().equals(castOther.getD50()) ) )
+ && ( (this.getD40()==castOther.getD40()) || ( this.getD40()!=null && castOther.getD40()!=null && this.getD40().equals(castOther.getD40()) ) )
+ && ( (this.getD30()==castOther.getD30()) || ( this.getD30()!=null && castOther.getD30()!=null && this.getD30().equals(castOther.getD30()) ) )
+ && ( (this.getD25()==castOther.getD25()) || ( this.getD25()!=null && castOther.getD25()!=null && this.getD25().equals(castOther.getD25()) ) )
+ && ( (this.getD20()==castOther.getD20()) || ( this.getD20()!=null && castOther.getD20()!=null && this.getD20().equals(castOther.getD20()) ) )
+ && ( (this.getD16()==castOther.getD16()) || ( this.getD16()!=null && castOther.getD16()!=null && this.getD16().equals(castOther.getD16()) ) )
+ && ( (this.getD10()==castOther.getD10()) || ( this.getD10()!=null && castOther.getD10()!=null && this.getD10().equals(castOther.getD10()) ) )
+ && ( (this.getDmin()==castOther.getDmin()) || ( this.getDmin()!=null && castOther.getDmin()!=null && this.getDmin().equals(castOther.getDmin()) ) )
+ && ( (this.getDurchdmin()==castOther.getDurchdmin()) || ( this.getDurchdmin()!=null && castOther.getDurchdmin()!=null && this.getDurchdmin().equals(castOther.getDurchdmin()) ) )
+ && ( (this.getDmax()==castOther.getDmax()) || ( this.getDmax()!=null && castOther.getDmax()!=null && this.getDmax().equals(castOther.getDmax()) ) )
+ && ( (this.getDurchdmax()==castOther.getDurchdmax()) || ( this.getDurchdmax()!=null && castOther.getDurchdmax()!=null && this.getDurchdmax().equals(castOther.getDurchdmax()) ) )
+ && ( (this.getNGeschieb()==castOther.getNGeschieb()) || ( this.getNGeschieb()!=null && castOther.getNGeschieb()!=null && this.getNGeschieb().equals(castOther.getNGeschieb()) ) )
+ && ( (this.getNVielpkt()==castOther.getNVielpkt()) || ( this.getNVielpkt()!=null && castOther.getNVielpkt()!=null && this.getNVielpkt().equals(castOther.getNVielpkt()) ) )
+ && ( (this.getSysDate()==castOther.getSysDate()) || ( this.getSysDate()!=null && castOther.getSysDate()!=null && this.getSysDate().equals(castOther.getSysDate()) ) )
+ && ( (this.getBemerkung()==castOther.getBemerkung()) || ( this.getBemerkung()!=null && castOther.getBemerkung()!=null && this.getBemerkung().equals(castOther.getBemerkung()) ) )
+ && ( (this.getLastupdated()==castOther.getLastupdated()) || ( this.getLastupdated()!=null && castOther.getLastupdated()!=null && this.getLastupdated().equals(castOther.getLastupdated()) ) )
+ && ( (this.getKm()==castOther.getKm()) || ( this.getKm()!=null && castOther.getKm()!=null && this.getKm().equals(castOther.getKm()) ) )
+ && ( (this.getGlotabstoffset()==castOther.getGlotabstoffset()) || ( this.getGlotabstoffset()!=null && castOther.getGlotabstoffset()!=null && this.getGlotabstoffset().equals(castOther.getGlotabstoffset()) ) )
+ && ( (this.getSlotabstoffset()==castOther.getSlotabstoffset()) || ( this.getSlotabstoffset()!=null && castOther.getSlotabstoffset()!=null && this.getSlotabstoffset().equals(castOther.getSlotabstoffset()) ) )
+ && ( (this.getGbreitevonlinks()==castOther.getGbreitevonlinks()) || ( this.getGbreitevonlinks()!=null && castOther.getGbreitevonlinks()!=null && this.getGbreitevonlinks().equals(castOther.getGbreitevonlinks()) ) )
+ && ( (this.getGbreitebislinks()==castOther.getGbreitebislinks()) || ( this.getGbreitebislinks()!=null && castOther.getGbreitebislinks()!=null && this.getGbreitebislinks().equals(castOther.getGbreitebislinks()) ) )
+ && ( (this.getStaname()==castOther.getStaname()) || ( this.getStaname()!=null && castOther.getStaname()!=null && this.getStaname().equals(castOther.getStaname()) ) )
+ && ( (this.getStakm()==castOther.getStakm()) || ( this.getStakm()!=null && castOther.getStakm()!=null && this.getStakm().equals(castOther.getStakm()) ) )
+ && ( (this.getGewaesserid()==castOther.getGewaesserid()) || ( this.getGewaesserid()!=null && castOther.getGewaesserid()!=null && this.getGewaesserid().equals(castOther.getGewaesserid()) ) )
+ && ( (this.getGewname()==castOther.getGewname()) || ( this.getGewname()!=null && castOther.getGewname()!=null && this.getGewname().equals(castOther.getGewname()) ) )
+ && ( (this.getBezugspegelid()==castOther.getBezugspegelid()) || ( this.getBezugspegelid()!=null && castOther.getBezugspegelid()!=null && this.getBezugspegelid().equals(castOther.getBezugspegelid()) ) );
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + ( getMessungid() == null ? 0 : this.getMessungid().hashCode() );
+         result = 37 * result + ( getStationid() == null ? 0 : this.getStationid().hashCode() );
+         result = 37 * result + ( getDatum() == null ? 0 : this.getDatum().hashCode() );
+         result = 37 * result + ( getHpeilungid() == null ? 0 : this.getHpeilungid().hashCode() );
+         result = 37 * result + ( getMpeilungid() == null ? 0 : this.getMpeilungid().hashCode() );
+         result = 37 * result + ( getGfaengerid() == null ? 0 : this.getGfaengerid().hashCode() );
+         result = 37 * result + ( getGsiebsatzid() == null ? 0 : this.getGsiebsatzid().hashCode() );
+         result = 37 * result + ( getMessnr() == null ? 0 : this.getMessnr().hashCode() );
+         result = 37 * result + ( getFgue() == null ? 0 : this.getFgue().hashCode() );
+         result = 37 * result + ( getUhrvon() == null ? 0 : this.getUhrvon().hashCode() );
+         result = 37 * result + ( getUhrbis() == null ? 0 : this.getUhrbis().hashCode() );
+         result = 37 * result + ( getWspcm() == null ? 0 : this.getWspcm().hashCode() );
+         result = 37 * result + ( getQBpegel() == null ? 0 : this.getQBpegel().hashCode() );
+         result = 37 * result + ( getWspnn() == null ? 0 : this.getWspnn().hashCode() );
+         result = 37 * result + ( getIe() == null ? 0 : this.getIe().hashCode() );
+         result = 37 * result + ( getWtemp() == null ? 0 : this.getWtemp().hashCode() );
+         result = 37 * result + ( getGbreite() == null ? 0 : this.getGbreite().hashCode() );
+         result = 37 * result + ( getGbreitevon() == null ? 0 : this.getGbreitevon().hashCode() );
+         result = 37 * result + ( getGbreitebis() == null ? 0 : this.getGbreitebis().hashCode() );
+         result = 37 * result + ( getTgeschiebe() == null ? 0 : this.getTgeschiebe().hashCode() );
+         result = 37 * result + ( getTsand() == null ? 0 : this.getTsand().hashCode() );
+         result = 37 * result + ( getTschweb() == null ? 0 : this.getTschweb().hashCode() );
+         result = 37 * result + ( getCschweb() == null ? 0 : this.getCschweb().hashCode() );
+         result = 37 * result + ( getUferliabst() == null ? 0 : this.getUferliabst().hashCode() );
+         result = 37 * result + ( getUferreabst() == null ? 0 : this.getUferreabst().hashCode() );
+         result = 37 * result + ( getQ() == null ? 0 : this.getQ().hashCode() );
+         result = 37 * result + ( getAHpeil() == null ? 0 : this.getAHpeil().hashCode() );
+         result = 37 * result + ( getAMpeil() == null ? 0 : this.getAMpeil().hashCode() );
+         result = 37 * result + ( getB() == null ? 0 : this.getB().hashCode() );
+         result = 37 * result + ( getHm() == null ? 0 : this.getHm().hashCode() );
+         result = 37 * result + ( getVm() == null ? 0 : this.getVm().hashCode() );
+         result = 37 * result + ( getVsohle() == null ? 0 : this.getVsohle().hashCode() );
+         result = 37 * result + ( getTau() == null ? 0 : this.getTau().hashCode() );
+         result = 37 * result + ( getTauv() == null ? 0 : this.getTauv().hashCode() );
+         result = 37 * result + ( getTeilQ() == null ? 0 : this.getTeilQ().hashCode() );
+         result = 37 * result + ( getTeilAHpeil() == null ? 0 : this.getTeilAHpeil().hashCode() );
+         result = 37 * result + ( getTeilAMpeil() == null ? 0 : this.getTeilAMpeil().hashCode() );
+         result = 37 * result + ( getTeilB() == null ? 0 : this.getTeilB().hashCode() );
+         result = 37 * result + ( getTeilHm() == null ? 0 : this.getTeilHm().hashCode() );
+         result = 37 * result + ( getTeilVm() == null ? 0 : this.getTeilVm().hashCode() );
+         result = 37 * result + ( getTeilVsohle() == null ? 0 : this.getTeilVsohle().hashCode() );
+         result = 37 * result + ( getTeilTau() == null ? 0 : this.getTeilTau().hashCode() );
+         result = 37 * result + ( getTeilTauv() == null ? 0 : this.getTeilTauv().hashCode() );
+         result = 37 * result + ( getMitteltyp() == null ? 0 : this.getMitteltyp().hashCode() );
+         result = 37 * result + ( getDm() == null ? 0 : this.getDm().hashCode() );
+         result = 37 * result + ( getSk() == null ? 0 : this.getSk().hashCode() );
+         result = 37 * result + ( getSo() == null ? 0 : this.getSo().hashCode() );
+         result = 37 * result + ( getU() == null ? 0 : this.getU().hashCode() );
+         result = 37 * result + ( getD90() == null ? 0 : this.getD90().hashCode() );
+         result = 37 * result + ( getD84() == null ? 0 : this.getD84().hashCode() );
+         result = 37 * result + ( getD80() == null ? 0 : this.getD80().hashCode() );
+         result = 37 * result + ( getD75() == null ? 0 : this.getD75().hashCode() );
+         result = 37 * result + ( getD70() == null ? 0 : this.getD70().hashCode() );
+         result = 37 * result + ( getD60() == null ? 0 : this.getD60().hashCode() );
+         result = 37 * result + ( getD50() == null ? 0 : this.getD50().hashCode() );
+         result = 37 * result + ( getD40() == null ? 0 : this.getD40().hashCode() );
+         result = 37 * result + ( getD30() == null ? 0 : this.getD30().hashCode() );
+         result = 37 * result + ( getD25() == null ? 0 : this.getD25().hashCode() );
+         result = 37 * result + ( getD20() == null ? 0 : this.getD20().hashCode() );
+         result = 37 * result + ( getD16() == null ? 0 : this.getD16().hashCode() );
+         result = 37 * result + ( getD10() == null ? 0 : this.getD10().hashCode() );
+         result = 37 * result + ( getDmin() == null ? 0 : this.getDmin().hashCode() );
+         result = 37 * result + ( getDurchdmin() == null ? 0 : this.getDurchdmin().hashCode() );
+         result = 37 * result + ( getDmax() == null ? 0 : this.getDmax().hashCode() );
+         result = 37 * result + ( getDurchdmax() == null ? 0 : this.getDurchdmax().hashCode() );
+         result = 37 * result + ( getNGeschieb() == null ? 0 : this.getNGeschieb().hashCode() );
+         result = 37 * result + ( getNVielpkt() == null ? 0 : this.getNVielpkt().hashCode() );
+         result = 37 * result + ( getSysDate() == null ? 0 : this.getSysDate().hashCode() );
+         result = 37 * result + ( getBemerkung() == null ? 0 : this.getBemerkung().hashCode() );
+         result = 37 * result + ( getLastupdated() == null ? 0 : this.getLastupdated().hashCode() );
+         result = 37 * result + ( getKm() == null ? 0 : this.getKm().hashCode() );
+         result = 37 * result + ( getGlotabstoffset() == null ? 0 : this.getGlotabstoffset().hashCode() );
+         result = 37 * result + ( getSlotabstoffset() == null ? 0 : this.getSlotabstoffset().hashCode() );
+         result = 37 * result + ( getGbreitevonlinks() == null ? 0 : this.getGbreitevonlinks().hashCode() );
+         result = 37 * result + ( getGbreitebislinks() == null ? 0 : this.getGbreitebislinks().hashCode() );
+         result = 37 * result + ( getStaname() == null ? 0 : this.getStaname().hashCode() );
+         result = 37 * result + ( getStakm() == null ? 0 : this.getStakm().hashCode() );
+         result = 37 * result + ( getGewaesserid() == null ? 0 : this.getGewaesserid().hashCode() );
+         result = 37 * result + ( getGewname() == null ? 0 : this.getGewname().hashCode() );
+         result = 37 * result + ( getBezugspegelid() == null ? 0 : this.getBezugspegelid().hashCode() );
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Messunguferbezug.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,45 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Messunguferbezug generated by hbm2java
+ */
+@Entity
+@Table(name="MESSUNGUFERBEZUG"
+    ,schema="SEDDB"
+)
+public class Messunguferbezug  implements java.io.Serializable {
+
+
+     private MessunguferbezugId id;
+
+    public Messunguferbezug() {
+    }
+
+    public Messunguferbezug(MessunguferbezugId id) {
+       this.id = id;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="messungid", column=@Column(name="MESSUNGID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="uferistlinks", column=@Column(name="UFERISTLINKS", nullable=false, precision=1, scale=0) ),
+        @AttributeOverride(name="hmabst", column=@Column(name="HMABST", precision=8, scale=3) ) } )
+    public MessunguferbezugId getId() {
+        return this.id;
+    }
+
+    public void setId(MessunguferbezugId id) {
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/MessunguferbezugId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,84 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * MessunguferbezugId generated by hbm2java
+ */
+@Embeddable
+public class MessunguferbezugId  implements java.io.Serializable {
+
+
+     private long messungid;
+     private boolean uferistlinks;
+     private BigDecimal hmabst;
+
+    public MessunguferbezugId() {
+    }
+
+    public MessunguferbezugId(long messungid, boolean uferistlinks) {
+        this.messungid = messungid;
+        this.uferistlinks = uferistlinks;
+    }
+    public MessunguferbezugId(long messungid, boolean uferistlinks, BigDecimal hmabst) {
+       this.messungid = messungid;
+       this.uferistlinks = uferistlinks;
+       this.hmabst = hmabst;
+    }
+
+
+
+    @Column(name="MESSUNGID", nullable=false, precision=11, scale=0)
+    public long getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(long messungid) {
+        this.messungid = messungid;
+    }
+
+
+    @Column(name="UFERISTLINKS", nullable=false, precision=1, scale=0)
+    public boolean isUferistlinks() {
+        return this.uferistlinks;
+    }
+
+    public void setUferistlinks(boolean uferistlinks) {
+        this.uferistlinks = uferistlinks;
+    }
+
+
+    @Column(name="HMABST", precision=8, scale=3)
+    public BigDecimal getHmabst() {
+        return this.hmabst;
+    }
+
+    public void setHmabst(BigDecimal hmabst) {
+        this.hmabst = hmabst;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof MessunguferbezugId) ) return false;
+         MessunguferbezugId castOther = ( MessunguferbezugId ) other;
+
+         return (this.getMessungid()==castOther.getMessungid())
+ && (this.isUferistlinks()==castOther.isUferistlinks())
+ && ( (this.getHmabst()==castOther.getHmabst()) || ( this.getHmabst()!=null && castOther.getHmabst()!=null && this.getHmabst().equals(castOther.getHmabst()) ) );
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getMessungid();
+         result = 37 * result + (this.isUferistlinks()?1:0);
+         result = 37 * result + ( getHmabst() == null ? 0 : this.getHmabst().hashCode() );
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Mpeilpunkt.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,84 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+/**
+ * Mpeilpunkt generated by hbm2java
+ */
+@Entity
+@Table(name="MPEILPUNKT"
+    ,schema="SEDDB"
+)
+public class Mpeilpunkt  implements java.io.Serializable {
+
+
+     private MpeilpunktId id;
+     private Mpeilung mpeilung;
+     private BigDecimal y;
+     private BigDecimal z;
+
+    public Mpeilpunkt() {
+    }
+
+    public Mpeilpunkt(MpeilpunktId id, Mpeilung mpeilung, BigDecimal y, BigDecimal z) {
+       this.id = id;
+       this.mpeilung = mpeilung;
+       this.y = y;
+       this.z = z;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="mpeilungid", column=@Column(name="MPEILUNGID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="punktnr", column=@Column(name="PUNKTNR", nullable=false, precision=5, scale=0) ) } )
+    public MpeilpunktId getId() {
+        return this.id;
+    }
+
+    public void setId(MpeilpunktId id) {
+        this.id = id;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="MPEILUNGID", nullable=false, insertable=false, updatable=false)
+    public Mpeilung getMpeilung() {
+        return this.mpeilung;
+    }
+
+    public void setMpeilung(Mpeilung mpeilung) {
+        this.mpeilung = mpeilung;
+    }
+
+
+    @Column(name="Y", nullable=false, precision=8, scale=3)
+    public BigDecimal getY() {
+        return this.y;
+    }
+
+    public void setY(BigDecimal y) {
+        this.y = y;
+    }
+
+
+    @Column(name="Z", nullable=false, precision=8, scale=3)
+    public BigDecimal getZ() {
+        return this.z;
+    }
+
+    public void setZ(BigDecimal z) {
+        this.z = z;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/MpeilpunktId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,65 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * MpeilpunktId generated by hbm2java
+ */
+@Embeddable
+public class MpeilpunktId  implements java.io.Serializable {
+
+
+     private long mpeilungid;
+     private int punktnr;
+
+    public MpeilpunktId() {
+    }
+
+    public MpeilpunktId(long mpeilungid, int punktnr) {
+       this.mpeilungid = mpeilungid;
+       this.punktnr = punktnr;
+    }
+
+
+
+    @Column(name="MPEILUNGID", nullable=false, precision=11, scale=0)
+    public long getMpeilungid() {
+        return this.mpeilungid;
+    }
+
+    public void setMpeilungid(long mpeilungid) {
+        this.mpeilungid = mpeilungid;
+    }
+
+
+    @Column(name="PUNKTNR", nullable=false, precision=5, scale=0)
+    public int getPunktnr() {
+        return this.punktnr;
+    }
+
+    public void setPunktnr(int punktnr) {
+        this.punktnr = punktnr;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof MpeilpunktId) ) return false;
+         MpeilpunktId castOther = ( MpeilpunktId ) other;
+
+         return (this.getMpeilungid()==castOther.getMpeilungid())
+ && (this.getPunktnr()==castOther.getPunktnr());
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getMpeilungid();
+         result = 37 * result + this.getPunktnr();
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Mpeilung.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,140 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+/**
+ * Mpeilung generated by hbm2java
+ */
+@Entity
+@Table(name="MPEILUNG"
+    ,schema="SEDDB"
+)
+public class Mpeilung  implements java.io.Serializable {
+
+
+     private long mpeilungid;
+     private Station station;
+     private Date datum;
+     private BigDecimal km;
+     private String bemerkung;
+     private Date lastupdated;
+     private Long oldapeilid;
+     private Set<Mpeilpunkt> mpeilpunkts = new HashSet<Mpeilpunkt>(0);
+
+    public Mpeilung() {
+    }
+
+    public Mpeilung(long mpeilungid, Station station, Date datum, BigDecimal km, Date lastupdated) {
+        this.mpeilungid = mpeilungid;
+        this.station = station;
+        this.datum = datum;
+        this.km = km;
+        this.lastupdated = lastupdated;
+    }
+    public Mpeilung(long mpeilungid, Station station, Date datum, BigDecimal km, String bemerkung, Date lastupdated, Long oldapeilid, Set<Mpeilpunkt> mpeilpunkts) {
+       this.mpeilungid = mpeilungid;
+       this.station = station;
+       this.datum = datum;
+       this.km = km;
+       this.bemerkung = bemerkung;
+       this.lastupdated = lastupdated;
+       this.oldapeilid = oldapeilid;
+       this.mpeilpunkts = mpeilpunkts;
+    }
+
+     @Id
+
+
+    @Column(name="MPEILUNGID", unique=true, nullable=false, precision=11, scale=0)
+    public long getMpeilungid() {
+        return this.mpeilungid;
+    }
+
+    public void setMpeilungid(long mpeilungid) {
+        this.mpeilungid = mpeilungid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="STATIONID", nullable=false)
+    public Station getStation() {
+        return this.station;
+    }
+
+    public void setStation(Station station) {
+        this.station = station;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="DATUM", nullable=false, length=7)
+    public Date getDatum() {
+        return this.datum;
+    }
+
+    public void setDatum(Date datum) {
+        this.datum = datum;
+    }
+
+
+    @Column(name="KM", nullable=false, precision=8, scale=3)
+    public BigDecimal getKm() {
+        return this.km;
+    }
+
+    public void setKm(BigDecimal km) {
+        this.km = km;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="LASTUPDATED", nullable=false, length=7)
+    public Date getLastupdated() {
+        return this.lastupdated;
+    }
+
+    public void setLastupdated(Date lastupdated) {
+        this.lastupdated = lastupdated;
+    }
+
+
+    @Column(name="OLDAPEILID", precision=11, scale=0)
+    public Long getOldapeilid() {
+        return this.oldapeilid;
+    }
+
+    public void setOldapeilid(Long oldapeilid) {
+        this.oldapeilid = oldapeilid;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="mpeilung")
+    public Set<Mpeilpunkt> getMpeilpunkts() {
+        return this.mpeilpunkts;
+    }
+
+    public void setMpeilpunkts(Set<Mpeilpunkt> mpeilpunkts) {
+        this.mpeilpunkts = mpeilpunkts;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Probebild.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,194 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+/**
+ * Probebild generated by hbm2java
+ */
+@Entity
+@Table(name="PROBEBILD"
+    ,schema="SEDDB"
+)
+public class Probebild  implements java.io.Serializable {
+
+
+     private long probebildid;
+     private Zzthema zzthema;
+     private Sohlprobe sohlprobe;
+     private int lfdnr;
+     private boolean istdigital;
+     private String pfad;
+     private String standort;
+     private String medium;
+     private String medpfad;
+     private String bemerkung;
+     private String typklein;
+     private String typmittel;
+     private String typgross;
+
+    public Probebild() {
+    }
+
+    public Probebild(long probebildid, Zzthema zzthema, Sohlprobe sohlprobe, int lfdnr, boolean istdigital) {
+        this.probebildid = probebildid;
+        this.zzthema = zzthema;
+        this.sohlprobe = sohlprobe;
+        this.lfdnr = lfdnr;
+        this.istdigital = istdigital;
+    }
+    public Probebild(long probebildid, Zzthema zzthema, Sohlprobe sohlprobe, int lfdnr, boolean istdigital, String pfad, String standort, String medium, String medpfad, String bemerkung, String typklein, String typmittel, String typgross) {
+       this.probebildid = probebildid;
+       this.zzthema = zzthema;
+       this.sohlprobe = sohlprobe;
+       this.lfdnr = lfdnr;
+       this.istdigital = istdigital;
+       this.pfad = pfad;
+       this.standort = standort;
+       this.medium = medium;
+       this.medpfad = medpfad;
+       this.bemerkung = bemerkung;
+       this.typklein = typklein;
+       this.typmittel = typmittel;
+       this.typgross = typgross;
+    }
+
+     @Id
+
+
+    @Column(name="PROBEBILDID", unique=true, nullable=false, precision=11, scale=0)
+    public long getProbebildid() {
+        return this.probebildid;
+    }
+
+    public void setProbebildid(long probebildid) {
+        this.probebildid = probebildid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="THEMAID", nullable=false)
+    public Zzthema getZzthema() {
+        return this.zzthema;
+    }
+
+    public void setZzthema(Zzthema zzthema) {
+        this.zzthema = zzthema;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="SOHLPROBEID", nullable=false)
+    public Sohlprobe getSohlprobe() {
+        return this.sohlprobe;
+    }
+
+    public void setSohlprobe(Sohlprobe sohlprobe) {
+        this.sohlprobe = sohlprobe;
+    }
+
+
+    @Column(name="LFDNR", nullable=false, precision=5, scale=0)
+    public int getLfdnr() {
+        return this.lfdnr;
+    }
+
+    public void setLfdnr(int lfdnr) {
+        this.lfdnr = lfdnr;
+    }
+
+
+    @Column(name="ISTDIGITAL", nullable=false, precision=1, scale=0)
+    public boolean isIstdigital() {
+        return this.istdigital;
+    }
+
+    public void setIstdigital(boolean istdigital) {
+        this.istdigital = istdigital;
+    }
+
+
+    @Column(name="PFAD", length=512)
+    public String getPfad() {
+        return this.pfad;
+    }
+
+    public void setPfad(String pfad) {
+        this.pfad = pfad;
+    }
+
+
+    @Column(name="STANDORT", length=50)
+    public String getStandort() {
+        return this.standort;
+    }
+
+    public void setStandort(String standort) {
+        this.standort = standort;
+    }
+
+
+    @Column(name="MEDIUM", length=50)
+    public String getMedium() {
+        return this.medium;
+    }
+
+    public void setMedium(String medium) {
+        this.medium = medium;
+    }
+
+
+    @Column(name="MEDPFAD", length=50)
+    public String getMedpfad() {
+        return this.medpfad;
+    }
+
+    public void setMedpfad(String medpfad) {
+        this.medpfad = medpfad;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="TYPKLEIN", length=8)
+    public String getTypklein() {
+        return this.typklein;
+    }
+
+    public void setTypklein(String typklein) {
+        this.typklein = typklein;
+    }
+
+
+    @Column(name="TYPMITTEL", length=8)
+    public String getTypmittel() {
+        return this.typmittel;
+    }
+
+    public void setTypmittel(String typmittel) {
+        this.typmittel = typmittel;
+    }
+
+
+    @Column(name="TYPGROSS", length=8)
+    public String getTypgross() {
+        return this.typgross;
+    }
+
+    public void setTypgross(String typgross) {
+        this.typgross = typgross;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Siebanalyse.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,361 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+/**
+ * Siebanalyse generated by hbm2java
+ */
+@Entity
+@Table(name="SIEBANALYSE"
+    ,schema="SEDDB"
+)
+public class Siebanalyse  implements java.io.Serializable {
+
+
+     private long siebanalyseid;
+     private Sohlprobe sohlprobe;
+     private boolean istdigital;
+     private String standort;
+     private BigDecimal dm;
+     private BigDecimal so;
+     private BigDecimal sk;
+     private BigDecimal u;
+     private BigDecimal d90;
+     private BigDecimal d84;
+     private BigDecimal d80;
+     private BigDecimal d75;
+     private BigDecimal d70;
+     private BigDecimal d60;
+     private BigDecimal d50;
+     private BigDecimal d40;
+     private BigDecimal d30;
+     private BigDecimal d25;
+     private BigDecimal d20;
+     private BigDecimal d16;
+     private BigDecimal d10;
+     private BigDecimal dmin;
+     private BigDecimal durchdmin;
+     private BigDecimal dmax;
+     private BigDecimal durchdmax;
+     private String bemerkung;
+     private Ssiebung ssiebung;
+
+    public Siebanalyse() {
+    }
+
+    public Siebanalyse(long siebanalyseid, Sohlprobe sohlprobe, boolean istdigital) {
+        this.siebanalyseid = siebanalyseid;
+        this.sohlprobe = sohlprobe;
+        this.istdigital = istdigital;
+    }
+    public Siebanalyse(long siebanalyseid, Sohlprobe sohlprobe, boolean istdigital, String standort, BigDecimal dm, BigDecimal so, BigDecimal sk, BigDecimal u, BigDecimal d90, BigDecimal d84, BigDecimal d80, BigDecimal d75, BigDecimal d70, BigDecimal d60, BigDecimal d50, BigDecimal d40, BigDecimal d30, BigDecimal d25, BigDecimal d20, BigDecimal d16, BigDecimal d10, BigDecimal dmin, BigDecimal durchdmin, BigDecimal dmax, BigDecimal durchdmax, String bemerkung, Ssiebung ssiebung) {
+       this.siebanalyseid = siebanalyseid;
+       this.sohlprobe = sohlprobe;
+       this.istdigital = istdigital;
+       this.standort = standort;
+       this.dm = dm;
+       this.so = so;
+       this.sk = sk;
+       this.u = u;
+       this.d90 = d90;
+       this.d84 = d84;
+       this.d80 = d80;
+       this.d75 = d75;
+       this.d70 = d70;
+       this.d60 = d60;
+       this.d50 = d50;
+       this.d40 = d40;
+       this.d30 = d30;
+       this.d25 = d25;
+       this.d20 = d20;
+       this.d16 = d16;
+       this.d10 = d10;
+       this.dmin = dmin;
+       this.durchdmin = durchdmin;
+       this.dmax = dmax;
+       this.durchdmax = durchdmax;
+       this.bemerkung = bemerkung;
+       this.ssiebung = ssiebung;
+    }
+
+     @Id
+
+
+    @Column(name="SIEBANALYSEID", unique=true, nullable=false, precision=11, scale=0)
+    public long getSiebanalyseid() {
+        return this.siebanalyseid;
+    }
+
+    public void setSiebanalyseid(long siebanalyseid) {
+        this.siebanalyseid = siebanalyseid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="SOHLPROBEID", nullable=false)
+    public Sohlprobe getSohlprobe() {
+        return this.sohlprobe;
+    }
+
+    public void setSohlprobe(Sohlprobe sohlprobe) {
+        this.sohlprobe = sohlprobe;
+    }
+
+
+    @Column(name="ISTDIGITAL", nullable=false, precision=1, scale=0)
+    public boolean isIstdigital() {
+        return this.istdigital;
+    }
+
+    public void setIstdigital(boolean istdigital) {
+        this.istdigital = istdigital;
+    }
+
+
+    @Column(name="STANDORT", length=50)
+    public String getStandort() {
+        return this.standort;
+    }
+
+    public void setStandort(String standort) {
+        this.standort = standort;
+    }
+
+
+    @Column(name="DM", precision=7, scale=4)
+    public BigDecimal getDm() {
+        return this.dm;
+    }
+
+    public void setDm(BigDecimal dm) {
+        this.dm = dm;
+    }
+
+
+    @Column(name="SO", precision=8, scale=3)
+    public BigDecimal getSo() {
+        return this.so;
+    }
+
+    public void setSo(BigDecimal so) {
+        this.so = so;
+    }
+
+
+    @Column(name="SK", precision=8, scale=3)
+    public BigDecimal getSk() {
+        return this.sk;
+    }
+
+    public void setSk(BigDecimal sk) {
+        this.sk = sk;
+    }
+
+
+    @Column(name="U", precision=8, scale=3)
+    public BigDecimal getU() {
+        return this.u;
+    }
+
+    public void setU(BigDecimal u) {
+        this.u = u;
+    }
+
+
+    @Column(name="D90", precision=7, scale=4)
+    public BigDecimal getD90() {
+        return this.d90;
+    }
+
+    public void setD90(BigDecimal d90) {
+        this.d90 = d90;
+    }
+
+
+    @Column(name="D84", precision=7, scale=4)
+    public BigDecimal getD84() {
+        return this.d84;
+    }
+
+    public void setD84(BigDecimal d84) {
+        this.d84 = d84;
+    }
+
+
+    @Column(name="D80", precision=7, scale=4)
+    public BigDecimal getD80() {
+        return this.d80;
+    }
+
+    public void setD80(BigDecimal d80) {
+        this.d80 = d80;
+    }
+
+
+    @Column(name="D75", precision=7, scale=4)
+    public BigDecimal getD75() {
+        return this.d75;
+    }
+
+    public void setD75(BigDecimal d75) {
+        this.d75 = d75;
+    }
+
+
+    @Column(name="D70", precision=7, scale=4)
+    public BigDecimal getD70() {
+        return this.d70;
+    }
+
+    public void setD70(BigDecimal d70) {
+        this.d70 = d70;
+    }
+
+
+    @Column(name="D60", precision=7, scale=4)
+    public BigDecimal getD60() {
+        return this.d60;
+    }
+
+    public void setD60(BigDecimal d60) {
+        this.d60 = d60;
+    }
+
+
+    @Column(name="D50", precision=7, scale=4)
+    public BigDecimal getD50() {
+        return this.d50;
+    }
+
+    public void setD50(BigDecimal d50) {
+        this.d50 = d50;
+    }
+
+
+    @Column(name="D40", precision=7, scale=4)
+    public BigDecimal getD40() {
+        return this.d40;
+    }
+
+    public void setD40(BigDecimal d40) {
+        this.d40 = d40;
+    }
+
+
+    @Column(name="D30", precision=7, scale=4)
+    public BigDecimal getD30() {
+        return this.d30;
+    }
+
+    public void setD30(BigDecimal d30) {
+        this.d30 = d30;
+    }
+
+
+    @Column(name="D25", precision=7, scale=4)
+    public BigDecimal getD25() {
+        return this.d25;
+    }
+
+    public void setD25(BigDecimal d25) {
+        this.d25 = d25;
+    }
+
+
+    @Column(name="D20", precision=7, scale=4)
+    public BigDecimal getD20() {
+        return this.d20;
+    }
+
+    public void setD20(BigDecimal d20) {
+        this.d20 = d20;
+    }
+
+
+    @Column(name="D16", precision=7, scale=4)
+    public BigDecimal getD16() {
+        return this.d16;
+    }
+
+    public void setD16(BigDecimal d16) {
+        this.d16 = d16;
+    }
+
+
+    @Column(name="D10", precision=7, scale=4)
+    public BigDecimal getD10() {
+        return this.d10;
+    }
+
+    public void setD10(BigDecimal d10) {
+        this.d10 = d10;
+    }
+
+
+    @Column(name="DMIN", precision=7, scale=4)
+    public BigDecimal getDmin() {
+        return this.dmin;
+    }
+
+    public void setDmin(BigDecimal dmin) {
+        this.dmin = dmin;
+    }
+
+
+    @Column(name="DURCHDMIN", precision=6, scale=3)
+    public BigDecimal getDurchdmin() {
+        return this.durchdmin;
+    }
+
+    public void setDurchdmin(BigDecimal durchdmin) {
+        this.durchdmin = durchdmin;
+    }
+
+
+    @Column(name="DMAX", precision=7, scale=4)
+    public BigDecimal getDmax() {
+        return this.dmax;
+    }
+
+    public void setDmax(BigDecimal dmax) {
+        this.dmax = dmax;
+    }
+
+
+    @Column(name="DURCHDMAX", precision=6, scale=3)
+    public BigDecimal getDurchdmax() {
+        return this.durchdmax;
+    }
+
+    public void setDurchdmax(BigDecimal durchdmax) {
+        this.durchdmax = durchdmax;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+@OneToOne(fetch=FetchType.LAZY, mappedBy="siebanalyse")
+    public Ssiebung getSsiebung() {
+        return this.ssiebung;
+    }
+
+    public void setSsiebung(Ssiebung ssiebung) {
+        this.ssiebung = ssiebung;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Slotlinks.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,53 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Slotlinks generated by hbm2java
+ */
+@Entity
+@Table(name="SLOTLINKS"
+    ,schema="SEDDB"
+)
+public class Slotlinks  implements java.io.Serializable {
+
+
+     private SlotlinksId id;
+
+    public Slotlinks() {
+    }
+
+    public Slotlinks(SlotlinksId id) {
+       this.id = id;
+    }
+
+     @EmbeddedId
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="slotrechteid", column=@Column(name="SLOTRECHTEID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="messungid", column=@Column(name="MESSUNGID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="uferabst", column=@Column(name="UFERABST", nullable=false, precision=8, scale=3) ),
+        @AttributeOverride(name="tsand", column=@Column(name="TSAND", precision=8, scale=3) ),
+        @AttributeOverride(name="tschweb", column=@Column(name="TSCHWEB", precision=8, scale=3) ),
+        @AttributeOverride(name="fv", column=@Column(name="FV", precision=6, scale=3) ),
+        @AttributeOverride(name="vm", column=@Column(name="VM", precision=6, scale=4) ),
+        @AttributeOverride(name="tiefe", column=@Column(name="TIEFE", precision=8, scale=3) ),
+        @AttributeOverride(name="vsohle", column=@Column(name="VSOHLE", precision=6, scale=4) ),
+        @AttributeOverride(name="bemerkung", column=@Column(name="BEMERKUNG", length=240) ),
+        @AttributeOverride(name="uferablinks", column=@Column(name="UFERABLINKS", precision=8, scale=3) ),
+        @AttributeOverride(name="linksabst", column=@Column(name="LINKSABST", precision=22, scale=0) ) } )
+    public SlotlinksId getId() {
+        return this.id;
+    }
+
+    public void setId(SlotlinksId id) {
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/SlotlinksId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,211 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * SlotlinksId generated by hbm2java
+ */
+@Embeddable
+public class SlotlinksId  implements java.io.Serializable {
+
+
+     private long slotrechteid;
+     private long messungid;
+     private BigDecimal uferabst;
+     private BigDecimal tsand;
+     private BigDecimal tschweb;
+     private BigDecimal fv;
+     private BigDecimal vm;
+     private BigDecimal tiefe;
+     private BigDecimal vsohle;
+     private String bemerkung;
+     private BigDecimal uferablinks;
+     private BigDecimal linksabst;
+
+    public SlotlinksId() {
+    }
+
+    public SlotlinksId(long slotrechteid, long messungid, BigDecimal uferabst) {
+        this.slotrechteid = slotrechteid;
+        this.messungid = messungid;
+        this.uferabst = uferabst;
+    }
+    public SlotlinksId(long slotrechteid, long messungid, BigDecimal uferabst, BigDecimal tsand, BigDecimal tschweb, BigDecimal fv, BigDecimal vm, BigDecimal tiefe, BigDecimal vsohle, String bemerkung, BigDecimal uferablinks, BigDecimal linksabst) {
+       this.slotrechteid = slotrechteid;
+       this.messungid = messungid;
+       this.uferabst = uferabst;
+       this.tsand = tsand;
+       this.tschweb = tschweb;
+       this.fv = fv;
+       this.vm = vm;
+       this.tiefe = tiefe;
+       this.vsohle = vsohle;
+       this.bemerkung = bemerkung;
+       this.uferablinks = uferablinks;
+       this.linksabst = linksabst;
+    }
+
+
+
+    @Column(name="SLOTRECHTEID", nullable=false, precision=11, scale=0)
+    public long getSlotrechteid() {
+        return this.slotrechteid;
+    }
+
+    public void setSlotrechteid(long slotrechteid) {
+        this.slotrechteid = slotrechteid;
+    }
+
+
+    @Column(name="MESSUNGID", nullable=false, precision=11, scale=0)
+    public long getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(long messungid) {
+        this.messungid = messungid;
+    }
+
+
+    @Column(name="UFERABST", nullable=false, precision=8, scale=3)
+    public BigDecimal getUferabst() {
+        return this.uferabst;
+    }
+
+    public void setUferabst(BigDecimal uferabst) {
+        this.uferabst = uferabst;
+    }
+
+
+    @Column(name="TSAND", precision=8, scale=3)
+    public BigDecimal getTsand() {
+        return this.tsand;
+    }
+
+    public void setTsand(BigDecimal tsand) {
+        this.tsand = tsand;
+    }
+
+
+    @Column(name="TSCHWEB", precision=8, scale=3)
+    public BigDecimal getTschweb() {
+        return this.tschweb;
+    }
+
+    public void setTschweb(BigDecimal tschweb) {
+        this.tschweb = tschweb;
+    }
+
+
+    @Column(name="FV", precision=6, scale=3)
+    public BigDecimal getFv() {
+        return this.fv;
+    }
+
+    public void setFv(BigDecimal fv) {
+        this.fv = fv;
+    }
+
+
+    @Column(name="VM", precision=6, scale=4)
+    public BigDecimal getVm() {
+        return this.vm;
+    }
+
+    public void setVm(BigDecimal vm) {
+        this.vm = vm;
+    }
+
+
+    @Column(name="TIEFE", precision=8, scale=3)
+    public BigDecimal getTiefe() {
+        return this.tiefe;
+    }
+
+    public void setTiefe(BigDecimal tiefe) {
+        this.tiefe = tiefe;
+    }
+
+
+    @Column(name="VSOHLE", precision=6, scale=4)
+    public BigDecimal getVsohle() {
+        return this.vsohle;
+    }
+
+    public void setVsohle(BigDecimal vsohle) {
+        this.vsohle = vsohle;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="UFERABLINKS", precision=8, scale=3)
+    public BigDecimal getUferablinks() {
+        return this.uferablinks;
+    }
+
+    public void setUferablinks(BigDecimal uferablinks) {
+        this.uferablinks = uferablinks;
+    }
+
+
+    @Column(name="LINKSABST", precision=22, scale=0)
+    public BigDecimal getLinksabst() {
+        return this.linksabst;
+    }
+
+    public void setLinksabst(BigDecimal linksabst) {
+        this.linksabst = linksabst;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+		 if ( (other == null ) ) return false;
+		 if ( !(other instanceof SlotlinksId) ) return false;
+		 SlotlinksId castOther = ( SlotlinksId ) other;
+
+		 return (this.getSlotrechteid()==castOther.getSlotrechteid())
+ && (this.getMessungid()==castOther.getMessungid())
+ && ( (this.getUferabst()==castOther.getUferabst()) || ( this.getUferabst()!=null && castOther.getUferabst()!=null && this.getUferabst().equals(castOther.getUferabst()) ) )
+ && ( (this.getTsand()==castOther.getTsand()) || ( this.getTsand()!=null && castOther.getTsand()!=null && this.getTsand().equals(castOther.getTsand()) ) )
+ && ( (this.getTschweb()==castOther.getTschweb()) || ( this.getTschweb()!=null && castOther.getTschweb()!=null && this.getTschweb().equals(castOther.getTschweb()) ) )
+ && ( (this.getFv()==castOther.getFv()) || ( this.getFv()!=null && castOther.getFv()!=null && this.getFv().equals(castOther.getFv()) ) )
+ && ( (this.getVm()==castOther.getVm()) || ( this.getVm()!=null && castOther.getVm()!=null && this.getVm().equals(castOther.getVm()) ) )
+ && ( (this.getTiefe()==castOther.getTiefe()) || ( this.getTiefe()!=null && castOther.getTiefe()!=null && this.getTiefe().equals(castOther.getTiefe()) ) )
+ && ( (this.getVsohle()==castOther.getVsohle()) || ( this.getVsohle()!=null && castOther.getVsohle()!=null && this.getVsohle().equals(castOther.getVsohle()) ) )
+ && ( (this.getBemerkung()==castOther.getBemerkung()) || ( this.getBemerkung()!=null && castOther.getBemerkung()!=null && this.getBemerkung().equals(castOther.getBemerkung()) ) )
+ && ( (this.getUferablinks()==castOther.getUferablinks()) || ( this.getUferablinks()!=null && castOther.getUferablinks()!=null && this.getUferablinks().equals(castOther.getUferablinks()) ) )
+ && ( (this.getLinksabst()==castOther.getLinksabst()) || ( this.getLinksabst()!=null && castOther.getLinksabst()!=null && this.getLinksabst().equals(castOther.getLinksabst()) ) );
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getSlotrechteid();
+         result = 37 * result + (int) this.getMessungid();
+         result = 37 * result + ( getUferabst() == null ? 0 : this.getUferabst().hashCode() );
+         result = 37 * result + ( getTsand() == null ? 0 : this.getTsand().hashCode() );
+         result = 37 * result + ( getTschweb() == null ? 0 : this.getTschweb().hashCode() );
+         result = 37 * result + ( getFv() == null ? 0 : this.getFv().hashCode() );
+         result = 37 * result + ( getVm() == null ? 0 : this.getVm().hashCode() );
+         result = 37 * result + ( getTiefe() == null ? 0 : this.getTiefe().hashCode() );
+         result = 37 * result + ( getVsohle() == null ? 0 : this.getVsohle().hashCode() );
+         result = 37 * result + ( getBemerkung() == null ? 0 : this.getBemerkung().hashCode() );
+         result = 37 * result + ( getUferablinks() == null ? 0 : this.getUferablinks().hashCode() );
+         result = 37 * result + ( getLinksabst() == null ? 0 : this.getLinksabst().hashCode() );
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Slotrechte.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,183 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+/**
+ * Slotrechte generated by hbm2java
+ */
+@Entity
+@Table(name="SLOTRECHTE"
+    ,schema="SEDDB"
+)
+public class Slotrechte  implements java.io.Serializable {
+
+
+     private long slotrechteid;
+     private Messung messung;
+     private BigDecimal uferabst;
+     private BigDecimal tsand;
+     private BigDecimal tschweb;
+     private BigDecimal fv;
+     private BigDecimal vm;
+     private BigDecimal tiefe;
+     private BigDecimal vsohle;
+     private String bemerkung;
+     private BigDecimal uferablinks;
+     private Set<Sprobe> sprobes = new HashSet<Sprobe>(0);
+
+    public Slotrechte() {
+    }
+
+    public Slotrechte(long slotrechteid, Messung messung, BigDecimal uferabst) {
+        this.slotrechteid = slotrechteid;
+        this.messung = messung;
+        this.uferabst = uferabst;
+    }
+    public Slotrechte(long slotrechteid, Messung messung, BigDecimal uferabst, BigDecimal tsand, BigDecimal tschweb, BigDecimal fv, BigDecimal vm, BigDecimal tiefe, BigDecimal vsohle, String bemerkung, BigDecimal uferablinks, Set<Sprobe> sprobes) {
+       this.slotrechteid = slotrechteid;
+       this.messung = messung;
+       this.uferabst = uferabst;
+       this.tsand = tsand;
+       this.tschweb = tschweb;
+       this.fv = fv;
+       this.vm = vm;
+       this.tiefe = tiefe;
+       this.vsohle = vsohle;
+       this.bemerkung = bemerkung;
+       this.uferablinks = uferablinks;
+       this.sprobes = sprobes;
+    }
+
+     @Id
+
+
+    @Column(name="SLOTRECHTEID", unique=true, nullable=false, precision=11, scale=0)
+    public long getSlotrechteid() {
+        return this.slotrechteid;
+    }
+
+    public void setSlotrechteid(long slotrechteid) {
+        this.slotrechteid = slotrechteid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="MESSUNGID", nullable=false)
+    public Messung getMessung() {
+        return this.messung;
+    }
+
+    public void setMessung(Messung messung) {
+        this.messung = messung;
+    }
+
+
+    @Column(name="UFERABST", nullable=false, precision=8, scale=3)
+    public BigDecimal getUferabst() {
+        return this.uferabst;
+    }
+
+    public void setUferabst(BigDecimal uferabst) {
+        this.uferabst = uferabst;
+    }
+
+
+    @Column(name="TSAND", precision=8, scale=3)
+    public BigDecimal getTsand() {
+        return this.tsand;
+    }
+
+    public void setTsand(BigDecimal tsand) {
+        this.tsand = tsand;
+    }
+
+
+    @Column(name="TSCHWEB", precision=8, scale=3)
+    public BigDecimal getTschweb() {
+        return this.tschweb;
+    }
+
+    public void setTschweb(BigDecimal tschweb) {
+        this.tschweb = tschweb;
+    }
+
+
+    @Column(name="FV", precision=6, scale=3)
+    public BigDecimal getFv() {
+        return this.fv;
+    }
+
+    public void setFv(BigDecimal fv) {
+        this.fv = fv;
+    }
+
+
+    @Column(name="VM", precision=6, scale=4)
+    public BigDecimal getVm() {
+        return this.vm;
+    }
+
+    public void setVm(BigDecimal vm) {
+        this.vm = vm;
+    }
+
+
+    @Column(name="TIEFE", precision=8, scale=3)
+    public BigDecimal getTiefe() {
+        return this.tiefe;
+    }
+
+    public void setTiefe(BigDecimal tiefe) {
+        this.tiefe = tiefe;
+    }
+
+
+    @Column(name="VSOHLE", precision=6, scale=4)
+    public BigDecimal getVsohle() {
+        return this.vsohle;
+    }
+
+    public void setVsohle(BigDecimal vsohle) {
+        this.vsohle = vsohle;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="UFERABLINKS", precision=8, scale=3)
+    public BigDecimal getUferablinks() {
+        return this.uferablinks;
+    }
+
+    public void setUferablinks(BigDecimal uferablinks) {
+        this.uferablinks = uferablinks;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="slotrechte")
+    public Set<Sprobe> getSprobes() {
+        return this.sprobes;
+    }
+
+    public void setSprobes(Set<Sprobe> sprobes) {
+        this.sprobes = sprobes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Sohlprobe.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,156 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+/**
+ * Sohlprobe generated by hbm2java
+ */
+@Entity
+@Table(name="SOHLPROBE"
+    ,schema="SEDDB"
+)
+public class Sohlprobe  implements java.io.Serializable {
+
+
+     private long sohlprobeid;
+     private Zzprobenahmeart zzprobenahmeart;
+     private Sohltest sohltest;
+     private BigDecimal tiefevon;
+     private BigDecimal tiefebis;
+     private String beschreibung;
+     private Date lastupdated;
+     private Set<Probebild> probebilds = new HashSet<Probebild>(0);
+     private Set<Siebanalyse> siebanalyses = new HashSet<Siebanalyse>(0);
+
+    public Sohlprobe() {
+    }
+
+    public Sohlprobe(long sohlprobeid, Zzprobenahmeart zzprobenahmeart, Sohltest sohltest, Date lastupdated) {
+        this.sohlprobeid = sohlprobeid;
+        this.zzprobenahmeart = zzprobenahmeart;
+        this.sohltest = sohltest;
+        this.lastupdated = lastupdated;
+    }
+    public Sohlprobe(long sohlprobeid, Zzprobenahmeart zzprobenahmeart, Sohltest sohltest, BigDecimal tiefevon, BigDecimal tiefebis, String beschreibung, Date lastupdated, Set<Probebild> probebilds, Set<Siebanalyse> siebanalyses) {
+       this.sohlprobeid = sohlprobeid;
+       this.zzprobenahmeart = zzprobenahmeart;
+       this.sohltest = sohltest;
+       this.tiefevon = tiefevon;
+       this.tiefebis = tiefebis;
+       this.beschreibung = beschreibung;
+       this.lastupdated = lastupdated;
+       this.probebilds = probebilds;
+       this.siebanalyses = siebanalyses;
+    }
+
+     @Id
+
+
+    @Column(name="SOHLPROBEID", unique=true, nullable=false, precision=11, scale=0)
+    public long getSohlprobeid() {
+        return this.sohlprobeid;
+    }
+
+    public void setSohlprobeid(long sohlprobeid) {
+        this.sohlprobeid = sohlprobeid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="PROBENAHMEARTID", nullable=false)
+    public Zzprobenahmeart getZzprobenahmeart() {
+        return this.zzprobenahmeart;
+    }
+
+    public void setZzprobenahmeart(Zzprobenahmeart zzprobenahmeart) {
+        this.zzprobenahmeart = zzprobenahmeart;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="SOHLTESTID", nullable=false)
+    public Sohltest getSohltest() {
+        return this.sohltest;
+    }
+
+    public void setSohltest(Sohltest sohltest) {
+        this.sohltest = sohltest;
+    }
+
+
+    @Column(name="TIEFEVON", precision=8, scale=3)
+    public BigDecimal getTiefevon() {
+        return this.tiefevon;
+    }
+
+    public void setTiefevon(BigDecimal tiefevon) {
+        this.tiefevon = tiefevon;
+    }
+
+
+    @Column(name="TIEFEBIS", precision=8, scale=3)
+    public BigDecimal getTiefebis() {
+        return this.tiefebis;
+    }
+
+    public void setTiefebis(BigDecimal tiefebis) {
+        this.tiefebis = tiefebis;
+    }
+
+
+    @Column(name="BESCHREIBUNG", length=1024)
+    public String getBeschreibung() {
+        return this.beschreibung;
+    }
+
+    public void setBeschreibung(String beschreibung) {
+        this.beschreibung = beschreibung;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="LASTUPDATED", nullable=false, length=7)
+    public Date getLastupdated() {
+        return this.lastupdated;
+    }
+
+    public void setLastupdated(Date lastupdated) {
+        this.lastupdated = lastupdated;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="sohlprobe")
+    public Set<Probebild> getProbebilds() {
+        return this.probebilds;
+    }
+
+    public void setProbebilds(Set<Probebild> probebilds) {
+        this.probebilds = probebilds;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="sohlprobe")
+    public Set<Siebanalyse> getSiebanalyses() {
+        return this.siebanalyses;
+    }
+
+    public void setSiebanalyses(Set<Siebanalyse> siebanalyses) {
+        this.siebanalyses = siebanalyses;
+    }
+
+
+
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Sohltest.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,299 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+/**
+ * Sohltest generated by hbm2java
+ */
+@Entity
+@Table(name="SOHLTEST"
+    ,schema="SEDDB"
+)
+public class Sohltest  implements java.io.Serializable {
+
+     private long sohltestid;
+     private Station station;
+     private Zzsondierungart zzsondierungart;
+     private Zzarchiv zzarchiv;
+     private Date datum;
+     private boolean istnurjahr;
+     private BigDecimal km;
+     private BigDecimal abstand;
+     private boolean abstistvonlinks;
+     private boolean abstbezug;
+     private BigDecimal abstoffset;
+     private BigDecimal abstlinks;
+     private BigDecimal rechts;
+     private BigDecimal hoch;
+     private BigDecimal hoehe;
+     private String bemerkung;
+     private String sohlebeschreib;
+     private String sondierungbeschreib;
+     private Date lastupdated;
+     private Set<Bild> bilds = new HashSet<Bild>(0);
+     private Set<Sohlprobe> sohlprobes = new HashSet<Sohlprobe>(0);
+
+    public Sohltest() {
+    }
+
+
+    public Sohltest(long sohltestid, Station station, Date datum, boolean istnurjahr, BigDecimal abstand, boolean abstistvonlinks, boolean abstbezug, BigDecimal abstoffset, Date lastupdated) {
+        this.sohltestid = sohltestid;
+        this.station = station;
+        this.datum = datum;
+        this.istnurjahr = istnurjahr;
+        this.abstand = abstand;
+        this.abstistvonlinks = abstistvonlinks;
+        this.abstbezug = abstbezug;
+        this.abstoffset = abstoffset;
+        this.lastupdated = lastupdated;
+    }
+    public Sohltest(long sohltestid, Station station, Zzsondierungart zzsondierungart, Zzarchiv zzarchiv, Date datum, boolean istnurjahr, BigDecimal km, BigDecimal abstand, boolean abstistvonlinks, boolean abstbezug, BigDecimal abstoffset, BigDecimal abstlinks, BigDecimal rechts, BigDecimal hoch, BigDecimal hoehe, String bemerkung, String sohlebeschreib, String sondierungbeschreib, Date lastupdated, Set<Bild> bilds, Set<Sohlprobe> sohlprobes) {
+       this.sohltestid = sohltestid;
+       this.station = station;
+       this.zzsondierungart = zzsondierungart;
+       this.zzarchiv = zzarchiv;
+       this.datum = datum;
+       this.istnurjahr = istnurjahr;
+       this.km = km;
+       this.abstand = abstand;
+       this.abstistvonlinks = abstistvonlinks;
+       this.abstbezug = abstbezug;
+       this.abstoffset = abstoffset;
+       this.abstlinks = abstlinks;
+       this.rechts = rechts;
+       this.hoch = hoch;
+       this.hoehe = hoehe;
+       this.bemerkung = bemerkung;
+       this.sohlebeschreib = sohlebeschreib;
+       this.sondierungbeschreib = sondierungbeschreib;
+       this.lastupdated = lastupdated;
+       this.bilds = bilds;
+       this.sohlprobes = sohlprobes;
+    }
+
+     @Id
+
+
+    @Column(name="SOHLTESTID", unique=true, nullable=false, precision=11, scale=0)
+    public long getSohltestid() {
+        return this.sohltestid;
+    }
+
+    public void setSohltestid(long sohltestid) {
+        this.sohltestid = sohltestid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="STATIONID", nullable=false)
+    public Station getStation() {
+        return this.station;
+    }
+
+    public void setStation(Station station) {
+        this.station = station;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="SONDIERUNGARTID")
+    public Zzsondierungart getZzsondierungart() {
+        return this.zzsondierungart;
+    }
+
+    public void setZzsondierungart(Zzsondierungart zzsondierungart) {
+        this.zzsondierungart = zzsondierungart;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="ARCHIVID")
+    public Zzarchiv getZzarchiv() {
+        return this.zzarchiv;
+    }
+
+    public void setZzarchiv(Zzarchiv zzarchiv) {
+        this.zzarchiv = zzarchiv;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="DATUM", nullable=false, length=7)
+    public Date getDatum() {
+        return this.datum;
+    }
+
+    public void setDatum(Date datum) {
+        this.datum = datum;
+    }
+
+
+    @Column(name="ISTNURJAHR", nullable=false, precision=1, scale=0)
+    public boolean isIstnurjahr() {
+        return this.istnurjahr;
+    }
+
+    public void setIstnurjahr(boolean istnurjahr) {
+        this.istnurjahr = istnurjahr;
+    }
+
+
+    @Column(name="KM", precision=8, scale=3)
+    public BigDecimal getKm() {
+        return this.km;
+    }
+
+    public void setKm(BigDecimal km) {
+        this.km = km;
+    }
+
+
+    @Column(name="ABSTAND", nullable=false, precision=8, scale=3)
+    public BigDecimal getAbstand() {
+        return this.abstand;
+    }
+
+    public void setAbstand(BigDecimal abstand) {
+        this.abstand = abstand;
+    }
+
+
+    @Column(name="ABSTISTVONLINKS", nullable=false, precision=1, scale=0)
+    public boolean isAbstistvonlinks() {
+        return this.abstistvonlinks;
+    }
+
+    public void setAbstistvonlinks(boolean abstistvonlinks) {
+        this.abstistvonlinks = abstistvonlinks;
+    }
+
+
+    @Column(name="ABSTBEZUG", nullable=false, precision=1, scale=0)
+    public boolean isAbstbezug() {
+        return this.abstbezug;
+    }
+
+    public void setAbstbezug(boolean abstbezug) {
+        this.abstbezug = abstbezug;
+    }
+
+
+    @Column(name="ABSTOFFSET", nullable=false, precision=8, scale=3)
+    public BigDecimal getAbstoffset() {
+        return this.abstoffset;
+    }
+
+    public void setAbstoffset(BigDecimal abstoffset) {
+        this.abstoffset = abstoffset;
+    }
+
+
+    @Column(name="ABSTLINKS", precision=8, scale=3)
+    public BigDecimal getAbstlinks() {
+        return this.abstlinks;
+    }
+
+    public void setAbstlinks(BigDecimal abstlinks) {
+        this.abstlinks = abstlinks;
+    }
+
+
+    @Column(name="RECHTS", precision=11, scale=3)
+    public BigDecimal getRechts() {
+        return this.rechts;
+    }
+
+    public void setRechts(BigDecimal rechts) {
+        this.rechts = rechts;
+    }
+
+
+    @Column(name="HOCH", precision=11, scale=3)
+    public BigDecimal getHoch() {
+        return this.hoch;
+    }
+
+    public void setHoch(BigDecimal hoch) {
+        this.hoch = hoch;
+    }
+
+
+    @Column(name="HOEHE", precision=8, scale=3)
+    public BigDecimal getHoehe() {
+        return this.hoehe;
+    }
+
+    public void setHoehe(BigDecimal hoehe) {
+        this.hoehe = hoehe;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="SOHLEBESCHREIB", length=1024)
+    public String getSohlebeschreib() {
+        return this.sohlebeschreib;
+    }
+
+    public void setSohlebeschreib(String sohlebeschreib) {
+        this.sohlebeschreib = sohlebeschreib;
+    }
+
+
+    @Column(name="SONDIERUNGBESCHREIB", length=1024)
+    public String getSondierungbeschreib() {
+        return this.sondierungbeschreib;
+    }
+
+    public void setSondierungbeschreib(String sondierungbeschreib) {
+        this.sondierungbeschreib = sondierungbeschreib;
+    }
+
+    @Temporal(TemporalType.DATE)
+    @Column(name="LASTUPDATED", nullable=false, length=7)
+    public Date getLastupdated() {
+        return this.lastupdated;
+    }
+
+    public void setLastupdated(Date lastupdated) {
+        this.lastupdated = lastupdated;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="sohltest")
+    public Set<Bild> getBilds() {
+        return this.bilds;
+    }
+
+    public void setBilds(Set<Bild> bilds) {
+        this.bilds = bilds;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="sohltest")
+    public Set<Sohlprobe> getSohlprobes() {
+        return this.sohlprobes;
+    }
+
+    public void setSohlprobes(Set<Sohlprobe> sohlprobes) {
+        this.sohlprobes = sohlprobes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Sprobe.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,154 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+/**
+ * Sprobe generated by hbm2java
+ */
+@Entity
+@Table(name="SPROBE"
+    ,schema="SEDDB"
+)
+public class Sprobe  implements java.io.Serializable {
+
+
+     private SprobeId id;
+     private Slotrechte slotrechte;
+     private short wprozpkt;
+     private BigDecimal wpkt;
+     private BigDecimal vpkt;
+     private BigDecimal csandpkt;
+     private BigDecimal cschwebpkt;
+     private BigDecimal sandtrieb;
+     private BigDecimal schwebtrieb;
+
+    public Sprobe() {
+    }
+
+
+    public Sprobe(SprobeId id, Slotrechte slotrechte, short wprozpkt, BigDecimal wpkt, BigDecimal vpkt, BigDecimal csandpkt, BigDecimal cschwebpkt) {
+        this.id = id;
+        this.slotrechte = slotrechte;
+        this.wprozpkt = wprozpkt;
+        this.wpkt = wpkt;
+        this.vpkt = vpkt;
+        this.csandpkt = csandpkt;
+        this.cschwebpkt = cschwebpkt;
+    }
+    public Sprobe(SprobeId id, Slotrechte slotrechte, short wprozpkt, BigDecimal wpkt, BigDecimal vpkt, BigDecimal csandpkt, BigDecimal cschwebpkt, BigDecimal sandtrieb, BigDecimal schwebtrieb) {
+       this.id = id;
+       this.slotrechte = slotrechte;
+       this.wprozpkt = wprozpkt;
+       this.wpkt = wpkt;
+       this.vpkt = vpkt;
+       this.csandpkt = csandpkt;
+       this.cschwebpkt = cschwebpkt;
+       this.sandtrieb = sandtrieb;
+       this.schwebtrieb = schwebtrieb;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="slotrechteid", column=@Column(name="SLOTRECHTEID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="lfdnr", column=@Column(name="LFDNR", nullable=false, precision=5, scale=0) ) } )
+    public SprobeId getId() {
+        return this.id;
+    }
+
+    public void setId(SprobeId id) {
+        this.id = id;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="SLOTRECHTEID", nullable=false, insertable=false, updatable=false)
+    public Slotrechte getSlotrechte() {
+        return this.slotrechte;
+    }
+
+    public void setSlotrechte(Slotrechte slotrechte) {
+        this.slotrechte = slotrechte;
+    }
+
+
+    @Column(name="WPROZPKT", nullable=false, precision=3, scale=0)
+    public short getWprozpkt() {
+        return this.wprozpkt;
+    }
+
+    public void setWprozpkt(short wprozpkt) {
+        this.wprozpkt = wprozpkt;
+    }
+
+
+    @Column(name="WPKT", nullable=false, precision=8, scale=3)
+    public BigDecimal getWpkt() {
+        return this.wpkt;
+    }
+
+    public void setWpkt(BigDecimal wpkt) {
+        this.wpkt = wpkt;
+    }
+
+
+    @Column(name="VPKT", nullable=false, precision=6, scale=4)
+    public BigDecimal getVpkt() {
+        return this.vpkt;
+    }
+
+    public void setVpkt(BigDecimal vpkt) {
+        this.vpkt = vpkt;
+    }
+
+
+    @Column(name="CSANDPKT", nullable=false, precision=8, scale=3)
+    public BigDecimal getCsandpkt() {
+        return this.csandpkt;
+    }
+
+    public void setCsandpkt(BigDecimal csandpkt) {
+        this.csandpkt = csandpkt;
+    }
+
+
+    @Column(name="CSCHWEBPKT", nullable=false, precision=8, scale=3)
+    public BigDecimal getCschwebpkt() {
+        return this.cschwebpkt;
+    }
+
+    public void setCschwebpkt(BigDecimal cschwebpkt) {
+        this.cschwebpkt = cschwebpkt;
+    }
+
+
+    @Column(name="SANDTRIEB", precision=8, scale=3)
+    public BigDecimal getSandtrieb() {
+        return this.sandtrieb;
+    }
+
+    public void setSandtrieb(BigDecimal sandtrieb) {
+        this.sandtrieb = sandtrieb;
+    }
+
+
+    @Column(name="SCHWEBTRIEB", precision=8, scale=3)
+    public BigDecimal getSchwebtrieb() {
+        return this.schwebtrieb;
+    }
+
+    public void setSchwebtrieb(BigDecimal schwebtrieb) {
+        this.schwebtrieb = schwebtrieb;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/SprobeId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,65 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * SprobeId generated by hbm2java
+ */
+@Embeddable
+public class SprobeId  implements java.io.Serializable {
+
+
+     private long slotrechteid;
+     private int lfdnr;
+
+    public SprobeId() {
+    }
+
+    public SprobeId(long slotrechteid, int lfdnr) {
+       this.slotrechteid = slotrechteid;
+       this.lfdnr = lfdnr;
+    }
+
+
+
+    @Column(name="SLOTRECHTEID", nullable=false, precision=11, scale=0)
+    public long getSlotrechteid() {
+        return this.slotrechteid;
+    }
+
+    public void setSlotrechteid(long slotrechteid) {
+        this.slotrechteid = slotrechteid;
+    }
+
+
+    @Column(name="LFDNR", nullable=false, precision=5, scale=0)
+    public int getLfdnr() {
+        return this.lfdnr;
+    }
+
+    public void setLfdnr(int lfdnr) {
+        this.lfdnr = lfdnr;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof SprobeId) ) return false;
+         SprobeId castOther = ( SprobeId ) other;
+
+         return (this.getSlotrechteid()==castOther.getSlotrechteid())
+ && (this.getLfdnr()==castOther.getLfdnr());
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getSlotrechteid();
+         result = 37 * result + this.getLfdnr();
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Ssiebung.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,351 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.Table;
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Parameter;
+
+/**
+ * Ssiebung generated by hbm2java
+ */
+@Entity
+@Table(name="SSIEBUNG"
+    ,schema="SEDDB"
+)
+public class Ssiebung  implements java.io.Serializable {
+
+
+     private long siebanalyseid;
+     private Siebanalyse siebanalyse;
+     private Gsiebsatz gsiebsatz;
+     private BigDecimal gmasse;
+     private BigDecimal rsieb01;
+     private BigDecimal rsieb02;
+     private BigDecimal rsieb03;
+     private BigDecimal rsieb04;
+     private BigDecimal rsieb05;
+     private BigDecimal rsieb06;
+     private BigDecimal rsieb07;
+     private BigDecimal rsieb08;
+     private BigDecimal rsieb09;
+     private BigDecimal rsieb10;
+     private BigDecimal rsieb11;
+     private BigDecimal rsieb12;
+     private BigDecimal rsieb13;
+     private BigDecimal rsieb14;
+     private BigDecimal rsieb15;
+     private BigDecimal rsieb16;
+     private BigDecimal rsieb17;
+     private BigDecimal rsieb18;
+     private BigDecimal rsieb19;
+     private BigDecimal rsieb20;
+     private BigDecimal rsieb21;
+     private BigDecimal rest;
+
+    public Ssiebung() {
+    }
+
+    public Ssiebung(Siebanalyse siebanalyse, Gsiebsatz gsiebsatz) {
+        this.siebanalyse = siebanalyse;
+        this.gsiebsatz = gsiebsatz;
+    }
+    public Ssiebung(Siebanalyse siebanalyse, Gsiebsatz gsiebsatz, BigDecimal gmasse, BigDecimal rsieb01, BigDecimal rsieb02, BigDecimal rsieb03, BigDecimal rsieb04, BigDecimal rsieb05, BigDecimal rsieb06, BigDecimal rsieb07, BigDecimal rsieb08, BigDecimal rsieb09, BigDecimal rsieb10, BigDecimal rsieb11, BigDecimal rsieb12, BigDecimal rsieb13, BigDecimal rsieb14, BigDecimal rsieb15, BigDecimal rsieb16, BigDecimal rsieb17, BigDecimal rsieb18, BigDecimal rsieb19, BigDecimal rsieb20, BigDecimal rsieb21, BigDecimal rest) {
+       this.siebanalyse = siebanalyse;
+       this.gsiebsatz = gsiebsatz;
+       this.gmasse = gmasse;
+       this.rsieb01 = rsieb01;
+       this.rsieb02 = rsieb02;
+       this.rsieb03 = rsieb03;
+       this.rsieb04 = rsieb04;
+       this.rsieb05 = rsieb05;
+       this.rsieb06 = rsieb06;
+       this.rsieb07 = rsieb07;
+       this.rsieb08 = rsieb08;
+       this.rsieb09 = rsieb09;
+       this.rsieb10 = rsieb10;
+       this.rsieb11 = rsieb11;
+       this.rsieb12 = rsieb12;
+       this.rsieb13 = rsieb13;
+       this.rsieb14 = rsieb14;
+       this.rsieb15 = rsieb15;
+       this.rsieb16 = rsieb16;
+       this.rsieb17 = rsieb17;
+       this.rsieb18 = rsieb18;
+       this.rsieb19 = rsieb19;
+       this.rsieb20 = rsieb20;
+       this.rsieb21 = rsieb21;
+       this.rest = rest;
+    }
+
+     @GenericGenerator(name="generator", strategy="foreign", parameters=@Parameter(name="property", value="siebanalyse"))@Id @GeneratedValue(generator="generator")
+
+
+    @Column(name="SIEBANALYSEID", unique=true, nullable=false, precision=11, scale=0)
+    public long getSiebanalyseid() {
+        return this.siebanalyseid;
+    }
+
+    public void setSiebanalyseid(long siebanalyseid) {
+        this.siebanalyseid = siebanalyseid;
+    }
+
+@OneToOne(fetch=FetchType.LAZY)@PrimaryKeyJoinColumn
+    public Siebanalyse getSiebanalyse() {
+        return this.siebanalyse;
+    }
+
+    public void setSiebanalyse(Siebanalyse siebanalyse) {
+        this.siebanalyse = siebanalyse;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="GSIEBSATZID", nullable=false)
+    public Gsiebsatz getGsiebsatz() {
+        return this.gsiebsatz;
+    }
+
+    public void setGsiebsatz(Gsiebsatz gsiebsatz) {
+        this.gsiebsatz = gsiebsatz;
+    }
+
+
+    @Column(name="GMASSE", precision=9, scale=3)
+    public BigDecimal getGmasse() {
+        return this.gmasse;
+    }
+
+    public void setGmasse(BigDecimal gmasse) {
+        this.gmasse = gmasse;
+    }
+
+
+    @Column(name="RSIEB01", precision=9, scale=3)
+    public BigDecimal getRsieb01() {
+        return this.rsieb01;
+    }
+
+    public void setRsieb01(BigDecimal rsieb01) {
+        this.rsieb01 = rsieb01;
+    }
+
+
+    @Column(name="RSIEB02", precision=9, scale=3)
+    public BigDecimal getRsieb02() {
+        return this.rsieb02;
+    }
+
+    public void setRsieb02(BigDecimal rsieb02) {
+        this.rsieb02 = rsieb02;
+    }
+
+
+    @Column(name="RSIEB03", precision=9, scale=3)
+    public BigDecimal getRsieb03() {
+        return this.rsieb03;
+    }
+
+    public void setRsieb03(BigDecimal rsieb03) {
+        this.rsieb03 = rsieb03;
+    }
+
+
+    @Column(name="RSIEB04", precision=9, scale=3)
+    public BigDecimal getRsieb04() {
+        return this.rsieb04;
+    }
+
+    public void setRsieb04(BigDecimal rsieb04) {
+        this.rsieb04 = rsieb04;
+    }
+
+
+    @Column(name="RSIEB05", precision=9, scale=3)
+    public BigDecimal getRsieb05() {
+        return this.rsieb05;
+    }
+
+    public void setRsieb05(BigDecimal rsieb05) {
+        this.rsieb05 = rsieb05;
+    }
+
+
+    @Column(name="RSIEB06", precision=9, scale=3)
+    public BigDecimal getRsieb06() {
+        return this.rsieb06;
+    }
+
+    public void setRsieb06(BigDecimal rsieb06) {
+        this.rsieb06 = rsieb06;
+    }
+
+
+    @Column(name="RSIEB07", precision=9, scale=3)
+    public BigDecimal getRsieb07() {
+        return this.rsieb07;
+    }
+
+    public void setRsieb07(BigDecimal rsieb07) {
+        this.rsieb07 = rsieb07;
+    }
+
+
+    @Column(name="RSIEB08", precision=9, scale=3)
+    public BigDecimal getRsieb08() {
+        return this.rsieb08;
+    }
+
+    public void setRsieb08(BigDecimal rsieb08) {
+        this.rsieb08 = rsieb08;
+    }
+
+
+    @Column(name="RSIEB09", precision=9, scale=3)
+    public BigDecimal getRsieb09() {
+        return this.rsieb09;
+    }
+
+    public void setRsieb09(BigDecimal rsieb09) {
+        this.rsieb09 = rsieb09;
+    }
+
+
+    @Column(name="RSIEB10", precision=9, scale=3)
+    public BigDecimal getRsieb10() {
+        return this.rsieb10;
+    }
+
+    public void setRsieb10(BigDecimal rsieb10) {
+        this.rsieb10 = rsieb10;
+    }
+
+
+    @Column(name="RSIEB11", precision=9, scale=3)
+    public BigDecimal getRsieb11() {
+        return this.rsieb11;
+    }
+
+    public void setRsieb11(BigDecimal rsieb11) {
+        this.rsieb11 = rsieb11;
+    }
+
+
+    @Column(name="RSIEB12", precision=9, scale=3)
+    public BigDecimal getRsieb12() {
+        return this.rsieb12;
+    }
+
+    public void setRsieb12(BigDecimal rsieb12) {
+        this.rsieb12 = rsieb12;
+    }
+
+
+    @Column(name="RSIEB13", precision=9, scale=3)
+    public BigDecimal getRsieb13() {
+        return this.rsieb13;
+    }
+
+    public void setRsieb13(BigDecimal rsieb13) {
+        this.rsieb13 = rsieb13;
+    }
+
+
+    @Column(name="RSIEB14", precision=9, scale=3)
+    public BigDecimal getRsieb14() {
+        return this.rsieb14;
+    }
+
+    public void setRsieb14(BigDecimal rsieb14) {
+        this.rsieb14 = rsieb14;
+    }
+
+
+    @Column(name="RSIEB15", precision=9, scale=3)
+    public BigDecimal getRsieb15() {
+        return this.rsieb15;
+    }
+
+    public void setRsieb15(BigDecimal rsieb15) {
+        this.rsieb15 = rsieb15;
+    }
+
+
+    @Column(name="RSIEB16", precision=9, scale=3)
+    public BigDecimal getRsieb16() {
+        return this.rsieb16;
+    }
+
+    public void setRsieb16(BigDecimal rsieb16) {
+        this.rsieb16 = rsieb16;
+    }
+
+
+    @Column(name="RSIEB17", precision=9, scale=3)
+    public BigDecimal getRsieb17() {
+        return this.rsieb17;
+    }
+
+    public void setRsieb17(BigDecimal rsieb17) {
+        this.rsieb17 = rsieb17;
+    }
+
+
+    @Column(name="RSIEB18", precision=9, scale=3)
+    public BigDecimal getRsieb18() {
+        return this.rsieb18;
+    }
+
+    public void setRsieb18(BigDecimal rsieb18) {
+        this.rsieb18 = rsieb18;
+    }
+
+
+    @Column(name="RSIEB19", precision=9, scale=3)
+    public BigDecimal getRsieb19() {
+        return this.rsieb19;
+    }
+
+    public void setRsieb19(BigDecimal rsieb19) {
+        this.rsieb19 = rsieb19;
+    }
+
+
+    @Column(name="RSIEB20", precision=9, scale=3)
+    public BigDecimal getRsieb20() {
+        return this.rsieb20;
+    }
+
+    public void setRsieb20(BigDecimal rsieb20) {
+        this.rsieb20 = rsieb20;
+    }
+
+
+    @Column(name="RSIEB21", precision=9, scale=3)
+    public BigDecimal getRsieb21() {
+        return this.rsieb21;
+    }
+
+    public void setRsieb21(BigDecimal rsieb21) {
+        this.rsieb21 = rsieb21;
+    }
+
+
+    @Column(name="REST", precision=9, scale=3)
+    public BigDecimal getRest() {
+        return this.rest;
+    }
+
+    public void setRest(BigDecimal rest) {
+        this.rest = rest;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Ssiebungsieb.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,88 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Ssiebungsieb generated by hbm2java
+ */
+@Entity
+@Table(name="SSIEBUNGSIEB"
+    ,schema="SEDDB"
+)
+public class Ssiebungsieb  implements java.io.Serializable {
+
+
+     private SsiebungsiebId id;
+
+    public Ssiebungsieb() {
+    }
+
+    public Ssiebungsieb(SsiebungsiebId id) {
+       this.id = id;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="siebanalyseid", column=@Column(name="SIEBANALYSEID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="gsiebsatzid", column=@Column(name="GSIEBSATZID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="gmasse", column=@Column(name="GMASSE", precision=9, scale=3) ),
+        @AttributeOverride(name="masche01", column=@Column(name="MASCHE01", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck01", column=@Column(name="RUECK01", precision=9, scale=3) ),
+        @AttributeOverride(name="masche02", column=@Column(name="MASCHE02", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck02", column=@Column(name="RUECK02", precision=9, scale=3) ),
+        @AttributeOverride(name="masche03", column=@Column(name="MASCHE03", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck03", column=@Column(name="RUECK03", precision=9, scale=3) ),
+        @AttributeOverride(name="masche04", column=@Column(name="MASCHE04", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck04", column=@Column(name="RUECK04", precision=9, scale=3) ),
+        @AttributeOverride(name="masche05", column=@Column(name="MASCHE05", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck05", column=@Column(name="RUECK05", precision=9, scale=3) ),
+        @AttributeOverride(name="masche06", column=@Column(name="MASCHE06", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck06", column=@Column(name="RUECK06", precision=9, scale=3) ),
+        @AttributeOverride(name="masche07", column=@Column(name="MASCHE07", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck07", column=@Column(name="RUECK07", precision=9, scale=3) ),
+        @AttributeOverride(name="masche08", column=@Column(name="MASCHE08", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck08", column=@Column(name="RUECK08", precision=9, scale=3) ),
+        @AttributeOverride(name="masche09", column=@Column(name="MASCHE09", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck09", column=@Column(name="RUECK09", precision=9, scale=3) ),
+        @AttributeOverride(name="masche10", column=@Column(name="MASCHE10", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck10", column=@Column(name="RUECK10", precision=9, scale=3) ),
+        @AttributeOverride(name="masche11", column=@Column(name="MASCHE11", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck11", column=@Column(name="RUECK11", precision=9, scale=3) ),
+        @AttributeOverride(name="masche12", column=@Column(name="MASCHE12", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck12", column=@Column(name="RUECK12", precision=9, scale=3) ),
+        @AttributeOverride(name="masche13", column=@Column(name="MASCHE13", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck13", column=@Column(name="RUECK13", precision=9, scale=3) ),
+        @AttributeOverride(name="masche14", column=@Column(name="MASCHE14", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck14", column=@Column(name="RUECK14", precision=9, scale=3) ),
+        @AttributeOverride(name="masche15", column=@Column(name="MASCHE15", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck15", column=@Column(name="RUECK15", precision=9, scale=3) ),
+        @AttributeOverride(name="masche16", column=@Column(name="MASCHE16", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck16", column=@Column(name="RUECK16", precision=9, scale=3) ),
+        @AttributeOverride(name="masche17", column=@Column(name="MASCHE17", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck17", column=@Column(name="RUECK17", precision=9, scale=3) ),
+        @AttributeOverride(name="masche18", column=@Column(name="MASCHE18", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck18", column=@Column(name="RUECK18", precision=9, scale=3) ),
+        @AttributeOverride(name="masche19", column=@Column(name="MASCHE19", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck19", column=@Column(name="RUECK19", precision=9, scale=3) ),
+        @AttributeOverride(name="masche20", column=@Column(name="MASCHE20", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck20", column=@Column(name="RUECK20", precision=9, scale=3) ),
+        @AttributeOverride(name="masche21", column=@Column(name="MASCHE21", precision=7, scale=4) ),
+        @AttributeOverride(name="rueck21", column=@Column(name="RUECK21", precision=9, scale=3) ),
+        @AttributeOverride(name="rest", column=@Column(name="REST", precision=9, scale=3) ) } )
+    public SsiebungsiebId getId() {
+        return this.id;
+    }
+
+    public void setId(SsiebungsiebId id) {
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/SsiebungsiebId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,686 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * SsiebungsiebId generated by hbm2java
+ */
+@Embeddable
+public class SsiebungsiebId  implements java.io.Serializable {
+
+
+     private long siebanalyseid;
+     private long gsiebsatzid;
+     private BigDecimal gmasse;
+     private BigDecimal masche01;
+     private BigDecimal rueck01;
+     private BigDecimal masche02;
+     private BigDecimal rueck02;
+     private BigDecimal masche03;
+     private BigDecimal rueck03;
+     private BigDecimal masche04;
+     private BigDecimal rueck04;
+     private BigDecimal masche05;
+     private BigDecimal rueck05;
+     private BigDecimal masche06;
+     private BigDecimal rueck06;
+     private BigDecimal masche07;
+     private BigDecimal rueck07;
+     private BigDecimal masche08;
+     private BigDecimal rueck08;
+     private BigDecimal masche09;
+     private BigDecimal rueck09;
+     private BigDecimal masche10;
+     private BigDecimal rueck10;
+     private BigDecimal masche11;
+     private BigDecimal rueck11;
+     private BigDecimal masche12;
+     private BigDecimal rueck12;
+     private BigDecimal masche13;
+     private BigDecimal rueck13;
+     private BigDecimal masche14;
+     private BigDecimal rueck14;
+     private BigDecimal masche15;
+     private BigDecimal rueck15;
+     private BigDecimal masche16;
+     private BigDecimal rueck16;
+     private BigDecimal masche17;
+     private BigDecimal rueck17;
+     private BigDecimal masche18;
+     private BigDecimal rueck18;
+     private BigDecimal masche19;
+     private BigDecimal rueck19;
+     private BigDecimal masche20;
+     private BigDecimal rueck20;
+     private BigDecimal masche21;
+     private BigDecimal rueck21;
+     private BigDecimal rest;
+
+    public SsiebungsiebId() {
+    }
+
+    public SsiebungsiebId(long siebanalyseid, long gsiebsatzid) {
+        this.siebanalyseid = siebanalyseid;
+        this.gsiebsatzid = gsiebsatzid;
+    }
+    public SsiebungsiebId(long siebanalyseid, long gsiebsatzid, BigDecimal gmasse, BigDecimal masche01, BigDecimal rueck01, BigDecimal masche02, BigDecimal rueck02, BigDecimal masche03, BigDecimal rueck03, BigDecimal masche04, BigDecimal rueck04, BigDecimal masche05, BigDecimal rueck05, BigDecimal masche06, BigDecimal rueck06, BigDecimal masche07, BigDecimal rueck07, BigDecimal masche08, BigDecimal rueck08, BigDecimal masche09, BigDecimal rueck09, BigDecimal masche10, BigDecimal rueck10, BigDecimal masche11, BigDecimal rueck11, BigDecimal masche12, BigDecimal rueck12, BigDecimal masche13, BigDecimal rueck13, BigDecimal masche14, BigDecimal rueck14, BigDecimal masche15, BigDecimal rueck15, BigDecimal masche16, BigDecimal rueck16, BigDecimal masche17, BigDecimal rueck17, BigDecimal masche18, BigDecimal rueck18, BigDecimal masche19, BigDecimal rueck19, BigDecimal masche20, BigDecimal rueck20, BigDecimal masche21, BigDecimal rueck21, BigDecimal rest) {
+       this.siebanalyseid = siebanalyseid;
+       this.gsiebsatzid = gsiebsatzid;
+       this.gmasse = gmasse;
+       this.masche01 = masche01;
+       this.rueck01 = rueck01;
+       this.masche02 = masche02;
+       this.rueck02 = rueck02;
+       this.masche03 = masche03;
+       this.rueck03 = rueck03;
+       this.masche04 = masche04;
+       this.rueck04 = rueck04;
+       this.masche05 = masche05;
+       this.rueck05 = rueck05;
+       this.masche06 = masche06;
+       this.rueck06 = rueck06;
+       this.masche07 = masche07;
+       this.rueck07 = rueck07;
+       this.masche08 = masche08;
+       this.rueck08 = rueck08;
+       this.masche09 = masche09;
+       this.rueck09 = rueck09;
+       this.masche10 = masche10;
+       this.rueck10 = rueck10;
+       this.masche11 = masche11;
+       this.rueck11 = rueck11;
+       this.masche12 = masche12;
+       this.rueck12 = rueck12;
+       this.masche13 = masche13;
+       this.rueck13 = rueck13;
+       this.masche14 = masche14;
+       this.rueck14 = rueck14;
+       this.masche15 = masche15;
+       this.rueck15 = rueck15;
+       this.masche16 = masche16;
+       this.rueck16 = rueck16;
+       this.masche17 = masche17;
+       this.rueck17 = rueck17;
+       this.masche18 = masche18;
+       this.rueck18 = rueck18;
+       this.masche19 = masche19;
+       this.rueck19 = rueck19;
+       this.masche20 = masche20;
+       this.rueck20 = rueck20;
+       this.masche21 = masche21;
+       this.rueck21 = rueck21;
+       this.rest = rest;
+    }
+
+
+
+    @Column(name="SIEBANALYSEID", nullable=false, precision=11, scale=0)
+    public long getSiebanalyseid() {
+        return this.siebanalyseid;
+    }
+
+    public void setSiebanalyseid(long siebanalyseid) {
+        this.siebanalyseid = siebanalyseid;
+    }
+
+
+    @Column(name="GSIEBSATZID", nullable=false, precision=11, scale=0)
+    public long getGsiebsatzid() {
+        return this.gsiebsatzid;
+    }
+
+    public void setGsiebsatzid(long gsiebsatzid) {
+        this.gsiebsatzid = gsiebsatzid;
+    }
+
+
+    @Column(name="GMASSE", precision=9, scale=3)
+    public BigDecimal getGmasse() {
+        return this.gmasse;
+    }
+
+    public void setGmasse(BigDecimal gmasse) {
+        this.gmasse = gmasse;
+    }
+
+
+    @Column(name="MASCHE01", precision=7, scale=4)
+    public BigDecimal getMasche01() {
+        return this.masche01;
+    }
+
+    public void setMasche01(BigDecimal masche01) {
+        this.masche01 = masche01;
+    }
+
+
+    @Column(name="RUECK01", precision=9, scale=3)
+    public BigDecimal getRueck01() {
+        return this.rueck01;
+    }
+
+    public void setRueck01(BigDecimal rueck01) {
+        this.rueck01 = rueck01;
+    }
+
+
+    @Column(name="MASCHE02", precision=7, scale=4)
+    public BigDecimal getMasche02() {
+        return this.masche02;
+    }
+
+    public void setMasche02(BigDecimal masche02) {
+        this.masche02 = masche02;
+    }
+
+
+    @Column(name="RUECK02", precision=9, scale=3)
+    public BigDecimal getRueck02() {
+        return this.rueck02;
+    }
+
+    public void setRueck02(BigDecimal rueck02) {
+        this.rueck02 = rueck02;
+    }
+
+
+    @Column(name="MASCHE03", precision=7, scale=4)
+    public BigDecimal getMasche03() {
+        return this.masche03;
+    }
+
+    public void setMasche03(BigDecimal masche03) {
+        this.masche03 = masche03;
+    }
+
+
+    @Column(name="RUECK03", precision=9, scale=3)
+    public BigDecimal getRueck03() {
+        return this.rueck03;
+    }
+
+    public void setRueck03(BigDecimal rueck03) {
+        this.rueck03 = rueck03;
+    }
+
+
+    @Column(name="MASCHE04", precision=7, scale=4)
+    public BigDecimal getMasche04() {
+        return this.masche04;
+    }
+
+    public void setMasche04(BigDecimal masche04) {
+        this.masche04 = masche04;
+    }
+
+
+    @Column(name="RUECK04", precision=9, scale=3)
+    public BigDecimal getRueck04() {
+        return this.rueck04;
+    }
+
+    public void setRueck04(BigDecimal rueck04) {
+        this.rueck04 = rueck04;
+    }
+
+
+    @Column(name="MASCHE05", precision=7, scale=4)
+    public BigDecimal getMasche05() {
+        return this.masche05;
+    }
+
+    public void setMasche05(BigDecimal masche05) {
+        this.masche05 = masche05;
+    }
+
+
+    @Column(name="RUECK05", precision=9, scale=3)
+    public BigDecimal getRueck05() {
+        return this.rueck05;
+    }
+
+    public void setRueck05(BigDecimal rueck05) {
+        this.rueck05 = rueck05;
+    }
+
+
+    @Column(name="MASCHE06", precision=7, scale=4)
+    public BigDecimal getMasche06() {
+        return this.masche06;
+    }
+
+    public void setMasche06(BigDecimal masche06) {
+        this.masche06 = masche06;
+    }
+
+
+    @Column(name="RUECK06", precision=9, scale=3)
+    public BigDecimal getRueck06() {
+        return this.rueck06;
+    }
+
+    public void setRueck06(BigDecimal rueck06) {
+        this.rueck06 = rueck06;
+    }
+
+
+    @Column(name="MASCHE07", precision=7, scale=4)
+    public BigDecimal getMasche07() {
+        return this.masche07;
+    }
+
+    public void setMasche07(BigDecimal masche07) {
+        this.masche07 = masche07;
+    }
+
+
+    @Column(name="RUECK07", precision=9, scale=3)
+    public BigDecimal getRueck07() {
+        return this.rueck07;
+    }
+
+    public void setRueck07(BigDecimal rueck07) {
+        this.rueck07 = rueck07;
+    }
+
+
+    @Column(name="MASCHE08", precision=7, scale=4)
+    public BigDecimal getMasche08() {
+        return this.masche08;
+    }
+
+    public void setMasche08(BigDecimal masche08) {
+        this.masche08 = masche08;
+    }
+
+
+    @Column(name="RUECK08", precision=9, scale=3)
+    public BigDecimal getRueck08() {
+        return this.rueck08;
+    }
+
+    public void setRueck08(BigDecimal rueck08) {
+        this.rueck08 = rueck08;
+    }
+
+
+    @Column(name="MASCHE09", precision=7, scale=4)
+    public BigDecimal getMasche09() {
+        return this.masche09;
+    }
+
+    public void setMasche09(BigDecimal masche09) {
+        this.masche09 = masche09;
+    }
+
+
+    @Column(name="RUECK09", precision=9, scale=3)
+    public BigDecimal getRueck09() {
+        return this.rueck09;
+    }
+
+    public void setRueck09(BigDecimal rueck09) {
+        this.rueck09 = rueck09;
+    }
+
+
+    @Column(name="MASCHE10", precision=7, scale=4)
+    public BigDecimal getMasche10() {
+        return this.masche10;
+    }
+
+    public void setMasche10(BigDecimal masche10) {
+        this.masche10 = masche10;
+    }
+
+
+    @Column(name="RUECK10", precision=9, scale=3)
+    public BigDecimal getRueck10() {
+        return this.rueck10;
+    }
+
+    public void setRueck10(BigDecimal rueck10) {
+        this.rueck10 = rueck10;
+    }
+
+
+    @Column(name="MASCHE11", precision=7, scale=4)
+    public BigDecimal getMasche11() {
+        return this.masche11;
+    }
+
+    public void setMasche11(BigDecimal masche11) {
+        this.masche11 = masche11;
+    }
+
+
+    @Column(name="RUECK11", precision=9, scale=3)
+    public BigDecimal getRueck11() {
+        return this.rueck11;
+    }
+
+    public void setRueck11(BigDecimal rueck11) {
+        this.rueck11 = rueck11;
+    }
+
+
+    @Column(name="MASCHE12", precision=7, scale=4)
+    public BigDecimal getMasche12() {
+        return this.masche12;
+    }
+
+    public void setMasche12(BigDecimal masche12) {
+        this.masche12 = masche12;
+    }
+
+
+    @Column(name="RUECK12", precision=9, scale=3)
+    public BigDecimal getRueck12() {
+        return this.rueck12;
+    }
+
+    public void setRueck12(BigDecimal rueck12) {
+        this.rueck12 = rueck12;
+    }
+
+
+    @Column(name="MASCHE13", precision=7, scale=4)
+    public BigDecimal getMasche13() {
+        return this.masche13;
+    }
+
+    public void setMasche13(BigDecimal masche13) {
+        this.masche13 = masche13;
+    }
+
+
+    @Column(name="RUECK13", precision=9, scale=3)
+    public BigDecimal getRueck13() {
+        return this.rueck13;
+    }
+
+    public void setRueck13(BigDecimal rueck13) {
+        this.rueck13 = rueck13;
+    }
+
+
+    @Column(name="MASCHE14", precision=7, scale=4)
+    public BigDecimal getMasche14() {
+        return this.masche14;
+    }
+
+    public void setMasche14(BigDecimal masche14) {
+        this.masche14 = masche14;
+    }
+
+
+    @Column(name="RUECK14", precision=9, scale=3)
+    public BigDecimal getRueck14() {
+        return this.rueck14;
+    }
+
+    public void setRueck14(BigDecimal rueck14) {
+        this.rueck14 = rueck14;
+    }
+
+
+    @Column(name="MASCHE15", precision=7, scale=4)
+    public BigDecimal getMasche15() {
+        return this.masche15;
+    }
+
+    public void setMasche15(BigDecimal masche15) {
+        this.masche15 = masche15;
+    }
+
+
+    @Column(name="RUECK15", precision=9, scale=3)
+    public BigDecimal getRueck15() {
+        return this.rueck15;
+    }
+
+    public void setRueck15(BigDecimal rueck15) {
+        this.rueck15 = rueck15;
+    }
+
+
+    @Column(name="MASCHE16", precision=7, scale=4)
+    public BigDecimal getMasche16() {
+        return this.masche16;
+    }
+
+    public void setMasche16(BigDecimal masche16) {
+        this.masche16 = masche16;
+    }
+
+
+    @Column(name="RUECK16", precision=9, scale=3)
+    public BigDecimal getRueck16() {
+        return this.rueck16;
+    }
+
+    public void setRueck16(BigDecimal rueck16) {
+        this.rueck16 = rueck16;
+    }
+
+
+    @Column(name="MASCHE17", precision=7, scale=4)
+    public BigDecimal getMasche17() {
+        return this.masche17;
+    }
+
+    public void setMasche17(BigDecimal masche17) {
+        this.masche17 = masche17;
+    }
+
+
+    @Column(name="RUECK17", precision=9, scale=3)
+    public BigDecimal getRueck17() {
+        return this.rueck17;
+    }
+
+    public void setRueck17(BigDecimal rueck17) {
+        this.rueck17 = rueck17;
+    }
+
+
+    @Column(name="MASCHE18", precision=7, scale=4)
+    public BigDecimal getMasche18() {
+        return this.masche18;
+    }
+
+    public void setMasche18(BigDecimal masche18) {
+        this.masche18 = masche18;
+    }
+
+
+    @Column(name="RUECK18", precision=9, scale=3)
+    public BigDecimal getRueck18() {
+        return this.rueck18;
+    }
+
+    public void setRueck18(BigDecimal rueck18) {
+        this.rueck18 = rueck18;
+    }
+
+
+    @Column(name="MASCHE19", precision=7, scale=4)
+    public BigDecimal getMasche19() {
+        return this.masche19;
+    }
+
+    public void setMasche19(BigDecimal masche19) {
+        this.masche19 = masche19;
+    }
+
+
+    @Column(name="RUECK19", precision=9, scale=3)
+    public BigDecimal getRueck19() {
+        return this.rueck19;
+    }
+
+    public void setRueck19(BigDecimal rueck19) {
+        this.rueck19 = rueck19;
+    }
+
+
+    @Column(name="MASCHE20", precision=7, scale=4)
+    public BigDecimal getMasche20() {
+        return this.masche20;
+    }
+
+    public void setMasche20(BigDecimal masche20) {
+        this.masche20 = masche20;
+    }
+
+
+    @Column(name="RUECK20", precision=9, scale=3)
+    public BigDecimal getRueck20() {
+        return this.rueck20;
+    }
+
+    public void setRueck20(BigDecimal rueck20) {
+        this.rueck20 = rueck20;
+    }
+
+
+    @Column(name="MASCHE21", precision=7, scale=4)
+    public BigDecimal getMasche21() {
+        return this.masche21;
+    }
+
+    public void setMasche21(BigDecimal masche21) {
+        this.masche21 = masche21;
+    }
+
+
+    @Column(name="RUECK21", precision=9, scale=3)
+    public BigDecimal getRueck21() {
+        return this.rueck21;
+    }
+
+    public void setRueck21(BigDecimal rueck21) {
+        this.rueck21 = rueck21;
+    }
+
+
+    @Column(name="REST", precision=9, scale=3)
+    public BigDecimal getRest() {
+        return this.rest;
+    }
+
+    public void setRest(BigDecimal rest) {
+        this.rest = rest;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+		 if ( (other == null ) ) return false;
+		 if ( !(other instanceof SsiebungsiebId) ) return false;
+		 SsiebungsiebId castOther = ( SsiebungsiebId ) other;
+
+		 return (this.getSiebanalyseid()==castOther.getSiebanalyseid())
+ && (this.getGsiebsatzid()==castOther.getGsiebsatzid())
+ && ( (this.getGmasse()==castOther.getGmasse()) || ( this.getGmasse()!=null && castOther.getGmasse()!=null && this.getGmasse().equals(castOther.getGmasse()) ) )
+ && ( (this.getMasche01()==castOther.getMasche01()) || ( this.getMasche01()!=null && castOther.getMasche01()!=null && this.getMasche01().equals(castOther.getMasche01()) ) )
+ && ( (this.getRueck01()==castOther.getRueck01()) || ( this.getRueck01()!=null && castOther.getRueck01()!=null && this.getRueck01().equals(castOther.getRueck01()) ) )
+ && ( (this.getMasche02()==castOther.getMasche02()) || ( this.getMasche02()!=null && castOther.getMasche02()!=null && this.getMasche02().equals(castOther.getMasche02()) ) )
+ && ( (this.getRueck02()==castOther.getRueck02()) || ( this.getRueck02()!=null && castOther.getRueck02()!=null && this.getRueck02().equals(castOther.getRueck02()) ) )
+ && ( (this.getMasche03()==castOther.getMasche03()) || ( this.getMasche03()!=null && castOther.getMasche03()!=null && this.getMasche03().equals(castOther.getMasche03()) ) )
+ && ( (this.getRueck03()==castOther.getRueck03()) || ( this.getRueck03()!=null && castOther.getRueck03()!=null && this.getRueck03().equals(castOther.getRueck03()) ) )
+ && ( (this.getMasche04()==castOther.getMasche04()) || ( this.getMasche04()!=null && castOther.getMasche04()!=null && this.getMasche04().equals(castOther.getMasche04()) ) )
+ && ( (this.getRueck04()==castOther.getRueck04()) || ( this.getRueck04()!=null && castOther.getRueck04()!=null && this.getRueck04().equals(castOther.getRueck04()) ) )
+ && ( (this.getMasche05()==castOther.getMasche05()) || ( this.getMasche05()!=null && castOther.getMasche05()!=null && this.getMasche05().equals(castOther.getMasche05()) ) )
+ && ( (this.getRueck05()==castOther.getRueck05()) || ( this.getRueck05()!=null && castOther.getRueck05()!=null && this.getRueck05().equals(castOther.getRueck05()) ) )
+ && ( (this.getMasche06()==castOther.getMasche06()) || ( this.getMasche06()!=null && castOther.getMasche06()!=null && this.getMasche06().equals(castOther.getMasche06()) ) )
+ && ( (this.getRueck06()==castOther.getRueck06()) || ( this.getRueck06()!=null && castOther.getRueck06()!=null && this.getRueck06().equals(castOther.getRueck06()) ) )
+ && ( (this.getMasche07()==castOther.getMasche07()) || ( this.getMasche07()!=null && castOther.getMasche07()!=null && this.getMasche07().equals(castOther.getMasche07()) ) )
+ && ( (this.getRueck07()==castOther.getRueck07()) || ( this.getRueck07()!=null && castOther.getRueck07()!=null && this.getRueck07().equals(castOther.getRueck07()) ) )
+ && ( (this.getMasche08()==castOther.getMasche08()) || ( this.getMasche08()!=null && castOther.getMasche08()!=null && this.getMasche08().equals(castOther.getMasche08()) ) )
+ && ( (this.getRueck08()==castOther.getRueck08()) || ( this.getRueck08()!=null && castOther.getRueck08()!=null && this.getRueck08().equals(castOther.getRueck08()) ) )
+ && ( (this.getMasche09()==castOther.getMasche09()) || ( this.getMasche09()!=null && castOther.getMasche09()!=null && this.getMasche09().equals(castOther.getMasche09()) ) )
+ && ( (this.getRueck09()==castOther.getRueck09()) || ( this.getRueck09()!=null && castOther.getRueck09()!=null && this.getRueck09().equals(castOther.getRueck09()) ) )
+ && ( (this.getMasche10()==castOther.getMasche10()) || ( this.getMasche10()!=null && castOther.getMasche10()!=null && this.getMasche10().equals(castOther.getMasche10()) ) )
+ && ( (this.getRueck10()==castOther.getRueck10()) || ( this.getRueck10()!=null && castOther.getRueck10()!=null && this.getRueck10().equals(castOther.getRueck10()) ) )
+ && ( (this.getMasche11()==castOther.getMasche11()) || ( this.getMasche11()!=null && castOther.getMasche11()!=null && this.getMasche11().equals(castOther.getMasche11()) ) )
+ && ( (this.getRueck11()==castOther.getRueck11()) || ( this.getRueck11()!=null && castOther.getRueck11()!=null && this.getRueck11().equals(castOther.getRueck11()) ) )
+ && ( (this.getMasche12()==castOther.getMasche12()) || ( this.getMasche12()!=null && castOther.getMasche12()!=null && this.getMasche12().equals(castOther.getMasche12()) ) )
+ && ( (this.getRueck12()==castOther.getRueck12()) || ( this.getRueck12()!=null && castOther.getRueck12()!=null && this.getRueck12().equals(castOther.getRueck12()) ) )
+ && ( (this.getMasche13()==castOther.getMasche13()) || ( this.getMasche13()!=null && castOther.getMasche13()!=null && this.getMasche13().equals(castOther.getMasche13()) ) )
+ && ( (this.getRueck13()==castOther.getRueck13()) || ( this.getRueck13()!=null && castOther.getRueck13()!=null && this.getRueck13().equals(castOther.getRueck13()) ) )
+ && ( (this.getMasche14()==castOther.getMasche14()) || ( this.getMasche14()!=null && castOther.getMasche14()!=null && this.getMasche14().equals(castOther.getMasche14()) ) )
+ && ( (this.getRueck14()==castOther.getRueck14()) || ( this.getRueck14()!=null && castOther.getRueck14()!=null && this.getRueck14().equals(castOther.getRueck14()) ) )
+ && ( (this.getMasche15()==castOther.getMasche15()) || ( this.getMasche15()!=null && castOther.getMasche15()!=null && this.getMasche15().equals(castOther.getMasche15()) ) )
+ && ( (this.getRueck15()==castOther.getRueck15()) || ( this.getRueck15()!=null && castOther.getRueck15()!=null && this.getRueck15().equals(castOther.getRueck15()) ) )
+ && ( (this.getMasche16()==castOther.getMasche16()) || ( this.getMasche16()!=null && castOther.getMasche16()!=null && this.getMasche16().equals(castOther.getMasche16()) ) )
+ && ( (this.getRueck16()==castOther.getRueck16()) || ( this.getRueck16()!=null && castOther.getRueck16()!=null && this.getRueck16().equals(castOther.getRueck16()) ) )
+ && ( (this.getMasche17()==castOther.getMasche17()) || ( this.getMasche17()!=null && castOther.getMasche17()!=null && this.getMasche17().equals(castOther.getMasche17()) ) )
+ && ( (this.getRueck17()==castOther.getRueck17()) || ( this.getRueck17()!=null && castOther.getRueck17()!=null && this.getRueck17().equals(castOther.getRueck17()) ) )
+ && ( (this.getMasche18()==castOther.getMasche18()) || ( this.getMasche18()!=null && castOther.getMasche18()!=null && this.getMasche18().equals(castOther.getMasche18()) ) )
+ && ( (this.getRueck18()==castOther.getRueck18()) || ( this.getRueck18()!=null && castOther.getRueck18()!=null && this.getRueck18().equals(castOther.getRueck18()) ) )
+ && ( (this.getMasche19()==castOther.getMasche19()) || ( this.getMasche19()!=null && castOther.getMasche19()!=null && this.getMasche19().equals(castOther.getMasche19()) ) )
+ && ( (this.getRueck19()==castOther.getRueck19()) || ( this.getRueck19()!=null && castOther.getRueck19()!=null && this.getRueck19().equals(castOther.getRueck19()) ) )
+ && ( (this.getMasche20()==castOther.getMasche20()) || ( this.getMasche20()!=null && castOther.getMasche20()!=null && this.getMasche20().equals(castOther.getMasche20()) ) )
+ && ( (this.getRueck20()==castOther.getRueck20()) || ( this.getRueck20()!=null && castOther.getRueck20()!=null && this.getRueck20().equals(castOther.getRueck20()) ) )
+ && ( (this.getMasche21()==castOther.getMasche21()) || ( this.getMasche21()!=null && castOther.getMasche21()!=null && this.getMasche21().equals(castOther.getMasche21()) ) )
+ && ( (this.getRueck21()==castOther.getRueck21()) || ( this.getRueck21()!=null && castOther.getRueck21()!=null && this.getRueck21().equals(castOther.getRueck21()) ) )
+ && ( (this.getRest()==castOther.getRest()) || ( this.getRest()!=null && castOther.getRest()!=null && this.getRest().equals(castOther.getRest()) ) );
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getSiebanalyseid();
+         result = 37 * result + (int) this.getGsiebsatzid();
+         result = 37 * result + ( getGmasse() == null ? 0 : this.getGmasse().hashCode() );
+         result = 37 * result + ( getMasche01() == null ? 0 : this.getMasche01().hashCode() );
+         result = 37 * result + ( getRueck01() == null ? 0 : this.getRueck01().hashCode() );
+         result = 37 * result + ( getMasche02() == null ? 0 : this.getMasche02().hashCode() );
+         result = 37 * result + ( getRueck02() == null ? 0 : this.getRueck02().hashCode() );
+         result = 37 * result + ( getMasche03() == null ? 0 : this.getMasche03().hashCode() );
+         result = 37 * result + ( getRueck03() == null ? 0 : this.getRueck03().hashCode() );
+         result = 37 * result + ( getMasche04() == null ? 0 : this.getMasche04().hashCode() );
+         result = 37 * result + ( getRueck04() == null ? 0 : this.getRueck04().hashCode() );
+         result = 37 * result + ( getMasche05() == null ? 0 : this.getMasche05().hashCode() );
+         result = 37 * result + ( getRueck05() == null ? 0 : this.getRueck05().hashCode() );
+         result = 37 * result + ( getMasche06() == null ? 0 : this.getMasche06().hashCode() );
+         result = 37 * result + ( getRueck06() == null ? 0 : this.getRueck06().hashCode() );
+         result = 37 * result + ( getMasche07() == null ? 0 : this.getMasche07().hashCode() );
+         result = 37 * result + ( getRueck07() == null ? 0 : this.getRueck07().hashCode() );
+         result = 37 * result + ( getMasche08() == null ? 0 : this.getMasche08().hashCode() );
+         result = 37 * result + ( getRueck08() == null ? 0 : this.getRueck08().hashCode() );
+         result = 37 * result + ( getMasche09() == null ? 0 : this.getMasche09().hashCode() );
+         result = 37 * result + ( getRueck09() == null ? 0 : this.getRueck09().hashCode() );
+         result = 37 * result + ( getMasche10() == null ? 0 : this.getMasche10().hashCode() );
+         result = 37 * result + ( getRueck10() == null ? 0 : this.getRueck10().hashCode() );
+         result = 37 * result + ( getMasche11() == null ? 0 : this.getMasche11().hashCode() );
+         result = 37 * result + ( getRueck11() == null ? 0 : this.getRueck11().hashCode() );
+         result = 37 * result + ( getMasche12() == null ? 0 : this.getMasche12().hashCode() );
+         result = 37 * result + ( getRueck12() == null ? 0 : this.getRueck12().hashCode() );
+         result = 37 * result + ( getMasche13() == null ? 0 : this.getMasche13().hashCode() );
+         result = 37 * result + ( getRueck13() == null ? 0 : this.getRueck13().hashCode() );
+         result = 37 * result + ( getMasche14() == null ? 0 : this.getMasche14().hashCode() );
+         result = 37 * result + ( getRueck14() == null ? 0 : this.getRueck14().hashCode() );
+         result = 37 * result + ( getMasche15() == null ? 0 : this.getMasche15().hashCode() );
+         result = 37 * result + ( getRueck15() == null ? 0 : this.getRueck15().hashCode() );
+         result = 37 * result + ( getMasche16() == null ? 0 : this.getMasche16().hashCode() );
+         result = 37 * result + ( getRueck16() == null ? 0 : this.getRueck16().hashCode() );
+         result = 37 * result + ( getMasche17() == null ? 0 : this.getMasche17().hashCode() );
+         result = 37 * result + ( getRueck17() == null ? 0 : this.getRueck17().hashCode() );
+         result = 37 * result + ( getMasche18() == null ? 0 : this.getMasche18().hashCode() );
+         result = 37 * result + ( getRueck18() == null ? 0 : this.getRueck18().hashCode() );
+         result = 37 * result + ( getMasche19() == null ? 0 : this.getMasche19().hashCode() );
+         result = 37 * result + ( getRueck19() == null ? 0 : this.getRueck19().hashCode() );
+         result = 37 * result + ( getMasche20() == null ? 0 : this.getMasche20().hashCode() );
+         result = 37 * result + ( getRueck20() == null ? 0 : this.getRueck20().hashCode() );
+         result = 37 * result + ( getMasche21() == null ? 0 : this.getMasche21().hashCode() );
+         result = 37 * result + ( getRueck21() == null ? 0 : this.getRueck21().hashCode() );
+         result = 37 * result + ( getRest() == null ? 0 : this.getRest().hashCode() );
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Station.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,305 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * Station generated by hbm2java
+ */
+@Entity
+@Table(name="STATION"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames={"GEWAESSERID", "NAME"})
+)
+public class Station  implements java.io.Serializable {
+
+
+     private long stationid;
+     private Bezugspegel bezugspegel;
+     private Gewaesser gewaesser;
+     private BigDecimal km;
+     private String name;
+     private boolean uferistlinks;
+     private BigDecimal teilVon;
+     private BigDecimal teilBis;
+     private BigDecimal abstHmst;
+     private BigDecimal LHochwert;
+     private BigDecimal LRechwert;
+     private BigDecimal LNn;
+     private BigDecimal RHochwert;
+     private BigDecimal RRechwert;
+     private BigDecimal RNn;
+     private String bemerkung;
+     private Long oldmstid;
+     private boolean istfeststoff;
+     private Set<Sohltest> sohltests = new HashSet<Sohltest>(0);
+     private Set<Hpeilung> hpeilungs = new HashSet<Hpeilung>(0);
+     private Set<Mpeilung> mpeilungs = new HashSet<Mpeilung>(0);
+     private Set<Messung> messungs = new HashSet<Messung>(0);
+
+    public Station() {
+    }
+
+    public Station(long stationid, Gewaesser gewaesser, BigDecimal km, String name, boolean uferistlinks, boolean istfeststoff) {
+        this.stationid = stationid;
+        this.gewaesser = gewaesser;
+        this.km = km;
+        this.name = name;
+        this.uferistlinks = uferistlinks;
+        this.istfeststoff = istfeststoff;
+    }
+    public Station(long stationid, Bezugspegel bezugspegel, Gewaesser gewaesser, BigDecimal km, String name, boolean uferistlinks, BigDecimal teilVon, BigDecimal teilBis, BigDecimal abstHmst, BigDecimal LHochwert, BigDecimal LRechwert, BigDecimal LNn, BigDecimal RHochwert, BigDecimal RRechwert, BigDecimal RNn, String bemerkung, Long oldmstid, boolean istfeststoff, Set<Sohltest> sohltests, Set<Hpeilung> hpeilungs, Set<Mpeilung> mpeilungs, Set<Messung> messungs) {
+       this.stationid = stationid;
+       this.bezugspegel = bezugspegel;
+       this.gewaesser = gewaesser;
+       this.km = km;
+       this.name = name;
+       this.uferistlinks = uferistlinks;
+       this.teilVon = teilVon;
+       this.teilBis = teilBis;
+       this.abstHmst = abstHmst;
+       this.LHochwert = LHochwert;
+       this.LRechwert = LRechwert;
+       this.LNn = LNn;
+       this.RHochwert = RHochwert;
+       this.RRechwert = RRechwert;
+       this.RNn = RNn;
+       this.bemerkung = bemerkung;
+       this.oldmstid = oldmstid;
+       this.istfeststoff = istfeststoff;
+       this.sohltests = sohltests;
+       this.hpeilungs = hpeilungs;
+       this.mpeilungs = mpeilungs;
+       this.messungs = messungs;
+    }
+
+     @Id
+
+
+    @Column(name="STATIONID", unique=true, nullable=false, precision=11, scale=0)
+    public long getStationid() {
+        return this.stationid;
+    }
+
+    public void setStationid(long stationid) {
+        this.stationid = stationid;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="BEZUGSPEGELID")
+    public Bezugspegel getBezugspegel() {
+        return this.bezugspegel;
+    }
+
+    public void setBezugspegel(Bezugspegel bezugspegel) {
+        this.bezugspegel = bezugspegel;
+    }
+
+@ManyToOne(fetch=FetchType.LAZY)
+    @JoinColumn(name="GEWAESSERID", nullable=false)
+    public Gewaesser getGewaesser() {
+        return this.gewaesser;
+    }
+
+    public void setGewaesser(Gewaesser gewaesser) {
+        this.gewaesser = gewaesser;
+    }
+
+
+    @Column(name="KM", nullable=false, precision=8, scale=3)
+    public BigDecimal getKm() {
+        return this.km;
+    }
+
+    public void setKm(BigDecimal km) {
+        this.km = km;
+    }
+
+
+    @Column(name="NAME", nullable=false, length=50)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="UFERISTLINKS", nullable=false, precision=1, scale=0)
+    public boolean isUferistlinks() {
+        return this.uferistlinks;
+    }
+
+    public void setUferistlinks(boolean uferistlinks) {
+        this.uferistlinks = uferistlinks;
+    }
+
+
+    @Column(name="TEIL_VON", precision=8, scale=3)
+    public BigDecimal getTeilVon() {
+        return this.teilVon;
+    }
+
+    public void setTeilVon(BigDecimal teilVon) {
+        this.teilVon = teilVon;
+    }
+
+
+    @Column(name="TEIL_BIS", precision=8, scale=3)
+    public BigDecimal getTeilBis() {
+        return this.teilBis;
+    }
+
+    public void setTeilBis(BigDecimal teilBis) {
+        this.teilBis = teilBis;
+    }
+
+
+    @Column(name="ABST_HMST", precision=8, scale=3)
+    public BigDecimal getAbstHmst() {
+        return this.abstHmst;
+    }
+
+    public void setAbstHmst(BigDecimal abstHmst) {
+        this.abstHmst = abstHmst;
+    }
+
+
+    @Column(name="L_HOCHWERT", precision=11, scale=3)
+    public BigDecimal getLHochwert() {
+        return this.LHochwert;
+    }
+
+    public void setLHochwert(BigDecimal LHochwert) {
+        this.LHochwert = LHochwert;
+    }
+
+
+    @Column(name="L_RECHWERT", precision=11, scale=3)
+    public BigDecimal getLRechwert() {
+        return this.LRechwert;
+    }
+
+    public void setLRechwert(BigDecimal LRechwert) {
+        this.LRechwert = LRechwert;
+    }
+
+
+    @Column(name="L_NN", precision=8, scale=3)
+    public BigDecimal getLNn() {
+        return this.LNn;
+    }
+
+    public void setLNn(BigDecimal LNn) {
+        this.LNn = LNn;
+    }
+
+
+    @Column(name="R_HOCHWERT", precision=11, scale=3)
+    public BigDecimal getRHochwert() {
+        return this.RHochwert;
+    }
+
+    public void setRHochwert(BigDecimal RHochwert) {
+        this.RHochwert = RHochwert;
+    }
+
+
+    @Column(name="R_RECHWERT", precision=11, scale=3)
+    public BigDecimal getRRechwert() {
+        return this.RRechwert;
+    }
+
+    public void setRRechwert(BigDecimal RRechwert) {
+        this.RRechwert = RRechwert;
+    }
+
+
+    @Column(name="R_NN", precision=8, scale=3)
+    public BigDecimal getRNn() {
+        return this.RNn;
+    }
+
+    public void setRNn(BigDecimal RNn) {
+        this.RNn = RNn;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="OLDMSTID", precision=11, scale=0)
+    public Long getOldmstid() {
+        return this.oldmstid;
+    }
+
+    public void setOldmstid(Long oldmstid) {
+        this.oldmstid = oldmstid;
+    }
+
+
+    @Column(name="ISTFESTSTOFF", nullable=false, precision=1, scale=0)
+    public boolean isIstfeststoff() {
+        return this.istfeststoff;
+    }
+
+    public void setIstfeststoff(boolean istfeststoff) {
+        this.istfeststoff = istfeststoff;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="station")
+    public Set<Sohltest> getSohltests() {
+        return this.sohltests;
+    }
+
+    public void setSohltests(Set<Sohltest> sohltests) {
+        this.sohltests = sohltests;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="station")
+    public Set<Hpeilung> getHpeilungs() {
+        return this.hpeilungs;
+    }
+
+    public void setHpeilungs(Set<Hpeilung> hpeilungs) {
+        this.hpeilungs = hpeilungs;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="station")
+    public Set<Mpeilung> getMpeilungs() {
+        return this.mpeilungs;
+    }
+
+    public void setMpeilungs(Set<Mpeilung> mpeilungs) {
+        this.mpeilungs = mpeilungs;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="station")
+    public Set<Messung> getMessungs() {
+        return this.messungs;
+    }
+
+    public void setMessungs(Set<Messung> messungs) {
+        this.messungs = messungs;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Stationgew.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,61 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * Stationgew generated by hbm2java
+ */
+@Entity
+@Table(name="STATIONGEW"
+    ,schema="SEDDB"
+)
+public class Stationgew  implements java.io.Serializable {
+
+
+     private StationgewId id;
+
+    public Stationgew() {
+    }
+
+    public Stationgew(StationgewId id) {
+       this.id = id;
+    }
+
+     @EmbeddedId
+
+
+    @AttributeOverrides( {
+        @AttributeOverride(name="stationid", column=@Column(name="STATIONID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="gewaesserid", column=@Column(name="GEWAESSERID", nullable=false, precision=11, scale=0) ),
+        @AttributeOverride(name="km", column=@Column(name="KM", nullable=false, precision=8, scale=3) ),
+        @AttributeOverride(name="bezugspegelid", column=@Column(name="BEZUGSPEGELID", precision=11, scale=0) ),
+        @AttributeOverride(name="name", column=@Column(name="NAME", nullable=false, length=50) ),
+        @AttributeOverride(name="uferistlinks", column=@Column(name="UFERISTLINKS", nullable=false, precision=1, scale=0) ),
+        @AttributeOverride(name="teilVon", column=@Column(name="TEIL_VON", precision=8, scale=3) ),
+        @AttributeOverride(name="teilBis", column=@Column(name="TEIL_BIS", precision=8, scale=3) ),
+        @AttributeOverride(name="abstHmst", column=@Column(name="ABST_HMST", precision=8, scale=3) ),
+        @AttributeOverride(name="LHochwert", column=@Column(name="L_HOCHWERT", precision=11, scale=3) ),
+        @AttributeOverride(name="LRechwert", column=@Column(name="L_RECHWERT", precision=11, scale=3) ),
+        @AttributeOverride(name="LNn", column=@Column(name="L_NN", precision=8, scale=3) ),
+        @AttributeOverride(name="RHochwert", column=@Column(name="R_HOCHWERT", precision=11, scale=3) ),
+        @AttributeOverride(name="RRechwert", column=@Column(name="R_RECHWERT", precision=11, scale=3) ),
+        @AttributeOverride(name="RNn", column=@Column(name="R_NN", precision=8, scale=3) ),
+        @AttributeOverride(name="bemerkung", column=@Column(name="BEMERKUNG", length=240) ),
+        @AttributeOverride(name="oldmstid", column=@Column(name="OLDMSTID", precision=11, scale=0) ),
+        @AttributeOverride(name="istfeststoff", column=@Column(name="ISTFESTSTOFF", nullable=false, precision=1, scale=0) ),
+        @AttributeOverride(name="gewname", column=@Column(name="GEWNAME", nullable=false, length=20) ) } )
+    public StationgewId getId() {
+        return this.id;
+    }
+
+    public void setId(StationgewId id) {
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/StationgewId.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,313 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.math.BigDecimal;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+/**
+ * StationgewId generated by hbm2java
+ */
+@Embeddable
+public class StationgewId  implements java.io.Serializable {
+
+
+     private long stationid;
+     private long gewaesserid;
+     private BigDecimal km;
+     private Long bezugspegelid;
+     private String name;
+     private boolean uferistlinks;
+     private BigDecimal teilVon;
+     private BigDecimal teilBis;
+     private BigDecimal abstHmst;
+     private BigDecimal LHochwert;
+     private BigDecimal LRechwert;
+     private BigDecimal LNn;
+     private BigDecimal RHochwert;
+     private BigDecimal RRechwert;
+     private BigDecimal RNn;
+     private String bemerkung;
+     private Long oldmstid;
+     private boolean istfeststoff;
+     private String gewname;
+
+    public StationgewId() {
+    }
+
+    public StationgewId(long stationid, long gewaesserid, BigDecimal km, String name, boolean uferistlinks, boolean istfeststoff, String gewname) {
+        this.stationid = stationid;
+        this.gewaesserid = gewaesserid;
+        this.km = km;
+        this.name = name;
+        this.uferistlinks = uferistlinks;
+        this.istfeststoff = istfeststoff;
+        this.gewname = gewname;
+    }
+    public StationgewId(long stationid, long gewaesserid, BigDecimal km, Long bezugspegelid, String name, boolean uferistlinks, BigDecimal teilVon, BigDecimal teilBis, BigDecimal abstHmst, BigDecimal LHochwert, BigDecimal LRechwert, BigDecimal LNn, BigDecimal RHochwert, BigDecimal RRechwert, BigDecimal RNn, String bemerkung, Long oldmstid, boolean istfeststoff, String gewname) {
+       this.stationid = stationid;
+       this.gewaesserid = gewaesserid;
+       this.km = km;
+       this.bezugspegelid = bezugspegelid;
+       this.name = name;
+       this.uferistlinks = uferistlinks;
+       this.teilVon = teilVon;
+       this.teilBis = teilBis;
+       this.abstHmst = abstHmst;
+       this.LHochwert = LHochwert;
+       this.LRechwert = LRechwert;
+       this.LNn = LNn;
+       this.RHochwert = RHochwert;
+       this.RRechwert = RRechwert;
+       this.RNn = RNn;
+       this.bemerkung = bemerkung;
+       this.oldmstid = oldmstid;
+       this.istfeststoff = istfeststoff;
+       this.gewname = gewname;
+    }
+
+
+
+    @Column(name="STATIONID", nullable=false, precision=11, scale=0)
+    public long getStationid() {
+        return this.stationid;
+    }
+
+    public void setStationid(long stationid) {
+        this.stationid = stationid;
+    }
+
+
+    @Column(name="GEWAESSERID", nullable=false, precision=11, scale=0)
+    public long getGewaesserid() {
+        return this.gewaesserid;
+    }
+
+    public void setGewaesserid(long gewaesserid) {
+        this.gewaesserid = gewaesserid;
+    }
+
+
+    @Column(name="KM", nullable=false, precision=8, scale=3)
+    public BigDecimal getKm() {
+        return this.km;
+    }
+
+    public void setKm(BigDecimal km) {
+        this.km = km;
+    }
+
+
+    @Column(name="BEZUGSPEGELID", precision=11, scale=0)
+    public Long getBezugspegelid() {
+        return this.bezugspegelid;
+    }
+
+    public void setBezugspegelid(Long bezugspegelid) {
+        this.bezugspegelid = bezugspegelid;
+    }
+
+
+    @Column(name="NAME", nullable=false, length=50)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="UFERISTLINKS", nullable=false, precision=1, scale=0)
+    public boolean isUferistlinks() {
+        return this.uferistlinks;
+    }
+
+    public void setUferistlinks(boolean uferistlinks) {
+        this.uferistlinks = uferistlinks;
+    }
+
+
+    @Column(name="TEIL_VON", precision=8, scale=3)
+    public BigDecimal getTeilVon() {
+        return this.teilVon;
+    }
+
+    public void setTeilVon(BigDecimal teilVon) {
+        this.teilVon = teilVon;
+    }
+
+
+    @Column(name="TEIL_BIS", precision=8, scale=3)
+    public BigDecimal getTeilBis() {
+        return this.teilBis;
+    }
+
+    public void setTeilBis(BigDecimal teilBis) {
+        this.teilBis = teilBis;
+    }
+
+
+    @Column(name="ABST_HMST", precision=8, scale=3)
+    public BigDecimal getAbstHmst() {
+        return this.abstHmst;
+    }
+
+    public void setAbstHmst(BigDecimal abstHmst) {
+        this.abstHmst = abstHmst;
+    }
+
+
+    @Column(name="L_HOCHWERT", precision=11, scale=3)
+    public BigDecimal getLHochwert() {
+        return this.LHochwert;
+    }
+
+    public void setLHochwert(BigDecimal LHochwert) {
+        this.LHochwert = LHochwert;
+    }
+
+
+    @Column(name="L_RECHWERT", precision=11, scale=3)
+    public BigDecimal getLRechwert() {
+        return this.LRechwert;
+    }
+
+    public void setLRechwert(BigDecimal LRechwert) {
+        this.LRechwert = LRechwert;
+    }
+
+
+    @Column(name="L_NN", precision=8, scale=3)
+    public BigDecimal getLNn() {
+        return this.LNn;
+    }
+
+    public void setLNn(BigDecimal LNn) {
+        this.LNn = LNn;
+    }
+
+
+    @Column(name="R_HOCHWERT", precision=11, scale=3)
+    public BigDecimal getRHochwert() {
+        return this.RHochwert;
+    }
+
+    public void setRHochwert(BigDecimal RHochwert) {
+        this.RHochwert = RHochwert;
+    }
+
+
+    @Column(name="R_RECHWERT", precision=11, scale=3)
+    public BigDecimal getRRechwert() {
+        return this.RRechwert;
+    }
+
+    public void setRRechwert(BigDecimal RRechwert) {
+        this.RRechwert = RRechwert;
+    }
+
+
+    @Column(name="R_NN", precision=8, scale=3)
+    public BigDecimal getRNn() {
+        return this.RNn;
+    }
+
+    public void setRNn(BigDecimal RNn) {
+        this.RNn = RNn;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+
+    @Column(name="OLDMSTID", precision=11, scale=0)
+    public Long getOldmstid() {
+        return this.oldmstid;
+    }
+
+    public void setOldmstid(Long oldmstid) {
+        this.oldmstid = oldmstid;
+    }
+
+
+    @Column(name="ISTFESTSTOFF", nullable=false, precision=1, scale=0)
+    public boolean isIstfeststoff() {
+        return this.istfeststoff;
+    }
+
+    public void setIstfeststoff(boolean istfeststoff) {
+        this.istfeststoff = istfeststoff;
+    }
+
+
+    @Column(name="GEWNAME", nullable=false, length=20)
+    public String getGewname() {
+        return this.gewname;
+    }
+
+    public void setGewname(String gewname) {
+        this.gewname = gewname;
+    }
+
+
+   public boolean equals(Object other) {
+         if ( (this == other ) ) return true;
+         if ( (other == null ) ) return false;
+         if ( !(other instanceof StationgewId) ) return false;
+         StationgewId castOther = ( StationgewId ) other;
+
+         return (this.getStationid()==castOther.getStationid())
+ && (this.getGewaesserid()==castOther.getGewaesserid())
+ && ( (this.getKm()==castOther.getKm()) || ( this.getKm()!=null && castOther.getKm()!=null && this.getKm().equals(castOther.getKm()) ) )
+ && ( (this.getBezugspegelid()==castOther.getBezugspegelid()) || ( this.getBezugspegelid()!=null && castOther.getBezugspegelid()!=null && this.getBezugspegelid().equals(castOther.getBezugspegelid()) ) )
+ && ( (this.getName()==castOther.getName()) || ( this.getName()!=null && castOther.getName()!=null && this.getName().equals(castOther.getName()) ) )
+ && (this.isUferistlinks()==castOther.isUferistlinks())
+ && ( (this.getTeilVon()==castOther.getTeilVon()) || ( this.getTeilVon()!=null && castOther.getTeilVon()!=null && this.getTeilVon().equals(castOther.getTeilVon()) ) )
+ && ( (this.getTeilBis()==castOther.getTeilBis()) || ( this.getTeilBis()!=null && castOther.getTeilBis()!=null && this.getTeilBis().equals(castOther.getTeilBis()) ) )
+ && ( (this.getAbstHmst()==castOther.getAbstHmst()) || ( this.getAbstHmst()!=null && castOther.getAbstHmst()!=null && this.getAbstHmst().equals(castOther.getAbstHmst()) ) )
+ && ( (this.getLHochwert()==castOther.getLHochwert()) || ( this.getLHochwert()!=null && castOther.getLHochwert()!=null && this.getLHochwert().equals(castOther.getLHochwert()) ) )
+ && ( (this.getLRechwert()==castOther.getLRechwert()) || ( this.getLRechwert()!=null && castOther.getLRechwert()!=null && this.getLRechwert().equals(castOther.getLRechwert()) ) )
+ && ( (this.getLNn()==castOther.getLNn()) || ( this.getLNn()!=null && castOther.getLNn()!=null && this.getLNn().equals(castOther.getLNn()) ) )
+ && ( (this.getRHochwert()==castOther.getRHochwert()) || ( this.getRHochwert()!=null && castOther.getRHochwert()!=null && this.getRHochwert().equals(castOther.getRHochwert()) ) )
+ && ( (this.getRRechwert()==castOther.getRRechwert()) || ( this.getRRechwert()!=null && castOther.getRRechwert()!=null && this.getRRechwert().equals(castOther.getRRechwert()) ) )
+ && ( (this.getRNn()==castOther.getRNn()) || ( this.getRNn()!=null && castOther.getRNn()!=null && this.getRNn().equals(castOther.getRNn()) ) )
+ && ( (this.getBemerkung()==castOther.getBemerkung()) || ( this.getBemerkung()!=null && castOther.getBemerkung()!=null && this.getBemerkung().equals(castOther.getBemerkung()) ) )
+ && ( (this.getOldmstid()==castOther.getOldmstid()) || ( this.getOldmstid()!=null && castOther.getOldmstid()!=null && this.getOldmstid().equals(castOther.getOldmstid()) ) )
+ && (this.isIstfeststoff()==castOther.isIstfeststoff())
+ && ( (this.getGewname()==castOther.getGewname()) || ( this.getGewname()!=null && castOther.getGewname()!=null && this.getGewname().equals(castOther.getGewname()) ) );
+   }
+
+   public int hashCode() {
+         int result = 17;
+
+         result = 37 * result + (int) this.getStationid();
+         result = 37 * result + (int) this.getGewaesserid();
+         result = 37 * result + ( getKm() == null ? 0 : this.getKm().hashCode() );
+         result = 37 * result + ( getBezugspegelid() == null ? 0 : this.getBezugspegelid().hashCode() );
+         result = 37 * result + ( getName() == null ? 0 : this.getName().hashCode() );
+         result = 37 * result + (this.isUferistlinks()?1:0);
+         result = 37 * result + ( getTeilVon() == null ? 0 : this.getTeilVon().hashCode() );
+         result = 37 * result + ( getTeilBis() == null ? 0 : this.getTeilBis().hashCode() );
+         result = 37 * result + ( getAbstHmst() == null ? 0 : this.getAbstHmst().hashCode() );
+         result = 37 * result + ( getLHochwert() == null ? 0 : this.getLHochwert().hashCode() );
+         result = 37 * result + ( getLRechwert() == null ? 0 : this.getLRechwert().hashCode() );
+         result = 37 * result + ( getLNn() == null ? 0 : this.getLNn().hashCode() );
+         result = 37 * result + ( getRHochwert() == null ? 0 : this.getRHochwert().hashCode() );
+         result = 37 * result + ( getRRechwert() == null ? 0 : this.getRRechwert().hashCode() );
+         result = 37 * result + ( getRNn() == null ? 0 : this.getRNn().hashCode() );
+         result = 37 * result + ( getBemerkung() == null ? 0 : this.getBemerkung().hashCode() );
+         result = 37 * result + ( getOldmstid() == null ? 0 : this.getOldmstid().hashCode() );
+         result = 37 * result + (this.isIstfeststoff()?1:0);
+         result = 37 * result + ( getGewname() == null ? 0 : this.getGewname().hashCode() );
+         return result;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/TmpGloChanged.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * TmpGloChanged generated by hbm2java
+ */
+@Entity
+@Table(name="TMP_GLO_CHANGED"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames="GLOTRECHTEID")
+)
+public class TmpGloChanged  implements java.io.Serializable {
+
+
+     private long glotrechteid;
+
+    public TmpGloChanged() {
+    }
+
+    public TmpGloChanged(long glotrechteid) {
+       this.glotrechteid = glotrechteid;
+    }
+
+     @Id
+
+
+    @Column(name="GLOTRECHTEID", unique=true, nullable=false, precision=11, scale=0)
+    public long getGlotrechteid() {
+        return this.glotrechteid;
+    }
+
+    public void setGlotrechteid(long glotrechteid) {
+        this.glotrechteid = glotrechteid;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/TmpMesAchanged.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * TmpMesAchanged generated by hbm2java
+ */
+@Entity
+@Table(name="TMP_MES_ACHANGED"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames="MESSUNGID")
+)
+public class TmpMesAchanged  implements java.io.Serializable {
+
+
+     private long messungid;
+
+    public TmpMesAchanged() {
+    }
+
+    public TmpMesAchanged(long messungid) {
+       this.messungid = messungid;
+    }
+
+     @Id
+
+
+    @Column(name="MESSUNGID", unique=true, nullable=false, precision=11, scale=0)
+    public long getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(long messungid) {
+        this.messungid = messungid;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/TmpMesGchanged.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * TmpMesGchanged generated by hbm2java
+ */
+@Entity
+@Table(name="TMP_MES_GCHANGED"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames="MESSUNGID")
+)
+public class TmpMesGchanged  implements java.io.Serializable {
+
+
+     private long messungid;
+
+    public TmpMesGchanged() {
+    }
+
+    public TmpMesGchanged(long messungid) {
+       this.messungid = messungid;
+    }
+
+     @Id
+
+
+    @Column(name="MESSUNGID", unique=true, nullable=false, precision=11, scale=0)
+    public long getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(long messungid) {
+        this.messungid = messungid;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/TmpMesQchanged.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * TmpMesQchanged generated by hbm2java
+ */
+@Entity
+@Table(name="TMP_MES_QCHANGED"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames="MESSUNGID")
+)
+public class TmpMesQchanged  implements java.io.Serializable {
+
+
+     private long messungid;
+
+    public TmpMesQchanged() {
+    }
+
+    public TmpMesQchanged(long messungid) {
+       this.messungid = messungid;
+    }
+
+     @Id
+
+
+    @Column(name="MESSUNGID", unique=true, nullable=false, precision=11, scale=0)
+    public long getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(long messungid) {
+        this.messungid = messungid;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/TmpMesSchanged.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+/**
+ * TmpMesSchanged generated by hbm2java
+ */
+@Entity
+@Table(name="TMP_MES_SCHANGED"
+    ,schema="SEDDB"
+    , uniqueConstraints = @UniqueConstraint(columnNames="MESSUNGID")
+)
+public class TmpMesSchanged  implements java.io.Serializable {
+
+
+     private long messungid;
+
+    public TmpMesSchanged() {
+    }
+
+    public TmpMesSchanged(long messungid) {
+       this.messungid = messungid;
+    }
+
+     @Id
+
+
+    @Column(name="MESSUNGID", unique=true, nullable=false, precision=11, scale=0)
+    public long getMessungid() {
+        return this.messungid;
+    }
+
+    public void setMessungid(long messungid) {
+        this.messungid = messungid;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Zzarchiv.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,96 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+/**
+ * Zzarchiv generated by hbm2java
+ */
+@Entity
+@Table(name="ZZARCHIV"
+    ,schema="SEDDB"
+)
+public class Zzarchiv  implements java.io.Serializable {
+
+
+     private long archivid;
+     private String name;
+     private boolean istaktiv;
+     private String bemerkung;
+     private Set<Sohltest> sohltests = new HashSet<Sohltest>(0);
+
+    public Zzarchiv() {
+    }
+
+    public Zzarchiv(long archivid, String name, boolean istaktiv) {
+        this.archivid = archivid;
+        this.name = name;
+        this.istaktiv = istaktiv;
+    }
+    public Zzarchiv(long archivid, String name, boolean istaktiv, String bemerkung, Set<Sohltest> sohltests) {
+       this.archivid = archivid;
+       this.name = name;
+       this.istaktiv = istaktiv;
+       this.bemerkung = bemerkung;
+       this.sohltests = sohltests;
+    }
+
+     @Id
+
+
+    @Column(name="ARCHIVID", unique=true, nullable=false, precision=11, scale=0)
+    public long getArchivid() {
+        return this.archivid;
+    }
+
+    public void setArchivid(long archivid) {
+        this.archivid = archivid;
+    }
+
+
+    @Column(name="NAME", nullable=false, length=50)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="ISTAKTIV", nullable=false, precision=1, scale=0)
+    public boolean isIstaktiv() {
+        return this.istaktiv;
+    }
+
+    public void setIstaktiv(boolean istaktiv) {
+        this.istaktiv = istaktiv;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="zzarchiv")
+    public Set<Sohltest> getSohltests() {
+        return this.sohltests;
+    }
+
+    public void setSohltests(Set<Sohltest> sohltests) {
+        this.sohltests = sohltests;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Zzprobenahmeart.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,110 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+/**
+ * Zzprobenahmeart generated by hbm2java
+ */
+@Entity
+@Table(name="ZZPROBENAHMEART"
+    ,schema="SEDDB"
+)
+public class Zzprobenahmeart  implements java.io.Serializable {
+
+
+     private long probenahmeartid;
+     private boolean istkern;
+     private String name;
+     private boolean istaktiv;
+     private String bemerkung;
+     private Set<Sohlprobe> sohlprobes = new HashSet<Sohlprobe>(0);
+
+    public Zzprobenahmeart() {
+    }
+
+
+    public Zzprobenahmeart(long probenahmeartid, boolean istkern, String name, boolean istaktiv) {
+        this.probenahmeartid = probenahmeartid;
+        this.istkern = istkern;
+        this.name = name;
+        this.istaktiv = istaktiv;
+    }
+    public Zzprobenahmeart(long probenahmeartid, boolean istkern, String name, boolean istaktiv, String bemerkung, Set<Sohlprobe> sohlprobes) {
+       this.probenahmeartid = probenahmeartid;
+       this.istkern = istkern;
+       this.name = name;
+       this.istaktiv = istaktiv;
+       this.bemerkung = bemerkung;
+       this.sohlprobes = sohlprobes;
+    }
+
+     @Id
+
+
+    @Column(name="PROBENAHMEARTID", unique=true, nullable=false, precision=11, scale=0)
+    public long getProbenahmeartid() {
+        return this.probenahmeartid;
+    }
+
+    public void setProbenahmeartid(long probenahmeartid) {
+        this.probenahmeartid = probenahmeartid;
+    }
+
+
+    @Column(name="ISTKERN", nullable=false, precision=1, scale=0)
+    public boolean isIstkern() {
+        return this.istkern;
+    }
+
+    public void setIstkern(boolean istkern) {
+        this.istkern = istkern;
+    }
+
+
+    @Column(name="NAME", nullable=false, length=50)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="ISTAKTIV", nullable=false, precision=1, scale=0)
+    public boolean isIstaktiv() {
+        return this.istaktiv;
+    }
+
+    public void setIstaktiv(boolean istaktiv) {
+        this.istaktiv = istaktiv;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="zzprobenahmeart")
+    public Set<Sohlprobe> getSohlprobes() {
+        return this.sohlprobes;
+    }
+
+    public void setSohlprobes(Set<Sohlprobe> sohlprobes) {
+        this.sohlprobes = sohlprobes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Zzsondierungart.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,96 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+/**
+ * Zzsondierungart generated by hbm2java
+ */
+@Entity
+@Table(name="ZZSONDIERUNGART"
+    ,schema="SEDDB"
+)
+public class Zzsondierungart  implements java.io.Serializable {
+
+
+     private long sondierungartid;
+     private String name;
+     private boolean istaktiv;
+     private String bemerkung;
+     private Set<Sohltest> sohltests = new HashSet<Sohltest>(0);
+
+    public Zzsondierungart() {
+    }
+
+    public Zzsondierungart(long sondierungartid, String name, boolean istaktiv) {
+        this.sondierungartid = sondierungartid;
+        this.name = name;
+        this.istaktiv = istaktiv;
+    }
+    public Zzsondierungart(long sondierungartid, String name, boolean istaktiv, String bemerkung, Set<Sohltest> sohltests) {
+       this.sondierungartid = sondierungartid;
+       this.name = name;
+       this.istaktiv = istaktiv;
+       this.bemerkung = bemerkung;
+       this.sohltests = sohltests;
+    }
+
+     @Id
+
+
+    @Column(name="SONDIERUNGARTID", unique=true, nullable=false, precision=11, scale=0)
+    public long getSondierungartid() {
+        return this.sondierungartid;
+    }
+
+    public void setSondierungartid(long sondierungartid) {
+        this.sondierungartid = sondierungartid;
+    }
+
+
+    @Column(name="NAME", nullable=false, length=50)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="ISTAKTIV", nullable=false, precision=1, scale=0)
+    public boolean isIstaktiv() {
+        return this.istaktiv;
+    }
+
+    public void setIstaktiv(boolean istaktiv) {
+        this.istaktiv = istaktiv;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="zzsondierungart")
+    public Set<Sohltest> getSohltests() {
+        return this.sohltests;
+    }
+
+    public void setSohltests(Set<Sohltest> sohltests) {
+        this.sohltests = sohltests;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-backend/src/main/java/de/intevation/seddb/model/Zzthema.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,108 @@
+package de.intevation.seddb.model;
+// Generated 14.06.2012 11:30:57 by Hibernate Tools 3.4.0.CR1
+
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+/**
+ * Zzthema generated by hbm2java
+ */
+@Entity
+@Table(name="ZZTHEMA"
+    ,schema="SEDDB"
+)
+public class Zzthema  implements java.io.Serializable {
+
+
+     private long themaid;
+     private String name;
+     private boolean istaktiv;
+     private String bemerkung;
+     private Set<Bild> bilds = new HashSet<Bild>(0);
+     private Set<Probebild> probebilds = new HashSet<Probebild>(0);
+
+    public Zzthema() {
+    }
+
+
+    public Zzthema(long themaid, String name, boolean istaktiv) {
+        this.themaid = themaid;
+        this.name = name;
+        this.istaktiv = istaktiv;
+    }
+    public Zzthema(long themaid, String name, boolean istaktiv, String bemerkung, Set<Bild> bilds, Set<Probebild> probebilds) {
+       this.themaid = themaid;
+       this.name = name;
+       this.istaktiv = istaktiv;
+       this.bemerkung = bemerkung;
+       this.bilds = bilds;
+       this.probebilds = probebilds;
+    }
+
+     @Id
+
+
+    @Column(name="THEMAID", unique=true, nullable=false, precision=11, scale=0)
+    public long getThemaid() {
+        return this.themaid;
+    }
+
+    public void setThemaid(long themaid) {
+        this.themaid = themaid;
+    }
+
+
+    @Column(name="NAME", nullable=false, length=50)
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Column(name="ISTAKTIV", nullable=false, precision=1, scale=0)
+    public boolean isIstaktiv() {
+        return this.istaktiv;
+    }
+
+    public void setIstaktiv(boolean istaktiv) {
+        this.istaktiv = istaktiv;
+    }
+
+
+    @Column(name="BEMERKUNG", length=240)
+    public String getBemerkung() {
+        return this.bemerkung;
+    }
+
+    public void setBemerkung(String bemerkung) {
+        this.bemerkung = bemerkung;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="zzthema")
+    public Set<Bild> getBilds() {
+        return this.bilds;
+    }
+
+    public void setBilds(Set<Bild> bilds) {
+        this.bilds = bilds;
+    }
+
+@OneToMany(fetch=FetchType.LAZY, mappedBy="zzthema")
+    public Set<Probebild> getProbebilds() {
+        return this.probebilds;
+    }
+
+    public void setProbebilds(Set<Probebild> probebilds) {
+        this.probebilds = probebilds;
+    }
+}
--- a/flys-client/.classpath	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<classpath>
-   <classpathentry kind="src" path="src/main/java"/>
-   <classpathentry kind="src" path="src/test/java"/>
-   <classpathentry kind="lib" path="/vol1/download/ingo/gwt-2.1.1/gwt-user.jar"/>
-   <classpathentry kind="lib" path="/vol1/download/ingo/gwt-2.1.1/gwt-dev.jar"/>
-   <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-   <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
-   <classpathentry kind="output" path="src/main/webapp/WEB-INF/classes"/>
-
-</classpath>
--- a/flys-client/.project	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<projectDescription>
-   <name>FLYS</name>
-   <comment>FLYS project</comment>
-   <projects/>
-   <buildSpec>
-       <buildCommand>
-           <name>org.eclipse.jdt.core.javabuilder</name>
-           <arguments/>
-       </buildCommand>
-   </buildSpec>
-   <natures>
-       <nature>org.eclipse.jdt.core.javanature</nature>
-   </natures>
-</projectDescription>
--- a/flys-client/ChangeLog	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/ChangeLog	Fri Sep 28 12:15:52 2012 +0200
@@ -1,3 +1,4584 @@
+2012-09-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/FLYSArtifactCreator.java,
+	  src/main/java/de/intevation/flys/client/server/ArtifactHelper.java,
+	  src/main/java/de/intevation/flys/client/shared/model/GaugeDischargeCurveArtifact.java,
+	  src/main/java/de/intevation/flys/client/client/services/ArtifactService.java,
+	  src/main/java/de/intevation/flys/client/client/services/ArtifactServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYS.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterList.java,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugeTree.java:
+	  Allow to create a discharge curve from a gauge info.
+	  Currently the dicharge curve will not be displayed.
+
+2012-09-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/GaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/server/GaugeOverviewInfoServiceImpl.java:
+	  Add river name to the GaugeInfo
+
+2012-09-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Work on issue724 (i18n in minfo).
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties:
+	  Translate data export.
+
+2012-09-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/services/ModuleServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Cosmetics, docs.
+
+2012-09-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/UserServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Donate own error message when no users were found.
+
+2012-09-27	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DoubleProperty.java,
+	  src/main/java/de/intevation/flys/client/shared/model/PropertySetting.java,
+	  src/main/java/de/intevation/flys/client/shared/model/PropertyGroup.java:
+	  Add "Date" support for Manual Points editor (not finished yet).
+
+	* src/main/java/de/intevation/flys/client/shared/model/MapMode.java:
+	  Add comment.
+
+2012-09-27	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/MapMode.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterMatrix.java:
+	  Removed trailing whitespace.
+
+2012-09-27	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/webapp/WEB-INF/web.xml:
+	  Add servlet mapping for the GaugeOverviewInfoService
+
+2012-09-26  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue897 (MissingResourceException: Cannot find constant '500 The call failed on the server; see server log for details')
+
+	* src/main/java/de/intevation/flys/client/shared/model/MapMode.java:
+	  Readded default constructor.
+
+2012-09-25	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java:
+	  Default from and to dates are now shown with english locale, too (#854).
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Cosmetics.
+
+2012-09-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Improved fix for issue860 (minfo parameterization in helper pane).
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java
+	  (createWidget, createCheckBox): Renamed.
+	  Use smartgwt stuff to profit from scrollbars (yay!).
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java:
+	  Place ParameterMatrix in helper pane if too long.
+
+2012-09-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Attempt at issue860 (minfo parameterization in helper pane).
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java:
+	  Place ParameterMatrix in helper pane if too long.
+
+2012-09-24	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/widgets/KMSpinner.java:
+	  Issue #853:
+	  - Height is now normal again
+	  - "Junk" chars are now removed on change	
+
+2012-09-24	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	issue846 (GGInA: Auth mechanism ignores URL prefix)
+
+	* src/main/java/de/intevation/flys/client/server/LoginServlet.java,
+	  src/main/java/de/intevation/flys/client/server/GGInAFilter.java,
+	  src/main/webapp/login.jsp:
+	  Consider the Context Path variable when using urls in the GGInAFilter.
+
+2012-09-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	issue871 (parameterization of flowvelocity loo¿s a tiny bit messy).
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java:
+	  Show horizontal line between entries.
+
+2012-09-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/RemoteServiceServlet.java,
+	  src/main/java/de/intevation/flys/client/shared/model/IntegerOptionsData.java:
+	  Cosmetics, docs.
+
+2012-09-24	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java:
+	  Finally store passed kmup value in member variable.
+
+2012-09-24	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GaugeOverviewInfoServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultRiverInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/RiverInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/GaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugeTree.java:
+	  Use i18n to calculate the info urls for the gauge overview instead of
+	  fechting the urls from the artifact service.
+
+2012-09-22	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixFunctionSelect.java:
+	  Show full function instead of internal name (#873).
+
+2012-09-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for bedheight difference calculation.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/GaugeTree.java:
+	  Open fold for historicalq reference.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GaugeOverviewInfoServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/GaugeInfo.java:
+	  Add the official gauge number to the GaugeInfo class.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/GaugeTree.java,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Refactor GaugeTree into its own java file. Due to the folding logic in the
+	  GaugeTree the code became quite lage. Therefore it is better preserved in
+	  its own file.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Additional refactoring to avoid code duplication and fixing reading double
+	  value from locations DataItem object. Also add another code path for
+	  location_distance winfo state.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Refactor to avoid code duplication
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Add html links to the additional gauge and river info pages.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GaugeOverviewInfoServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultRiverInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/RiverInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/GaugeInfo.java:
+	  Extend GaugeInfo and RiverInfo to store also the http url for additional
+	  info.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterList.java:
+	  Open and close gauge tree folds that correspond to the selected WINFO
+	  calculation.
+
+2012-09-21	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/DoubleArrayPanel.java:
+	  Fix NullPointerException on not available list
+
+2012-09-20	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixMultiPeriodPanel.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java:
+	  i18n for FixMultiPeriodPanel (#872).
+
+2012-09-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Prevent AIOOB exception.
+
+2012-09-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Removed superfluous import.
+
+2012-09-19	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  i18n (#858)
+
+2012-09-19	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GaugeOverviewInfoServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/GaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Use the wstunit from the river as unit for the Pegelnullpunkt.
+
+2012-09-19	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterList.java:
+	  Don't display the GaugePanel if no river is selected.
+
+2012-09-19	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/DefaultArtifactDescription.java:
+	  Fix NullPointerException when going back in WINFO artifact to the river
+	  selection.
+
+2012-09-19	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Add locale aware formatting of the gauge values.
+	  Don't reload the gauges if the river doesn't change.
+	  Correctly handle kmup of the river.
+
+2012-09-19	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterList.java:
+	  Improve handling of the GaugePanel and don't delete members of the
+	  GaugePanel.
+
+2012-09-19	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GaugeOverviewInfoServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/GaugeInfo.java:
+	  Add station information to the gauges.
+
+2012-09-19	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/webapp/FLYS.css,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Get a working GaugeInfo solution with scrolling adjustments if gauge info
+	  elements are folded in an out.
+
+2012-09-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java:
+	  Removed trailing whitespace.
+
+2012-09-17  Ingo Weinzierl <ingo@intevation.de>
+
+	Tagged RELEASE 2.9.1
+
+2012-09-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added missing i18n strings for minfo state description.
+
+2012-09-16	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/widgets/KMSpinnerChangeListener.java (NEW),
+	  src/main/java/de/intevation/flys/client/client/widgets/KMSpinner.java (NEW),
+	  src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Refactored some KMSpinner code. KMSpinner has now a human-readable size (#853).
+
+2012-09-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/DefaultRiverInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterList.java,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java,
+	  src/main/java/de/intevation/flys/client/client/services/GaugeOverviewInfoService.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java:
+	  Removed trailing whitespace and superfluous imports.
+
+2012-09-14	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterList.java,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java:
+	  Add first draft for the gauge overview info ui
+
+2012-09-14	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/services/GaugeOverviewInfoService.java,
+	  src/main/java/de/intevation/flys/client/client/services/GaugeOverviewInfoServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/shared/model/GaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/RiverInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultRiverInfo.java,
+	  src/main/java/de/intevation/flys/client/server/GaugeOverviewInfoServiceImpl.java:
+	  Implement a service to handle the gauge info
+
+2012-09-13	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/range/LocationsTable.java:
+	  Adding "from" and "to" in table columns with the green/red marker icons (#808).
+
+2012-09-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties:
+	  Translated german strings.
+
+2012-09-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added 'main_channel' and 'total_channel' strings.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java:
+	  Use the correct label for the UI.
+
+2012-09-13  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added strings for bed quality chart and export.
+
+2012-09-13	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ProjectList.java:
+	  Scrolling long Project lists is now more robust (#757), although
+	  the search box is now part of the scrolling pane.
+
+2012-09-13	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java:
+	  Adding string for error_no_modules_found (#855).
+
+2012-09-13	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Cosmetics.
+
+2012-09-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/minfo/BedCampaignChart.java,
+	  src/main/java/de/intevation/flys/client/client/ui/minfo/BedloadCampaignChart.java:
+	  New. Container for overview charts.
+
+	* src/main/java/de/intevation/flys/client/server/BedKMChartServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/BedloadKMChartServiceImpl.java:
+	  New. Services for overview charts.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrix.java:
+	  Show i18n strings in column titles.
+
+	* src/main/java/de/intevation/flys/client/client/ui/minfo/BedMultiPeriodPanel.java:
+	  New. UI provider that allows multiple period input and displays the overview
+	  charts.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Added new ui provider.
+
+	* src/main/webapp/WEB-INF/web.xml:
+	  Added new services.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings.
+
+2012-09-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/StringOptionsData.java:
+	  Fixed constructor.
+
+2012-09-11	Christian Lins 	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Fix for line label text in Delta W(t) chart (#837).
+
+2012-09-10	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Minimal fix for 'Transparency' combobox appearence (#840).
+
+2012-09-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* pom.xml: Java 1.5 -> 1.6
+
+2012-09-09	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Rename attribute 'alpha' to 'transparency' which now represents the 
+	  transparency percentage instead raw rgba alpha value. StyledEditorWindow
+	  can now handle this transparency attribute.
+
+2012-09-09	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Add 'error_update_collection_attribute' string (#843).
+
+2012-09-09	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/UserServiceImpl.java:
+	  Remove blank line.
+
+	* src/main/java/de/intevation/flys/client/client/FLYS.java:
+	  Catch MissingResourceException on unexpected server exceptions (#843).
+
+2012-09-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/plain/Authenticator.java:
+	  Reverted functional change from clins last commit.
+
+	* src/main/java/de/intevation/flys/client/server/LoginServlet.java,
+	  src/main/java/de/intevation/flys/client/server/auth/AuthenticationFactory.java,
+	  src/main/java/de/intevation/flys/client/server/auth/UserClient.java:
+	  Removed trailing whitespace.
+
+2012-09-08	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/RemoteServiceServlet.java,
+	  src/main/java/de/intevation/flys/client/server/LoginServlet.java,
+	  src/main/java/de/intevation/flys/client/server/auth/plain/Authenticator.java,
+	  src/main/java/de/intevation/flys/client/server/auth/AuthenticationFactory.java,
+	  src/main/java/de/intevation/flys/client/server/auth/UserClient.java,
+	  src/main/java/de/intevation/flys/client/client/FLYS.java:
+	  Cosmetics, add robustness checks etc.
+
+2012-09-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/UserServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/auth/UserClient.java:
+	  Be more defensive about fetchimg users from session.
+
+2012-09-07	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Improved panning in TimeseriesCharts (issue715).
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java
+	  (computeZoom): Prevent confusion of scoped 'zoom' variable.
+	  (divide): Cast to double, we do not want long precision divisions.
+
+2012-09-07	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/ChartInfo.java,
+	  src/main/java/de/intevation/flys/client/client/FLYS.java,
+	  src/main/java/de/intevation/flys/client/client/ui/FLYSView.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/MousePositionPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/OutputTab.java,
+	  src/main/java/de/intevation/flys/client/client/ui/CollectionView.java,
+	  src/main/java/de/intevation/flys/client/client/ui/FLYSWorkspace.java,
+	  src/main/java/de/intevation/flys/client/client/ui/DatacagePairWidget.java:
+	  Cosmetics, docs.
+
+2012-09-04	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/UserServiceImpl.java:
+	  Refactor getCurrentUser to return the logged in user and not the first
+	  user from the artifact database.
+
+2012-09-04	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/RemoteServiceServlet.java,
+	  src/main/java/de/intevation/flys/client/server/RiverServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/services/RemoteServiceServlet.java,
+	  src/main/java/de/intevation/flys/client/server/ModuleServiceImpl.java:
+	  Move RemoteServiceServlet to server package.
+
+2012-09-07  Ingo Weinzierl <ingo@intevation.de>
+
+	Tagged module as '2.9'.
+
+2012-09-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/RadioPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Removed trailing whitespace.
+
+2012-09-04	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix for issue63.
+
+	* src/main/java/de/intevation/flys/client/client/ui/LinkSelection.java:
+	  Place map image in helper section.
+
+2012-09-04	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/plain/Authenticator.java:
+	  Add some debug which file will be used for local user authentification
+
+2012-09-04	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/webapp/WEB-INF/features.xml:
+	  Add features for flys_wsa_schweinfurt role
+
+2012-09-04  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 808.
+
+	* src/main/java/de/intevation/flys/client/client/ui/wq/QDTable.java:
+	  Added new row for single selection and set field titles.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  Show the single selection row on init.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Updated i18n strings.
+
+2012-09-04  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 664.
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java:
+	  Made old value an i18n formatted string.
+
+2012-09-04	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/RiverServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/ModuleServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/services/RemoteServiceServlet.java:
+	  Add missing imports and fix package declaration.
+
+2012-09-04  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 791.
+
+	* src/main/java/de/intevation/flys/client/client/ui/MultipleLocationPanel.java:
+	  Do not allow the same values in reference and target location.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings.
+
+2012-09-04	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial fix for issue820.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Change i18n (middle height -> middle depth).
+
+2012-09-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Do not show labels in logo selection combobox.
+
+2012-09-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+
+	Show logos in selectbox in chart properties such that user gets a
+	visual idea of what she selects.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Show icons in select box that displays the chosen logo.
+
+	* src/main/webapp/images/logo-intevation.png,
+	  src/main/webapp/images/logo-bfg.gif:
+	  Two exemplary logos (copies in flys-artifacts).
+
+2012-09-01	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ModuleServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/ui/RadioPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java,
+	  src/main/java/de/intevation/flys/client/client/ui/minfo/CheckboxPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/minfo/BedHeightsDatacagePanel.java:
+	  Removed superfluous imports.
+
+2012-09-01	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Overflow for Toolbars is now HIDDEN to avoid nasty scrollbars (#761).
+
+2012-09-01	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/DatacagePairWidget.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Change button title in DatacagePairWidget (#746).
+
+2012-08-31	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java:
+	  ThemePanels are now resizable (fix for #750).
+
+2012-08-31	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Maybe sqashing issue531, calling projectlists superclasses constructor.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ProjectList.java:
+	  Call super() constructor.
+
+2012-08-31	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ModuleSelection.java:
+	  Set the default value of the RadioGroupItem if a module is selected.
+
+2012-08-31	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ModuleServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/services/ModuleService.java:
+	  Load the list of modules from the flys artifact server. Also respect the
+	  selected attribute of a module.
+
+2012-08-31	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/DefaultModule.java,
+	  src/main/java/de/intevation/flys/client/client/services/ModuleService.java:
+	  Add isSelected method to Module classes.
+
+2012-08-31  Raimund Renkert <raimund.renkert@intevation.de>
+
+	MINFO: Added new UI provider for bed quality calculation.
+
+	* src/main/java/de/intevation/flys/client/client/ui/minfo/CheckboxPanel.java:
+	  New. UI provider for a list of checkboxes.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Added new UI provider.
+
+2012-08-31  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java:
+	  Use river data in all states not only winfo.
+
+2012-08-31  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ExportPanel.java:
+	  Hide the W/Q AT export button in fix analysis parameter tab.
+
+2012-08-31	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/UserClient.java:
+	  User xml namespace for XPath attribute query.
+
+2012-08-31	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/webapp/WEB-INF/web.xml:
+	  Add servlet settings for ModuleService
+
+2012-08-30	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java,
+	  src/main/java/de/intevation/flys/client/client/ui/FLYSWorkspace.java:
+	  New projects are now initially maximized to prevent IE-layout issue (#755).
+
+2012-08-30	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfoWindow.java:
+	  Workaround for #775 (manually set window size to 500x500 pixels)
+
+	* src/main/java/de/intevation/flys/client/client/ui/WspDatacagePanel.java:
+	  Prevent NPE
+
+2012-08-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  i18n for logo placement.
+
+2012-08-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ModuleSelection.java:
+	  Load modules from the ModuleService instead of using hardcoded strings.
+
+2012-08-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ModuleServiceImpl.java:
+	  Hardcode German translations for module names until real translations are
+	  available.
+
+2012-08-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/webapp/WEB-INF/features.xml:
+	  Add roles and features for GGinA
+
+2012-08-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/services/ModuleServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/client/services/ModuleService.java,
+	  src/main/java/de/intevation/flys/client/server/ModuleServiceImpl.java:
+	  Added service to list available modules for a user.
+
+2012-08-29	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/DefaultModule.java,
+	  src/main/java/de/intevation/flys/client/shared/model/Module.java:
+	  Added class representation of a module artifact.
+
+2012-08-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Special chart properties should trigger different ui (logo placement box).
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for split logo-placement properties in charts.
+
+2012-08-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Special chart properties should trigger different ui (logo placement box).
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for logo-placements in charts.
+
+2012-08-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Special chart properties should trigger different ui (logo select box).
+
+2012-08-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added first i18n strings for logo-inclusion in charts.
+
+2012-08-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/CollectionHelper.java,
+	  src/main/java/de/intevation/flys/client/shared/model/StringProperty.java,
+	  src/main/java/de/intevation/flys/client/shared/model/OutputSettings.java,
+	  src/main/java/de/intevation/flys/client/shared/model/FacetRecord.java:
+	  Cosmetics.
+
+2012-08-28  Raimund Renkert <raimund.renkert@intevation.de>
+
+	MINFO: Added UI for minfo differences calculation.
+
+	* src/main/java/de/intevation/flys/client/client/ui/minfo,
+	  src/main/java/de/intevation/flys/client/client/ui/minfo/BedHeightsDatacagePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/RadioPanel.java:
+	  New. UI provider for states in minfo differences calculation.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Added new UI provider.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings.
+
+2012-08-24	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/UserClient.java:
+	  Use new find-user REST interface to check if a user already exists in the
+	  database or a new user must be created.
+
+2012-08-24	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/UserClient.java:
+	  Send account data to REST interface.
+
+2012-08-24	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/UserClient.java:
+	  Don't use XPath Query to get attribute of a XML Node
+
+2012-08-24	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/DefaultUser.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Response.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/User.java,
+	  src/main/java/de/intevation/flys/client/server/auth/User.java:
+	  Add account information to client user classes. Use the WAS/GGInA
+	  assertion NameIdentifier element for the account name. For text
+	  authentication user username also as account name.
+
+2012-08-24	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/LoginServlet.java:
+	  Add debug output if a database user will be created.
+
+2012-08-23	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/UserServiceImpl.java:
+	  Avoid using XPath queries for getting attributes of a node.
+
+2012-08-22	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYS.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ProjectList.java,
+	  src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Delete empty project after closing the CollectionView (#785).
+
+2012-08-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ExportServiceImpl.java:
+	  Removed superfluous import. Removed some inner whitespace.
+	  Made debug output conditional.
+
+2012-08-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added AT file export to FixAnalysis W/Q.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  New image link for AT export in W/Q tab.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java:
+	  Update link url on km change.
+
+	* src/main/java/de/intevation/flys/client/server/ExportServiceImpl.java:
+	  Add the km to the request document.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n string for tooltip.
+
+2012-08-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ProxyServlet.java:
+	  Shortend lines to 80 chars. Made debug outout conditional.
+	  Use block copy instead of tight byte wise loop.
+
+2012-08-16	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ProxyServlet.java:
+	  Implement a ProxyServlet to be able to restrict the access to the
+	  mapserver too. All queries to the provided map services should go throught
+	  this new ProxyServlet. Currently the ProxyServlet can only handle HTTP GET
+	  requests.
+
+2012-08-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/RiverServiceImpl.java:
+	  Replaced another attribute fetching XPath with a simple DOM
+	  getAttributeNS() call.
+
+2012-08-15	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/RiverServiceImpl.java:
+	  Avoid NullPointerException if user authetication is deactivated. If user
+	  Authentication is deactivated all rivers are returned.
+
+2012-08-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 752. Location input label.
+
+	* src/main/java/de/intevation/flys/client/client/ui/MultipleLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Added getter for label string.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties:
+	  Added i18n string for single location label.
+
+2012-08-15	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/RiverServiceImpl.java:
+	Only return rivers that the user is allowed to see. Evaluate the allowed
+	features of the current logged in user and hide rivers which aren't
+	mentioned in the features list.
+
+2012-08-15	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/services/RemoteServiceServlet.java:
+	  Implement an extended GWT RemoteServiceServlet to be able to get the
+	  current logged in user easily.
+
+2012-08-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/DefaultUser.java,
+	  src/main/java/de/intevation/flys/client/server/features/XMLFileFeatures.java:
+	  Removed superfluous imports.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/was/Response.java:
+	  Add debug log of a successfull authentification inclusive the
+	  corresponding features of the authenticated user.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/webapp/WEB-INF/features.xml:
+	  Add example features for GGinA/WAS role flys_bfg.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/features/XMLFileFeatures.java:
+	  Don't use a xml namespace to get the "name" attribute of a role.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+	* src/main/java/de/intevation/flys/client/server/auth/was/Authenticator.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Response.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/User.java:
+	  Implement Features handling for WAS authentication.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/LoginServlet.java,
+	  src/main/java/de/intevation/flys/client/server/auth/plain/Authenticator.java,
+	  src/main/java/de/intevation/flys/client/server/auth/DefaultUser.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Authenticator.java,
+	  src/main/java/de/intevation/flys/client/server/auth/Authenticator.java,
+	  src/main/java/de/intevation/flys/client/server/auth/User.java,
+	  src/main/java/de/intevation/flys/client/server/GGInAFilter.java:
+	  Refactor Authentication to allow to pass the Freatures to the user class.
+
+2012-08-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/features/XMLFileFeatures.java:
+	  Used HashMap instead of Hashtable. Limit to 80 chars per line.
+
+2012-08-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/meta/Converter.java:
+	  Removed trailing whitespace.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+	* src/main/java/de/intevation/flys/client/server/features/XMLFileFeatures.java:
+	  Always close FileInputStream, improve for loops and avoid XPath for
+	  getting a xml attribute.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+	* src/main/java/de/intevation/flys/client/server/CapabilitiesParser.java,
+	  src/main/java/de/intevation/flys/client/server/BaseServlet.java,
+	  src/main/webapp/WEB-INF/web.xml:
+	  Remove the obsolete BaseServlet. Initializing of logging is now handled by
+	  the BaseServletContextListener class which is loaded before any Servlet.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+	* src/main/java/de/intevation/flys/client/server/features/FeatureServletContextListener.java,
+	  src/main/java/de/intevation/flys/client/server/BaseServletContextListener.java,
+	  src/main/webapp/WEB-INF/web.xml:
+	  Rename and move FeatureServletContextListener.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+	* src/main/java/de/intevation/flys/client/server/features/FeatureServletContextListener.java,
+	  src/main/webapp/WEB-INF/web.xml:
+	  Implement a ServletContextListener to initialize the Fearures from a xml
+	  file. With the context parameter "features-file" in src/main/webapp/WEB-INF/web.xml
+	  a xml file to load features from can be specified.
+	  The FeatureServletContextListener class also initializes the logging now
+	  because it is loaded before the BaseServlet.
+
+2012-08-08	Björn Ricks <bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/features/XMLFileFeatures.java,
+	  src/main/java/de/intevation/flys/client/server/features/FeaturesNamespaceContext.java,
+	  src/main/java/de/intevation/flys/client/server/features/Features.java,
+	  src/main/webapp/WEB-INF/features.xml:
+	  Implementation of a feature representation. The XMLFileFeatures class can
+	  be used to load a feature xml file (src/main/webapp/WEB-INF/features.xml)
+	  and create a map of roles to a list of features.
+
+2012-08-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/meta/Converter.java:
+	  Cosmetics, reordered code.
+
+	* src/main/java/de/intevation/flys/client/client/ui/DatacageWidget.java:
+	  Show tooltip for rows in datacage widget.
+
+2012-08-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/meta/Converter.java:
+	  Documentation added, use static map instead of population in
+	  constructor.
+
+2012-07-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixQSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ProjectList.java:
+	  Removed superfluous imports.
+
+2012-07-27  Ingo Weinzierl <ingo@intevation.de>
+
+	Tagged module as '2.8.1'.
+
+2012-07-26  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/ChartMode.java: Let
+	  'fix_vollmer_wq_curve" Output also use the NaviChartOutputTab.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added titles for the 'fix_vollmer_wq_curve' Output tab.
+
+2012-07-26	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/StyleHelper.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Merge point/line label styles. Add new style options for point/line
+	  label background.
+
+2012-07-25	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/DefaultArtifactDescription.java:
+	  Accept differing state data names of FixationArtifacts.
+
+2012-07-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/Artifact.java,
+	  src/main/java/de/intevation/flys/client/shared/model/FixAnalysisArtifact.java,
+	  src/main/java/de/intevation/flys/client/client/FLYS.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ProjectList.java:
+	  Cosmetics.
+
+2012-07-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ProjectList.java:
+	  Respect factory of cloned artifact when cloning.
+
+2012-07-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/UserCollectionsServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/ChartInfoServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java,
+	  src/main/java/de/intevation/flys/client/server/RiverServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixMultiPeriodPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixQSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/PeriodPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/WMSLayersTree.java,
+	  src/main/java/de/intevation/flys/client/client/ui/DoubleInputPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/MultiPeriodPanel.java:
+	  Removed some superfluous casts.
+
+2012-07-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Catch the case that a previous gauge is before the start of the
+	  events. This led to a broken layout.
+
+2012-07-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Bring in sync with transformation in flys-client.
+
+2012-07-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Bring in sync with transformation in flys-client. Current weakness:
+	  Only english and german locales are supported.
+
+	* src/main/java/de/intevation/flys/client/server/FixingsOverviewServiceImpl.java:
+	  Depending on client given locale call transformation with
+	  locale "de" or "en".
+
+2012-07-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl: Merged
+	  changes from transformation in flys-artifacts: Render names
+	  to the gauges into the headline. Full names and spread are
+	  displayed as tooltips.
+
+2012-07-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/OverviewOutputTab.java:
+	  Removed the export buttons for SVG and PDF; those exports aren't
+	  implemented on server side yet.
+
+2012-07-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/sq/SQCampaignChart.java:
+	  New subclass of VLayout that displays a chart with field campaigns. The
+	  code is copied from SQMultiPeriodPanel.
+
+	* src/main/java/de/intevation/flys/client/client/ui/sq/SQMultiPeriodPanel.java:
+	  Moved the code to display the field campaign charts into SQCampaignChart
+	  class.
+
+	* src/main/java/de/intevation/flys/client/client/ui/sq/SQPeriodPanel.java:
+	  New UIProvider that allows the input of a time period; the helper panel
+	  displays a chart with field campaigns.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Registered SQPeriodPanel as new UIProvider.
+
+2012-07-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Added a new UI provider that supports input of a time period (without
+	  any helper panel).
+
+2012-07-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Removed superfluous import.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Removed trailing whitespace.
+
+2012-07-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Made getChartOutputTab() protected.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Moved creation of a ChartToolbar and a ChartThemePanel from constructor to
+	  own methods which enables subclasses to override those.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/OverviewOutputTab.java:
+	  Override createThemePanel() and createChartToolbar() of parent class. Both
+	  methods return instances of minimalistic implementations of a
+	  ChartThemePanel and ChartToolbar. In addition, the overview chart is
+	  fetched as single image.
+
+2012-07-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/DoubleInputPanel.java:
+	  Read default value from Data item; set textfield to this value of a
+	  default value is existing.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/FixAnalysisArtifact.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DoubleProperty.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java:
+	  Use more idiomatic Java when parsing doubles and ints.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* ChangeLog: Removed remains from former conflict.
+
+2012-07-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixFunctionSelect.java
+	  src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java:
+	  Removed superfluous imports.
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Removed trailing whitespace.
+
+2012-07-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Register (to-be-implemented) fix.qselect_panel UIProvider.
+
+2012-07-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Prepare for bandwidthcolor, and preset bandwidth with previously
+	  entered values.
+
+2012-07-19	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java,
+	  src/main/java/de/intevation/flys/client/client/ui/WspDatacagePanel.java:
+	  Cosmetics.
+
+2012-07-19  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java:
+	  Input fields for chart navigation now use the correct i18n number formats.
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Generate only legend entries for existing discharge sectors.
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java:
+	  Replaced discharge sectors with more human readable labels.
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Added legend at bottom of overview table.
+
+2012-07-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixFunctionSelect.java:
+	  New. UI provider for function selection in fix analysis. This UI provider
+	  shows the overview and chart in the helper panel.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Use the new UI provider in function select state.
+
+2012-07-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Populate double type theme attributes with already set values.
+
+2012-07-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Code compres	  Code compression.
+
+2012-07-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Improve validation.
+
+2012-07-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ManualWSPEditor.java:
+	  Cosmetic compression.
+
+2012-07-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Added public methods to lock and unlock the CollectionView. Locking the
+	  view means, a semi transparent layer prevents the user to use the
+	  control elements in the CollectionView. In addition to the semi
+	  transparent layer, a progress image is displayed.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterList.java:
+	  Lock the CollectionView when StepBack and StepForward events are fired.
+	  Unlock the screen on success or failure.
+
+2012-07-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Handle upcoming "double" theme attribute type.
+
+2012-07-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/utils/DoubleValidator.java,
+	  src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java,
+	  src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  Cosmetics.
+
+2012-07-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/DefaultUser.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/OverviewOutputTab.java:
+	  Removed trailing whitespace.
+
+2012-07-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for bandwidth.
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Include bandwidth field.
+
+2012-07-17	Christian Lins	<christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Correct height of ChartToolbar to 35 pixels.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfoWindow.java:
+	  Make use of generics and cosmetics.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/FloodMap.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/MapOutputTab.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/MapPanel.java:
+	  ThemePanel toggle stuff.
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Increase default size as the toolbar has grown as well.
+
+	* pom.xml:
+	  Add commons-codec dependency.
+
+2012-07-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MetaDataServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/AdvanceServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterList.java:
+	  Cosmetics, docs.
+
+2012-07-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* Tagged module as '2.8'.
+
+2012-07-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java,
+	  src/main/java/de/intevation/flys/client/server/auth/Authentication.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultTheme.java,
+	  src/main/java/de/intevation/flys/client/shared/model/FacetRecord.java,
+	  src/main/java/de/intevation/flys/client/shared/model/Theme.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultData.java:
+	  Removed same package imports.
+
+2012-07-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for officiallines.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/web.xml: Separate two context params correctly.
+
+	* src/main/java/de/intevation/flys/client/server/auth/was/ServiceException.java,
+	  src/main/java/de/intevation/flys/client/server/auth/AuthenticationException.java:
+	  Removed imports.
+
+	* src/main/java/de/intevation/flys/client/server/auth/plain/Authenticator.java,
+	  src/main/java/de/intevation/flys/client/server/auth/AuthenticationFactory.java:
+	  Added debug output.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/LoginServlet.java,
+	  src/main/java/de/intevation/flys/client/server/auth/UserClient.java:
+	  Add UserClient class to handle REST communication for user related
+	  interfaces. If a logged in user is not known add him to the database
+	  via the REST protocol.
+
+2012-07-13	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/MainMenu.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/MapOutputTab.java,
+	  src/main/java/de/intevation/flys/client/client/ui/CollectionView.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Add "Manage Themes" button to ChartToolbar and MapToolbar to toggle themes window.
+
+	* pom.xml:
+	  Remove gwt-dev from dependencies as it contains an ancient Apache Commons Codec version
+	  and add a recent version of it as separate dependency.
+	  This fixes the nasty eclipse compile errors with Base64 class etc.
+
+2012-07-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/OverviewOutputTab.java:
+	  Switched row count and column count.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	 * src/main/java/de/intevation/flys/client/server/auth/DefaultUser.java,
+	   src/main/java/de/intevation/flys/client/server/auth/was/Response.java:
+	   Removed superfluous imports.
+
+2012-07-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/plain/Authenticator.java,
+	  src/main/java/de/intevation/flys/client/server/auth/DefaultUser.java:
+	  Cosmetics.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/User.java:
+	  Add javadoc for the user class.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/User.java,
+	  src/main/java/de/intevation/flys/client/server/auth/plain/Authenticator.java
+	  src/main/java/de/intevation/flys/client/server/auth/DefaultUser.java
+	  src/main/java/de/intevation/flys/client/server/auth/was/Response.java
+	  src/main/java/de/intevation/flys/client/server/auth/was/User.java:
+	  Implement getting a list of roles from a logged in user.
+
+2012-07-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* main/java/de/intevation/flys/client/server/CollectionHelper.java:
+	  Added new output mode 'overview' and added type to chart mode.
+
+	* main/java/de/intevation/flys/client/shared/model/ChartMode.java:
+	  Added type to constructor.
+
+	* main/java/de/intevation/flys/client/shared/model/OverviewMode.java:
+	  New. Output mode for chart overviews.
+
+	* main/java/de/intevation/flys/client/client/ui/chart/OverviewOutputTab.java:
+	  New. Output tab for chart overviews.
+
+	* main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/was/Request.java:
+	  Removed System.out.println debug statement for the request uri.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/webapp/WEB-INF/web.xml:
+	  Removed trailing whitespace.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GGInAFilter.java:
+	  Implement re-authentication if the user (ticket) has expired.
+	  Every "ticket" in GGInA has an end date. Therefore send a new
+	  authentication request if the current date is after the end date.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/LoginServlet.java,
+	  src/main/webapp/WEB-INF/web.xml:
+	  Use servlet context to specify the authentication method.
+	  Using the servlet context allows to set the method globally and
+	  not only for one servlet.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/webapp/FLYS.css:
+	  Add styles for the authentication error at the login page.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/LoginServlet.java:
+	  Also log an authentication failure. Several reasons could exist
+	  why an authentication will fail. Mostly because the user did provide
+	  wrong credentials but also because the GGInA protocol has changed
+	  unexpectedly. Therefore also log the error.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/webapp/login.jsp,
+	  src/main/java/de/intevation/flys/client/server/LoginServlet.java:
+	  Display exception details to the user if an authentication fails.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/Authentication.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Response.java:
+	  Extend Authentication getUser method to throw an AuthenticationException.
+	  Also the Response constructor now throws an IOException.
+
+2012-07-13	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/fly/client/server/auth/was/User.java:
+	  Derive User class from new
+	  de.intevation.fly.client.server.auth.DefaultUser class and implement
+	  hasExpired method via SAML Assertion.
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/web.xml: Set artifact server port back to 8181
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GGInAFilter.java:
+	  Cast session user to abstract type not WAS specific.
+
+2012-07-12	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Removed superfluous import.
+
+2012-07-12  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue698 (FLYS-Client: Release-Version verschluckt Clicks auf Stepback)
+
+	* src/main/java/de/intevation/flys/client/shared/model/FixFilter.java:
+	  New. The code of this class was moved from FixationPanel to FixFilter.
+
+	* src/main/java/de/intevation/flys/client/shared/model/FixAnalysisArtifact.java:
+	  Adapted the reference to FixFilter which had been an inner class of
+	  FixationPanel before.
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Moved the FixFilter code to an own top level class in the 'shared' part.
+
+2012-07-11	Christian Lins <christian.lins@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Add showpointlabel stlye attribute.
+
+2012-07-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/plain/Authenticator.java:
+	  Authenticates against simple text file. Specified by env variable FLYS_USER_FILE
+	  or system property flys.user.file .
+	  File format: One user per line, '#' at line start means comment.
+	  <user>\t<password>\t<role>
+
+	* src/main/java/de/intevation/flys/client/server/auth/DefaultUser.java:
+	  Simple user implementation.
+
+	* src/main/java/de/intevation/flys/client/server/auth/AuthenticationFactory.java:
+	  Check for 'plain' as authentication method.
+
+	* src/main/java/de/intevation/flys/client/server/auth/User.java:
+	  Expires return boolean instead of Boolean, now.
+
+	* src/main/java/de/intevation/flys/client/server/auth/was/User.java:
+	  Adjusted
+
+	* src/main/java/de/intevation/flys/client/server/auth/was/Response.java:
+	  Added override annotation.
+	  
+	* src/main/java/de/intevation/flys/client/server/auth/Authenticator.java:
+	  Removed same package imports.
+	
+2012-07-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java:
+	  Removed trailing whitespace.
+
+2012-07-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GGInAFilter.java,
+	  src/main/java/de/intevation/flys/client/client/ui/sq/SQMultiPeriodPanel.java:
+	  Removed superfluous imports.
+
+2012-07-11	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/auth/Authentication.java,
+	  src/main/java/de/intevation/flys/client/server/auth/AuthenticationFactory.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Namespaces.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/ServiceException.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Signature.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Assertion.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Request.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Authenticator.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/Response.java,
+	  src/main/java/de/intevation/flys/client/server/auth/was/User.java,
+	  src/main/java/de/intevation/flys/client/server/auth/Authenticator.java,
+	  src/main/java/de/intevation/flys/client/server/auth/AuthenticationException.java,
+	  src/main/java/de/intevation/flys/client/server/auth/User.java,
+	  src/main/webapp/WEB-INF/web.xml:
+	  Move authentication related classes to de.intevation.fly.client.server.auth
+	  package. Abstract the authentication classes to allow other authentications
+	  beside WAS/GGInA.
+
+2012-07-11	Björn Ricks	<bjoern.ricks@intevation.de>
+	* src/main/java/de/intevation/flys/client/server/GGInAFilter.java:
+	  Check filter config in web.xml for String false to deactivate the
+	  GGInAFilter instead of "1".
+
+2012-07-11	Christian Lins <christian.lins@intevation.de>
+
+	Eclipse specific project files removed from SVN.
+
+	* src/main/java/de/intevation/flys/client/server/FileUploadServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Fix exceptions on unknown style attributes.
+	  Introduce alpha transparency attribut for areas.
+
+
+2012-07-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/SQKMChartServiceImpl.java:
+	  New. Service to request the sq relation helper chart.
+
+	* src/main/java/de/intevation/flys/client/client/ui/sq/SQMultiPeriodPanel.java:
+	  New. Multi period input panel with overview chart in helper panel.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Use the new panel in sq relation period input.
+
+	* src/main/webapp/WEB-INF/web.xml:
+	  Added new service to config.
+
+2012-07-11	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GGInAFilter.java:
+	  Redirect a user to the login page if he isn't authenticated.
+
+2012-07-11	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/LoginServlet.java,
+	  src/main/webapp/login.jsp,
+	  src/main/webapp/FLYS.css,
+	  src/main/webapp/WEB-INF/web.xml:
+	  Implement a login page to be able to authenticate a user.
+
+2012-07-11	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GGInATrustStrategy.java:
+	  Add a TrustStrategy to be able to accept all SSL certificates.
+
+2012-07-11	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/was/User.java:
+	  Add a first implementation of a WAS user class.
+
+2012-07-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/was/Response.java:
+	  Directly use Base64InputStream filter stream instead of reading into
+	  memory first.
+
+2012-07-10	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* pom.xml: Add dependencies for jdom 1.1.3, Apache commons-io 2.2
+	  and Apache httpcomponents 4.2. All are dependencies are used in
+	  the new WAS classes.
+
+2012-07-10	Björn Ricks	<bjoern.ricks@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/was/Assertion.java
+	  src/main/java/de/intevation/flys/client/server/was/Request.java,
+	  src/main/java/de/intevation/flys/client/server/was/Response.java,
+	  src/main/java/de/intevation/flys/client/server/was/ServiceException.java,
+	  src/main/java/de/intevation/flys/client/server/was/Signature.java,
+	  src/main/java/de/intevation/flys/client/server/was/Namespaces.java:
+	  Implement class representation of a Web Authentication Service (WAS)
+	  request and response. If the authentication is successful the WAS
+	  responses with a base64 encoded Security Assertion Markup Language (SAML)
+	  v1.0 message.
+
+2012-07-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* pom.xml: Bumped GWT from 2.3 up to 2.4 which is the current stable.
+
+2012-07-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/CreateCollectionServiceImpl.java:
+	  Minor Cosmetics.
+
+2012-07-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ChartOutputServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/RiverServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Cosmetics, whitespaces and doc.
+
+2012-07-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ManualWSPEditor.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Removed superfluous imports.
+
+2012-07-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue706.
+
+	* src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Allow only one value to be entered by clicking.
+
+2012-07-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ManualWSPEditor.java,
+	  src/main/java/de/intevation/flys/client/client/utils/DoubleValidator.java:
+	  Removed trailing whitespace.
+
+2012-07-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Added method to deselect active controls. Currently only zoom control is
+	  deselected.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Changed type of tool bar to 'ChartToolbar'.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java:
+	  Deselect controls on navigate and return chart in 'getChartPanel'.
+
+2012-07-03  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java:
+	  Add km to chart info request parameters to get valid chart infos.
+
+2012-07-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue457.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Store and consider direction (up, down) when using the km spinner.
+
+2012-07-02	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for export of adjusted coefficients.
+
+2012-07-02	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ExportPanel.java:
+	  Make getting tooltip string more robust when trying to resolve
+	  missing I18N strings.
+
+2012-06-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Show area menu also for newer manual wsp line facet.
+
+2012-06-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualWSPEditor.java:
+	  Improved validation.
+
+	* src/main/java/de/intevation/flys/client/client/utils/DoubleValidator.java
+	  (isDouble): New, shortcut.
+
+2012-06-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualWSPEditor.java:
+	  Added basic validation
+
+2012-06-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Improved manual line editor.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Fix i18n key for buttons tooltip.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Fix translation.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualWSPEditor.java:
+	  Label the input fields, nicen dialog dimensions.
+
+2012-06-28	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Use different i18n key for button.
+	
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  new i18n strings used for the manual WSP editor button.
+
+2012-06-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Added basic GUI to register manual lines in cross section.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Add Button to register Manual WSPs.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualWSPEditor.java:
+	  New. Basic manual WSP Editor.
+	
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  new i18n strings used for the manual WSP editor.
+
+2012-06-27	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Minor refactoring.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Removed some stupid programming. Make the chart km more useful.
+
+2012-06-25	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Do not throw layout away if only the km chart needs reloading.
+	  Fix floating point vs. integer rounding issues.
+
+2012-06-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/FixingsOverviewServiceImpl.java:
+	  Removed trailing whitespace.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* pom.xml: Bumped SmartGWT to version 3.0
+	  This solves the date issues in fixings analysis for me.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java:
+	  Usability: Limit the number of displayed old items to 5. Use label "..." as
+	  a placeholder there are more.
+	
+2012-06-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java:
+	  Changed handler for km navigation input from changed to keypress listening
+	  to 'Enter'-key.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Create 
+	    "columns": { "cids": "1 2 3" }
+	  instead of 
+	    "or": ["column": { "cid": 1 }, "column": { "cid": 2 }, "column": { "cid": 3 }]
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/FixingsOverviewServiceImpl.java:
+	  Added more debug ouput about the transmitted documents.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/FixingsOverviewServiceImpl.java:
+	  Removed some XPath misuse.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Removed example comment about JSON filter.
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java:
+	  Set discharge sectors 0 and 3 as default in UI.
+
+2012-06-21	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Forgot header cell when rendering checkboxes.
+	  Some small layout adjustments.
+
+2012-06-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Extent of overview is determined by min/max km of sectors.
+
+2012-06-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ThemeListingServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java:
+	  Removed superfluous imports.
+
+2012-06-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix issue665, issue459, issue667 (zoom different in export).
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Fake a zoom-event when a zoom-value changing action was taken.
+
+2012-06-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/StyleHelper.java: Added
+	  missing class from last commit.
+
+2012-06-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/StyleHelper.java: New
+	  helper class which currently implements a function getStyle() that returns
+	  a Style object from XML Element.
+
+	* src/main/java/de/intevation/flys/client/server/CollectionItemAttributeServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/ThemeListingServiceImpl.java:
+	  Sources getStyle() out to StyleHelper.
+
+	* src/main/java/de/intevation/flys/client/shared/model/StyleSetting.java:
+	  Added new boolean property 'hidden' and improved constructor.
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Added attribute 'pointcolor' to whitelist and display only attributes that
+	  are not 'hidden'.
+
+2012-06-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  new i18n strings used in the theme editor for point colors.
+
+2012-06-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added navigation to fix analysis charts.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java:
+	  New. Chart output tab with km navigation.
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Added member variables and getter/setter for km navigation values.
+
+	* src/main/java/de/intevation/flys/client/shared/model/ChartMode.java:
+	  Create NaviChartOutputTabs for chart tabs in fix analysis.
+
+	* src/main/java/de/intevation/flys/client/server/ChartOutputServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/ChartServiceHelper.java:
+	  Added the current km as parameter in requests.
+
+	* src/main/java/de/intevation/flys/client/shared/model/FixAnalysisArtifact.java:
+	  Create the filter by getting the attributes via artifact description.
+
+2012-06-15	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/**/*.java: Removed trailing whitespace.
+
+2012-06-15  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/config.xml,
+	  src/main/webapp/WEB-INF/web.xml,
+	  pom.xml: Reverted accidently commited personal changes (ports).
+
+2012-06-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  chart and export titles for sq relation calculation in MINFO.
+
+2012-06-14  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java:
+	  Add all events to the list of selected events.
+
+2012-06-14  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Changed helper chart size to avoid overlapping in maximized project window.
+
+2012-06-14  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Render checked checkboxes in html event overview.
+
+2012-06-11	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/FixAnalysisArtifact.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java,
+	  src/main/java/de/intevation/flys/client/client/ui/PeriodPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/DoubleInputPanel.java:
+	  Removed superfluous imports.
+
+2012-06-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added UI for S-Q-relation parameters.
+
+	* src/main/java/de/intevation/flys/client/client/ui/MultipleLocationPanel.java:
+	  Use different filter strings for annotations.
+
+	* src/main/java/de/intevation/flys/client/client/ui/PeriodPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/DoubleInputPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/MultiPeriodPanel.java:
+	  New. UIProvider for S-Q-relation parameters.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Added new states for S-Q-relation.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings.
+
+2012-06-07	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Fix doc.
+
+2012-06-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java:
+	  Removed duplicated i18n methods.
+
+2012-06-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings.
+
+2012-06-07  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n stubs that let us continue working with the GUI.
+
+2012-06-05	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GGInAFilter.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixMultiPeriodPanel.java:
+	  Removed superfluous imports.
+
+2012-06-05  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java:
+	  Fixed creation of initial date string.
+
+2012-06-04	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/webapp/WEB-INF/web.xml: Register Servlet Filter.
+
+2012-06-04	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/BaseServlet.java:
+	  Cosmetics, doc.
+
+2012-06-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GGinAFilter.java:
+	  New. Stub for upcoming authentication and authorization servlet
+	  filter.
+
+2012-06-01	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java:
+	  Fixed descriptions of Q sectors.
+
+2012-06-01  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java:
+	  Changed numbers in gauge sector selection state to strings.
+
+2012-06-01  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java:
+	  Set initial values for start and end date.
+
+2012-06-01  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/FixAnalysisArtifact.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixMultiPeriodPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java:
+	  Removed some debug outputs.
+
+2012-06-01  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/FixAnalysisArtifact.java:
+	  Added filter to artifact. The artifact extracts old state data to create the
+	  filter.
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Implemented filter object.
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixMultiPeriodPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixQSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java:
+	  Removed getter and setter for filter object. Moved filter to fix artifact.
+
+2012-05-30  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixMultiPeriodPanel.java:
+	  New. UI provider for multiple date range input.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Use the new ui provider for fix analysis parameter input.
+
+2012-05-29	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+
+2012-05-28	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings used by Delta W/t export of the fixing analysis.
+
+2012-05-28  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added more i18n strings used in the floodmap datacage.
+
+2012-05-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Corrected image path to add_wms.png.
+
+2012-05-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* Tagged module as '2.7'.
+
+2012-05-24  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 671.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Added tooltips to toolbar buttons.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for tooltips.
+
+2012-05-24  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Resized the km spinner for cross section themes.
+
+2012-05-24  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Set the facet and index of the available styles to the values of the
+	  current one.
+
+2012-05-24	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Cosmetics.
+
+2012-05-23  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/FixAnalysisArtifact.java:
+	  New. Concrete artifact for fixing analysis.
+
+	* src/main/java/de/intevation/flys/client/server/FLYSArtifactCreator.java:
+	  Create a fixanalysis artifact if the project is a fixing analysis.
+
+2012-05-23  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/services/ThemeListingService.java,
+	  src/main/java/de/intevation/flys/client/client/services/ThemeListingServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/server/ThemeListingServiceImpl.java:
+	  New. Service to request themes filtered by name. Response is a list of
+	  theme groups each containing the filtered theme.
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Added a style chooser. The user can now choose predefined styles.
+
+	* src/main/webapp/WEB-INF/web.xml:
+	  Added new service.
+
+2012-05-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterMatrix.java:
+	  Removed superfluous imports.
+
+2012-05-22	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java:
+	  Make the names of state parameters configurable by constructor.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Create specialized FixPeriodPanels when using "fix.period_ref_panel" or
+	  "fix.period_ana_panel" provider types.
+
+2012-05-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixQSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SelectProvider.java:
+	  Added new method 'success', called on successful requested fixings
+	  overview document.
+	  Implemented 'createOld' to display old values.
+	  Changed data field 'name' to 'description'.
+
+2012-05-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/FixingsOverviewServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/shared/model/FixingsOverviewInfo.java:
+	  Changed data field 'name' to 'description'.
+
+2012-05-21  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/Data.java,
+	  src/main/java/de/intevation/flys/client/shared/model/IntegerOptionsData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DoubleArrayData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DoubleRangeData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/IntegerRangeData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/StringOptionsData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/LongRangeData.java:
+	  Added getter that returns the value as string.
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntegerArrayData.java:
+	  Refactored data type. Now stores data items of type IntDataItem
+	  instead of int[].
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntDataItem.java:
+	  New. Data type for int array data.
+
+	* src/main/java/de/intevation/flys/client/server/FeedServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/server/StepForwardServiceImpl.java:
+	  Use new getter in data.
+
+	* src/main/java/de/intevation/flys/client/server/DataFactory.java:
+	  Create int array data using int data items.
+
+2012-05-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added csv export and chart title for MINFO bed height calculation.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/StringOptionsData.java:
+	  Added. This class was missing in the last commit.
+
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/StringOptionsData.java:
+	  New Data implementation that should be used for user input with string
+	  options.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java,
+	  src/main/java/de/intevation/flys/client/server/DataFactory.java: Create
+	  new StringOptionsData if the data type equals "options".
+
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java.
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterMatrix.java:
+	  Enabled this panel to handle StringOptionsData.
+
+2012-05-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Render the Q class to the title of the sectors of the events.
+
+2012-05-16	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Make the description of the event the title of the date column cells.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  i18n strings for flow velocity output.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/DataFactory.java: Extract
+	  the 'label' attribute of a <data> element and set this label as
+	  description of new Data instances. If no 'label' attribute is
+	  provided, the 'name' attribute (which is required) is used as
+	  description.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java:
+	  Implemented the createOld() method to display the user specified values.
+
+2012-05-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  titles for flow velocity export.
+
+2012-05-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Changed filter data types.
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java:
+	  Add data to filterobject.
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java:
+	  Changed data type for this state.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Added preprocessing state.
+
+2012-05-15  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java:
+	  Implemented getData() which now returns the selected values from
+	  ParameterMatrix as colon separated string.
+
+2012-05-14	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ModuleSelection.java:
+	  Fix fixation analysis factory from fix to fixanalysis.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n string for fixanalysis.
+
+2012-05-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrix.java:
+	  New class that builds a matrix of checkboxes in the following form:
+
+	           | Column A | Column B | ... | Column N
+	   Value A |    [ ]   |    [ ]   | ... |   [ ]
+	   Value B |    [ ]   |    [ ]   | ... |   [ ]
+	     ...
+	   Value C |    [ ]   |    [ ]   | ... |   [ ]
+
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java: New
+	  UIProvider that uses ParameterMatrix for user input.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java:
+	  Create a new IntegerOptionsData instance if uiprovider is
+	  'parameter-matrix' and the input type is 'intoptions'.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Return an instance of ParamterMatrixPanel if the uiprovider 'parameter-
+	  matrix' is required.
+
+2012-05-14  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/MINFOArtifact.java:
+	  New Artifact that is used for the MINFO module.
+
+	* src/main/java/de/intevation/flys/client/server/FLYSArtifactCreator.java:
+	  Create new MINFO Artifacts if the Artifact's name is "minfo".
+
+	* src/main/java/de/intevation/flys/client/client/ui/DistancePanel.java:
+	  Use ArtifactDescription.getRiver() to retrieve the name of the selected
+	  river.
+
+2012-05-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapPrintServiceImpl.java:
+	  Call MapFish print via Apache Commons Http Client to re-establish
+	  LGPL conformance.
+
+	* src/main/webapp/WEB-INF/web.xml: Configured the MapFish Print servlet
+	  again. You need to adjust the init parameter 'print-url' of the 
+	  servlet MapPrintService to point to the MapFish Print servlet.
+
+	* pom.xml: Added dependency to Apache Commons Http Client 3.1
+
+2012-05-13	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for computed discharge curves in datacage.
+
+2012-05-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java:
+	  Added scrollable chart to helperpanel and added filter object class.
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation/FixLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixQSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java:
+	  Added getter and setter for filter object.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings.
+
+2012-05-11	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Fix german middleheight i18n string.
+
+2012-05-10	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapPrintServiceImpl.java:
+	  Fixed problem with selecting the wrong map scale for printing.
+
+	* src/main/webapp/WEB-INF/config.yaml: Added scales 1:2500, 1:5000, 1:10000
+	  and 1:15000 for "close-ups".
+
+2012-05-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Further input checking in kmspinner.
+
+2012-05-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	issue652: Empty spinner leads to exception.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Employ ValueFormatter and ValueParser to respect locale and stabilize.
+
+2012-05-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for showmiddleheight theme property strings.
+
+2012-05-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/config.yaml: Simplified config. Still ugly.
+
+2012-05-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapPrintServiceImpl.java:
+	  Generate legen via getlegendgraphic of the layers. Does not
+	  look too pretty right now.
+
+	* src/main/webapp/WEB-INF/config.yaml: Added legend block. We need
+	  to learn how the layout really work to make it look pretty.
+
+2012-05-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java:
+	  Added zoom listener a adjust the print link bbox. Link bbox parameters
+	  are generated correctly but the service does not respect them. Needs
+	  debugging.
+
+2012-05-09	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapPrintServiceImpl.java:
+	  Accept the case that no bbox is given. Fall back to max extent in this case.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java:
+	  Generate a valid URL for the print service.
+	  A nasty internal bug in gwtopenmaps bounds (type cast problem) prevents
+	  fetching bbox when map in new. Cope with this case.
+	  TODO: Add listeners to follow the current extent.
+
+	* src/main/webapp/WEB-INF/config.yaml: Allowed another host to fetch
+	  remote images from.
+
+2012-05-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java:
+	  Added link to print map. TODO: Figure out how create link.
+
+2012-05-07	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapPrintServiceImpl.java:
+	  Extract layer order and visibility from the describe document of
+	  the collection. TODO: Generate legend by inserting icon urls to
+	  GETLEGENDGRAPHIC of the layers.
+
+2012-05-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	First implementation for fixing analysis parameter.
+
+	* src/main/java/de/intevation/flys/client/server/FixingsOverviewServiceImpl.java:
+	  Updated services implementation. The service now returns an info
+	  object containing the fixing overview data and html representation.
+
+	* src/main/java/de/intevation/flys/client/shared/model/FixingsOverviewInfo.java:
+	  New. Info object containing overview data and html representation.
+
+	* src/main/java/de/intevation/flys/client/client/services/FixingsOverviewServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/client/services/FixingsOverviewService.java:
+	  Updated interfaces.
+
+	* src/main/java/de/intevation/flys/client/client/ui/fixation,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixQSelectPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java,
+	  src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java:
+	  New. Panels for fixing analysis parameter.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Added new UI-Provider to factory.
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl:
+	  Modified the stylesheet to take a parameter containing a callback.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings.
+
+2012-05-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapPrintServiceImpl.java:
+	  Dynamically generate spec from artifact. TODO: Interfere with collection.
+
+	* src/main/webapp/WEB-INF/config.yaml: Simplified a bit.
+
+2012-05-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapHelper.java:
+	  Added logger.isDebugEnable() as a condition for serializing
+	  XML to the log.
+
+	* src/main/java/de/intevation/flys/client/server/MapPrintServiceImpl.java:
+	  Evaluate 'uuid', 'minx', 'maxx', 'miny', 'maxy' and 'maptype'
+	  from GET parameters.
+
+2012-05-04	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapPrintServiceImpl.java:
+	  New. Call the MapPrint of MapFish Print directly. This removes the
+	  need of stupid passing around a complex JSON document to another servlet.
+	  The generation of the PDF is done nearly the same way the ShellMapPrinter
+	  works without the shell overhead.
+
+	* src/main/webapp/WEB-INF/web.xml: Register new servlet and remove old
+	  MapFish Print one.
+
+	* src/main/webapp/WEB-INF/config.yaml: Fix some image refs.
+
+2012-05-03	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for linelabel theme property strings.
+
+2012-05-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java:
+	  Parse 'helpText' field in DESCRIBE document.
+
+	* src/main/java/de/intevation/flys/client/shared/model/DataList.java:
+	  Added an attribute 'helpText' to store an URL reference to an online help
+	  page.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProvider.java,
+	  src/main/java/de/intevation/flys/client/client/ui/AbstractUIProvider.java:
+	  Defined and implemented a method to create a Canvas with a link to an
+	  online help page.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ParameterList.java:
+	  Create the link to an online help page for each current parameter and
+	  put it in front of the input panel.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ImgLink.java: Added an
+	  attribute 'newTab' that could be used to open the link in a new tab
+	  (HTML target='_blank').
+
+2012-05-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Define order for linelabel theme properties.
+
+2012-05-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for linelabel theme property strings.
+
+2012-04-26	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* pom.xml: Added dependency to MapFish Print (http://www.mapfish.org/doc/print/)
+	  License GPLv3. (This is okay, because we only use it via out-of-process calls).
+
+	* src/main/webapp/WEB-INF/web.xml: Added servlet and servlet mapping.
+
+	* src/main/webapp/WEB-INF/config.yaml: New. Just copied from MapFish config examples.
+	  TODO: Adjust for out use case.
+
+2012-04-26	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added 'showlinelabel' i18n strings.
+
+2012-04-25  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 657.
+
+	* src/main/java/de/intevation/flys/client/server/FileUploadServiceImpl.java:
+	  New. Service to upload a base64 encoded file embedded in xml structure.
+
+	* src/main/java/de/intevation/flys/client/client/ui/DigitizePanel.java:
+	  Added upload form to the UI.
+
+	* src/main/webapp/WEB-INF/web.xml:
+	  Registered new servlet and added mapping.
+
+	* pom.xml:
+	  Added dependency apache commons fileupload.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings.
+
+2012-04-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/FixingsKMChartServiceImpl.java:
+	  Use the XSL transform to render the overview.
+
+	* src/main/java/de/intevation/flys/client/server/FixingsOverviewServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/services/FixingsOverviewServiceAsync.java:
+	  Adjusted signature to pass locale, too.
+
+	* src/main/java/de/intevation/flys/client/client/services/FixingsOverviewService.java:
+	  Simplification.
+
+	* src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl: New. Generates the
+	  HTML table overview.
+
+2012-04-20	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/webapp/WEB-INF/web.xml: Fixed incorrect servlet mapping.
+
+2012-04-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Fix imports.
+
+2012-04-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/FixingsOverviewServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/services/FixingsOverviewServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/client/services/FixingsOverviewService.java:
+	  New. Stub for overview service to be called from JS side to generate the fixings
+	  overview.
+
+	* src/main/webapp/WEB-INF/web.xml: Registered new overview service.
+
+2012-04-19	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/FixingsKMChartServiceImpl.java:
+	  New. Bridge fixings km chart requests from web to artefact server. The filters
+	  have to be JSON encoded and passed in the the 'filter' parameter.
+
+	  src/main/webapp/WEB-INF/web.xml: Registered the new proxy servlet.
+
+2012-04-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Improve km-Spinner behaviour, allow text input (alpha).
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java
+	  (KmSpinner): Replaced Label by somewhat working TextItem.
+
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfoWindow.java:
+	  Adjusted the layout.
+
+2012-04-18	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapUrlServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ManualDatePointsEditor.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/MousePositionPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/ExternalWMSWindow.java,
+	  src/main/java/de/intevation/flys/client/client/ui/GaugeTimeRangePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ImgLink.java:
+	  Removed superflous imports. Some commented out because they are referenced
+	  by a big commented out block.
+
+2012-04-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Improve km-Spinner behaviour but regressing on input-possibility (no
+	direct text input possible).
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java
+	  (KmSpinner): New inner class.
+	  (createGrid): Use new inner class as experiment (old code commented).
+
+2012-04-18	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java
+	  (closest): Fix bug that prevented that always the closest km was fetched.
+
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java:
+	  Open the ManualDatePointsEditor from context menu.
+
+2012-04-18  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java:
+	  Open the ManualDatePointsEditor from context menu.
+
+2012-04-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Cosmetics.
+
+2012-04-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Cosmetics.
+
+2012-04-17	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue462.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualDatePointsEditor.java:
+	  (createUI): Avoid NPE when trying to format a NULL value).
+
+2012-04-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 494.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualDatePointsEditor.java:
+	  New. Editor to create manual points from date and y value.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Use ManualDatePointsEditor to create new points.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for error message.
+
+2012-04-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 424.
+
+	* src/main/java/de/intevation/flys/client/client/ui/DatacageWidget.java:
+	  Show folder icon for folder nodes with no children.
+
+2012-04-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 502.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/MousePositionPanel.java:
+	  Dynamically create a label for each y axis in the chart.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Added getter for transformer count.
+	  Update chart info on output parameter changed.
+
+	* src/main/java/de/intevation/flys/client/shared/model/ChartInfo.java:
+	  Added getter for transformer count.
+
+2012-04-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added missing i18n strings and removed duplicates.
+
+2012-04-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 492.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Added axis validation. Same values in fields 'from' and 'to' in axis
+	  scale are not allowed.
+
+2012-04-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  Fixed range input for 'W free'.
+
+2012-04-05  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 499.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  Added panels for 'W free' input. Added validation for 'W free' input
+	  values.
+
+2012-04-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  titles for WSPLGEN layer depths.
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Improved the layout of the window; convert HTML string into a RGB color
+	  if the type of a theme field is 'color'.
+
+2012-04-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Modified references to images.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/MeasureControl.java:
+	  Explicitly disabled mouse over effects.
+
+	* src/main/webapp/images/arrow_up.png,
+	  src/main/webapp/images/hand.png,
+	  src/main/webapp/images/mag_zoom_plus.png,
+	  src/main/webapp/images/mag_zoom_back.png,
+	  src/main/webapp/images/mag_zoom_box_Selected.png,
+	  src/main/webapp/images/mag_100_Selected.png,
+	  src/main/webapp/images/png_export_Selected.png,
+	  src/main/webapp/images/svg_export.png,
+	  src/main/webapp/images/arrow_first.png,
+	  src/main/webapp/images/properties_Selected.png,
+	  src/main/webapp/images/measure_line.png,
+	  src/main/webapp/images/measure_plane.png,
+	  src/main/webapp/images/mag_zoom_plus_Selected.png,
+	  src/main/webapp/images/png_export.png,
+	  src/main/webapp/images/info.png,
+	  src/main/webapp/images/mag_glass.png,
+	  src/main/webapp/images/save.png,
+	  src/main/webapp/images/save_Selected.png,
+	  src/main/webapp/images/pdf_export.png,
+	  src/main/webapp/images/arrow_last.png,
+	  src/main/webapp/images/mag_zoom_box.png,
+	  src/main/webapp/images/arrow_down.png,
+	  src/main/webapp/images/pdf_export_Selected.png,
+	  src/main/webapp/images/mag_zoom_minus.png,
+	  src/main/webapp/images/properties.png,
+	  src/main/webapp/images/add_map_Selected.png,
+	  src/main/webapp/images/mag_zoom_back_Selected.png,
+	  src/main/webapp/images/info_Selected.png,
+	  src/main/webapp/images/svg_export_Selected.png,
+	  src/main/webapp/images/mag_100.png,
+	  src/main/webapp/images/measure_line_Selected.png,
+	  src/main/webapp/images/add_map.png,
+	  src/main/webapp/images/measure_plane_Selected.png,
+	  src/main/webapp/images/mag_zoom_minus_Selected.png: New icons.
+
+	* src/main/webapp/images/addWMS.png,
+	  src/main/webapp/images/theme_top.png,
+	  src/main/webapp/images/zoom-in_Selected.png,
+	  src/main/webapp/images/theme_up.png,
+	  src/main/webapp/images/getFeatureInfo.png,
+	  src/main/webapp/images/getFeatureInfo_Selected.png,
+	  src/main/webapp/images/measureLine_Selected.png,
+	  src/main/webapp/images/measurePolygon_Selected.png,
+	  src/main/webapp/images/zoom-1.png,
+	  src/main/webapp/images/zoom-back.png,
+	  src/main/webapp/images/theme_bottom.png,
+	  src/main/webapp/images/zoom-in.png,
+	  src/main/webapp/images/zoom-out.png,
+	  src/main/webapp/images/measureLine.png,
+	  src/main/webapp/images/measurePolygon.png,
+	  src/main/webapp/images/theme_down.png: Removed old icons (replaced by
+	  new icons).
+
+2012-04-02  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue556 (ÜSK: neues Projekt, wenn zuvor INFO-Button verwendet wurde)
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfoWindow.java:
+	  Made window modal and display a modal mask.
+
+2012-03-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java:
+	  Take care on Nullpointers; the info button is not available in the
+	  helper panel.
+
+2012-03-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 506.
+
+	* src/main/java/de/intevation/flys/client/client/ui/GaugeTimeRangePanel.java:
+	  The Panel now accepts dates and has a date chooser.
+
+	* src/main/java/de/intevation/flys/client/shared/model/LongRangeData.java:
+	  New. Datatype for long values. Used to store dates in ms.
+
+	* src/main/java/de/intevation/flys/client/server/DataFactory.java:
+	  Added method to create LongRangeData objects.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n string for error message.
+
+2012-03-20  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue544 (Historische ATs: Eingabeunterstützung W/Q)
+
+	* src/main/java/de/intevation/flys/client/shared/model/ArtifactDescription.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultArtifactDescription.java:
+	  Added new method for fetching specific data values and a method for
+	  fetching the reference gauge number.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQSimpleArrayPanel.java:
+	  Added the WQ tables to the helper panel.
+
+
+2012-03-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GaugeInfoServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/services/GaugeInfoService.java,
+	  src/main/java/de/intevation/flys/client/client/services/GaugeInfoServiceAsync.java:
+	  New service to fetch information of gauges for a specific river.
+
+	* src/main/webapp/WEB-INF/web.xml: Registered the gauge info service.
+
+2012-03-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/GaugeImpl.java,
+	  src/main/java/de/intevation/flys/client/shared/model/Gauge.java: New
+	  model classes for gauges.
+
+2012-03-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Last step for fix flys/issue618.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Do not enable spinner if theme is disabled.
+
+2012-03-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Make synchron navigation a per-theme option, not a global one.
+
+2012-03-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue462, hinted to by Raimund Renkert.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Changed location of reference selectbox to top, resolved i18n todos.
+	 
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added and modified i18n strings.
+
+2012-03-20	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue462, hinted to by Raimund Renkert.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java
+	  (createUI): Do not try to parse NULL values.
+
+2012-03-20  Ingo Weinzierl <ingo@intevation.de>
+
+	* flys/issue204 (W-INFO: Wasserspiegellagenberechnung / Layout Auswahlunterstützung Q/W/D) 
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added and modified i18n strings.
+
+	* src/main/java/de/intevation/flys/client/client/ui/wq/QDTable.java,
+	  src/main/java/de/intevation/flys/client/client/ui/wq/WTable.java:
+	  Renamed value columns.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  Renamed tab titles for W/Q/D tables.
+
+2012-03-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/webapp/WEB-INF/wms-services.xml: More WMS services configured.
+
+2012-03-16  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 493.
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Create an empty element for the symbol property.
+
+2012-03-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* Tagged module as 'pre2.7-2012-03-16'.
+
+2012-03-15  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 630.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQAdaptedInputPanel.java:
+	  Added input helper panel to wq selection.
+
+2012-03-14  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 508.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/ExternalWMSWindow.java:
+	  Added service to load a list of WMS services and show this list in a
+	  combobox.
+
+	* src/main/java/de/intevation/flys/client/server/MapUrlServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/services/MapUrlService.java,
+	  src/main/java/de/intevation/flys/client/client/services/MapUrlServiceAsync.java:
+	  New. Service to load a list of WMS services.
+
+	* src/main/webapp/WEB-INF/wms-services.xml:
+	  New. Config file containing the list of WMS services.
+
+	* src/main/webapp/WEB-INF/web.xml:
+	  Added new service.
+
+2012-03-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 514.
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationPicker.java:
+	Remove filter if selection changes from description to range.
+
+2012-03-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 616.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Only append the synchron navigation item to context menu if the theme
+	  is a cross section.
+
+2012-03-08  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 563.
+
+	* src/main/java/de/intevation/flys/client/client/ui/Toolbar.java:
+	  Set overflow to 'auto'.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Added resize handler to increase or decrease the height if a scrollbar
+	  is visible.
+
+2012-03-08  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 553.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapPositionPanel.java:
+	  Cut the last 3 digits.
+
+2012-03-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings used in the floodmaps section of the datacage.
+
+2012-03-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java:
+	  Deactivate GetFeatureInfo tool when activating Measure tool and reverse.
+
+2012-03-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/GFIServiceImpl.java:
+	  Suppress adding superflous colons during GetFeatureInfo URL creation.
+	  Now, GetFeatureInfo requests with one layer only are queryable.
+
+2012-03-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java:
+	  Deactivate GetFeatureInfo button if another toggle button is pressed.
+
+2012-03-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ProjectList.java:
+	  Removed the last column (at the right border) of the project list which
+	  has been a placeholder for a scrollbar.
+
+2012-03-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java:
+	  Removed the last column (at the right border) of those theme panels.
+
+2012-03-05  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added I18N string for 'dems' (digital elevation models).
+
+2012-03-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial Fix flys/issue624 (removing cross section does not remove it
+	from select box).
+
+	* src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java
+	  (removeThemes): Extracted to be able to override.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java
+	  (removeThemes): Overridden to also remove theme from select box.
+			  This has side effects though (TODO).
+
+2012-03-02	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue621 (areas against deleted themes.)
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java:
+	  Do not include deleted themes in menu.
+
+2012-03-01  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue557 (ÜSK: Flächenmessung --> Tooltip falsch)
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Fixed wrong i18n string used for tooltip.
+
+2012-03-01  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue558 (ÜSK: Farbänderung in Karte / keine Änderung in der Themenliste)
+
+	* src/main/java/de/intevation/flys/client/shared/MapUtils.java: Append the
+	  current time millis at the end of the GetLegendGraphic URL to trick the
+	  caching mechanisms.
+
+2012-03-01  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue555 (ÜSK: Info-Button)
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfo.java:
+	  Close old GetFeatureInfoWindows before creating new ones.
+
+2012-03-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/ThemeList.java: New
+	  method getActiveThemes() that returns the active themes only.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfo.java:
+	  Query GetFeatureInfo for active layers only!
+
+2012-03-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Removed the Collection's UUID from title.
+
+2012-03-01  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 572.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapThemePanel.java:
+	  Catch the header double click event and do nothing, do not allow field
+	  reorder and resized style row.
+
+2012-03-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added message for datacage window.
+
+	* src/main/java/de/intevation/flys/client/client/ui/DatacageWidget.java:
+	  Display better message for an empty datacage.
+
+2012-03-01  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Fixed Issue 498.
+
+	* src/main/java/de/intevation/flys/client/server/CollectionHelper.java:
+	  Do not return 'null' if no settings are available. Returning 'null'
+	  discards theme attributes!
+
+2012-03-01	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue613 (points too big to play perfectly with other legend
+	items).
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Restrict point size. Add intermediate levels instead.
+
+2012-02-17  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/WQAdaptedInputPanel.java:
+	  Renamed state data fields: wq_mode      -> wq_isq
+	                             wq_free      -> wq_isfree
+	                             wq_selection -> wq_isrange
+	  Removed some logs.
+
+2012-02-17  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue459 (Diagramm-Export hat nicht die gleiche Axenskalierung wie
+	Diagramm-Ansicht)
+
+	* src/main/java/de/intevation/flys/client/client/ui/ImgLink.java: Added a
+	  method setSource() that allows to reset the url of the export.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Implements ZoomHandler to update the export url of PNG, PDF and SVG
+	  download links. This is necessary to take the current zoom information
+	  into account.
+
+2012-02-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Removed the server URL provided by Config. The URL is no longer
+	  required since it is configured in web.xml.
+
+2012-02-17  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ChartOutputServiceImpl.java:
+	  Print debug messages for zoom values.
+
+2012-02-16  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Refactored the wq input data fields.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/WQAdaptedInputPanel.java:
+	  Refactored the wq input data fields. The data fields wq_mode, wq_free
+	  and wq_selection are now of type 'boolean'.
+
+2012-02-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Modified german translation of qps in floodmap's datacage panel.
+
+2012-02-14	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Another partial fix/workaround for flys/issue499.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  _DIRTY_ hack to be able to enter values for "W am Pegel".
+	  The validator should check against min W / max W of the gauge
+	  where the start km is in.
+	  We currently assume hard coded that the have to be between
+	  0 and 100000.
+
+2012-02-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Another partial fix/workaround for flys/issue499.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  _DIRTY_ hack to be able to enter values for "W auf freier Strecke".
+	  We need to get the interpolated min/max Ws at the start km to do
+	  proper validation.
+	  We currently assume hard coded that the have to be between
+	  0 and 100000.
+
+2012-02-13	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	Client side fix for flys/issue499. There is an server issue, too.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  Send W/Q mode WQ_FREE if calculating "W auf freier Strecke."
+
+2012-02-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Fix flys/issue481 (i18n: Datenkorb).
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added translations some datacage entities.
+
+2012-02-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Reactivated the Enterprise Blue theme.
+
+	* src/main/java/de/intevation/flys/client/FLYS.gwt.xml:
+	  Inherit the Enterprise Blue Theme.
+
+	* src/main/java/de/intevation/flys/client/client/FLYS.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/ElevationWindow.java,
+	  src/main/java/de/intevation/flys/client/client/ui/Toolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/CollectionView.java,
+	  src/main/java/de/intevation/flys/client/client/ui/DatacageButton.java:
+	  CloseClientEvent was renamed to CloseClickEvent.
+
+	* src/main/java/de/intevation/flys/client/client/ui/DatacageWidget.java:
+	  Adjusted icon path.
+
+	* pom.xml:
+	  Added dependency for smartgwt-2.5-patch containing changes for Enterprise
+	  Blue Theme.
+
+2012-02-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/MultipleLocationPanel.java:
+	  Cosmetics, renamed local 'values' variables to avoid confusion with
+	  values field from superclass.
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationPanel.java:
+	  Cosmetics.
+
+2012-02-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/MultipleLocationPanel.java:
+	  Allow selection of more than one location via clicks to the
+	  locationpicker.
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationPanel.java:
+	  Initialize values in constructor.
+
+	* src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Minor cosmetics.
+
+2012-02-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/DoubleUtils.java:
+	  (fill,copyOf): Pendant to java.util.Arrays, which misbehaves with
+			 GWT.
+
+2012-02-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/MultipleLocationPanel.java:
+	  Minor refactoring, cosmetics and documentation.
+	  Also use translated data item name as label instead of fixed
+	  "location" string.
+
+2012-02-09	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added translations for reference curve state data.
+
+2012-02-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Cosmetics.
+
+2012-02-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	New UIProvider to enter multiple locations (so far only via keyboard).
+
+	* src/main/java/de/intevation/flys/client/client/ui/MultipleLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/LocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Refactored. New UIProvider does allow and provide multiple values,
+	  which are whitespace separated in data item.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Serve the new UIProvider if somebody orders it.
+
+2012-02-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  missing translation for "waterlevels" used in the datacage window.
+
+2012-02-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ChartInfoServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/shared/model/NumberAxis.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DateAxis.java:
+	  Removed obsolete includes.
+
+2012-02-08	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ReportServiceImpl.java:
+	  Prefix error message for a certain km with 'KM'.
+
+2012-02-08  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  missing translation for "columns" used in the datacage window.
+
+2012-02-08  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue482 (i18n: UPPER ERROS bei Historischen Abflusskurven)
+
+	* src/main/java/de/intevation/flys/client/client/ui/RangePanel.java:
+	  Defined new abstract methods to determine the max lower and upper
+	  values. Implemented the validate() method which now shows i18n error
+	  messages.
+
+	* src/main/java/de/intevation/flys/client/client/ui/IntegerRangePanel.java:
+	  Implemented the methods to determine the max lower and upper values.
+
+2012-02-08	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	Partial fix flys/issue471.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Treat as manual points every theme that ends as manualpoints.
+
+2012-02-07  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 473. Manual point input is now localized.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Added formatter and parser for 'X' and 'Y' values and return 'false' in
+	  'isDialogValid' if the grid contains any errors.
+
+2012-02-07  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/webapp/WEB-INF/web.xml: Reverted port 8182 to 8181 which is the
+	  default port of artifact-server.
+
+2012-02-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/GaugeTimeRangePanel.java:
+	  New. Shows the integer input fields and a helper table containing discharge
+	  informations.
+
+	* src/main/java/de/intevation/flys/client/client/ui/range/DischargeInfoDataSource.java:
+	  New. Data source container for discharge infos.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Create a GaugeTimeRangePanel.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for table header.
+
+2012-02-06	Felix Wolfsteller	<felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  I18N for Reference Curve export.
+
+2012-02-06  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added service to request discharge infos at a specific gauge.
+
+	* src/main/java/de/intevation/flys/client/client/services/DischargeInfoService.java,
+	  src/main/java/de/intevation/flys/client/client/services/DischargeInfoServiceAsync.java:
+	  New. Interfaces for new service.
+
+	* src/main/java/de/intevation/flys/client/server/DischargeInfoServiceImpl.java:
+	  New. Service implementation.
+
+	* src/main/java/de/intevation/flys/client/server/DischargeInfoXML.java:
+	  New. Service to request the discharge infos and provide the data via servlet
+	  to a data source object.
+
+	* src/main/java/de/intevation/flys/client/shared/model/DischargeInfoObject.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DischargeInfoObjectImpl.java:
+	  New. Interface and implementation for objects containing discharge infos.
+
+	* src/main/webapp/WEB-INF/web.xml:
+	  Added entries for discharge info servlets and servlet mappings.
+
+2012-02-06	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  I18N for "Reduzierte Bezugslinie".
+
+2012-02-06  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/Transform2D.java: A
+	  Transform2D object now knows about the type of x and y axis and implements
+	  a method format() that returns an 2dim string array with formatted values
+	  for x and y axis.
+
+	* src/main/java/de/intevation/flys/client/server/ChartInfoServiceImpl.java:
+	  Read x and y axis type for transformation matrix and create new
+	  Transform2D instances with these information. This allows the Transform2D
+	  object to format date values as well.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/MousePositionPanel.java:
+	  Don't format x and y values itself - let Transform2D do this.
+
+2012-02-06  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/Axis.java: Axis is an
+	  interface now. The code moved to NumberAxis which should be the default
+	  Axis.
+
+	* src/main/java/de/intevation/flys/client/shared/model/NumberAxis.java: New.
+	  This axis stores the parameter min, max, from and to as double values.
+
+	* src/main/java/de/intevation/flys/client/shared/model/DateAxis.java: New.
+	  This axis stores the parameter min, max, from and to as long values. These
+	  values represent the miliseconds until January 1, 1970.
+
+	* src/main/java/de/intevation/flys/client/server/ChartInfoServiceImpl.java:
+	  Create new DateAxis instances if the axis type is set to "date". In this
+	  case, the parameters from, to, min and max are parsed as Long values. The
+	  default is to create new instances of NumberAxis and to parse those values
+	  as Double.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java,
+	  src/main/java/de/intevation/flys/client/shared/model/ZoomObj.java: Save
+	  the zoom values as Number.
+
+2012-02-06  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  i18n string for the export button of historical discharge curves.
+
+2012-02-03  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/DataFactory.java: Read
+	  double values inserted for doublearray data types.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java:
+	  Create new instances of DoubleArrayData if the data type is "doublearray".
+
+	* src/main/java/de/intevation/flys/client/shared/model/DoubleArrayData.java:
+	  Do no longer subclass DefaultData but implement the whole stuff we need
+	  for a Data class.
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntegerArrayData.java:
+	  Added a method getValues() that returns the raw int values as array.
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQSimpleArrayPanel.java:
+	  Display the W/Q input values in createOld().
+
+2012-02-03	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/FloodMap.java,
+	  src/main/java/de/intevation/flys/client/client/ui/LocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Removed superfluous imports.
+
+2012-02-03  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Improvements in relation to reference curves.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java:
+	  Parse min/max values.
+
+	* src/main/java/de/intevation/flys/client/shared/model/DoubleRangeData.java:
+	  New.
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationPanel.java:
+	  Refactored to use data item name as given (take first).
+
+	* src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Exploit former refacorisation.
+
+2012-02-03  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java:
+	  Added TODO and create defaultdata for unknown typed dynamic data.
+
+2012-02-03  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/AbstractUIProvider.java
+	  (createDataArray): Helper.
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Extracted new LocationPanel class to ease code-reuse.
+
+2012-02-02  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/LocationPicker.java:
+	  Amateurly extracted Input-Helper-related code to ease code re-use.
+
+2012-02-02  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java:
+	  Removed obsolete import.
+
+2012-02-02  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/MapThemePanel.java:
+	  Removed obsolete imports.
+
+2012-02-02  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 466: CSV export for chart themes.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Added button for CSV download.
+
+	* src/main/java/de/intevation/flys/client/server/ChartOutputServiceImpl.java:
+	  Added 'csv' as export format.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added path for csv export icon.
+
+2012-02-02  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/DataFactory.java,
+	  src/main/java/de/intevation/flys/client/client/ui/AbstractUIProvider.java:
+	  Cosmetics.
+
+	* src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Cosmetics, removed MESSAGES, use super.MSG instead, comments, minor
+	  refactoring.
+
+2012-02-01  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SelectProvider.java:
+	  Cosmetics.
+
+2012-02-01  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n title for 'reference curve' output.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n title for 'historical discharge curve' output.
+
+2012-02-01  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Changed wording.
+
+2012-02-01  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue469 (I18N der Zahlen Parameterisierung (z.B. Orte))
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java:
+	  Display the I18N location string in createOld().
+
+2012-02-01  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  javadoc.
+
+2012-02-01  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java:
+	  Avoid NPEs when a theme is null (which should not happen anyways).
+
+2012-01-31  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntegerRangeData.java:
+	  Create a label "min - max" for the DataItem returned by getItems().
+
+2012-01-31  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQSimpleArrayPanel.java:
+	  Finished implementation of createOld();
+
+2012-01-31  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/DoubleArrayData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/StringData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/IntegerData.java:
+	  New. Subclasses of DefaultData. They are currently used to distinguish
+	  them during UI creation.
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntegerOptionsData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/IntegerArrayData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/IntegerRangeData.java:
+	  Added a static TYPE field.
+
+	* src/main/java/de/intevation/flys/client/server/DataFactory.java: Added
+	further methods to create concrete Data instances for specific data types.
+
+2012-01-31  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Fix strange "javascript-npes" which occurred when clicking and
+	  pressing enter too fast.
+
+2012-01-31  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Added documentation, minor cleanup.
+	  Added KeyPressHandler to km-spinnerItem, lose focus on
+	  Enter-KeyPress.
+
+2012-01-31  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Refactored und introduces a temproray regression: Update only when
+	  losing the focus (not on click or enter- press).
+
+2012-01-31  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/DataFactory.java: New.
+	  This class should be used to create new Data instances.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java:
+	  Use DataFactory to create new Data instances for the old Data objects
+	  contained in the static ui part of the Artifact's DESCRIBE document.
+
+2012-01-30  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Adjusted table height to fill the window.
+
+2012-01-30  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Get the axes name from collection settings and use them as header.
+
+2012-01-30  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Use outputmodes name to handle manual points on a per-chart basis.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Pass outputmode name to ManualPointEditor.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/OutputTab.java:
+	  Add accessor to outputmode.
+
+2012-01-30  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/DistancePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Show count of hits in filtered input helper tables.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n string.
+
+2012-01-30  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/RangeData.java:
+	  Added getDefaultLower() and getDefaultUpper() methods.
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntegerRangeData.java:
+	  Added a new constructor that takes default values for min and max and
+	  implemented the getDefaultLower() and getDefaultUpper() methods.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java:
+	  Read default values for min and max data items from DESCRIBE document.
+
+	* src/main/java/de/intevation/flys/client/client/ui/RangePanel.java:
+	  Initialize the min and max field with default values provided by
+	  RangeData's getDefaultLower() and getDefaultUpper() methods.
+
+2012-01-30  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Added basic validation of entered values at a higher level. Removed
+	  TODOs, cosmetics.
+
+2012-01-30  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Set activity field to 'active' by default.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Added dummy handling for new boolean 'active' flag of each point.
+	  Refactoring.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added translations for manual points related words.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Added basic validation and improved editing function to manual point
+	  editor. Minor refac.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Made previously entered values edit- and removable, added TODOs.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java:
+	  Docu-waitforit-mentation.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added translations for manual points related words.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java:
+	  Added context menu to open point editor from themepanel.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added accidentally ommitted german translation, use key when
+	  building ui.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Invested 2 seconds after losing 3.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/MapThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/MapOutputTab.java:
+	  Refactored to not hold own reference to Collection, always use Views
+	  one instead.
+
+2012-01-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQSimpleArrayPanel.java:
+	  Implemented the first part of createOld(). TODO: display selected data.
+
+2012-01-27  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/RangeData.java: New
+	  interface for ranges that declares two methods getUpper() and getLower().
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntegerRangeData.java:
+	  Subclasses RangeData.
+
+	* src/main/java/de/intevation/flys/client/client/ui/RangePanel.java:
+	  Implemented the createOld() method.
+
+	* src/main/java/de/intevation/flys/client/client/ui/IntegerRangePanel.java:
+	  Cast objects returned by IntegerRangeData's getLower() and getUpper()
+	  method to Integer. The signature of both methods have changed slightly.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Added i18n for points-button.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Transfer name of points.
+	  Resolved various i18n TODOs.
+	  Minor layout improvement.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added translations for manual points related words.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java:
+	  Pass updated collection to ManualPointsEditor, like this freshly
+	  added points are visible when opening the editor next time.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Cosmetics, docs.
+	
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Fire RedrawRequest when finished adding points.
+	
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Register RedrawRequestHandler with ManualPointsEditor.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java,
+	  src/main/java/de/intevation/flys/client/client/ui/map/FloodMap.java:
+	  Cosmetics, removed obsolete imports.
+
+2012-01-27  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  Cosmetics.
+
+2012-01-26  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n string for PDF export button.
+
+2012-01-26  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Added basic UI to enter 'manual points'.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java:
+	  New. UI to enter and modify manual points.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Modified constructor to avoid passing unused parameters, instantiate
+	  ManualPointsEditor on users command.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java:
+	  Reflect change in ChartToolbars constructor.
+	  (getView): New.
+
+2012-01-26  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	In preparation of 'manual points' feature, opened Collection
+	interface.
+
+	* src/main/java/de/intevation/flys/client/shared/model/Collection.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DefaultCollection.java:
+	  (getItem): Pick CollectionItem by identifier.
+
+2012-01-26  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/Recommendation.java:
+	  Fix typo, doc.
+
+	* src/main/java/de/intevation/flys/client/client/ui/DatacageTwinPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java,
+	  src/main/java/de/intevation/flys/client/client/ui/PropertyEditor.java:
+	  Cosmetics.
+
+2012-01-25  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 265.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/FloodMap.java:
+	  Added method to activate/deactivate scale line. The method removes the
+	  control on deactivation and adds the control on activation.
+
+	* src/main/java/de/intevation/flys/client/client/ui/map/MapOutputTab.java:
+	  Implements TabSelectedHandler now. If the tab is selected, the scale line
+	  and measure control are deactivated. Scale line is activated if the tab is
+	  selected.
+
+2012-01-25  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  Fix typo, more stub for add points ui.
+
+2012-01-25  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java:
+	  (adjustImageButton): Extracted/Refactored. Laid minimal groundstep
+			       for adding points ui.
+
+2012-01-24  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Suppress onCollectionChange event if an artifact is added to the collection
+	  to avoid loading maps twice. The event is triggered by the
+	  describeCollection call.
+
+2012-01-24  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/DistancePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Added filter implementation for input helper tables.
+
+2012-01-24  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java:
+	  Added filter criterion and clear filter on tab selection changed and
+	  input mode changed.
+
+2012-01-24  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java:
+	  Apply the filter input on the tables.
+
+	* src/main/java/de/intevation/flys/client/client/ui/RangeTableFilter.java:
+	  Added validator to the input fields. Validates data on key up event.
+
+	* src/main/java/de/intevation/flys/client/client/event/RangeFilterEvent.java:
+	  Use Float as data type instead of String.
+
+	* src/main/java/de/intevation/flys/client/client/utils/DoubleValidator.java:
+	  Return false if the FormItem is null.
+
+2012-01-23	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  Added UI for the simple case of the "Bezugslinienverfahren" ("W auf freier Strecke").
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties:
+	  Adjusted i18n.
+
+2012-01-23  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added UI parts and event for filtering distances and locations.
+
+	* src/main/java/de/intevation/flys/client/client/ui/RangeTableFilter.java:
+	  New. Creates textitems for user input.
+
+	* src/main/java/de/intevation/flys/client/client/event/RangeFilterEvent.java:
+	  New. The range filter events contains the 'from' and 'to' value.
+
+	* src/main/java/de/intevation/flys/client/client/event/FilterHandler.java:
+	  Added new filter criteria changed method.
+
+	* src/main/java/de/intevation/flys/client/client/ui/TableFilter.java:
+	  Set the textitem width to a fix value.
+
+	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/DistancePanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Added UI parts to Panels.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ProjectList.java:
+	  Empty implementation for range filter event. The project list has no
+	  ranges to filter.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n strings for new filter.
+
+2012-01-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Add cross sections loaded from datacage to the master artifacts list.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Overrides updateGrid() to update the list of master artifacts, too.
+
+2012-01-20  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Fix flys/issue458 (typo).
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Fix typo in key for translation.
+
+2012-01-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Set the empty facet to invisible.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java:
+	  Hide empty facets in theme list.
+
+2012-01-20  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Added new artifact to be able to open existing 'new chart' projects.
+
+	* src/main/java/de/intevation/flys/client/shared/model/ChartArtifact.java:
+	  New. Artifact for 'new chart' module.
+
+	* src/main/java/de/intevation/flys/client/server/FLYSArtifactCreator.java:
+	  Create a ChartArtifact if the artifact name equals 'new_chart'.
+
+2012-01-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQSimpleArrayPanel.java,
+	  src/main/java/de/intevation/flys/client/client/ui/RangePanel.java: Removed
+	  useless imports.
+
+2012-01-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/WQSimpleArrayPanel.java:
+	  New. This widget allows choosing between W/Q mode and inserting values as
+	  array.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added labels for historical WQ selection used in WQSimpleArrayPanel.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Create new instances of WQSimpleArrayPanel if ui provider is set to
+	  'wq_simple_array'.
+
+2012-01-19  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntegerOptionsData.java,
+	  src/main/java/de/intevation/flys/client/shared/model/IntegerArrayData.java:
+	  New Data types for better handling of options (radio buttons) and integer
+	  arrays.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java:
+	  Create new instances of IntegerOptionsData if the type is 'intoptions' and
+	  new instances of IntegerArrayData if type is 'intarray'.
+
+2012-01-19  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java:
+	  Read river from artifact description in state.chart.river to be able
+	  to load the list of locations.
+
+2012-01-19  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Set the collection if all recommended artifacts are loaded or the
+	  collection has no recommended artifacts.
+
+2012-01-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntegerRangeData.java:
+	  Modified getItems(): it will now return a single DataItem which value
+	  consists of the min and max value seperated by a ';'.
+
+	* src/main/java/de/intevation/flys/client/client/ui/TimerangePanel.java:
+	  Removed, because there is no time relevant code here. All code has moved
+	  to IntegerRangePanel.
+
+	* src/main/java/de/intevation/flys/client/client/ui/IntegerRangePanel.java:
+	  Added new methods getLowerAsInt() and getUpperAsInt() and setMaxLower()
+	  and setMaxUpper() from TimerangePanel. Furthermore, the still missing
+	  getData() method has been implemented. It returns a single
+	  IntegerRangeData object.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Create new instances of IntegerRangePanel if the ui provider is set to
+	  'intrange'.
+
+	* src/main/java/de/intevation/flys/client/client/ui/RangePanel.java: The
+	  range panel stores the data name now and has new methods that return the
+	  lower and upper value.
+
+2012-01-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/RangePanel.java: New.
+	  This panel allows inserting two values (min and max) for ranges. It is
+	  abstract, so concrete subclasses are required.
+
+	* src/main/java/de/intevation/flys/client/client/ui/IntegerRangePanel.java:
+	  New. A subclass of RangePanel that allows inserting an integer range.
+
+	* src/main/java/de/intevation/flys/client/client/ui/TimerangePanel.java:
+	  New. A subclass of IntegerRangePanel that requires an IntegerRangeData
+	  object to set the min and max values for the range.
+
+	* src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java:
+	  Create new instances of TimerangePanel if the ui provider is set to
+	  'timerange'.
+
+2012-01-18  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/IntegerRangeData.java:
+	  New. This Data instance is used to save data objects with an integer
+	  range.
+
+	* src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java:
+	  Create new instances of IntegerRangeData if the data type is 'intrange'.
+
+2012-01-16  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/FLYSArtifactCreator.java:
+	  Repaired MapArtifact creation: create new instances of this type if the
+	  name of the Artifact (provided in the DESCRIBE document) equals
+	  'new_map'. The internal name of the MapArtifact has changed in the last
+	  commits.
+
+2012-01-13  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/ModuleSelection.java:
+	  Renamed new chart module.
+
+2012-01-13  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Implemented synchronous navigationi of cross section profiles..
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added translation for synchronous navigation.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Allow switching of manyfeed/synchronous navigation via context menu.
+
+2012-01-13  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Added feedMany() function to FeedService to feed multiple artifacts
+	at once.
+
+	* src/main/java/de/intevation/flys/client/client/services/FeedService.java,
+	  src/main/java/de/intevation/flys/client/client/services/FeedServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/server/FeedServiceImpl.java:
+	  (feedMany): New. Still issue single feeds per artifact but with only
+		      one async callback.
+
+2012-01-13  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Cosmetics.
+
+	* src/main/java/de/intevation/flys/client/shared/model/Theme.java:
+	  Doc added.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java:
+	  Cosmetics, doc.
+
+2012-01-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/MapArtifact.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ModuleSelection.java:
+	  Changed the visible i18n strings for module 'new map.'
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n string for module 'new map'.
+
+2012-01-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue451.
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Load and add all recommendations together in one async request using
+	  the LoadArtifactService. This is a better way to avoid loading
+	  multiple map tabs and reduces the amount of async requests.
+
+2012-01-12  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Partial flys/issue441 (Fläche über HSQ (zweite Achse) verkehrt). 
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java:
+	  Adjust data content to what is expected on server side (to allow
+	  unique identification of facets).
+
+2012-01-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/shared/model/MapArtifact.java:
+	New. Map artifact for module 'new map'. The artifact allows to open an
+	existing map project.
+
+	* src/main/java/de/intevation/flys/client/server/FLYSArtifactCreator.java:
+	Create a new map artifact if the artifact name is 'map'.
+
+2012-01-12  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue451.
+
+	* src/main/java/de/intevation/flys/client/client/ui/CollectionView.java:
+	  Added recommendations queue. The queue avoids loading more than one
+	  map output tab.
+
+2012-01-11  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Partial flys/issue439 (Streckenfavoriten lassen sich nicht über den
+		Datenkorb hinzuladen)
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added "annotation" translation.
+
+2012-01-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/MapOutputServiceImpl.java:
+	  Find the output mode in collection to request the correct map.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n string for error message.
+
+2012-01-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 435.
+
+	* src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java:
+	  Changed request redraw event parameter from 'RESET' to 'DEFAULT'.
+
+2012-01-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Fixed initial boolean value setting.
+
+2012-01-11  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Improved validation and property handling.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Changed the way of validating and setting values.
+
+	* src/main/java/de/intevation/flys/client/client/utils/Validator.java,
+	  src/main/java/de/intevation/flys/client/client/utils/DoubleValidator.java,
+	  src/main/java/de/intevation/flys/client/client/utils/IntegerValidator.java:
+	  Changed the validator to an interface and removed the ChangedHandler
+	  implementation. The concrete validators implement the new interface.
+
+	* src/main/java/de/intevation/flys/client/shared/model/PropertySetting.java,
+	  src/main/java/de/intevation/flys/client/shared/model/BooleanProperty.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DoubleProperty.java,
+	  src/main/java/de/intevation/flys/client/shared/model/IntegerProperty.java,
+	  src/main/java/de/intevation/flys/client/shared/model/StringProperty.java:
+	  The concrete property classes return the appropriate value type for
+	  better handling.
+
+	  * src/main/java/de/intevation/flys/client/server/CollectionHelper.java:
+	  Set the values via toString() to describe document.
+
+2012-01-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 358.
+
+	* src/main/java/de/intevation/flys/client/client/utils/DoubleValidator.java:
+	  Added method to convert double values to a protocoll conform string.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Convert double values to i18n conform strings.
+
+2012-01-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Fixed initial values of boolean properties.
+
+2012-01-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Implemented the validators more object oriented.
+
+	* src/main/java/de/intevation/flys/client/client/utils/Validator.java:
+	  Removed the concrete validate methods.
+
+	* src/main/java/de/intevation/flys/client/client/utils/DoubleValidator.java,
+	  src/main/java/de/intevation/flys/client/client/utils/IntegerValidator.java:
+	  New. Implemented concrete validators.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Use the new validators to validate the input values.
+
+2012-01-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 433. Allways load original chart settings when opening the dialog.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Clone the settings object and set the original values while initializing
+	  the dialog.
+
+	* src/main/java/de/intevation/flys/client/shared/model/Property.java,
+	  src/main/java/de/intevation/flys/client/shared/model/PropertySetting.java,
+	  src/main/java/de/intevation/flys/client/shared/model/PropertyGroup.java,
+	  src/main/java/de/intevation/flys/client/shared/model/BooleanProperty.java,
+	  src/main/java/de/intevation/flys/client/shared/model/DoubleProperty.java,
+	  src/main/java/de/intevation/flys/client/shared/model/IntegerProperty.java,
+	  src/main/java/de/intevation/flys/client/shared/model/StringProperty.java,
+	  src/main/java/de/intevation/flys/client/shared/model/OutputSettings.java:
+	  Made the properties and settings classes cloneable.
+
+	* src/main/java/de/intevation/flys/client/shared/model/Collection.java:
+	  Added a method of DefaultCollection to the interface.
+
+2012-01-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 358. Validate dialog on accept.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Validate all forms before updating the chart.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added i18n string for error message.
+
+2012-01-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 358. Axis range fix.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Changed 'from' and 'to' fields for axis fixation.
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Changed i18n strings for 'from' and 'to'.
+
+2012-01-09  Raimund Renkert <raimund.renkert@intevation.de>
+
+	Issue 358. Validation.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java:
+	  Added validator to integer and double field items.
+
+	* src/main/java/de/intevation/flys/client/client/utils/Validator.java:
+	  New. Validator for SmartGWT FormItems. Currently validates integer and
+	  double values.
+
+2012-01-06  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Survive if no style for given Facet exists, notify user.
+
+2012-01-06  Ingo Weinzierl <ingo@intevation.de>
+
+	flys/issue196 (i18n/l10n: Zahlenformate einheitlich)
+
+	* src/main/java/de/intevation/flys/client/client/ui/wq/QDTable.java,
+	  src/main/java/de/intevation/flys/client/client/ui/wq/WTable.java: Set a
+	  CellFormatter for the W/Q/D columns that localizes the double values.
+
+2012-01-06  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	flys/issue442 (i18n: Datenkorb: flood-protections)
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties:
+	  Added "flood_protection" translation.
+
+2012-01-04  Felix Wolfsteller <felix.wolfsteller@intevation.de>
+
+	Adjusted the 'master' and 'km' mechanisms of CrossSections to
+	server-side changes, set stepwidth of spinner to hektokilometer.
+
+	* src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java:
+	  Do not need to sendFeed for km/master setting, set spinners
+	  stepwidth to hektokilometer.
+
+2012-01-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java:
+	  Added support for multiple point sizes.
+
+2012-01-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  strings used in the theme editor.
+
+2012-01-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/server/UserCollectionsServiceImpl.java,
+	  src/main/java/de/intevation/flys/client/client/services/UserCollectionsServiceAsync.java,
+	  src/main/java/de/intevation/flys/client/client/services/UserCollectionsService.java,
+	  src/main/java/de/intevation/flys/client/client/FLYS.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ParameterList.java,
+	  src/main/java/de/intevation/flys/client/client/ui/CollectionView.java,
+	  src/main/java/de/intevation/flys/client/client/ui/ProjectList.java,
+	  src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java:
+	  Removed unused Config.getServerUrl() calls.
+
+2012-01-04  Ingo Weinzierl <ingo@intevation.de>
+
+	* src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties,
+	  src/main/java/de/intevation/flys/client/client/FLYSConstants.java: Added
+	  strings displayed in the theme editor.
+
 2012-01-02  Ingo Weinzierl <ingo@intevation.de>
 
 	* src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java:
--- a/flys-client/FLYS.launch	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
-<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot; javaProject=&quot;FLYS&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/FLYS/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento project=&quot;FLYS&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256M"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war src/main/webapp -startupUrl FLYS.html de.intevation.flys.client.FLYS"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="FLYS"/>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-</launchConfiguration>
--- a/flys-client/FLYSTest-dev.launch	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="de.intevation.flys.client.client.FLYSTest"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot; javaProject=&quot;FLYS&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/FLYS/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/FLYS/src/test/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#13;&#10;&lt;memento project=&quot;FLYS&quot;/&gt;&#13;&#10;&lt;/runtimeClasspathEntry&gt;&#13;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry externalArchive=&quot;/vol1/download/ingo/gwt-2.1.1/gwt-dev.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="FLYS"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dgwt.args=&quot;-standardsMode -logLevel WARN&quot; -Xmx256M"/>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-</launchConfiguration>
--- a/flys-client/FLYSTest-prod.launch	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="de.intevation.flys.client.client.FLYSTest"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot; javaProject=&quot;FLYS&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/FLYS/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/FLYS/src/test/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#13;&#10;&lt;memento project=&quot;FLYS&quot;/&gt;&#13;&#10;&lt;/runtimeClasspathEntry&gt;&#13;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry externalArchive=&quot;/vol1/download/ingo/gwt-2.1.1/gwt-dev.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="FLYS"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dgwt.args=&quot;-prod -standardsMode -logLevel WARN -out www-test&quot; -Xmx256M"/>
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-</launchConfiguration>
--- a/flys-client/pom.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/pom.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -13,10 +13,10 @@
   <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
       <!-- Convenience property to set the GWT version -->
-      <gwtVersion>2.3.0</gwtVersion>
+      <gwtVersion>2.4.0</gwtVersion>
       <!-- GWT needs at least java 1.5 -->
-      <maven.compiler.source>1.5</maven.compiler.source>
-      <maven.compiler.target>1.5</maven.compiler.target>
+      <maven.compiler.source>1.6</maven.compiler.source>
+      <maven.compiler.target>1.6</maven.compiler.target>
   </properties>
 
   <dependencies>
@@ -32,16 +32,15 @@
       <version>${gwtVersion}</version>
       <scope>provided</scope>
     </dependency>
-    <dependency>
-      <groupId>com.google.gwt</groupId>
-      <artifactId>gwt-dev</artifactId>
-      <version>${gwtVersion}</version>
-      <scope>test</scope>
-    </dependency>
+    <!--dependency>
+      <groupId>com.smartgwt</groupId>
+      <artifactId>smartgwt</artifactId>
+      <version>2.5</version>
+    </dependency-->
     <dependency>
       <groupId>com.smartgwt</groupId>
       <artifactId>smartgwt</artifactId>
-      <version>2.5</version>
+      <version>3.0</version>
     </dependency>
     <dependency>
       <groupId>de.intevation.artifacts.common</groupId>
@@ -70,27 +69,75 @@
       <version>2.6</version>
     </dependency>
     <dependency>
+      <groupId>commons-fileupload</groupId>
+      <artifactId>commons-fileupload</artifactId>
+      <version>1.2.1</version>
+    </dependency>
+    <dependency>
       <groupId>org.gwtopenmaps.openlayers</groupId>
       <artifactId>gwt-openlayers-client</artifactId>
       <version>0.6</version>
     </dependency>
     <dependency>
+      <groupId>commons-httpclient</groupId>
+      <artifactId>commons-httpclient</artifactId>
+      <version>3.1</version>
+    </dependency>
+    <dependency>
+        <groupId>org.apache.httpcomponents</groupId>
+        <artifactId>httpclient</artifactId>
+        <version>4.2</version>
+    </dependency>
+    <dependency>
       <groupId>log4j</groupId>
       <artifactId>log4j</artifactId>
       <version>1.2.14</version>
     </dependency>
+    <dependency>
+      <groupId>org.mapfish.print</groupId>
+      <artifactId>print-lib</artifactId>
+      <version>1.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+        <groupId>org.jdom</groupId>
+        <artifactId>jdom</artifactId>
+        <version>1.1.3</version>
+    </dependency>
+    <dependency>
+        <groupId>commons-io</groupId>
+        <artifactId>commons-io</artifactId>
+        <version>2.2</version>
+    </dependency>
+    <dependency>
+    	<groupId>commons-codec</groupId>
+    	<artifactId>commons-codec</artifactId>
+    	<version>1.4</version>
+    </dependency>
   </dependencies>
-  
+
   <build>
     <!-- Generate compiled stuff in the folder used for developing mode --> 
     <outputDirectory>target/www/WEB-INF/classes</outputDirectory>
-    
+
     <plugins>
-      
+
       <!-- GWT Maven Plugin-->
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>gwt-maven-plugin</artifactId>
+        <version>${gwtVersion}</version>
+        <dependencies>
+          <dependency>
+            <groupId>com.google.gwt</groupId>
+            <artifactId>gwt-user</artifactId>
+            <version>${gwtVersion}</version>
+          </dependency>
+          <dependency>
+            <groupId>com.google.gwt</groupId>
+            <artifactId>gwt-dev</artifactId>
+            <version>${gwtVersion}</version>
+          </dependency>
+        </dependencies>
         <!-- JS is only needed in the package phase, this speeds up testing --> 
         <executions>
           <execution>
@@ -176,6 +223,10 @@
            <name>SmartGWT</name>
            <url>http://www.smartclient.com/maven2</url>
       </repository>
+      <repository>
+        <id>org.mapfish</id>
+        <url>http://dev.mapfish.org/maven/repository</url>
+      </repository>
     </repositories>
 </project>
 
--- a/flys-client/src/main/java/de/intevation/flys/client/FLYS.gwt.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/FLYS.gwt.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -16,13 +16,12 @@
 
   <!-- Inherit the smartgwt Enterprise Theme.                -->
   <inherits name="com.smartgwt.SmartGwtNoTheme" />
-  <inherits name="com.smartclient.theme.enterprise.Enterprise"/>
-  <inherits name="com.smartclient.theme.enterprise.EnterpriseResources"/>
+  <!--inherits name="com.smartclient.theme.enterprise.Enterprise"/>
+  <inherits name="com.smartclient.theme.enterprise.EnterpriseResources"/-->
 
-  <!-- Does not work
+  <!-- Works again with smart-gwt2.5 patch from maven repository-->
   <inherits name="com.smartclient.theme.enterpriseblue.EnterpriseBlue"/>
   <inherits name="com.smartclient.theme.enterpriseblue.EnterpriseBlueResources"/>
-  -->
 
   <!-- Works:
   <inherits name="com.smartclient.theme.graphite.Graphite"/>
--- a/flys-client/src/main/java/de/intevation/flys/client/client/FLYS.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/FLYS.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,33 +1,24 @@
 package de.intevation.flys.client.client;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
 import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.core.client.GWT;
 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;
-import com.smartgwt.client.widgets.HTMLPane;
-import com.smartgwt.client.widgets.layout.VLayout;
-import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.events.CloseClickEvent;
 import com.smartgwt.client.widgets.events.CloseClickHandler;
-import com.smartgwt.client.widgets.events.CloseClientEvent;
-
-import de.intevation.flys.client.shared.model.Artifact;
-import de.intevation.flys.client.shared.model.Collection;
-import de.intevation.flys.client.shared.model.CollectionItem;
-import de.intevation.flys.client.shared.model.River;
-import de.intevation.flys.client.shared.model.User;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
 
 import de.intevation.flys.client.client.event.CollectionChangeEvent;
 import de.intevation.flys.client.client.event.CollectionChangeHandler;
 import de.intevation.flys.client.client.services.ArtifactService;
 import de.intevation.flys.client.client.services.ArtifactServiceAsync;
+import de.intevation.flys.client.client.services.CreateCollectionService;
+import de.intevation.flys.client.client.services.CreateCollectionServiceAsync;
 import de.intevation.flys.client.client.services.DescribeCollectionService;
 import de.intevation.flys.client.client.services.DescribeCollectionServiceAsync;
 import de.intevation.flys.client.client.services.GetArtifactService;
@@ -37,12 +28,22 @@
 import de.intevation.flys.client.client.services.UserService;
 import de.intevation.flys.client.client.services.UserServiceAsync;
 import de.intevation.flys.client.client.ui.CollectionView;
+import de.intevation.flys.client.client.ui.FLYSFooter;
 import de.intevation.flys.client.client.ui.FLYSHeader;
 import de.intevation.flys.client.client.ui.FLYSView;
 import de.intevation.flys.client.client.ui.FLYSWorkspace;
 import de.intevation.flys.client.client.ui.MainMenu;
 import de.intevation.flys.client.client.ui.ProjectList;
-import de.intevation.flys.client.client.ui.FLYSFooter;
+import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.CollectionItem;
+import de.intevation.flys.client.shared.model.River;
+import de.intevation.flys.client.shared.model.User;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.MissingResourceException;
+import java.util.Set;
 
 
 /**
@@ -73,11 +74,14 @@
     protected GetArtifactServiceAsync getArtifactService =
         GWT.create(GetArtifactService.class);
 
+    /** The CreateCollectionServiceAsync used to create a new collection */
+    protected CreateCollectionServiceAsync collectionService =
+        GWT.create(CreateCollectionService.class);
 
     /** The menu bar at the top of the application. */
     protected MainMenu menu;
 
-    /** The content window. It takes the whole space beneath the menu bar.*/
+    /** The content window. It takes the whole space beneath the menu bar. */
     protected FLYSView view;
 
     /** The project list that displays the projects of the user. */
@@ -102,6 +106,7 @@
     /**
      * This is the entry point method.
      */
+    @Override
     public void onModuleLoad() {
         openProjects = new ArrayList<String>();
 
@@ -138,14 +143,25 @@
         Config config = Config.getInstance();
         String locale = config.getLocale();
 
-        getRivers();
-
         userService.getCurrentUser(locale, new AsyncCallback<User>() {
+            @Override
             public void onFailure(Throwable caught) {
                 GWT.log("Could not find a logged in user.");
-                SC.warn(MSG.getString(caught.getMessage()));
+                String msg = caught.getLocalizedMessage();
+                try {
+                    msg = MSG.getString(caught.getMessage());
+                }
+                catch(MissingResourceException ex) {
+                    // There are some server error exceptions with
+                    // varying text messages that cannot be localized
+                    // easily. In this rare cases, use the plain
+                    // exception message.
+                    GWT.log("Missing resource for: " + caught.getMessage());
+                }
+                SC.warn(msg);
             }
 
+            @Override
             public void onSuccess(User user) {
                 GWT.log("Found a user. Set '"+ user.getName() + "'");
                 setCurrentUser(user);
@@ -255,17 +271,16 @@
 
     protected void readRivers() {
         Config config = Config.getInstance();
-        String url    = config.getServerUrl();
         String locale = config.getLocale();
 
-        GWT.log("Fetch rivers from server '" + url + "'");
-
         riverService.list(locale, new AsyncCallback<River[]>() {
+            @Override
             public void onFailure(Throwable caught) {
                 GWT.log("Could not recieve a list of rivers.");
                 SC.warn(MSG.getString(caught.getMessage()));
             }
 
+            @Override
             public void onSuccess(River[] newRivers) {
                 GWT.log("Retrieved " + newRivers.length + " new rivers.");
                 rivers = newRivers;
@@ -314,11 +329,13 @@
     }
 
 
+    /** Whether project uuid is currently opened. */
     protected boolean isProjectLocked(String uuid) {
         return openProjects.contains(uuid);
     }
 
 
+    /** Opens (or bring into foreground) project with given id. */
     public void openProject(final String collectionID) {
         if (collectionID == null) {
             return;
@@ -338,10 +355,12 @@
 
         describeCollectionService.describe(collectionID, locale,
             new AsyncCallback<Collection>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     SC.warn(MSG.getString(caught.getMessage()));
                 }
 
+                @Override
                 public void onSuccess(Collection c) {
                     final Collection collection = c;
 
@@ -360,7 +379,7 @@
                         return;
                     }
 
-                    final CollectionItem   item = c.getItem(0);
+                    final CollectionItem item = c.getItem(0);
 
                     if (item == null) {
                         SC.warn(MSG.error_load_parameterization());
@@ -372,11 +391,13 @@
                         item.identifier(),
                         item.hash(),
                         new AsyncCallback<Artifact>() {
+                            @Override
                             public void onFailure(Throwable caught) {
                                 unlockProject(collectionID);
                                 SC.warn(MSG.getString(caught.getMessage()));
                             }
 
+                            @Override
                             public void onSuccess(Artifact artifact) {
                                 CollectionView view = new CollectionView(
                                     FLYS.this, collection, artifact);
@@ -407,23 +428,74 @@
      */
     public void newArtifact(String factory) {
         Config config = Config.getInstance();
-        String url    = config.getServerUrl();
         String locale = config.getLocale();
 
         artifactService.create(locale, factory, null,
             new AsyncCallback<Artifact>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("Could not create the new artifact.");
                     SC.warn(MSG.getString(caught.getMessage()));
                 }
 
+                @Override
                 public void onSuccess(Artifact artifact) {
                     GWT.log("Successfully created a new artifact.");
                 }
         });
     }
 
+    public void newGaugeDischargeCurve(String river, Long gaugeref) {
+        Config config = Config.getInstance();
 
+        final String locale = config.getLocale();
+        final String riv = river;
+        final Long ref = gaugeref;
+        final FLYS   flys = this;
+
+        User user = getCurrentUser();
+
+        if (user == null) {
+            SC.warn(MSG.error_not_logged_in());
+            return;
+        }
+
+        collectionService.create(locale, user.identifier(),
+            new AsyncCallback<Collection>() {
+                @Override
+                public void onFailure(Throwable caught) {
+                    GWT.log("Could not create new collection.");
+                    SC.warn(MSG.getString(caught.getMessage()));
+                }
+
+                @Override
+                public void onSuccess(Collection collection) {
+                    GWT.log("Successfully created a new collection.");
+                    final Collection col = collection;
+                    artifactService.createGaugeDischargeCurverArtifact(
+                        col, locale, riv, ref,
+                        new AsyncCallback<Artifact>() {
+                            @Override
+                            public void onFailure(Throwable caught) {
+                                GWT.log("Could not create the new artifact.");
+                                SC.warn(MSG.getString(caught.getMessage()));
+                            }
+
+                            @Override
+                            public void onSuccess(Artifact artifact) {
+                                GWT.log("Successfully created a new artifact.");
+                                CollectionView view = new CollectionView(flys,
+                                    col, artifact);
+                                workspace.addView("new-project", view);
+
+                                view.addCollectionChangeHandler(getProjectList());
+                            }
+                    });
+                }
+            });
+    }
+
+    @Override
     public void onCollectionChange(CollectionChangeEvent event) {
         Collection oldC = event.getOldValue();
 
@@ -448,7 +520,8 @@
             this.uuid = uuid;
         }
 
-        public void onCloseClick(CloseClientEvent event) {
+        @Override
+        public void onCloseClick(CloseClickEvent event) {
             flys.closeProject(uuid);
         }
     }
--- a/flys-client/src/main/java/de/intevation/flys/client/client/FLYSConstants.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/FLYSConstants.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,6 +8,8 @@
  */
 public interface FLYSConstants extends ConstantsWithLookup {
 
+    String add();
+
     String unexpected_exception();
 
     String title();
@@ -82,6 +84,8 @@
 
     String map();
 
+    String new_map();
+
     String new_chart();
 
     String diagram();
@@ -116,10 +120,14 @@
 
     String show_legend();
 
+    String aggregation_threshold();
+
     String scale();
 
     String databasket();
 
+    String databasket_loading();
+
     String theme_top();
 
     String theme_up();
@@ -144,6 +152,8 @@
 
     String fix();
 
+    String fixanalysis();
+
     String next();
 
     String river_km();
@@ -160,6 +170,8 @@
 
     String locations();
 
+    String single_location();
+
     String distance();
 
     String unitFrom();
@@ -208,8 +220,6 @@
 
     String too_many_values ();
 
-    String description();
-
     String from();
 
     String to();
@@ -220,12 +230,18 @@
 
     String helperPanelTitle();
 
+    String gaugePanelTitle();
+
     String wqTitle();
 
     String wqadaptedTitle();
 
+    String wqHistorical();
+
     String unitWNN();
 
+    String wqWFree();
+
     String wqW();
 
     String wqQ();
@@ -252,6 +268,10 @@
 
     String unitQStep();
 
+    String main_channel();
+
+    String total_channel();
+
     String footerHome();
 
     String footerContact();
@@ -274,6 +294,8 @@
 
     String removeTheme();
 
+    String manageThemes();
+
     String label_ok();
 
     String label_cancel();
@@ -292,6 +314,8 @@
 
     String downloadSVG();
 
+    String downloadCSV();
+
     String loadingImg();
 
     String cancelCalculation();
@@ -302,6 +326,60 @@
 
     String riverMap();
 
+    String range();
+
+    String description();
+
+    String resultCount();
+
+    String start_year();
+
+    String end_year();
+
+    String period();
+
+    String gauge_class();
+
+    String eventselect();
+
+    String events();
+
+    String kmchart();
+
+    String addPointsTooltip();
+
+    String addWSPTooltip();
+
+    String downloadPNGTooltip();
+
+    String downloadPDFTooltip();
+
+    String downloadSVGTooltip();
+
+    String downloadCSVTooltip();
+
+    String zoomToMaxExtentTooltip();
+
+    String zoomOutTooltip();
+
+    String historyBackTooltip();
+
+    String panControlTooltip();
+
+    String zoomboxTooltip();
+
+    String chartPropertiesTooltip();
+
+    // Gauges
+
+    String gauge_mnq();
+
+    String gauge_mq();
+
+    String gauge_mhq();
+
+    String gauge_hq5();
+
     // Elevation window
 
     String ele_window_title();
@@ -328,17 +406,35 @@
 
     String discharge_curve();
 
+    String gauge_discharge_curve();
+
     String computed_discharge_curve();
 
+    String computed_discharge_curves();
+
     String longitudinal_section();
 
     String duration_curve();
 
+    String reference_curve();
+
+    String reference_curve_normalized();
+
+    String reference_endpoint();
+
+    String reference_startpoint();
+
     String name();
 
     String type();
 
-    String wq_value();
+    String wq_table_w();
+
+    String wq_table_q();
+
+    String wq_value_w();
+
+    String wq_value_q();
 
     String discharge_longitudinal_section();
 
@@ -346,8 +442,22 @@
 
     String cross_section();
 
+    String cross_sections();
+
     String w_differences();
 
+    String historical_discharge();
+
+    String fix_wq_curve();
+
+    String fix_deltawt_curve();
+
+    String fix_longitudinal_section_curve();
+
+    String fix_derivate_curve();
+
+    String fix_vollmer_wq_curve();
+
     // EXPORTS
 
     String waterlevel_export();
@@ -370,18 +480,28 @@
 
     String dataexport();
 
+    String reference_curve_export();
+
     String w_differences_export();
 
+    String historical_discharge_export();
+
     String csv();
 
     String wst();
 
     String at();
 
+    String pdf();
+
     String chart_themepanel_header_themes();
 
     String chart_themepanel_header_actions();
 
+    String chart_themepanel_synchron();
+
+    String chart_themepanel_asynchron();
+
     String chart_themepanel_set_master();
 
     String chart_themepanel_new_area();
@@ -396,12 +516,54 @@
 
     String discharge();
 
+    String flow_velocity();
+
+    String flow_velocity_export();
+
+    String bedheight_middle();
+
+    String bedheight_middle_export();
+
+    String bed_longitudinal_section();
+
+    String bed_longitudinal_section_export();
+
+    String sq_relation_a();
+
+    String sq_relation_b();
+
+    String sq_relation_c();
+
+    String sq_relation_d();
+
+    String sq_relation_e();
+
+    String sq_relation_f();
+
+    String sq_relation_export();
+
+    String exportATTooltip();
+
+    String load_diameter();
+
+    String bed_diameter();
+
+    String soundings();
+
+    String bed_difference_year();
+
+    String bed_difference_epoch();
+
+    String bed_difference_height_year();
+
     // ERRORS
 
     String error_read_minmax_values();
 
     String error_validate_range();
 
+    String error_validate_date_range();
+
     String error_validate_lower_range();
 
     String error_validate_upper_range();
@@ -424,8 +586,12 @@
 
     String error_no_rivers_found();
 
+    String error_no_gaugeoverviewinfo_found();
+
     String error_no_such_user();
 
+    String error_no_users();
+
     String error_no_waterlevel_pair_selected();
 
     String error_same_waterlevels_in_pair();
@@ -476,6 +642,10 @@
 
     String error_no_map_config();
 
+    String error_no_map_output_type();
+
+    String error_no_module_found();
+
     String warning_use_first_feature();
 
     String error_no_valid_gfi_url();
@@ -498,12 +668,22 @@
 
     String error_bad_dgm_river();
 
+    String error_dialog_not_valid();
 
+    String error_invalid_date();
+
+    String error_wrong_date();
 
     String bottom_edge();
 
     String top_edge();
 
+    String error_same_location();
+
+    String error_contains_same_location();
+
+    String error_update_collection_attribute();
+
     // MAP RELATED STRINGS
 
     String digitize();
@@ -570,18 +750,32 @@
 
     String requireDGM();
 
+    String upload_file();
+
+    String shape_file_upload();
+
     // data cage
 
+    String waterlevels();
+
     String old_calculations();
 
+    String officiallines();
+
     String datacageAdd();
 
     String fixations();
 
+    String flood_protections();
+
+    String columns();
+
     String basedata();
 
     String heightmarks();
 
+    String annotation();
+
     String additionals();
 
     String differences();
@@ -606,10 +800,44 @@
 
     String fixpoints();
 
+    String uesk();
+
+    String calculations();
+
+    String current();
+
+    String bfg();
+
+    String land();
+
+    String potentiel();
+
     String rastermap();
 
     String background();
 
+    String discharge_table_nn();
+
+    String discharge_table_gauge();
+
+    String mainvalue();
+
+    String dems();
+
+    String hydrboundaries();
+
+    String gaugelocations();
+
+    String single();
+
+    String epoch();
+
+    String bedheights();
+
+    String datacage();
+
+    String datacage_add_pair();
+
     // Capabilities Information Panel
 
     String addwmsInputTitle();
@@ -666,12 +894,38 @@
 
     String display_grid();
 
+    String display_logo();
+
+    String logo_placeh();
+
+    String logo_placev();
+
+    String top();
+
+    String bottom();
+
+    String center();
+
+    String left();
+
+    String right();
+
+    String none();
+
     String linetype();
 
     String textstyle();
 
     String linecolor();
 
+    String showhorizontalline();
+
+    String showverticalline();
+
+    String horizontal();
+
+    String vertical();
+
     String textcolor();
 
     String textsize();
@@ -690,12 +944,108 @@
 
     String linesize();
 
+    String pointsize();
+
+    String bandwidth();
+
+    String pointcolor();
+
     String showlines();
 
+    String showlinelabel();
+
+    String showpointlabel();
+
+    String labelfontsize();
+
+    String labelfontcolor();
+
+    String labelfontface();
+
+    String labelfontstyle();
+
+    String labelbgcolor();
+
+    String labelshowbg();
+
+    String showwidth();
+
+    String showlevel();
+
+    String showminimum();
+
+    String showmaximum();
+
     String transparent();
 
+    String transparency();
+
     String showarea();
 
+    String showmiddleheight();
+
     String fillcolor();
+
+    String wsplgen_cat1();
+
+    String wsplgen_cat2();
+
+    String wsplgen_cat3();
+
+    String wsplgen_cat4();
+
+    String wsplgen_cat5();
+
+    // Manual Points editor
+
+    String addpoints();
+
+    String pointname();
+
+    String removepoint();
+
+    String newpoint();
+
+    String standby();
+
+    String points();
+
+    String editpoints();
+
+    // Manual WaterLine (WSP) Editor.
+
+    String addWSPButton();
+
+    String addWSP();
+
+    String selection();
+
+    String fix_deltawt_export();
+
+    String select();
+
+    String add_date();
+
+    String fix_parameters_export();
+
+    String fix_parameters();
+
+    String sq_overview();
+
+    // Gauge Overview Info
+
+    String gauge_zero();
+
+    String gauge_q_unit();
+
+    String gauge_info_link();
+
+    String gauge_river_info_link();
+
+    String gauge_river_url();
+
+    String gauge_url();
+
+    String gauge_curve_link();
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/FLYSConstants.properties	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/FLYSConstants.properties	Fri Sep 28 12:15:52 2012 +0200
@@ -1,4 +1,3 @@
-title = FLYS-3.0
 fullname = Flusshydrologische Software
 user = User:
 guest = guest
@@ -33,7 +32,8 @@
 river_selection = Rivers
 winfo = WINFO
 minfo = MINFO
-map = New Map
+new_map = New Map
+map = Map
 new_chart = New Chart
 diagram = Chart
 axes = Axes
@@ -51,44 +51,55 @@
 y3_axis = Y3-Axis
 legend_name = Name
 show_legend = Show
+aggregation_threshold = Threshold for aggregation of legend entries
 scale = Scale
 databasket = Databasket
-fix = TODO FIX ANALYSE TODO
+databasket_loading = Loading Databasket content
+fix = Fixing
+fixanalysis = Fixing Analysis
 next = Next
 location_distance_state = Choose calculation location(s) / range [km]
 distance_state = Choose calculation range [km]
 waterlevel_ground_state = Choose differences betweeen waterlevel and ground [m]
 location = Location(s)
 locations = Locations
+single_location = Location
 distance = Range
 unitFrom = km
 unitTo = km a
 unitWidth = m
 search = Search
-discharge = FIXME(Name)
+discharge = Discharge Name
 properties = Properties
 activateTheme = Activate
 deactivateTheme = Deactivate
 removeTheme = Remove
+manageThemes = Manage themes
 label_ok = Ok
 label_cancel = Cancel
 cancelCalculationLabel = Stop the current calculation.
 calculationCanceled = The calculation has been canceled.
+range = Range
+resultCount = Hits
+start_year = Start
+end_year = End
+period = Period
 
 # Header images
 flysLogo = images/flys_logo.gif
 bfgLogo = images/bfg_logo.gif
 
 # Images
-downloadPNG = images/downloadPNG.png
-downloadPDF = images/downloadPDF.png
-downloadSVG = images/downloadSVG.png
+downloadPNG = images/png_export.png
+downloadPDF = images/pdf_export.png
+downloadSVG = images/svg_export.png
+downloadCSV = images/save.png
 loadingImg = images/loading.gif
 cancelCalculation = images/cancelCalculation.png
 markerRed = images/marker_red.png
 markerGreen = images/marker_green.png
 riverMap = images/gewkarte.png
-properties_ico = images/properties.gif
+properties_ico = images/properties.png
 
 dpLabelFrom = From
 dpUnitFrom = km
@@ -113,6 +124,19 @@
 missingInput = You need to enter a value.
 too_many_values = Only one value allowed
 
+addPointsTooltip = Add manual points
+addWSPTooltip = Add manual LS
+downloadPNGTooltip = Download chart as PNG
+downloadPDFTooltip = Download chart as PDF
+downloadSVGTooltip = Download chart as SVG
+downloadCSVTooltip = Download data as CSV
+zoomToMaxExtentTooltip = Zoom to max extent
+zoomOutTooltip = Zoom out
+historyBackTooltip = Previous zoom
+panControlTooltip = Pan
+zoomboxTooltip = Zoombox
+chartPropertiesTooltip = Chartproperties
+
 description = Description
 from = From
 to = To
@@ -121,16 +145,22 @@
 top_edge = Top edge
 name = Name
 type = Type
-wq_value = Q/D
+wq_table_w = Characteristic Waterlevels
+wq_table_q = Characteristic Discharges / Durations
+wq_value_w = W [cm at Gauge]
+wq_value_q = Q [m\u00b3/s]
 river_km = River-Km
 uesk_profile_distance = Distance [m]
 
 wqTitle = Input for W/Q Data
 wqadaptedTitle = Input for W/Q Data
+wqHistorical = Selection of Analyse Type
 calcTableTitle = Calculated Output
 helperPanelTitle = Input Support
+gaugePanelTitle = Gauge Information
 wqW = W at Gauge [cm]
 wqQ = Q [m\u00b3/s]
+wqWFree = W free position [m+NHN]
 wqQGauge = Discharge at Gauge
 wqSingle = Single values
 wqRange = Range
@@ -143,34 +173,69 @@
 unitQFrom = m³/s&nbsp;-
 unitQTo = m³/s&nbsp;a
 unitQStep = m³/s
+main_channel = Main Channel
+total_channel = Total Channel
 footerHome = Home
-footerContact = Kontakt
-footerImpressum = Impressum
+footerContact = Contact
+footerImpressum = Legal info
 
 buttonNext = Next
 imageBack = images/back_en.png
-imageSave = images/save.gif
-theme_top = images/theme_top.png
-theme_up = images/theme_up.png
-theme_down = images/theme_down.png
-theme_bottom = images/theme_bottom.png
-zoom_all = images/zoom-1.png
-zoom_in = images/zoom-in.png
-zoom_out = images/zoom-out.png
-zoom_back = images/zoom-back.png
-pan = images/pan.png
+imageSave = images/save.png
+theme_top = images/arrow_first.png
+theme_up = images/arrow_up.png
+theme_down = images/arrow_down.png
+theme_bottom = images/arrow_last.png
+zoom_all = images/mag_100.png
+zoom_in = images/mag_zoom_box.png
+zoom_out = images/mag_zoom_minus.png
+zoom_back = images/mag_zoom_back.png
+pan = images/hand.png
 askThemeRemove = Are you sure that you want to remove the selected theme / themes?
+add = Add
 
 discharge_curve = Discharge Curves at Gauges
+gauge_discharge_curve = Discharge Curves at Gauge
 computed_discharge_curve = Discharge Curve
+computed_discharge_curves = Discharge Curves
 longitudinal_section = Longitudinal Section Curve
 duration_curve = Duration Curve
 discharge_longitudinal_section = Discharge Longitudinal Section
 floodmap = Floodmap
-
+historical_discharge = Historical Discharge Curves
+flow_velocity = Flow Velocity
+flow_velocity_export = Flow Velocity Export
+bedheight_middle = Middle Bed Height
+bedheight_middle_export = Middle Bed Height Export
+bed_longitudinal_section = Bed Quality
+bed_longitudinal_section_export = Bed Quality Export
+sq_relation_a = A Feinkornanteil
+sq_relation_b = B Sand (Suspensionstransport)
+sq_relation_c = C Sand (Geschiebetransport)
+sq_relation_d = D Fein- und Mittelkies
+sq_relation_e = E Grobkornanteil (> Mittelkies)
+sq_relation_f = F Geschiebetransport Gesamt
+sq_relation_export = SQ Export
 cross_section = Cross Section
+cross_sections = Cross Sections
 w_differences = Differences
 w_differences_export = Differences Export
+reference_curve_export = Reference Curve Export
+historical_discharge_export = Historical Discharge Curve Export
+fix_wq_curve = W/Q
+fix_deltawt_curve = \u0394 W/t
+fix_longitudinal_section_curve = Longitudinal Section
+fix_derivate_curve = Derivate
+fix_vollmer_wq_curve = W/Q
+datacage_add_pair = Add difference pair
+load_diameter = Bedload Diameter
+bed_diameter = Bed Diameter
+soundings = Soundings
+bed_difference_year = Single Bedheight Differences
+bed_difference_epoch = Epoch Bedheight Differences
+bed_difference_height_year = Bedheight Differences per year
+
+exportATTooltip = Export as AT file
 
 waterlevel_export = Waterlevel Export
 waterlevel_report = Waterlevel Report
@@ -180,14 +245,21 @@
 discharge_longitudinal_section_report = Discharge Longitudinal Section Report
 durationcurve_export = Duration Curve Export
 durationcurve_report = Duration Curve Report
-dataexport = Datenexport
+dataexport = Data export
 csv = CSV
 wst = WST
 at = AT
+pdf = PDF
 computed_dischargecurve_at_export = AT Export
+gauge_class = Gauge Class
+eventselect = Eventselection
+events = Events
+kmchart = Chart
 
 chart_themepanel_header_themes = Theme
 chart_themepanel_header_actions = Actions
+chart_themepanel_synchron = Navigate synchronously
+chart_themepanel_asynchron = Navigate independently
 chart_themepanel_set_master = Reference
 chart_themepanel_new_area = New Area...
 chart_themepanel_area_under = under ...
@@ -195,6 +267,11 @@
 chart_themepanel_area_between = between ...
 against_x_axis = Over X-Axis
 
+gauge_mnq = around MNQ
+gauge_mq  = around MQ
+gauge_mhq = around MHQ
+gauge_hq5 = above HQ5
+
 ele_window_title = Elevation Node
 ele_window_label = Elevation settings in m \u00fc. NN.
 ele_window_x_col = X
@@ -209,6 +286,7 @@
 unexpected_exception = There occured an unexpected exception
 error_read_minmax_values = Error while reading min/max values for the location input.
 error_validate_range = The value $1 needs to be smaller than $3 and bigger than $2.
+error_validate_date_range = Start date needs to be before end date.
 error_validate_lower_range = The lower value $1 needs to be bigger than $2.
 error_validate_upper_range = The upper value $1 needs to be smaller than $2.
 error_empty_state = Required inputs are missing.
@@ -223,10 +301,13 @@
 error_describe_collection = Error while fetching the projects state.
 error_no_rivers_found = Error while reading supported rivers.
 error_no_such_user = Error - no such user found.
+error_no_users = Error - no users found.
 error_no_waterlevel_pair_selected = Error - no waterlevel pair for building differences selected.
 error_same_waterlevels_in_pair = Error - minuend and subtrahend have to differ.
 error_not_logged_in = You need to log in before you are allowed to start your work.
 error_load_parameterization = Could not load the parameterization.
+error_wrong_date = Please enter valid dates.
+error_no_gaugeoverviewinfo_found = Error while fetching the river and gauge info
 
 error_feed_no_data = No input data found.
 error_feed_from_out_of_range = The lower value is bigger than the upper value.
@@ -248,6 +329,7 @@
 error_no_theme_styles_found=No style for the selected theme found.
 error_no_feature_selected = No object selected.
 error_no_map_config = No Map configuration found.
+error_no_map_output_type = No Map output found.
 warning_use_first_feature = You have more that one object selected. The first one is used.
 error_no_valid_gfi_url = No valid GetFeatureInfo response found.
 error_gfi_req_failed = GetFeatureInfo request failed.
@@ -259,6 +341,12 @@
 error_invalid_dgm_selected = You have selected an invalid DEM.
 error_bad_dgm_range = You have selected a DEM with an invalid range.
 error_bad_dgm_river = You have selected a DEM for a wrong river.
+error_dialog_not_valid = One or more values are not valid.
+error_invalid_date = The entered date is not valid.
+error_same_location = Reference location equals selected location.
+error_contains_same_location = Target locations contains reference location.
+error_update_collection_attribute = Error while updating the collection attribut
+error_no_module_found = No modules found
 
 ## map related strings
 digitize = images/digitize.png
@@ -269,14 +357,14 @@
 ring_dike = Ringdike
 selectFeature = images/selectFeature.png
 removeFeature = images/removeFeature.png
-getFeatureInfo = images/getFeatureInfo.png
+getFeatureInfo = images/info.png
 getFeatureInfoTooltip = Information Tool
 getFeatureInfoWindowTitle = Informations for Map Layers.
-addWMS = images/addWMS.png
+addWMS = images/add_map.png
 addWMSTooltip = Load layers from external WMS service.
 adjustElevation = images/adjustElevation.png
-measureLine = images/measureLine.png
-measurePolygon = images/measurePolygon.png
+measureLine = images/measure_line.png
+measurePolygon = images/measure_plane.png
 step = Step
 calculationStarted = Calculation started.
 zoomMaxExtent = Max extent
@@ -293,13 +381,20 @@
 map_themepanel_header_style = Style
 zoomToLayer = Layer-Zoom
 requireDGM = You need to choose a DEM.
+upload_file = upload
+shape_file_upload = Upload shapefile
 
 # data cage
+waterlevels = Waterlevels
 old_calculations = Former Calculations
+officiallines = Official lines
 datacageAdd = Add data
 heightmarks = Height Marks
 basedata = Base Data
 fixations = Fixations
+flood_protections = Flood Protections
+columns = Columns
+annotation = Annotations
 additionals = Additional Longitudinal Section Curves
 differences = Differences
 kilometrage = Kilometrage
@@ -312,8 +407,24 @@
 lines = Lines
 buildings = Buildings
 fixpoints = Fixpoints
+uesk = Floodmaps
+calculations = Calculations
+current = Current
+potentiel = Potentiel
+bfg = BfG
+land = Land
 rastermap = Rastermap
 background = Background Map
+discharge_table_nn = Discharge Tables at Gauge
+discharge_table_gauge = Discharge Table at Gauge
+mainvalue = Mainvalue
+dems = Digital Elevation Models
+hydrboundaries = Hydrological Boundaries
+gaugelocations = Location of Gauges
+single = Year
+epoch = Epoch
+bedheights = Bedheights
+datacage = Datacage
 
 # capabilities information panel
 addwmsInputTitle = Base URL of WMS service
@@ -338,18 +449,29 @@
 width = Width
 height = Height
 visibility = Visibility
-upper = from
-lower = to
+upper = to
+lower = from
 fixation = Fix
 font_size = Fontsize
 label = Title
 title = Title
 subtitle = Subtitle
 display_grid = Display grid
+display_logo = Display logo
+logo_placeh = Horiz. Place for logo
+logo_placev = Vertic. Place for logo
+top = top
+bottom = bottom
+center = center
+left = left
+right = right
+none = none
 
 linetype = Linetype
 textstyle = Textstyle
 linecolor = Linecolor
+showhorizontalline = Show horizonal line
+showverticalline = Show vertical line
 textcolor = Textcolor
 textsize = Textsize
 font = Font
@@ -358,8 +480,67 @@
 backgroundcolor = Backgroundcolor
 textorientation = Textorientation
 linesize = Linesize
+pointsize = Pointsize
+bandwidth = Bandwidth
+pointcolor = Punktfarbe
 showlines = Show lines
+showlinelabel = Show line label
+showpointlabel = Show point label
+labelfontface = Label: Font
+labelfontcolor = Label: Color
+labelfontsize = Label: Size
+labelfontstyle = Label: Style
+labelbgcolor = Label: Background Color
+labelshowbg = Label: Show Background
+horizontal = horizontal
+vertical = vertical
+showwidth = Show width
+showlevel = Show waterlevel
+showminimum = Show minimum
+showmaximum = Show maximum
 showborder = Show line
 transparent = Transparency
+transparency = Transparency
 showarea = Show Area
+showmiddleheight = Show middle depth
 fillcolor = Fill Color
+wsplgen_cat1 = Fill Color 0.0 <= DIFF < 1
+wsplgen_cat2 = Fill Color 1.0 <= DIFF < 2
+wsplgen_cat3 = Fill Color 2.0 <= DIFF < 3
+wsplgen_cat4 = Fill Color 3.0 <= DIFF < 4
+wsplgen_cat5 = Fill Color 4.0 <= DIFF
+
+# Manual Points Editor
+addpoints = Add points
+pointname = Name
+removepoint = Remove
+newpoint = New Point
+standby = Creating Artifact ... please wait.
+points = Points
+editpoints = Edit Points
+addWSPButton = Add Manual LS
+addWSP = Add Manual LS
+selection = Selection
+
+# Reference Curves
+reference_curve = Reference Curve
+reference_curve_normalized = Reduced Reference Curve
+reference_startpoint = Point of reference
+reference_endpoint = Point(s) of projection
+
+fix_deltawt_export = \u0394 W/t
+select=Selected
+add_date=Add
+
+fix_parameters_export = Adjusted coefficient
+fix_parameters = CSV
+
+sq_overview=Overview
+
+gauge_zero = Gauge zero ground
+gauge_q_unit = m\u00b3/s
+gauge_river_info_link = Riverinfo
+gauge_info_link = Gaugeinfo
+gauge_url = https://flys-intern.intevation.de/PegelInfo/
+gauge_river_url = https://flys-intern.intevation.de/GewaesserInfo/
+gauge_curve_link = Dischargecurve
--- a/flys-client/src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/FLYSConstants_de.properties	Fri Sep 28 12:15:52 2012 +0200
@@ -1,4 +1,3 @@
-title = FLYS-3.0
 fullname = Flusshydrologische Software
 user = Benutzer:
 guest = Gast
@@ -33,7 +32,8 @@
 river_selection = Gew\u00e4sser
 winfo = WINFO
 minfo = MINFO
-map = Neue Karte
+map = Karte
+new_map = Neue Karte
 new_chart = Neues Diagramm
 diagram = Diagramm
 axes = Achsen
@@ -41,7 +41,7 @@
 chart_title = Titel
 chart_subtitle = Untertitel
 grid = Gitternetz
-antialiasing = Kantenglättung
+antialiasing = Kantengl\u00e4ttung
 axis_name = Name
 chart_start = von
 chart_end = bis
@@ -51,15 +51,19 @@
 y3_axis = Y3-Achse
 legend_name = Name
 show_legend = Anzeigen
+aggregation_threshold = Schwellwert zur Aggregation von Legendeneintr\u00e4gen
 scale = Skalierung
 databasket = Datenkorb
+databasket_loading=Lade Datenkorb Inhalt
 fix = Fixierungsanalyse
+fixanalysis = Fixierungsanalyse
 next = Weiter
 location_distance_state = Berechnungsort(e) / strecke w\u00e4hlen [km]
 distance_state = Berechnungsstrecke w\u00e4hlen [km]
 waterlevel_ground_state = Differenzen zwischen Wasserspiegel und Gel\u00e4nde [m]
 location = Ort(e)
 locations = Orte
+single_location = Ort
 distance = Strecke
 unitFrom = km&nbsp;-
 unitTo = km a
@@ -70,25 +74,31 @@
 activateTheme = Aktivieren
 deactivateTheme = Deaktivieren
 removeTheme = Entfernen
+manageThemes = Themen verwalten
 label_ok = Ok
 label_cancel = Abbrechen
 cancelCalculationLabel = Aktuelle Berechnung abbrechen.
 calculationCanceled = Die Berechnung wurde abgebrochen.
-
+range = Bereich
+resultCount = Treffer
+start_year = Start
+end_year = Ende
+period = Zeitraum
 # Header images
 flysLogo = images/flys_logo.gif
 bfgLogo = images/bfg_logo.gif
 
 # Images
-downloadPNG = images/downloadPNG.png
-downloadPDF = images/downloadPDF.png
-downloadSVG = images/downloadSVG.png
+downloadPNG = images/png_export.png
+downloadPDF = images/pdf_export.png
+downloadSVG = images/svg_export.png
+downloadCSV = images/save.png
 loadingImg = images/loading.gif
 cancelCalculation = images/cancelCalculation.png
 markerRed = images/marker_red.png
 markerGreen = images/marker_green.png
 riverMap = images/gewkarte.png
-properties_ico = images/properties.gif
+properties_ico = images/properties.png
 
 dpLabelFrom = Von
 dpUnitFrom = km
@@ -121,16 +131,22 @@
 riverside = Flussseite
 name = Name
 type = Typ
-wq_value = Q/D
+wq_table_w = Kennzeichnende Wasserst\u00e4nde
+wq_table_q = Kennzeichnende Abfl\u00fcsse / Dauerzahlen
+wq_value_w = W [cm am Pegel]
+wq_value_q = Q [m\u00b3/s]
 river_km = Fluss-Km
 uesk_profile_distance = Abstand [m]
 
 wqTitle = Eingabe f\u00fcr W/Q Daten
 wqadaptedTitle = Eingabe f\u00fcr W/Q Daten
+wqHistorical = Auswahl der Analyseart
 calcTableTitle = Berechnungsausgabe
 helperPanelTitle = Eingabeunterst\u00fctzung
+gaugePanelTitle = Gew\u00e4sser/Pegel-Info
 wqW = W am Pegel [cm]
 wqQ = Q [m\u00b3/s]
+wqWFree = W auf freier Strecke [m+NHN]
 wqQGauge = Kennzeichnender Abfluss am Pegel
 wqSingle = Einzelwerte
 wqRange = Wertebereich
@@ -143,34 +159,80 @@
 unitQFrom = m\u00b3/s&nbsp;-
 unitQTo = m\u00b3/s&nbsp;a
 unitQStep = m\u00b3/s
+main_channel = Hauptgerinne
+total_channel = Gesamtgerinne
 footerHome = Home
 footerContact = Kontakt
 footerImpressum = Impressum
 
 buttonNext = \u00dcbernehmen
 imageBack = images/back_de.png
-imageSave = images/save.gif
-theme_top = images/theme_top.png
-theme_up = images/theme_up.png
-theme_down = images/theme_down.png
-theme_bottom = images/theme_bottom.png
-zoom_all = images/zoom-1.png
-zoom_in = images/zoom-in.png
-zoom_out = images/zoom-out.png
-zoom_back = images/zoom-back.png
-pan = images/pan.png
+imageSave = images/save.png
+theme_top = images/arrow_first.png
+theme_up = images/arrow_up.png
+theme_down = images/arrow_down.png
+theme_bottom = images/arrow_last.png
+zoom_all = images/mag_100.png
+zoom_in = images/mag_zoom_box.png
+zoom_out = images/mag_zoom_minus.png
+zoom_back = images/mag_zoom_back.png
+pan = images/hand.png
 askThemeRemove = Sind Sie sicher, dass sie die gew\u00e4hlten / das gew\u00e4lte Thema l\u00f6eschen wollen?
+add = Hinzuf\u00fcgen
+
+addPointsTooltip = Manuelle Punkte hinzuf\u00fcgen
+addWSPTooltip = Manuelle WSP hinzuf\u00fcgen
+downloadPNGTooltip = Diagramm als PNG herunterladen
+downloadPDFTooltip = Diagramm als PDF herunterladen
+downloadSVGTooltip = Diagramm als SVG herunterladen
+downloadCSVTooltip = Daten als CSV herunterladen
+zoomToMaxExtentTooltip = Auf maximale Ausdehnung zoomen
+zoomOutTooltip = Herauszoomen
+historyBackTooltip = Voriger Zoom
+panControlTooltip = Verschieben
+zoomboxTooltip = Ausschnitt vergr\u00f6\u00dfern
+chartPropertiesTooltip = Diagrammeigenschaften
 
 discharge_curve = Abflusskurven an Pegeln
+gauge_discharge_curve = Abflusskurven an Pegel
 computed_discharge_curve = Abflusskurve
+computed_discharge_curves = Abflusskurven
 longitudinal_section = L\u00e4ngsschnitt
 duration_curve = Dauerlinie
-discharge_longitudinal_section = W bei ungleichwertigem Abflussl\u00e4ngsschnitt
+discharge_longitudinal_section = W f\u00fcr ungleichwertigen Abflussl\u00e4ngsschnitt
 floodmap = \u00dcberschwemmungsfl\u00e4che
-
+historical_discharge = Historische Abflusskurven
+flow_velocity = Flie\u00dfgeschwindigkeiten
+flow_velocity_export = Flie\u00dfgeschwindigkeiten Export
+bedheight_middle = Mittlere Sohlh\u00f6he
+bedheight_middle_export = Mittlere Sohlh\u00f6he Export
+bed_longitudinal_section = Sohlbeschaffenheit
+bed_longitudinal_section_export = Sohlbeschaffenheit Export
+sq_relation_a = A Feinkornanteil
+sq_relation_b = B Sand (Suspensionstransport)
+sq_relation_c = C Sand (Geschiebetransport)
+sq_relation_d = D Fein- und Mittelkies
+sq_relation_e = E Grobkornanteil (> Mittelkies)
+sq_relation_f = F Geschiebetransport Gesamt
+sq_relation_export = SQ Export
 cross_section = Querprofil
+cross_sections = Querprofile
 w_differences = Differenzen
 w_differences_export = Differenzen Export
+reference_curve_export = Bezugslinien Export
+historical_discharge_export = Historische Abflusskurven Export
+fix_wq_curve = W/Q
+fix_deltawt_curve = \u0394 W/t
+fix_longitudinal_section_curve = L\u00e4ngsschnitt
+fix_derivate_curve = Ableitungskurve
+fix_vollmer_wq_curve = W/Q
+datacage_add_pair = Differenzenpaar hinzuf\u00fcgen
+load_diameter = Geschiebedurchmesser
+bed_diameter = Sohldurchmesser
+soundings = Peilungen
+bed_difference_year = Sohlh\u00f6hendifferenz (Jahr)
+bed_difference_epoch = Sohlh\u00f6hendifferenz (Epoche)
+bed_difference_height_year = Sohlh\u00f6hendifferenz pro Jahr
 
 waterlevel_export = Wasserstand/Wasserspiegellagen Export
 waterlevel_report = Wasserstand/Wasserspiegellagen Bericht
@@ -184,10 +246,19 @@
 csv = CSV
 wst = WST
 at = AT
+pdf = PDF
 computed_dischargecurve_at_export = AT Export
+gauge_class = Abflussklasse
+eventselect = Ereignisauswahl
+events = Ereignisse
+kmchart = Diagramm
+
+exportATTooltip = Daten als AT Datei exportieren
 
 chart_themepanel_header_themes = Thema
-chart_themepanel_header_action = Aktionen
+chart_themepanel_header_actions = Aktionen
+chart_themepanel_synchron = Synchron navigieren
+chart_themepanel_asynchron = Einzeln navigieren
 chart_themepanel_set_master = Referenz
 chart_themepanel_new_area = Erzeuge Fl\u00e4che ...
 chart_themepanel_area_under = unter ...
@@ -195,6 +266,11 @@
 chart_themepanel_area_between = zwischen ...
 against_x_axis =  \u00fcber X-Achse
 
+gauge_mnq = um MNQ
+gauge_mq  = um MQ
+gauge_mhq = um MHQ
+gauge_hq5 = \u00fcber HQ5
+
 ele_window_title = H\u00f6henknoten setzen
 ele_window_label = H\u00f6henangaben in m \u00fc. NN.
 ele_window_x_col = X
@@ -209,6 +285,7 @@
 unexpected_exception = Ein unerwarteter Fehler ist aufgetreten
 error_read_minmax_values = Fehler beim Lesen der min/max Werte. Es kann keine Validierung der eingegebenen Strecke durchgef\u00fchrt werden.
 error_validate_range = Der Wert $1 muss kleiner als $3 und gr\u00f6\u00dfer als $2 sein.
+error_validate_date_range = Anfangsdatum muss früher sein als Enddatum.
 error_validate_lower_range = Der untere Wert $1 muss gr\u00f6\u00dfer sein als $2.
 error_validate_upper_range = Der obere Wert $1 muss kleiner sein als $2.
 error_empty_state = Es wurden nicht alle ben\u00d6tigten Daten eingegeben.
@@ -222,11 +299,14 @@
 error_create_collection = Fehler beim Erstellen eines neuen Projektes.
 error_describe_collection = Fehler beim Laden des Projektzustandes.
 error_no_rivers_found = Fehler beim Lesen der unterst\u00fctzten Fl\u00fcsse.
-error_no_such_user = Fehler - Kein Benutzer vorhanden.
+error_no_such_user = Fehler - Kein solcher Benutzer vorhanden.
+error_no_users = Fehler - Keine Benutzer vorhanden.
 error_no_waterlevel_pair_selected = Fehler - kein Paar zur Differenzenbildung gew\u00e4hlt.
 error_same_waterlevels_in_pair = Error - minuend and subtrahend m\u00fcssen sich unterscheiden.
 error_not_logged_in = Sie m\u00fcssen sich erst einloggen um mit der Arbeit beginnen zu k\u00f6nnen.
 error_load_parameterization = Fehler beim Laden der Parametrisierung.
+error_wrong_date = Bitte geben Sie gültige Daten ein.
+error_no_gaugeoverviewinfo_found = Fehler beim Laden der Fluss- und Pegelinformationen
 
 error_feed_no_data = Keine Eingabedaten gefunden.
 error_feed_from_out_of_range = Der untere Wert liegt au\u00dferhalb des g\u00fcltigen Wertebereiches.
@@ -248,6 +328,7 @@
 error_no_theme_styles_found=Es konnten keine Stile f\u00fcr das gew\u00e4hlte Thema gefunden werden.
 error_no_feature_selected = Kein Objekt ausgew\u00e4hlt.
 error_no_map_config = Es konnte keine Kartenkonfiguration gefunden werden.
+error_no_map_output_type = Es konnte kein Ausgabemodus f\u00fcr Karten gefunden werden.
 warning_use_first_feature = Sie haben mehr als ein Objekt ausgew\u00e4hlt. Das erste Objekt wird benutzt.
 error_no_valid_gfi_url = Ung\u00fcltige GetFeatureInfo URL.
 error_gfi_req_failed = Die GetFeatureInfo Anfrage ist fehlgeschlagen.
@@ -259,6 +340,12 @@
 error_invalid_dgm_selected = Sie haben ein falsches DGM gew\u00e4hlt.
 error_bad_dgm_range = Das gew\u00e4hlte DGM passt nicht zur gew\u00e4hlten Berechnungsstrecke.
 error_bad_dgm_river = Das gew\u00e4hlte DGM passt nicht zum gew\u00e4hlten Fluss.
+error_dialog_not_valid = Eine oder mehrere Daten sind nicht korrekt.
+error_invalid_date = Das eingegebene Datum ist nicht korrekt.
+error_same_location = Der gewählte Ort ist der Bezugsort.
+error_contains_same_location = Zielorte beinhalten den Bezugsort.
+error_update_collection_attribute = Fehler beim Aktualisieren des Collection-Attributs.
+error_no_module_found = Keine nutzbaren Module gefunden.
 
 ## map related strings
 digitize = images/digitize.png
@@ -269,14 +356,14 @@
 ring_dike = Ringdeich
 selectFeature = images/selectFeature.png
 removeFeature = images/removeFeature.png
-getFeatureInfo = images/getFeatureInfo.png
+getFeatureInfo = images/info.png
 getFeatureInfoTooltip = Informationswerkzeug
 getFeatureInfoWindowTitle = Informationen zu Kartenebenen
-addWMS = images/addWMS.png
+addWMS = images/add_map.png
 addWMSTooltip = Laden von Kartenebenen eines externen WMS Dienstes.
 adjustElevation = images/adjustElevation.png
-measureLine = images/measureLine.png
-measurePolygon = images/measurePolygon.png
+measureLine = images/measure_line.png
+measurePolygon = images/measure_plane.png
 step = Schritt
 calculationStarted = Berechnung wurde gestarted.
 zoomMaxExtent = Gesamtausschnitt
@@ -289,31 +376,54 @@
 removeObject = Ausgew\u00e4hltes Objekt l\u00f6schen
 adjustElevationTooltip = Festlegen von H\u00f6hen f\u00fcr D\u00e4mme, Ringeiche, Gr\u00e4ben und Rohre
 measureDistance = L\u00e4ngenmessung
-measureArea = Streckenmessung
+measureArea = Fl\u00e4chenmessung
 map_themepanel_header_style = Stil
 zoomToLayer = Layer-Zoom
 requireDGM = Sie m\u00fcssen ein DGM ausw\u00e4hlen.
+upload_file = hochladen
+shape_file_upload = Shapedatei hochladen
 
 # data cage
+waterlevels = Wasserst\u00e4nde
 old_calculations = Fr\u00fchere Berechnungen
+officiallines = Amtliche Linien
 datacageAdd = Daten laden
 heightmarks = Hochwassermarken
 basedata = Basis-Daten
 fixations = Fixierungen
+flood_protections = HW-Schutzanlagen
+columns = Spalten
+annotation = Streckenfavoriten
 additionals = Zus\u00e4tzliche L\u00e4ngsschnitte
 differences = Differenzen
 kilometrage = Kilometrierung
 riveraxis = Flussachse
 km = Km
-qps = Querprofile
+qps = Querprofilspuren
 hws = Hochwasserschutzanlagen
 catchments = Einzugsgebiet
 floodplain = Talaue
 lines = Linien
 buildings = Bauwerke
 fixpoints = Festpunkte
+uesk = \u00dcberschwemmungsfl\u00e4chen
+calculations = Berechnungen
+current = Aktuell
+potentiel = Potenziell
+bfg = BfG
+land = Land
 rastermap = Rasterkarte
 background = Hintergrundkarte
+discharge_table_nn = Abflusstafeln am Pegel
+discharge_table_gauge = Abflusstafel am Pegel
+mainvalue = Hauptwerte
+dems = Digitale Gel\u00e4ndemodelle
+hydrboundaries = Hydrologische Grenzen
+gaugelocations = Pegellagen
+single = Jahr
+epoch = Epoche
+bedheights = Sohlh\u00f6hen
+datacage = Datenkorb
 
 # capabilities information panel
 addwmsInputTitle = Basis URL des WMS Dienstes
@@ -338,18 +448,29 @@
 width = Breite
 height = H\u00f6he
 visibility = Sichtbarkeit
-upper = von
-lower = bis
+upper = bis
+lower = von
 fixation = Fix
 font_size = Schriftgr\u00f6\u00dfe
 label = Titel
 title = Titel
 subtitle = Untertitel
 display_grid = Gitterlinien anzeigen
+display_logo = Logo anzeigen
+logo_placeh = Horizontale Ausrichtung Logo
+logo_placev = Vertikale Ausrichtung Logo
+top = oben
+bottom = unten
+center = mittig
+left = links
+right = rechts
+none = keines
 
 linetype = Linientyp
 textstyle = Textstil
 linecolor = Linienfarbe
+showhorizontalline = Horizontale Linie
+showverticalline = Vertikale Linie
 textcolor = Textfarbe
 textsize = Textgr\u00f6\u00dfe
 font = Schriftart
@@ -358,8 +479,66 @@
 backgroundcolor = Hintergrundfarbe
 textorientation = Textausrichtung
 linesize = Liniendicke
+pointsize = Punktdicke
+bandwidth = Bandbreite
+pointcolor = Punktfarbe
 showlines = Linien anzeigen
+showlinelabel = Linienbeschriftung anzeigen
+showpointlabel = Punktbeschriftung anzeigen
+labelfontface = Beschriftung: Schriftart
+labelfontcolor = Beschriftung: Schriftfarbe
+labelfontsize =  Beschriftung: Schriftgr\u00f6\u00dfe
+labelfontstyle = Beschriftung: Schriftstil
+labelbgcolor = Beschriftung: Hintergrundfarbe
+labelshowbg = Beschriftung: Hintergrund f\u00fcllen
+horizontal = horizontal
+vertical = vertikal
+showwidth = Breite anzeigen
+showlevel = Wasserstand anzeigen
+showminimum = Minimum anzeigen
+showmaximum = Maximum anzeigen
 showborder = Linie anzeigen
-transparent = Transparenz
-showarea = Fl\u00e4che anzeigen
+transparent = Transparent
+transparency = Transparenz
+showarea = Fl\u00e4che beschriften
+showmiddleheight = Mittlere Tiefe anzeigen
 fillcolor = F\u00fcllfarbe
+wsplgen_cat1 = F\u00fcllfarbe 0.0 <= DIFF < 1
+wsplgen_cat2 = F\u00fcllfarbe 1.0 <= DIFF < 2
+wsplgen_cat3 = F\u00fcllfarbe 2.0 <= DIFF < 3
+wsplgen_cat4 = F\u00fcllfarbe 3.0 <= DIFF < 4
+wsplgen_cat5 = F\u00fcllfarbe 4.0 <= DIFF
+
+# Manual Points Editor
+addpoints = Punkte hinzuf\u00fcgen
+pointname = Bezeichner
+removepoint = Entfernen
+newpoint = Neuer Punkt
+standby = Erstelle Parameterisierung ... bitte warten.
+points = Punktthema
+editpoints = Eintr\u00e4ge editieren
+addWSP = Neues WSP Thema anlegen
+addWSPButton = WSP Thema
+selection = Auswahl
+
+# Reference Curves
+reference_curve = Bezugslinie
+reference_curve_normalized = Reduzierte Bezugslinie
+reference_startpoint = Bezugsort/pegel
+reference_endpoint = Zielort/pegel
+
+fix_deltawt_export = \u0394 W/t
+select=Ausgewählt
+add_date=Hinzuf\u00fcgen
+
+fix_parameters_export = Angepasste Koeffizienten
+fix_parameters = CSV
+sq_overview=\u00dcbersicht
+
+gauge_zero = Pegelnullpunkt
+gauge_q_unit = m\u00b3/s
+gauge_river_info_link = Gew\u00e4sserinfo
+gauge_info_link = Pegelinfo
+gauge_url = https://flys-intern.intevation.de/PegelInfo/
+gauge_river_url = https://flys-intern.intevation.de/GewaesserInfo/
+gauge_curve_link = Abflusskurve
--- a/flys-client/src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/FLYSConstants_en.properties	Fri Sep 28 12:15:52 2012 +0200
@@ -1,4 +1,3 @@
-title = FLYS-3.0
 fullname = Flusshydrologische Software
 user = User:
 guest = guest
@@ -33,7 +32,8 @@
 river_selection = Rivers
 winfo = WINFO
 minfo = MINFO
-map = New Map
+map = Map
+new_map = New Map
 new_chart = New Chart
 diagram = Chart
 axes = Axes
@@ -51,15 +51,19 @@
 y3_axis = Y3-Axis
 legend_name = Name
 show_legend = Show
+aggregation_threshold = Threshold for aggregation of legend entries
 scale = Scale
 databasket = Databasket
-fix = TODO FIX ANALYSE TODO
+databasket_loading = Loading Databasket content
+fix = Fixing
+fixanalysis = Fixing Analysis
 next = Next
 location_distance_state = Choose calculation location(s) / range [km]
 distance_state = Choose calculation range [km]
 waterlevel_ground_state = Choose differences betweeen waterlevel and ground [m]
 location = Location(s)
 locations = Locations
+single_location = Location
 distance = Range
 unitFrom = km
 unitTo = km a
@@ -70,25 +74,32 @@
 activateTheme = Activate
 deactivateTheme = Deactivate
 removeTheme = Remove
+manageThemes = Manage themes
 label_ok = Ok
 label_cancel = Cancel
 cancelCalculationLabel = Stop the current calculation.
 calculationCanceled = The calculation has been canceled.
+range = Range
+resultCount = Hits
+start_year = Start
+end_year = end
+period = Period
 
 # Header images
 flysLogo = images/flys_logo.gif
 bfgLogo = images/bfg_logo.gif
 
 # Images
-downloadPNG = images/downloadPNG.png
-downloadPDF = images/downloadPDF.png
-downloadSVG = images/downloadSVG.png
+downloadPNG = images/png_export.png
+downloadPDF = images/pdf_export.png
+downloadSVG = images/svg_export.png
+downloadCSV = images/save.png
 loadingImg = images/loading.gif
 cancelCalculation = images/cancelCalculation.png
 markerRed = images/marker_red.png
 markerGreen = images/marker_green.png
 riverMap = images/gewkarte.png
-properties_ico = images/properties.gif
+properties_ico = images/properties.png
 
 dpLabelFrom = From
 dpUnitFrom = km
@@ -113,6 +124,19 @@
 missingInput = You need to enter a value.
 too_many_values = Only one value allowed
 
+addPointsTooltip = Add manual points
+addWSPTooltip = Add manual LS
+downloadPNGTooltip = Download chart as PNG
+downloadPDFTooltip = Download chart as PDF
+downloadSVGTooltip = Download chart as SVG
+downloadCSVTooltip = Download data as CSV
+zoomToMaxExtentTooltip = Zoom to max extent
+zoomOutTooltip = Zoom out
+historyBackTooltip = Previous zoom
+panControlTooltip = Pan
+zoomboxTooltip = Zoombox
+chartPropertiesTooltip = Chartproperties
+
 description = Description
 from = From
 to = To
@@ -121,16 +145,22 @@
 top_edge = Top edge
 name = Name
 type = Type
-wq_value = Q/D
+wq_table_w = Characteristic Waterlevels
+wq_table_q = Characteristic Discharges / Durations
+wq_value_w = W [cm at Gauge]
+wq_value_q = Q [m\u00b3/s]
 river_km = River-Km
 uesk_profile_distance = Distance [m]
 
 wqTitle = Input for W/Q Data
 wqadaptedTitle = Input for W/Q Data
+wqHistorical = Selection of Analyse Type
 calcTableTitle = Calculated Output
 helperPanelTitle = Input Support
+gaugePanelTitle = Gauge Information
 wqW = W at Gauge [cm]
 wqQ = Q [m\u00b3/s]
+wqWFree = W at free position [m+NHN]
 wqQGauge = Discharge at Gauge
 wqSingle = Single values
 wqRange = Range
@@ -143,34 +173,69 @@
 unitQFrom = m³/s&nbsp;-
 unitQTo = m³/s&nbsp;a
 unitQStep = m³/s
+main_channel = Main Channel
+total_channel = Total Channel
 footerHome = Home
-footerContact = Kontakt
-footerImpressum = Impressum
+footerContact = Contact
+footerImpressum = Legal info
 
 buttonNext = Next
 imageBack = images/back_en.png
-imageSave = images/save.gif
-theme_top = images/theme_top.png
-theme_up = images/theme_up.png
-theme_down = images/theme_down.png
-theme_bottom = images/theme_bottom.png
-zoom_all = images/zoom-1.png
-zoom_in = images/zoom-in.png
-zoom_out = images/zoom-out.png
-zoom_back = images/zoom-back.png
-pan = images/pan.png
+imageSave = images/save.png
+theme_top = images/arrow_first.png
+theme_up = images/arrow_up.png
+theme_down = images/arrow_down.png
+theme_bottom = images/arrow_last.png
+zoom_all = images/mag_100.png
+zoom_in = images/mag_zoom_box.png
+zoom_out = images/mag_zoom_minus.png
+zoom_back = images/mag_zoom_back.png
+pan = images/hand.png
 askThemeRemove = Are you sure that you want to remove the selected theme / themes?
+add = Add
 
 discharge_curve = Discharge Curves at Gauges
+gauge_discharge_curve = Discharge Curves at Gauge
 computed_discharge_curve = Discharge Curve
+computed_discharge_curves = Discharge Curves
 longitudinal_section = Longitudinal Section Curve
 duration_curve = Duration Curve
 discharge_longitudinal_section = Discharge Longitudinal Section
 floodmap = Floodmap
-
+historical_discharge = Historical Discharge Curves
+flow_velocity = Flow Velocity
+flow_velocity_export = Flow Velocity Export
+bedheight_middle = Middle Bed Height
+bedheight_middle_export = Middle Bed Height Export
+bed_longitudinal_section = Bed Quality
+bed_longitudinal_section_export = Bed Quality Export
+sq_relation_a = A Feinkornanteil
+sq_relation_b = B Sand (Suspensionstransport)
+sq_relation_c = C Sand (Geschiebetransport)
+sq_relation_d = D Fein- und Mittelkies
+sq_relation_e = E Grobkornanteil (> Mittelkies)
+sq_relation_f = F Geschiebetransport Gesamt
+sq_relation_export = SQ Export
 cross_section = Cross Section
+cross_sections = Cross Sections
 w_differences = Differences
 w_differences_export = Differences Export
+reference_curve_export = Reference Curve Export
+historical_discharge_export = Historical Discharge Curve Export
+fix_wq_curve = W/Q
+fix_deltawt_curve = \u0394 W/t
+fix_longitudinal_section_curve = Longitudinal Section
+fix_derivate_curve = Derivate
+fix_vollmer_wq_curve = W/Q
+datacage_add_pair = Add difference pair
+load_diameter = Bedload Diameter
+bed_diameter = Bed Diameter
+soundings = Soundings
+bed_difference_year = Single Bedheight Differences
+bed_difference_epoch = Epoch Bedheight Differences
+bed_difference_height_year = Bedheight Difference per year
+
+exportATTooltip = Export as AT file
 
 waterlevel_export = Waterlevel Export
 waterlevel_report = Waterlevel Report
@@ -180,14 +245,21 @@
 discharge_longitudinal_section_report = Discharge Longitudinal Section Report
 durationcurve_export = Duration Curve Export
 durationcurve_report = Duration Curve Report
-dataexport = Datenexport
+dataexport = Data export
 csv = CSV
 wst = WST
 at = AT
+pdf = PDF
 computed_dischargecurve_at_export = AT Export
+gauge_class = Gauge Class
+eventselect = Eventselection
+events = Events
+kmchart = Chart
 
 chart_themepanel_header_themes = Theme
 chart_themepanel_header_actions = Actions
+chart_themepanel_synchron = Navigate synchronously
+chart_themepanel_asynchron = Navigate independently
 chart_themepanel_set_master = Reference
 chart_themepanel_new_area = New Area...
 chart_themepanel_area_under = under ...
@@ -195,6 +267,11 @@
 chart_themepanel_area_between = between ...
 against_x_axis = Over X-Axis
 
+gauge_mnq = around MNQ
+gauge_mq  = around MQ
+gauge_mhq = around MHQ
+gauge_hq5 = above HQ5
+
 ele_window_title = Elevation Node
 ele_window_label = Elevation settings in m \u00fc. NN.
 ele_window_x_col = X
@@ -209,6 +286,7 @@
 unexpected_exception = There occured an unexpected exception
 error_read_minmax_values = Error while reading min/max values for the location input.
 error_validate_range = The value $1 needs to be smaller than $3 and bigger than $2.
+error_validate_date_range = Start date needs to be before end date.
 error_validate_lower_range = The lower value $1 needs to be bigger than $2.
 error_validate_upper_range = The upper value $1 needs to be smaller than $2.
 error_empty_state = Required inputs are missing.
@@ -223,10 +301,13 @@
 error_describe_collection = Error while fetching the projects state.
 error_no_rivers_found = Error while reading supported rivers.
 error_no_such_user = Error - no such user found.
+error_no_users = Error - no users found.
 error_no_waterlevel_pair_selected = Error - no waterlevel pair for building differences selected.
 error_same_waterlevels_in_pair = Error - minuend and subtrahend have to differ.
 error_not_logged_in = You need to log in before you are allowed to start your work.
 error_load_parameterization = Could not load the parameterization.
+error_wrong_date = Please enter valid dates.
+error_no_gaugeoverviewinfo_found = Error while fetching the river and gauge info
 
 error_feed_no_data = No input data found.
 error_feed_from_out_of_range = The lower value is bigger than the upper value.
@@ -248,6 +329,7 @@
 error_no_theme_styles_found=No style for the selected theme found.
 error_no_feature_selected = No object selected.
 error_no_map_config = No Map configuration found.
+error_no_map_output_type = No Map output found.
 warning_use_first_feature = You have more that one object selected. The first one is used.
 error_no_valid_gfi_url = No valid GetFeatureInfo response found.
 error_gfi_req_failed = GetFeatureInfo request failed.
@@ -259,6 +341,12 @@
 error_invalid_dgm_selected = You have selected an invalid DEM.
 error_bad_dgm_range = You have selected a DEM with an invalid range.
 error_bad_dgm_river = You have selected a DEM for a wrong river.
+error_dialog_not_valid = One or more values are not valid.
+error_invalid_date = The entered date is not valid.
+error_same_location = Reference location equals selected location.
+error_contains_same_location = Target locations contains reference location.
+error_update_collection_attribute = Error while updating the collection attribut
+error_no_module_found = No modules found
 
 ## map related strings
 digitize = images/digitize.png
@@ -269,14 +357,14 @@
 ring_dike = Ringdike
 selectFeature = images/selectFeature.png
 removeFeature = images/removeFeature.png
-getFeatureInfo = images/getFeatureInfo.png
+getFeatureInfo = images/info.png
 getFeatureInfoTooltip = Information Tool
 getFeatureInfoWindowTitle = Informations for Map Layers.
-addWMS = images/addWMS.png
+addWMS = images/add_map.png
 addWMSTooltip = Load layers from external WMS service.
 adjustElevation = images/adjustElevation.png
-measureLine = images/measureLine.png
-measurePolygon = images/measurePolygon.png
+measureLine = images/measure_line.png
+measurePolygon = images/measure_plane.png
 step = Step
 calculationStarted = Calculation started.
 zoomMaxExtent = Max extent
@@ -293,13 +381,20 @@
 map_themepanel_header_style = Style
 zoomToLayer = Layer-Zoom
 requireDGM = You need to choose a DEM.
+upload_file = upload
+shape_file_upload = Upload shapefile
 
 # data cage
+waterlevels = Waterlevels
 old_calculations = Former Calculations
+officiallines = Official lines
 datacageAdd = Add data
 heightmarks = Height Marks
 basedata = Base Data
 fixations = Fixations
+flood_protections = Flood Protections
+columns = Columns
+annotation = Annotations
 additionals = Additional Longitudinal Section Curves
 differences = Differences
 kilometrage = Kilometrage
@@ -312,8 +407,24 @@
 lines = Lines
 buildings = Buildings
 fixpoints = Fixpoints
+uesk = Floodmaps
+calculations = Calculations
+current = Current
+potentiel = Potentiel
+bfg = BfG
+land = Land
 rastermap = Rastermap
 background = Background Layer
+discharge_table_nn = Discharge Tables at Gauge
+discharge_table_gauge = Discharge Table at Gauge
+mainvalue = Mainvalue
+dems = Digital Elevation Models
+hydrboundaries = Hydrological Boundaries
+gaugelocations = Location of Gauges
+single = Year
+epoch = Epoch
+bedheights = Bedheights
+datacage = Datacage
 
 # capabilities information panel
 addwmsInputTitle = Base URL of WMS service
@@ -338,18 +449,29 @@
 width = Width
 height = Height
 visibility = Visibility
-upper = from
-lower = to
+upper = to
+lower = from
 fixation = Fix
 font_size = Fontsize
 label = Title
 title = Title
 subtitle = Subtitle
 display_grid = Display grid
+display_logo = Display logo
+logo_placeh = Horiz. Place for logo
+logo_placev = Vertic. Place for logo
+top = top
+bottom = bottom
+center = center
+left = left
+right = right
+none = none
 
 linetype = Linetype
 textstyle = Textstyle
 linecolor = Linecolor
+showhorizontalline = Show horizonal line
+showverticalline = Show vertical line
 textcolor = Textcolor
 textsize = Textsize
 font = Font
@@ -358,8 +480,66 @@
 backgroundcolor = Backgroundcolor
 textorientation = Textorientation
 linesize = Linesize
+pointsize = Pointsize
+bandwidth = Bandwidth
+pointcolor = Pointcolor
 showlines = Show lines
+showlinelabel = Show label
+showpointlabel = Show point label
+labelfontface = Label: Font
+labelfontcolor = Label: Color
+labelfontsize = Label: Size
+labelfontstyle = Label: Style
+labelbgcolor = Label: Background Color
+labelshowbg = Label: Show Background
+horizontal = horizontal
+vertical = vertical
+showwidth = Show width
+showlevel = Show waterlevel
+showminimum = Show minimum
+showmaximum = Show maximum
 showborder = Show line
 transparent = Transparency
+transparency = Transparency
 showarea = Show Area
+showmiddleheight = Show middle depth
 fillcolor = Fill Color
+wsplgen_cat1 = Fill Color 0.0 <= DIFF < 1
+wsplgen_cat2 = Fill Color 1.0 <= DIFF < 2
+wsplgen_cat3 = Fill Color 2.0 <= DIFF < 3
+wsplgen_cat4 = Fill Color 3.0 <= DIFF < 4
+wsplgen_cat5 = Fill Color 4.0 <= DIFF
+
+# Manual Points Editor
+addpoints = Add points
+pointname = Name
+removepoint = Remove
+newpoint = New Point
+standby = Creating Artifact ... please wait.
+points = Points
+editpoints = Edit Points
+addWSP = Add Manual LS
+addWSPButton = Add Manual LS
+selection = Selection
+
+# Reference Curves
+reference_curve = Reference Curve
+reference_curve_normalized = Reduced Reference Curve
+reference_startpoint = Point of reference
+reference_endpoint = Point(s) of projection
+
+fix_deltawt_export = \u0394 W/t
+select=Selected
+add_date=Add
+
+fix_parameters_export = Adjusted coefficient
+fix_parameters = CSV
+sq_overview=Overview
+
+gauge_zero = Gauge zero ground
+gauge_q_unit = m\u00b3/s
+gauge_river_info_link = Riverinfo
+gauge_info_link = Gaugeinfo
+gauge_url = https://flys-intern.intevation.de/PegelInfo/
+gauge_river_url = https://flys-intern.intevation.de/GewaesserInfo/
+gauge_curve_link = Dischargecurve
--- a/flys-client/src/main/java/de/intevation/flys/client/client/event/FilterHandler.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/event/FilterHandler.java	Fri Sep 28 12:15:52 2012 +0200
@@ -7,5 +7,7 @@
 public interface FilterHandler {
 
     void onFilterCriteriaChanged(StringFilterEvent event);
+
+    void onFilterCriteriaChanged(RangeFilterEvent event);
 }
 // 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-client/src/main/java/de/intevation/flys/client/client/event/RangeFilterEvent.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,44 @@
+package de.intevation.flys.client.client.event;
+
+import com.google.gwt.i18n.client.NumberFormat;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class RangeFilterEvent {
+
+    protected Float from;
+    protected Float to;
+
+
+    public RangeFilterEvent(String from, String to) {
+        NumberFormat nf = NumberFormat.getDecimalFormat();
+        double d;
+
+        try {
+            d = nf.parse(from);
+            this.from = Float.valueOf(String.valueOf(d));
+        }
+        catch(NumberFormatException nfe) {
+            this.from = Float.NaN;
+        }
+        try {
+            d = nf.parse(to);
+            this.to = Float.valueOf(String.valueOf(d));
+        }
+        catch(NumberFormatException nfe) {
+            this.to = Float.NaN;
+        }
+    }
+
+
+    public Float getFrom() {
+        return this.from;
+    }
+
+
+    public Float getTo() {
+        return this.to;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/services/ArtifactService.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/ArtifactService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,6 +5,7 @@
 
 import de.intevation.flys.client.shared.exceptions.ServerException;
 import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
 
 import de.intevation.flys.client.shared.model.Recommendation;
 
@@ -31,5 +32,19 @@
         String         factory,
         Recommendation recommendation
     ) throws ServerException;
+
+    /**
+     * Create a new GaugeDischageCurveArtifact
+     *
+     * @param collection the collection to add the artifact to
+     * @param river      the river
+     * @param gaugeref   reference id of the gauge
+     */
+    public Artifact createGaugeDischargeCurverArtifact(
+            Collection collection,
+            String locale,
+            String river,
+            Long   gaugeref
+    ) throws ServerException;
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/services/ArtifactServiceAsync.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/ArtifactServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,6 +3,7 @@
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
 import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
 
 import de.intevation.flys.client.shared.model.Recommendation;
 
@@ -19,5 +20,13 @@
         String         factory,
         Recommendation recommendation,
         AsyncCallback<Artifact> callback);
+
+    public void createGaugeDischargeCurverArtifact(
+        Collection collection,
+        String locale,
+        String river,
+        Long   gaugeref,
+        AsyncCallback<Artifact> callback
+    );
 }
 // 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-client/src/main/java/de/intevation/flys/client/client/services/DischargeInfoService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,26 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.DischargeInfoObject;
+
+/**
+ * This service is used to fetch a list of DischargeInfoObjects from artifact
+ * server for a specific gauge.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+@RemoteServiceRelativePath("dischargeinfo")
+public interface DischargeInfoService extends RemoteService {
+
+    /**
+     * This method returns a list of DischargeInfoObjects for a specific gauge.
+     */
+    DischargeInfoObject[] getDischargeInfo(
+        String locale,
+        long gauge)
+    throws ServerException;
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/services/DischargeInfoServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,18 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import de.intevation.flys.client.shared.model.DischargeInfoObject;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public interface DischargeInfoServiceAsync {
+
+    void getDischargeInfo(
+        String locale,
+        long gauge,
+        AsyncCallback<DischargeInfoObject[]> cb);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/services/FeedService.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/FeedService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,7 @@
 package de.intevation.flys.client.client.services;
 
+import java.util.List;
+
 import com.google.gwt.user.client.rpc.RemoteService;
 import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
 
@@ -27,5 +29,21 @@
         Artifact artifact,
         Data[]   data)
     throws ServerException;
+
+
+    /**
+     * Inserts (the same) new data into existing artifacts.
+     *
+     * @param locale The locale used for the request.
+     * @param artifact The artifact.
+     * @param data The data that should be inserted.
+     *
+     * @return the artifact which description might have been changed.
+     */
+    public List<Artifact> feedMany(
+        String         locale,
+        List<Artifact> artifacts,
+        Data[]         data)
+    throws ServerException;
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/services/FeedServiceAsync.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/FeedServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,7 @@
 package de.intevation.flys.client.client.services;
 
+import java.util.List;
+
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
 import de.intevation.flys.client.shared.model.Artifact;
@@ -11,10 +13,30 @@
  */
 public interface FeedServiceAsync {
 
+    /**
+     * Inserts new data into an existing artifact.
+     *
+     * @param locale The locale used for the request.
+     * @param artifact The artifact.
+     * @param data The data that should be inserted.
+     */
     public void feed(
         String                  locale,
         Artifact                artifact,
         Data[]                  data,
         AsyncCallback<Artifact> callback);
+
+    /**
+     * Inserts (the same) new data into existing artifacts.
+     *
+     * @param locale The locale used for the request.
+     * @param artifact The artifact.
+     * @param data The data that should be inserted.
+     */
+    public void feedMany(
+        String                  locale,
+        List<Artifact>          artifacts,
+        Data[]                  data,
+        AsyncCallback<List<Artifact>> callback);
 }
 // 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-client/src/main/java/de/intevation/flys/client/client/services/FixingsOverviewService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,21 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+
+import de.intevation.flys.client.shared.model.FixingsOverviewInfo;
+
+@RemoteServiceRelativePath("fixings-overview")
+public interface FixingsOverviewService extends RemoteService {
+
+    FixingsOverviewInfo generateOverview(
+        String locale,
+        String uuid,
+        String filter,
+        boolean checkbox,
+        String callback
+    ) throws ServerException;
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/services/FixingsOverviewServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import de.intevation.flys.client.shared.model.FixingsOverviewInfo;
+
+public interface FixingsOverviewServiceAsync {
+
+    void generateOverview(
+        String  locale,
+        String  uuid,
+        String  filter,
+        boolean checkbox,
+        String callbackFunction,
+        AsyncCallback<FixingsOverviewInfo> callback);
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/services/GaugeInfoService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,20 @@
+package de.intevation.flys.client.client.services;
+
+import java.util.List;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.Gauge;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+@RemoteServiceRelativePath("gaugeinfo")
+public interface GaugeInfoService extends RemoteService {
+
+    List<Gauge> getGaugeInfo(String river, String  refnumber)
+    throws ServerException;
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/services/GaugeInfoServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,20 @@
+package de.intevation.flys.client.client.services;
+
+import java.util.List;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import de.intevation.flys.client.shared.model.Gauge;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public interface GaugeInfoServiceAsync {
+
+    void getGaugeInfo(
+        String river,
+        String refnumber,
+        AsyncCallback<List<Gauge>> gauges);
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/services/GaugeOverviewInfoService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.RiverInfo;
+
+/**
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+@RemoteServiceRelativePath("gaugeoverviewinfo")
+public interface GaugeOverviewInfoService extends RemoteService {
+
+    public RiverInfo getRiverInfo(String river) throws ServerException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/GaugeOverviewInfoServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,16 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import de.intevation.flys.client.shared.model.RiverInfo;
+
+
+/**
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public interface GaugeOverviewInfoServiceAsync {
+
+    public void getRiverInfo(String river, AsyncCallback<RiverInfo> callback);
+}
+
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/MapUrlService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,20 @@
+package de.intevation.flys.client.client.services;
+
+import java.util.Map;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+
+/**
+ * This interface describes the service to get wms urls for UESK and new maps.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+@RemoteServiceRelativePath("map-urls")
+public interface MapUrlService extends RemoteService {
+
+    Map<String, String> getUrls() throws ServerException;
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/services/MapUrlServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.client.client.services;
+
+import java.util.Map;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public interface MapUrlServiceAsync {
+
+    public void getUrls(AsyncCallback<Map<String, String> > callback);
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/services/ModuleService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,22 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.Module;
+
+@RemoteServiceRelativePath("modules")
+public interface ModuleService extends RemoteService {
+
+    /**
+     * Returns the list of available modules of a user
+     *
+     * @param locale The locale used for the request
+     * @return a String array of all available modules
+     *
+     */
+    public Module[] list(String locale) throws ServerException;
+}
+
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/ModuleServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,12 @@
+package de.intevation.flys.client.client.services;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import de.intevation.flys.client.shared.model.Module;
+
+public interface ModuleServiceAsync {
+
+    public void list(String locale,
+        AsyncCallback<Module[]> callback);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/ThemeListingService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,29 @@
+package de.intevation.flys.client.client.services;
+
+import java.util.Map;
+
+import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.Style;
+
+/**
+ * This interface provides a method to list themes filtered by name.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund.Renkert</a>
+ */
+@RemoteServiceRelativePath("themelisting")
+public interface ThemeListingService extends RemoteService {
+
+    /**
+     * This method returns a list of themes filtered by name.
+     *
+     * @param locale The locale used for the request.
+     *
+     * @return a list of themes provided by the artifact server.
+     */
+    public Map<String, Style> list(String locale, String name)
+    throws ServerException;
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/services/ThemeListingServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,22 @@
+package de.intevation.flys.client.client.services;
+
+import java.util.Map;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import de.intevation.flys.client.shared.model.Style;
+
+
+/**
+ * This interface provides a method to list themes filterd by name.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public interface ThemeListingServiceAsync {
+
+    public void list(
+        String locale,
+        String name,
+        AsyncCallback<Map<String, Style>> callback);
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/services/UserCollectionsService.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/UserCollectionsService.java	Fri Sep 28 12:15:52 2012 +0200
@@ -24,9 +24,6 @@
      *
      * @return the current {@link User}.
      */
-    Collection[] getUserCollections(
-        String serverUrl,
-        String locale,
-        String userid);
+    Collection[] getUserCollections(String locale, String userid);
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/services/UserCollectionsServiceAsync.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/services/UserCollectionsServiceAsync.java	Fri Sep 28 12:15:52 2012 +0200
@@ -14,7 +14,6 @@
 public interface UserCollectionsServiceAsync {
 
     void getUserCollections(
-        String serverUrl,
         String locale,
         String userid,
         AsyncCallback<Collection[]> callback);
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/AbstractUIProvider.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/AbstractUIProvider.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,10 +1,6 @@
 package de.intevation.flys.client.client.ui;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import com.google.gwt.core.client.GWT;
-
 import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.Button;
 import com.smartgwt.client.widgets.Canvas;
@@ -26,6 +22,12 @@
 import de.intevation.flys.client.shared.model.Data;
 import de.intevation.flys.client.shared.model.DataItem;
 import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+
+import java.util.ArrayList;
+import java.util.List;
+
 
 /**
  * An abstract UIProvider that provides some basic methods.
@@ -39,7 +41,6 @@
     /** The message class that provides i18n strings.*/
     protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
 
-
     /** The StepForwardHandlers.*/
     protected List<StepForwardHandler> forwardHandlers;
 
@@ -72,6 +73,7 @@
      *
      * @param handler A new StepBackHandler.
      */
+    @Override
     public void addStepBackHandler(StepBackHandler handler) {
         if (handler != null) {
             backHandlers.add(handler);
@@ -84,6 +86,7 @@
      *
      * @param handler A new StepForwardHandler.
      */
+    @Override
     public void addStepForwardHandler(StepForwardHandler handler) {
         if (handler != null) {
             forwardHandlers.add(handler);
@@ -125,6 +128,7 @@
      *
      * @param e The click event.
      */
+    @Override
     public void onClick(ClickEvent e) {
         List<String> errors = validate();
         if (errors == null || errors.isEmpty()) {
@@ -162,6 +166,15 @@
     }
 
 
+    @Override
+    public Canvas createHelpLink(DataList dataList, Data data) {
+        String iUrl    = GWT.getHostPageBaseURL() + MSG.getFeatureInfo();
+        String helpUrl = dataList.getHelpText();
+
+        return new ImgLink(iUrl, helpUrl, 30, 30, true);
+    }
+
+
     /**
      * Creates the 'back' button to step back to a previous state.
      *
@@ -174,6 +187,7 @@
         Img back   = new Img(url, 16, 16);
 
         back.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 fireStepBackEvent(new StepBackEvent(targetState));
             }
@@ -189,6 +203,7 @@
      * @param helperContainer A container that is used to position helper
      * widgets.
      */
+    @Override
     public void setContainer(VLayout helperContainer) {
         this.helperContainer = helperContainer;
     }
@@ -199,16 +214,19 @@
      *
      * @param art An artifact containing status information.
      */
+    @Override
     public void setArtifact(Artifact art) {
         this.artifact = art;
     }
 
 
+    @Override
     public void setCollection(Collection collection) {
         this.collection = collection;
     }
 
 
+    @Override
     public void setParameterList(ParameterList list) {
         this.parameterList = list;
     }
@@ -280,6 +298,20 @@
     }
 
 
+    /** Create simple DefaultData with single DataItem inside. */
+    public static DefaultData createDataArray(String name, String value) {
+        DataItem item = new DefaultDataItem(
+            name,
+            name,
+            value);
+
+        return new DefaultData(name,
+            null,
+            null,
+            new DataItem[] {item});
+    }
+
+
     /**
      * This method needs to be implemented by concrete subclasses. It should
      * create a new Canvas object with a representation of <i>data</i>.
@@ -288,6 +320,7 @@
      *
      * @return a Canvas object that displays <i>data</i>.
      */
+    @Override
     public abstract Canvas create(DataList data);
 
 
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/CollectionView.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/CollectionView.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,24 +1,43 @@
 package de.intevation.flys.client.client.ui;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Stack;
-
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.rpc.AsyncCallback;
-
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.types.VerticalAlignment;
 import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.Img;
 import com.smartgwt.client.widgets.Window;
-import com.smartgwt.client.widgets.events.CloseClientEvent;
+import com.smartgwt.client.widgets.events.CloseClickEvent;
 import com.smartgwt.client.widgets.events.CloseClickHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.layout.Layout;
 import com.smartgwt.client.widgets.layout.VLayout;
 import com.smartgwt.client.widgets.tab.TabSet;
 import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
 
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.FLYS;
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.event.CollectionChangeEvent;
+import de.intevation.flys.client.client.event.CollectionChangeHandler;
+import de.intevation.flys.client.client.event.HasCollectionChangeHandlers;
+import de.intevation.flys.client.client.event.HasOutputModesChangeHandlers;
+import de.intevation.flys.client.client.event.OutputModesChangeEvent;
+import de.intevation.flys.client.client.event.OutputModesChangeHandler;
+import de.intevation.flys.client.client.event.ParameterChangeEvent;
+import de.intevation.flys.client.client.event.ParameterChangeHandler;
+import de.intevation.flys.client.client.services.AddArtifactService;
+import de.intevation.flys.client.client.services.AddArtifactServiceAsync;
+import de.intevation.flys.client.client.services.ArtifactService;
+import de.intevation.flys.client.client.services.ArtifactServiceAsync;
+import de.intevation.flys.client.client.services.CollectionAttributeService;
+import de.intevation.flys.client.client.services.CollectionAttributeServiceAsync;
+import de.intevation.flys.client.client.services.CreateCollectionService;
+import de.intevation.flys.client.client.services.CreateCollectionServiceAsync;
+import de.intevation.flys.client.client.services.DescribeCollectionService;
+import de.intevation.flys.client.client.services.DescribeCollectionServiceAsync;
+import de.intevation.flys.client.client.services.LoadArtifactService;
+import de.intevation.flys.client.client.services.LoadArtifactServiceAsync;
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.shared.model.ArtifactDescription;
 import de.intevation.flys.client.shared.model.Collection;
@@ -28,27 +47,12 @@
 import de.intevation.flys.client.shared.model.ReportMode;
 import de.intevation.flys.client.shared.model.User;
 
-import de.intevation.flys.client.client.Config;
-import de.intevation.flys.client.client.FLYS;
-import de.intevation.flys.client.client.FLYSConstants;
-import de.intevation.flys.client.client.event.HasCollectionChangeHandlers;
-import de.intevation.flys.client.client.event.HasOutputModesChangeHandlers;
-import de.intevation.flys.client.client.event.CollectionChangeEvent;
-import de.intevation.flys.client.client.event.CollectionChangeHandler;
-import de.intevation.flys.client.client.event.OutputModesChangeEvent;
-import de.intevation.flys.client.client.event.OutputModesChangeHandler;
-import de.intevation.flys.client.client.event.ParameterChangeEvent;
-import de.intevation.flys.client.client.event.ParameterChangeHandler;
-import de.intevation.flys.client.client.services.ArtifactService;
-import de.intevation.flys.client.client.services.ArtifactServiceAsync;
-import de.intevation.flys.client.client.services.AddArtifactService;
-import de.intevation.flys.client.client.services.AddArtifactServiceAsync;
-import de.intevation.flys.client.client.services.CollectionAttributeService;
-import de.intevation.flys.client.client.services.CollectionAttributeServiceAsync;
-import de.intevation.flys.client.client.services.CreateCollectionService;
-import de.intevation.flys.client.client.services.CreateCollectionServiceAsync;
-import de.intevation.flys.client.client.services.DescribeCollectionService;
-import de.intevation.flys.client.client.services.DescribeCollectionServiceAsync;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
 
 
 /**
@@ -79,6 +83,10 @@
     protected CollectionAttributeServiceAsync updater =
         GWT.create(CollectionAttributeService.class);
 
+    /** The LoadArtifactService used to load recommendations*/
+    protected LoadArtifactServiceAsync loadArtifactService =
+        GWT.create(LoadArtifactService.class);
+
     /** The message class that provides i18n strings. */
     protected FLYSConstants messages = GWT.create(FLYSConstants.class);
 
@@ -108,15 +116,21 @@
     /** The layout. */
     protected Layout layout;
 
+    protected VLayout lockScreen;
+
     protected int artifactsQueue;
+    protected int recommendationQueue;
     protected Stack<Recommendation> newRecommendations;
 
+    /** Values for fix analysis charts*/
+    protected double currentKm;
+    protected double minKm;
+    protected double maxKm;
+    protected double steps;
 
     /**
      * This constructor creates a new CollectionView that is used to display the
      * <i>collection</i>.
-     *
-     * @param collection The collection to be displayed.
      */
     public CollectionView(FLYS flys) {
         // do this first because it takes longer than the other stuff in here.
@@ -131,8 +145,14 @@
         this.layout        = new VLayout();
         this.parameterList = new ParameterList(
             flys, this, messages.new_project());
-        this.artifactsQueue     = 0;
-        this.newRecommendations = new Stack<Recommendation>();
+        this.artifactsQueue      = 0;
+        this.recommendationQueue = 0;
+        this.newRecommendations  = new Stack<Recommendation>();
+
+        this.currentKm = -1d;
+        this.minKm = -1d;
+        this.maxKm = -1d;
+        this.steps = -1d;
 
         addCollectionChangeHandler(this);
         addCollectionChangeHandler(parameterList);
@@ -146,7 +166,9 @@
         init();
     }
 
-
+    /**
+     * @param collection The collection to be displayed.
+     */
     public CollectionView(FLYS flys, Collection collection, Artifact artifact) {
         this.flys          = flys;
         this.artifact      = artifact;
@@ -157,6 +179,11 @@
         this.outHandlers   = new ArrayList<OutputModesChangeHandler>();
         this.layout        = new VLayout();
 
+        this.currentKm = -1d;
+        this.minKm = -1d;
+        this.maxKm = -1d;
+        this.steps = -1d;
+
         if (artifact != null) {
             this.parameterList = new ParameterList(
                 flys,
@@ -195,8 +222,10 @@
      * This method handles the initial layout stuff.
      */
     protected void init() {
-        setWidth(750);
-        setHeight(600);
+        setWidth(1010);
+        setHeight(700);
+
+        setMaximized(true);
 
         layout.setWidth100();
 
@@ -230,11 +259,13 @@
             locale,
             ownerId,
             new AsyncCallback<Collection>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("Could not create the new collection.");
                     SC.warn(messages.getString(caught.getMessage()));
                 }
 
+                @Override
                 public void onSuccess(Collection collection) {
                     GWT.log("Successfully created a new collection.");
                     setCollection(collection);
@@ -253,6 +284,7 @@
      *
      * @param handler The new CollectionChangeHandler.
      */
+    @Override
     public void addCollectionChangeHandler(CollectionChangeHandler handler) {
         if (handler != null) {
             handlers.add(handler);
@@ -265,6 +297,7 @@
      *
      * @param handler The new OutputModesChangeHandler.
      */
+    @Override
     public void addOutputModesChangeHandler(OutputModesChangeHandler handler) {
         if (handler != null) {
             outHandlers.add(handler);
@@ -296,6 +329,41 @@
     }
 
 
+    /** Disables input, grey out, show spinning wheel of joy. */
+    public void lockUI() {
+        if (lockScreen == null) {
+            lockScreen = new VLayout();
+            lockScreen.setWidth100();
+            lockScreen.setHeight100();
+            lockScreen.setBackgroundColor("#7f7f7f");
+            lockScreen.setOpacity(50);
+            lockScreen.setAlign(VerticalAlignment.CENTER);
+            lockScreen.setDefaultLayoutAlign(VerticalAlignment.CENTER);
+
+            HLayout inner = new HLayout();
+            inner.setAlign(Alignment.CENTER);
+            inner.setDefaultLayoutAlign(Alignment.CENTER);
+            inner.setOpacity(100);
+
+            Img img = new Img(
+                GWT.getHostPageBaseURL() + messages.loadingImg(),
+                25, 25);
+
+            inner.addMember(img);
+
+            lockScreen.addMember(inner);
+        }
+
+        layout.addChild(lockScreen);
+    }
+
+
+    /** Enable input, remove grey, remove spinning wheel of joy. */
+    public void unlockUI() {
+        layout.removeChild(lockScreen);
+    }
+
+
     /**
      * This method returns true, if the Collection is new and no plugins has
      * been chosen.
@@ -350,6 +418,7 @@
      *
      * @param event The ParameterChangeEvent.
      */
+    @Override
     public void onParameterChange(ParameterChangeEvent event) {
         GWT.log("CollectionView.onParameterChange");
         setArtifact(event.getNewValue());
@@ -358,30 +427,39 @@
 
     protected void artifactChanged() {
         ArtifactDescription desc = getArtifact().getArtifactDescription();
-        OutputMode[] outs        = desc.getOutputModes();
-        Recommendation[] recom   = desc.getRecommendations();
+        //OutputMode[] outs        = desc.getOutputModes();
+        final Recommendation[] recom = desc.getRecommendations();
 
         Collection c = getCollection();
 
-        if (recom != null && collection != null) {
-            loadRecommendedArtifacts(recom);
-        }
-
         if (c != null) {
             Config config = Config.getInstance();
             String locale = config.getLocale();
 
             describeCollectionService.describe(c.identifier(), locale,
                 new AsyncCallback<Collection>() {
+                    @Override
                     public void onFailure(Throwable caught) {
                         GWT.log("Could not DESCRIBE collection.");
                         SC.warn(messages.getString(caught.getMessage()));
                     }
 
 
+                    @Override
                     public void onSuccess(Collection newCollection) {
                         GWT.log("Successfully DESCRIBED collection.");
-                        setCollection(newCollection);
+                        boolean loaded = true;
+                        for (Recommendation r: recom) {
+                            if(!newCollection.loadedRecommendation(r)) {
+                                loaded = false;
+                            }
+                        }
+                        if  (!loaded) {
+                            loadRecommendedArtifacts(recom);
+                        }
+                        else {
+                            setCollection(newCollection);
+                        }
                     }
                 }
             );
@@ -411,6 +489,7 @@
      * Set the current collection.
      *
      * @param collection The new collection.
+     * @param suppress Whether to fire a collectionchangeevent.
      */
     protected void setCollection(Collection collection, boolean suppress) {
         if (collection != null && this.collection == null) {
@@ -420,7 +499,7 @@
         Collection tmp  = this.collection;
         this.collection = collection;
 
-        setTitle(collection.getName() + " (UUID: " + collection.identifier() + ")");
+        setTitle(collection.getName());
 
         if (!suppress) {
             fireCollectionChangeEvent(tmp, this.collection);
@@ -428,6 +507,7 @@
     }
 
 
+    @Override
     public void onCollectionChange(CollectionChangeEvent event) {
         if (artifactsQueue > 0) {
             GWT.log("Do not update UI because we are still loading Artifacts.");
@@ -452,6 +532,7 @@
     }
 
 
+    @Override
     public void onOutputModesChange(OutputModesChangeEvent event) {
         clearOutputTabs();
         OutputMode[] outs = event.getOutputModes();
@@ -555,9 +636,15 @@
     }
 
 
-    public void onCloseClick(CloseClientEvent event) {
+    @Override
+    public void onCloseClick(CloseClickEvent event) {
         if (collection != null) {
-            flys.closeProject(collection.identifier());
+            if(artifact != null) {
+                flys.closeProject(collection.identifier());
+            }
+            else {
+                flys.getProjectList().deleteCollection(collection);
+            }
         }
         else {
             hide();
@@ -566,29 +653,24 @@
     }
 
 
-    public void addArtifactToCollection(final Artifact artifact) {
+    public void addArtifactToCollection(Artifact artifact) {
         Config config               = Config.getInstance();
-        final String url            = config.getServerUrl();
         final String locale         = config.getLocale();
         final Collection collection = getCollection();
 
-        artifactsQueue++;
-
         addArtifactService.add(
             collection, artifact, locale,
             new AsyncCallback<Collection>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("An error occured while adding artifact.");
-                    artifactsQueue--;
                     SC.warn(messages.getString(caught.getMessage()));
                 }
 
+                @Override
                 public void onSuccess(Collection newCollection) {
-                    GWT.log("Successfully added artifact.");
-                    setCollection(newCollection);
-
-                    artifactsQueue--;
-                    addRecommendationsToCollection();
+                    GWT.log("Successfully added artifacts.");
+                    setCollection(newCollection, true);
                 }
             }
         );
@@ -604,6 +686,7 @@
 
         updater.update(collection, locale,
             new AsyncCallback<Collection>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     newRecommendations.removeAllElements();
                     setCollection(collection);
@@ -612,6 +695,7 @@
                     // TODO POPUP WARNING
                 }
 
+                @Override
                 public void onSuccess(Collection newCol) {
                     GWT.log("Successfully saved recommendations.");
                     newRecommendations.removeAllElements();
@@ -624,14 +708,11 @@
 
     protected void loadRecommendedArtifacts(Recommendation[] recommendations) {
         Config config               = Config.getInstance();
-        final String url            = config.getServerUrl();
         final String locale         = config.getLocale();
         final Collection collection = getCollection();
 
-
         Artifact masterArtifact = getArtifact();
 
-
         if (recommendations == null) {
             GWT.log("WARNING: Currently no recommendations.");
             return;
@@ -641,37 +722,72 @@
             if (collection.loadedRecommendation(recommendation)) {
                 continue;
             }
+            newRecommendations.push(recommendation);
 
             // XXX: UGLY! If no reference artifact given use uuid of
-            //      current artifact as reference.      
+            //      current artifact as reference.
             if (recommendation.getMasterArtifact() == null) {
                 recommendation.setMasterArtifact(masterArtifact.getUuid());
             }
 
-            final String factory = recommendation.getFactory();
-
-            GWT.log("Load recommended artifact with factory: " + factory);
+        }
 
-            createArtifactService.create(
-                locale, factory, recommendation,
-                new AsyncCallback<Artifact>() {
-                    public void onFailure(Throwable caught) {
-                        GWT.log("Error loading recommendations: " +
-                            caught.getMessage());
-                    }
+        loadArtifactService.loadMany(
+            collection,
+            recommendations,
+            null,
+            locale,
+            new AsyncCallback<Artifact[]>() {
+                @Override
+                public void onFailure(Throwable caught) {
+                    GWT.log("Error loading recommendations: " +
+                        caught.getMessage());
+                }
 
-                    public void onSuccess(Artifact artifact) {
-                        GWT.log("Created new artifact: " + artifact.getUuid());
-                        addArtifactToCollection(artifact);
-                        newRecommendations.push(recommendation);
-                    }
-            });
-        }
+                @Override
+                public void onSuccess(Artifact[] artifacts) {
+                    GWT.log("Loaded artifacts: " + artifacts.length);
+                    addRecommendationsToCollection();
+                }
+        });
     }
 
 
     public void registerTabHandler(TabSelectedHandler tse) {
         tabs.addTabSelectedHandler(tse);
     }
+
+
+    public void setCurrentKm(double currentKm) {
+        this.currentKm = currentKm;
+    }
+
+    public double getCurrentKm() {
+        return this.currentKm;
+    }
+
+    public void setMinKm(double km) {
+        this.minKm = km;
+    }
+
+    public double getMinKm() {
+        return this.minKm;
+    }
+
+    public void setMaxKm(double km) {
+        this.maxKm = km;
+    }
+
+    public double getMaxKm() {
+        return this.maxKm;
+    }
+
+    public void setSteps(double step) {
+        this.steps = step;
+    }
+
+    public double getSteps() {
+        return this.steps;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacageButton.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacageButton.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,7 +4,7 @@
 import com.smartgwt.client.widgets.events.ClickEvent;
 import com.smartgwt.client.widgets.events.ClickHandler;
 import com.smartgwt.client.widgets.events.CloseClickHandler;
-import com.smartgwt.client.widgets.events.CloseClientEvent;
+import com.smartgwt.client.widgets.events.CloseClickEvent;
 
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.shared.model.User;
@@ -17,8 +17,8 @@
     protected CollectionView view;
 
     public DatacageButton(
-        String         title, 
-        Artifact       artifact, 
+        String         title,
+        Artifact       artifact,
         User           user,
         CollectionView view
     ) {
@@ -39,7 +39,7 @@
         final DatacageWindow dc = new DatacageWindow(
             artifact, user, outs, view);
         dc.addCloseClickHandler(new CloseClickHandler() {
-            public void onCloseClick(CloseClientEvent event) {
+            public void onCloseClick(CloseClickEvent event) {
                 dc.destroy();
             }
         });
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacagePairWidget.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacagePairWidget.java	Fri Sep 28 12:15:52 2012 +0200
@@ -20,25 +20,26 @@
 
 
 /**
- * Widget showing two Datacages and a plus-button.
- * Insert a record into a listgrid when plus-button clicked.
+ * Widget showing two Datacages and a add-this-button.
+ * Insert a record into a listgrid when add-this-button clicked.
  */
 public class DatacagePairWidget
 extends      VLayout
 {
-    protected FLYSConstants messages =
+    /** i18n resource. */
+    protected FLYSConstants MSG =
         GWT.create(FLYSConstants.class);
-    
+
     /** The "remote" ListGrid to insert data to when add-button is clicked. */
-    protected ListGrid grid; 
-    
+    protected ListGrid grid;
+
     /** First (upper) DataCage Grid. */
     protected DatacageWidget firstDatacageWidget;
-    
+
     /** Second (lower) DataCage Grid. */
     protected DatacageWidget secondDatacageWidget;
 
-    
+
     /**
      *
      * @param artifact Artifact to query datacage with.
@@ -56,7 +57,7 @@
         firstDatacageWidget  = new DatacageWidget(
             artifact,
             user,
-            outs, 
+            outs,
             "load-system:true",
             false);
         secondDatacageWidget = new DatacageWidget(
@@ -71,8 +72,9 @@
         hLayout.addMember(firstDatacageWidget);
         hLayout.addMember(secondDatacageWidget);
 
-        // TODO: i18n + icon
-        Button plusBtn = new Button("+");
+        // TODO: icon
+        Button plusBtn = new Button(MSG.datacage_add_pair());
+        plusBtn.setAutoFit(true);
         plusBtn.addClickHandler(new ClickHandler() {
             @Override
             public void onClick(ClickEvent event) {
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacageTwinPanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacageTwinPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -126,7 +126,7 @@
         Recommendation r = new Recommendation("waterlevel", parts[0],
             this.artifact.getUuid(), filter);
         r.setDisplayName(parts[3]);
-        return r; 
+        return r;
     }
 
 
@@ -177,7 +177,7 @@
         this.helperContainer.addMember(helperLayout);
 
         // Find old data, if any, handle "diffids".
-        Data   data   = dataList.get(0);
+        Data data     = dataList.get(0);
         this.dataName = data.getLabel();
         for (int i = 0; i < dataList.size(); i++) {
             if (dataList.get(i) != null && dataList.get(i).getItems() != null) {
@@ -245,13 +245,13 @@
 
         differencesList.setFields(new ListGridField[] {nameField,
            capitalField, removeField});
-        
+
         differencesList.addRecordClickHandler(new RecordClickHandler() {
                 public void onRecordClick(final RecordClickEvent event) {
                     // Just handle remove-clicks
                     if(!event.getField().getName().equals(removeField.getName())) {
                         return;
-                    }    
+                    }
                     trackRemoved(event.getRecord());
                     event.getViewer().removeData(event.getRecord());
                 }
@@ -426,7 +426,7 @@
             String uuid = newArtifact.getUuid();
             r.setMasterArtifact(uuid);
             if (i>0) dataItemString += "#";
-    
+
             dataItemString += createDataString(uuid, r);
         }
 
@@ -434,7 +434,7 @@
             Recommendation r = oldRecommendations[i];
             String uuid = r.getIDs();
             if (dataItemString.length() > 0) dataItemString += "#";
-    
+
             dataItemString += createDataString(uuid, r);
         }
 
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacageWidget.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacageWidget.java	Fri Sep 28 12:15:52 2012 +0200
@@ -28,6 +28,8 @@
 import com.smartgwt.client.widgets.grid.events.RecordDoubleClickEvent;
 import com.smartgwt.client.widgets.grid.events.RecordDoubleClickHandler;
 
+import com.smartgwt.client.widgets.grid.HoverCustomizer;
+
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.shared.model.User;
 import de.intevation.flys.client.shared.model.ToLoad;
@@ -131,8 +133,37 @@
         treeGrid.setWidth100();
         treeGrid.setHeight100();
         treeGrid.setShowRoot(false);
-        treeGrid.setNodeIcon("[SKIN]/images/blank.gif");
+        treeGrid.setNodeIcon("[SKIN]/../blank.gif");
         treeGrid.setShowConnectors(true);
+        treeGrid.setLoadingMessage(messages.databasket_loading());
+        treeGrid.setEmptyMessage(messages.databasket_loading());
+        treeGrid.setLoadingDataMessage(messages.databasket_loading());
+
+        treeGrid.setHoverMoveWithMouse(true);
+        treeGrid.setCanHover(true);
+        treeGrid.setShowHover(true);
+        treeGrid.setHoverOpacity(75);
+
+        treeGrid.setHoverCustomizer(new HoverCustomizer() {
+            @Override
+            public String hoverHTML(Object value,
+                ListGridRecord record,
+                int rowNum,
+                int colNum
+                ) {
+                if(record instanceof TreeNode) {
+                    TreeNode hoveredTreeNode = (TreeNode)record;
+                    String info = hoveredTreeNode.getAttribute("info");
+                    if (info == null) {
+                        info = hoveredTreeNode.getName();
+                    }
+                    return info;
+                }
+                else {
+                    return "";// should not happen
+                }
+            }
+        });
 
         treeGrid.addRecordDoubleClickHandler(new RecordDoubleClickHandler() {
             @Override
@@ -355,6 +386,7 @@
     }
 
 
+    /** Get meta-data and populate tree with it. */
     protected void triggerTreeBuilding() {
         Config config = Config.getInstance();
         String locale = config.getLocale();
@@ -381,6 +413,14 @@
                     TreeNode root = buildRecursiveChildren(
                         dcRoot, idGenerator);
                     tree.setRoot(root);
+
+                    TreeNode[] nodes = tree.getChildren(root);
+                    for (int i = 0; i < nodes.length; i++) {
+                        if(!tree.hasChildren(nodes[i])) {
+                            nodes[i].setIsFolder(true);
+                        }
+                    }
+
                     if (idGenerator.current() < MAX_OPEN) {
                         tree.openAll();
                     }
@@ -421,7 +461,7 @@
     }
 
     protected TreeNode buildRecursiveChildren(
-        DataCageNode   node, 
+        DataCageNode   node,
         IdGenerator    idGenerator
     ) {
         TreeNode tn = new TreeNode();
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacageWindow.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DatacageWindow.java	Fri Sep 28 12:15:52 2012 +0200
@@ -55,7 +55,7 @@
 
 
     public DatacageWindow(
-        Artifact       artifact, 
+        Artifact       artifact,
         User           user,
         String         outs,
         CollectionView view
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/DigitizePanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DigitizePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,18 +1,30 @@
 package de.intevation.flys.client.client.ui;
 
 import java.util.List;
+import java.util.LinkedHashMap;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
 import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.Label;
 import com.smartgwt.client.widgets.events.ResizedEvent;
 import com.smartgwt.client.widgets.events.ResizedHandler;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
 import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
 import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
 import com.smartgwt.client.widgets.events.VisibilityChangedHandler;
 import com.smartgwt.client.widgets.events.VisibilityChangedEvent;
+import com.smartgwt.client.widgets.layout.VLayout;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.UploadItem;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.types.VerticalAlignment;
+import com.smartgwt.client.widgets.HTMLPane;
+import com.smartgwt.client.types.Encoding;
 
 import org.gwtopenmaps.openlayers.client.Map;
 import org.gwtopenmaps.openlayers.client.feature.VectorFeature;
@@ -104,6 +116,101 @@
     }
 
 
+    /**
+     * This method creates the content of the widget.
+     *
+     * @param data The {@link DataList} object.
+     *
+     * @return a combobox.
+     */
+    protected Canvas createWidget(DataList data) {
+        GWT.log("DigitizePanel - createWidget()");
+
+        VLayout layout   = new VLayout();
+        layout.setAlign(VerticalAlignment.TOP);
+        layout.setHeight(25);
+
+        LinkedHashMap initial = new LinkedHashMap();
+
+        form = new DynamicForm();
+
+        int size = data.size();
+
+        for (int i = 0; i < size; i++) {
+            Data d = data.get(i);
+
+            Label label = new Label(d.getDescription());
+            label.setValign(VerticalAlignment.TOP);
+            label.setHeight(20);
+            label.setWidth(400);
+
+            SelectItem combobox = new SelectItem(d.getLabel());
+            combobox.setWidth(250);
+
+            LinkedHashMap<String, String> it = new LinkedHashMap<String, String>();
+
+            boolean  defaultSet = false;
+            boolean  first      = true;
+
+            DataItem def      = d.getDefault();
+            String   defValue = def != null ? def.getStringValue() : null;
+
+            if (defValue != null && defValue.length() > 0) {
+                initial.put(d.getLabel(), def.getStringValue());
+                defaultSet = true;
+            }
+
+            // I was here.
+            for (DataItem item: d.getItems()) {
+                if (!defaultSet && first) {
+                    initial.put(d.getLabel(), item.getStringValue());
+                    first = false;
+                }
+
+                it.put(item.getStringValue(), item.getLabel());
+            }
+
+            label.setWidth(50);
+            combobox.setValueMap(it);
+            combobox.setShowTitle(false);
+            form.setItems(combobox);
+
+            HTMLPane frame = new HTMLPane();
+            frame.setWidth("1px");
+            frame.setHeight("1px");
+            frame.setContents("<iframe id='uploadTarget' name='uploadTarget'></iframe>");
+
+            final DynamicForm uploadForm = new DynamicForm();
+            uploadForm.setAction("flys/fileupload?uuid=" + artifact.getUuid());
+            uploadForm.setTarget("uploadTarget");
+            uploadForm.setEncoding(Encoding.MULTIPART);
+            Label uploadLabel = new Label(MSG.shape_file_upload());
+            uploadLabel.setHeight(20);
+            UploadItem uploadItem = new UploadItem();
+            uploadItem.setShowTitle(false);
+            uploadForm.setFields(uploadItem);
+            Button submit = new Button(MSG.upload_file());
+            submit.addClickHandler(new ClickHandler() {
+                public void onClick(ClickEvent e) {
+                    uploadForm.submitForm();
+                }
+            });
+            layout.addMember(frame);
+            layout.addMember(label);
+            layout.addMember(form);
+            layout.addMember(uploadLabel);
+            layout.addMember(uploadForm);
+            layout.addMember(submit);
+        }
+
+        form.setValues(initial);
+
+        layout.setAlign(VerticalAlignment.TOP);
+
+        return layout;
+    }
+
+
     @Override
     protected Data[] getData() {
         Data[] data  = super.getData();
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/DistancePanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DistancePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,15 +2,27 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.LinkedHashMap;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.i18n.client.NumberFormat;
 
 import com.smartgwt.client.data.Criteria;
+import com.smartgwt.client.data.Criterion;
+import com.smartgwt.client.data.AdvancedCriteria;
+import com.smartgwt.client.types.OperatorId;
+
 import com.smartgwt.client.data.Record;
 import com.smartgwt.client.util.SC;
+import com.smartgwt.client.types.Alignment;
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
+import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
 import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
 import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
 import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
@@ -36,6 +48,7 @@
 import de.intevation.flys.client.client.ui.range.LocationsTable;
 import de.intevation.flys.client.client.event.FilterHandler;
 import de.intevation.flys.client.client.event.StringFilterEvent;
+import de.intevation.flys.client.client.event.RangeFilterEvent;
 
 
 public class DistancePanel extends AbstractUIProvider implements BlurHandler, FilterHandler
@@ -55,13 +68,16 @@
 
     protected DoubleRangePanel distancePanel;
 
-    protected TableFilter filter;
+    protected TableFilter filterDescription;
+    protected RangeTableFilter filterRange;
 
     protected TabSet tabs;
 
     protected double min;
     protected double max;
 
+    protected StaticTextItem filterResultCount;
+    protected ListGrid currentFiltered;
 
     public DistancePanel() {
         this("right");
@@ -478,18 +494,71 @@
         tabs.addTab(locations, 0);
         tabs.addTab(distances, 1);
 
-        filter = new TableFilter();
-        filter.setHeight("30px");
-        filter.addFilterHandler(this);
+        filterResultCount = new StaticTextItem(MSG.resultCount());
+        filterResultCount.setTitleAlign(Alignment.LEFT);
+        filterResultCount.setTitleStyle("color: #000");
 
+        filterDescription = new TableFilter();
+        filterDescription.setHeight("30px");
+        filterDescription.addFilterHandler(this);
+
+        filterRange = new RangeTableFilter();
+        filterRange.setHeight("30px");
+        filterRange.addFilterHandler(this);
+        filterRange.setVisible(false);
+
+        SelectItem filterCriteria = new SelectItem();
+        filterCriteria.setShowTitle(false);
+        filterCriteria.setWidth(100);
+        filterCriteria.addChangedHandler(new ChangedHandler() {
+            public void onChanged(ChangedEvent e) {
+                if(e.getValue().toString().equals("range")) {
+                    filterRange.setVisible(true);
+                    filterDescription.setVisible(false);
+                    filterDescription.clear();
+                }
+                else {
+                    filterRange.setVisible(false);
+                    filterRange.clear();
+                    filterDescription.setVisible(true);
+                }
+            }
+        });
+
+        LinkedHashMap<String, String> filterMap =
+            new LinkedHashMap<String, String>();
+        filterMap.put("description", MSG.description());
+        filterMap.put("range", MSG.range());
+        filterCriteria.setValueMap(filterMap);
+        filterCriteria.setValue("description");
+
+        DynamicForm form = new DynamicForm();
+        form.setFields(filterCriteria);
+
+        DynamicForm form2 = new DynamicForm();
+        form2.setFields(filterResultCount);
+
+        HLayout filterLayout = new HLayout();
+        filterLayout.addMember(form);
+        filterLayout.addMember(filterDescription);
+        filterLayout.addMember(filterRange);
+        filterLayout.setHeight(30);
         tabs.addTabSelectedHandler(new TabSelectedHandler() {
             public void onTabSelected(TabSelectedEvent evt) {
-                filter.clear();
+                filterDescription.clear();
+                filterRange.clear();
+                filterResultCount.setValue("");
+
+                Canvas c = evt.getTabPane();
+                if(c instanceof ListGrid) {
+                    currentFiltered = (ListGrid)c;
+                }
             }
         });
 
         helperContainer.addMember(tabs);
-        helperContainer.addMember(filter);
+        helperContainer.addMember(filterLayout);
+        helperContainer.addMember(form2);
     }
 
 
@@ -500,36 +569,75 @@
             Criteria c = new Criteria("description", search);
             locationsTable.filterData(c);
             distancesTable.filterData(c);
+            filterResultCount.setValue(currentFiltered.getRecords().length);
         }
         else {
             locationsTable.clearCriteria();
             distancesTable.clearCriteria();
+            filterResultCount.setValue("");
         }
     }
 
 
+    public void onFilterCriteriaChanged(RangeFilterEvent event) {
+        Float from = event.getFrom() - 0.001f;
+        Float to = event.getTo() + 0.001f;
+
+        Criterion combinedFilter = null;
+        Criterion locationFilter = null;
+        if (from.equals(Float.NaN) && to.equals(Float.NaN)) {
+            locationsTable.clearCriteria();
+            distancesTable.clearCriteria();
+            filterResultCount.setValue("");
+            return;
+        }
+        else if (from.equals(Float.NaN)) {
+            combinedFilter = new Criterion("to", OperatorId.LESS_OR_EQUAL, to);
+            locationFilter =
+                new Criterion("from", OperatorId.LESS_OR_EQUAL, to);
+            locationsTable.filterData(locationFilter);
+            distancesTable.filterData(combinedFilter);
+            filterResultCount.setValue(currentFiltered.getRecords().length);
+            return;
+        }
+        else if (to.equals(Float.NaN)) {
+            combinedFilter =
+                new Criterion("from", OperatorId.GREATER_OR_EQUAL, from);
+        }
+        else {
+            AdvancedCriteria c1 =
+                new AdvancedCriteria(OperatorId.AND, new Criterion[] {
+                    new Criterion("from", OperatorId.GREATER_OR_EQUAL, from),
+                    new Criterion("from", OperatorId.LESS_OR_EQUAL, to)
+                });
+
+            AdvancedCriteria c2 =
+                new AdvancedCriteria(OperatorId.AND, new Criterion[] {
+                    new Criterion("to", OperatorId.GREATER_OR_EQUAL, from),
+                    new Criterion("to", OperatorId.LESS_OR_EQUAL, to)
+                });
+
+            AdvancedCriteria c3 =
+                new AdvancedCriteria(OperatorId.AND, new Criterion[] {
+                    new Criterion("from", OperatorId.LESS_OR_EQUAL, to),
+                    new Criterion("to", OperatorId.GREATER_OR_EQUAL, from)
+                });
+
+            combinedFilter =
+                new AdvancedCriteria(OperatorId.OR, new Criterion[] {
+                    c1, c2, c3
+                });
+        }
+        locationsTable.filterData(combinedFilter);
+        distancesTable.filterData(combinedFilter);
+        filterResultCount.setValue(currentFiltered.getRecords().length);
+
+    }
+
+
     protected String getRiverName() {
         ArtifactDescription adescr = artifact.getArtifactDescription();
-        DataList[] data = adescr.getOldData();
-
-        if (data != null && data.length > 0) {
-            for (int i = 0; i < data.length; i++) {
-                DataList dl = data[i];
-
-                if (dl.getState().equals("state.winfo.river")) {
-                    for (int j = 0; j < dl.size(); j++) {
-                        Data d = dl.get(j);
-                        DataItem[] di = d.getItems();
-
-                        if (di != null && di.length == 1) {
-                           return d.getItems()[0].getStringValue();
-                        }
-                    }
-                }
-            }
-        }
-
-        return null;
+        return adescr.getRiver();
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/DoubleArrayPanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DoubleArrayPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -100,7 +100,7 @@
     public void setValues(double[] values) {
         NumberFormat f = NumberFormat.getDecimalFormat();
 
-        if(values.length == 0) {
+        if(values == null || values.length == 0) {
             ti.clearValue();
             return;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DoubleInputPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,156 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.TextItem;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+
+/**
+ * This UIProvider creates a panel for location or distance input.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class DoubleInputPanel
+extends      AbstractUIProvider
+{
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    private TextItem inputPanel;
+
+    private double value;
+
+    public DoubleInputPanel() {
+    }
+
+
+    public Canvas create(DataList list) {
+        VLayout layout = new VLayout();
+
+        Canvas helper = createHelper();
+        this.helperContainer.addMember(helper);
+
+        Canvas submit = getNextButton();
+        Canvas widget = createWidget(list);
+
+        layout.addMember(widget);
+        layout.addMember(submit);
+        return layout;
+    }
+
+
+    public Canvas createWidget(DataList data) {
+        VLayout layout = new VLayout();
+
+        Label title = new Label(data.get(0).getDescription());
+        title.setHeight("25px");
+
+        DataItem defaultItem = data.get(0).getDefault();
+
+        DynamicForm form = new DynamicForm();
+        inputPanel = new TextItem();
+        inputPanel.setTitle("outliers");
+        inputPanel.setShowTitle(false);
+
+        if (defaultItem != null) {
+            inputPanel.setValue(defaultItem.getStringValue());
+        }
+
+        form.setFields(inputPanel);
+
+        layout.addMember(title);
+        layout.addMember(form);
+
+        return layout;
+    }
+
+    protected Canvas createHelper() {
+        return new VLayout();
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        List<Data> items = dataList.getAll();
+
+        Data d = getData(items, "outliers");
+        DataItem[] item = d.getItems();
+
+        String v = item[0].getLabel();
+
+        Label old = new Label(v);
+        old.setWidth(130);
+
+        HLayout layout = new HLayout();
+        layout.setWidth("400px");
+
+        Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+
+        Canvas back = getBackButton(dataList.getState());
+
+        layout.addMember(label);
+        layout.addMember(old);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+     */
+    public Data[] getData() {
+        List<Data> data = new ArrayList<Data>();
+
+        boolean valid = saveDataValues();
+        if(valid) {
+
+            String vs = Double.valueOf(this.value).toString();
+            DataItem item = new DefaultDataItem("outliers", "outliers", vs);
+            data.add(new DefaultData(
+                "outliers",
+                null,
+                null,
+                new DataItem[] { item }));
+        }
+
+        return data.toArray(new Data[data.size()]);
+    }
+
+
+    protected boolean saveDataValues() {
+        String st = inputPanel.getValueAsString();
+        if (st == null) {
+            SC.warn("fehler... TODO");
+            return false;
+        }
+
+        try {
+            NumberFormat nf = NumberFormat.getDecimalFormat();
+            double d = nf.parse(st);
+            this.value = d;
+        }
+        catch(NumberFormatException nfe) {
+            SC.warn("fehler... nfe... TODO");
+            return false;
+        }
+        return true;
+    }
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/ExportPanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/ExportPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,6 +1,7 @@
 package de.intevation.flys.client.client.ui;
 
 import java.util.List;
+import java.util.MissingResourceException;
 
 import com.google.gwt.core.client.GWT;
 
@@ -67,6 +68,9 @@
             List<Facet> facets = mode.getFacets();
 
             for (Facet facet: facets) {
+                if (name.equals("fix_wq_curve_at_export")) {
+                    continue;
+                }
                 layout.addMember(createExportButton(name, facet.getName()));
             }
         }
@@ -127,7 +131,12 @@
      * @return a tooltip text.
      */
     protected String getTooltipText(String name, String facet) {
-        return MSG.getString(name) + " | " + MSG.getString(facet);
+        try {
+            return MSG.getString(name) + " | " + MSG.getString(facet);
+        }
+        catch (MissingResourceException mre) {
+            return name + " | " + facet;
+        }
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/FLYSView.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/FLYSView.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,6 +5,8 @@
 
 
 /**
+ * Vertically speaking the main part of the ui (containing projectlist
+ * and workspace).
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class FLYSView extends Canvas {
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/FLYSWorkspace.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/FLYSWorkspace.java	Fri Sep 28 12:15:52 2012 +0200
@@ -7,6 +7,7 @@
 
 
 /**
+ * "Workspace" canvas showing the CollectionViews (subwindows).
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class FLYSWorkspace extends Canvas {
@@ -29,6 +30,9 @@
      */
     public FLYSWorkspace() {
         views = new HashMap<String, CollectionView>();
+
+        setWidth("100%");
+        setHeight("100%");
     }
 
 
@@ -39,10 +43,8 @@
      * @param collectionView A new CollectionView.
      */
     public void addView(String uuid, CollectionView collectionView) {
-        int num    = views != null ? views.size() : 0;
-        int factor = num % MAX_WINDOWS;
-
-        collectionView.moveTo(factor * WINDOW_OFFSET, factor * WINDOW_OFFSET);
+        collectionView.moveTo(0, 0);
+        collectionView.setMaximized(true);
 
         views.put(uuid, collectionView);
         addChild(collectionView);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/GaugePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,209 @@
+package de.intevation.flys.client.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.Anchor;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+
+import com.smartgwt.client.types.Overflow;
+import com.smartgwt.client.widgets.events.ResizedEvent;
+import com.smartgwt.client.widgets.events.ResizedHandler;
+import com.smartgwt.client.widgets.layout.SectionStackSection;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.FLYS;
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.services.GaugeOverviewInfoService;
+import de.intevation.flys.client.client.services.GaugeOverviewInfoServiceAsync;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.RiverInfo;
+
+/**
+ * The GaugePanel is intendet to be used within a SectionStackSection
+ * It extends the VLayout by two methods to show and hide the
+ * section stack section.
+ *
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public class GaugePanel extends VLayout implements ResizedHandler {
+
+    /** SectionStackSection where this GaugePanel belongs in*/
+    private SectionStackSection sectionStack;
+
+    /** Name of the river */
+    private String river;
+
+    /** The message class that provides i18n strings.*/
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    private FLYS flys;
+
+    protected GaugeOverviewInfoServiceAsync gaugeOverviewInfoService =
+        GWT.create(GaugeOverviewInfoService.class);
+
+    protected GaugeTree gaugetree;
+
+    protected RiverInfoPanel riverinfopanel;
+
+    /**
+     * Creates a new VLayout with a SectionStackSection
+     * The GaugePanel's SectionStackSection is hidden by default.
+     *
+     * @param flys The FLYS object
+     * @param sectionStack The section stack section to place the VLayout in.
+     */
+    public GaugePanel(FLYS flys, SectionStackSection sectionStack) {
+        gaugetree = new GaugeTree(flys);
+        setOverflow(Overflow.HIDDEN);
+        sectionStack.setHidden(true);
+        sectionStack.setItems(this);
+        this.sectionStack = sectionStack;
+        setStyleName("gaugepanel");
+        addResizedHandler(this);
+    }
+
+    /**
+     * Sets and loads the river data if river is not the current set river
+     */
+    public void setRiver(String river) {
+        if (!river.equals(this.river)) {
+            this.river = river;
+            this.refresh();
+        }
+    }
+
+    /**
+     * Sets the data and closes not corresponding folds in the gauge tree
+     */
+    public void setData(DataList[] data) {
+        gaugetree.setData(data);
+    }
+
+    /**
+     * Loads the river info and renders it afterwards
+     */
+    public void refresh() {
+        gaugeOverviewInfoService.getRiverInfo(this.river, new AsyncCallback<RiverInfo>() {
+            public void onFailure(Throwable e) {
+                GWT.log("Could not load the river info." + e);
+            }
+
+            public void onSuccess(RiverInfo riverinfo) {
+                GWT.log("Loaded river info");
+                renderGaugeOverviewInfo(riverinfo);
+            }
+        });
+    }
+
+    public void renderGaugeOverviewInfo(RiverInfo riverinfo) {
+        removeMembers(getMembers());
+
+        riverinfopanel = new RiverInfoPanel(riverinfo);
+        addMember(riverinfopanel);
+        addMember(gaugetree);
+
+        gaugetree.setGauges(riverinfo);
+    }
+
+    @Override
+    public void onResized(ResizedEvent event) {
+        /* this height calculation is only an approximation and doesn't reflect
+         * the real height of the the gaugetree. */
+        int height = getInnerContentHeight() -
+            (RiverInfoPanel.HEIGHT +
+            (2 * RiverInfoPanel.BORDER_WIDTH) +
+            (2 * RiverInfoPanel.PADDING) +
+            (2 * RiverInfoPanel.MARGIN));
+
+        if (height < 0) {
+            height = 0;
+        }
+
+        gaugetree.setHeight("" + height + "px");
+    }
+
+
+    /**
+     * Hide the section stack section.
+     */
+    public void hide() {
+        GWT.log("GaugePanel - hide");
+        this.sectionStack.setHidden(true);
+    }
+
+    /**
+     * Show the section stack section.
+     */
+    public void show() {
+        GWT.log("GaugePanel - show");
+        this.sectionStack.setHidden(false);
+    }
+
+    class RiverInfoPanel extends HorizontalPanel {
+
+        public final static int HEIGHT = 30;
+        public final static int BORDER_WIDTH = 3;
+        public final static int PADDING = 8;
+        public final static int MARGIN = 10;
+
+        public RiverInfoPanel(RiverInfo riverinfo) {
+            setStyleName("riverinfopanel");
+            setHeight("" + HEIGHT + "px");
+            setVerticalAlignment(ALIGN_MIDDLE);
+
+            NumberFormat nf = NumberFormat.getDecimalFormat();
+
+            addLabel(riverinfo.getName(), false);
+
+            String kmtext = "";
+            Double start = riverinfo.getKmStart();
+            Double end = riverinfo.getKmEnd();
+
+            if (!riverinfo.isKmUp()) {
+                Double tmp = end;
+                end = start;
+                start = tmp;
+            }
+            if (end != null) {
+                kmtext += nf.format(end);
+                kmtext += " - ";
+            }
+            if (start != null) {
+                kmtext += nf.format(start);
+            }
+            kmtext += " km";
+
+            addLabel(kmtext, false);
+
+            String qtext = "";
+            Double qmin = riverinfo.getMinQ();
+            Double qmax = riverinfo.getMaxQ();
+            if (qmin != null) {
+                qtext += nf.format(qmin);
+                qtext += " " + MSG.gauge_q_unit();
+                qtext += " - ";
+            }
+            if (qmax != null) {
+                qtext += nf.format(qmax);
+                qtext += " " + MSG.gauge_q_unit();
+            }
+
+            addLabel(qtext, false);
+
+            Long number = riverinfo.getOfficialNumber();
+            String url = number != null ?
+                MSG.gauge_river_url() + number :
+                MSG.gauge_river_url();
+            Anchor anchor = new Anchor(MSG.gauge_river_info_link(), url);
+            add(anchor);
+        }
+
+        private void addLabel(String text, boolean wordwrap) {
+            Label label = new Label(text, wordwrap);
+            add(label);
+            setCellHeight(label, "" + HEIGHT + "px");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/GaugeTimeRangePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,325 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Date;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.DateTimeFormat;
+
+import com.smartgwt.client.types.ListGridFieldType;
+
+import com.smartgwt.client.data.Record;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.DateRangeItem;
+import com.smartgwt.client.widgets.Label;
+
+import com.smartgwt.client.widgets.layout.VLayout;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.CellFormatter;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.Config;
+
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.ArtifactDescription;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.RangeData;
+import de.intevation.flys.client.shared.model.LongRangeData;
+
+import de.intevation.flys.client.client.ui.range.DischargeInfoDataSource;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class GaugeTimeRangePanel extends RangePanel {
+
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    protected ListGrid yearTable;
+
+    protected DateRangeItem dateRange;
+
+    public GaugeTimeRangePanel() {
+        GWT.log("Creating YearInputPanel");
+        yearTable = new ListGrid();
+        yearTable.setAutoFetchData(true);
+        yearTable.setShowHeaderContextMenu(false);
+
+    }
+
+    public Canvas create(DataList data) {
+        setDataName(data);
+
+        VLayout root = new VLayout();
+
+        root.addMember(createLabel(data));
+        root.addMember(createForm(data));
+        root.addMember(getNextButton());
+
+        initDefaults(data);
+
+
+        initYearTable();
+
+        long gauge = getGaugeNumber();
+
+        Config config = Config.getInstance();
+        String url = config.getServerUrl();
+        yearTable.setDataSource(new DischargeInfoDataSource(url, gauge));
+
+        helperContainer.addMember(yearTable);
+        return root;
+    }
+
+
+    @Override
+    protected void initDefaults(DataList dataList) {
+        RangeData data = findRangeData(dataList);
+
+        if(data != null) {
+            GWT.log("data: " + data);
+        }
+    }
+
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        GWT.log("create old date.");
+        Data       data  = dataList.get(0);
+        DataItem[] items = data.getItems();
+GWT.log(data.getClass().toString());
+        HLayout layout = new HLayout();
+
+        Label label = new Label(dataList.getLabel());
+        label.setWidth(200);
+        label.setHeight(20);
+
+        Date dl = new Date((Long)((LongRangeData)data).getLower());
+        Date du = new Date((Long)((LongRangeData)data).getUpper());
+        DateTimeFormat dtf = DateTimeFormat.getMediumDateFormat();
+        Label value = new Label(dtf.format(dl) + " - " + dtf.format(du));
+        value.setHeight(20);
+
+        layout.addMember(label);
+        layout.addMember(value);
+        layout.addMember(getBackButton(dataList.getState()));
+
+        return layout;
+    }
+
+
+    @Override
+    protected Data[] getData() {
+        long lo = getLowerAsLong();
+        long up = getUpperAsLong();
+
+        return new Data[] { new LongRangeData(getDataName(), null, lo, up) };
+    }
+
+
+    @Override
+    protected Canvas createForm(DataList dataList) {
+        HLayout layout = new HLayout();
+        DynamicForm form = new DynamicForm();
+        dateRange = new DateRangeItem();
+        dateRange.setToTitle(MESSAGES.to());
+        dateRange.setFromTitle(MESSAGES.from());
+        dateRange.setShowTitle(false);
+        form.setFields(dateRange);
+
+        layout.addMember(form);
+        return layout;
+
+    }
+
+
+    @Override
+    public Object getMaxLower() {
+        Date d = dateRange.getFromDate();
+        return new Long(d.getTime());
+    }
+
+
+    protected long getLowerAsLong() {
+        Date d = dateRange.getFromDate();
+        return d.getTime();
+    }
+
+
+    protected long getUpperAsLong() {
+        Date d = dateRange.getToDate();
+        return d.getTime();
+    }
+
+
+    @Override
+    public Object getMaxUpper() {
+        Date d = dateRange.getToDate();
+        return new Long(d.getTime());
+    }
+
+
+    @Override
+    public void setLower(String lower) {
+        try {
+            DateTimeFormat dtf =
+                DateTimeFormat.getFormat("yyyy");
+            Date dy = dtf.parse(lower);
+            dy.setMonth(0);
+            dy.setDate(1);
+            dateRange.setFromDate(dy);
+        }
+        catch(IllegalArgumentException iae) {
+            GWT.log("could not parse lower date.");
+            //TODO: Messagebox with error.
+        }
+    }
+
+
+    @Override
+    public void setUpper(String upper) {
+        try {
+            DateTimeFormat dtf =
+                DateTimeFormat.getFormat("yyyy");
+            Date dy = dtf.parse(upper);
+            dy.setMonth(0);
+            dy.setDate(1);
+            dateRange.setToDate(dy);
+        }
+        catch(IllegalArgumentException iae) {
+            GWT.log("could not parse upper date.");
+            //TODO: Messagebox with error.
+        }
+    }
+
+
+    protected ListGrid initYearTable() {
+        String baseUrl = GWT.getHostPageBaseURL();
+
+        yearTable.setWidth100();
+        yearTable.setHeight100();
+        yearTable.setShowRecordComponents(true);
+        yearTable.setShowRecordComponentsByCell(true);
+        yearTable.setEmptyMessage(MESSAGES.empty_filter());
+        yearTable.setCanReorderFields(false);
+
+        CellFormatter cf = new CellFormatter() {
+            public String format(
+                Object value,
+                ListGridRecord record,
+                int rowNum, int colNum) {
+                    if (value == null) return null;
+                    if (value.toString().equals("-1")) {
+                        return "";
+                    }
+                    return value.toString();
+            }
+        };
+
+
+        ListGridField addstart = new ListGridField ("", "");
+        addstart.setType (ListGridFieldType.ICON);
+        addstart.setWidth (20);
+        addstart.setCellIcon(baseUrl + MESSAGES.markerGreen());
+        addstart.addRecordClickHandler(new RecordClickHandler() {
+            public void onRecordClick(RecordClickEvent e) {
+                Record r = e.getRecord();
+                if (r.getAttribute("start").equals("-1")) {
+                    return;
+                }
+                else {
+                    setLower(r.getAttribute("start"));
+                }
+            }
+        });
+
+        ListGridField addend = new ListGridField ("", "");
+        addend.setType (ListGridFieldType.ICON);
+        addend.setWidth (20);
+        addend.setCellIcon(baseUrl + MESSAGES.markerRed());
+        addend.addRecordClickHandler(new RecordClickHandler() {
+            public void onRecordClick(RecordClickEvent e) {
+                Record r = e.getRecord();
+                if (r.getAttribute("end").equals("-1")) {
+                    return;
+                }
+                else {
+                    setUpper(r.getAttribute("end"));
+                }
+            }
+        });
+
+        ListGridField desc =
+            new ListGridField("description", MESSAGES.description());
+        desc.setType(ListGridFieldType.TEXT);
+        desc.setWidth("*");
+
+        ListGridField start =
+            new ListGridField("start", MESSAGES.start_year());
+        start.setType(ListGridFieldType.INTEGER);
+        start.setWidth(50);
+        start.setCellFormatter(cf);
+
+        ListGridField end =
+            new ListGridField("end", MESSAGES.end_year());
+        end.setType(ListGridFieldType.INTEGER);
+        end.setWidth(50);
+        end.setCellFormatter(cf);
+
+        yearTable.setFields(addstart, addend, desc, start, end);
+
+        return yearTable;
+    }
+
+
+    protected long getGaugeNumber() {
+        ArtifactDescription adescr = artifact.getArtifactDescription();
+        DataList[] data = adescr.getOldData();
+
+        String gauge = "";
+        if (data != null && data.length > 0) {
+            for (int i = 0; i < data.length; i++) {
+                DataList dl = data[i];
+                if (dl.getState().equals("state.winfo.historicalq.reference_gauge")) {
+                    for (int j = 0; j < dl.size(); j++) {
+                        Data d = dl.get(j);
+                        DataItem[] di = d.getItems();
+                        if (di != null && di.length == 1) {
+                           gauge = d.getItems()[0].getStringValue();
+                        }
+                    }
+                }
+            }
+        }
+        try {
+            return Long.parseLong(gauge);
+        }
+        catch (NumberFormatException nfe) {
+            GWT.log("Error parsing gauge.");
+            return 0;
+        }
+    }
+
+
+    @Override
+    public List<String> validate() {
+        List<String> errors = new ArrayList<String>();
+        if (dateRange.getFromDate() == null ||
+            dateRange.getToDate() == null ||
+            !dateRange.getFromDate().before(dateRange.getToDate()))
+        {
+            String msg = MSG.error_validate_date_range();
+            errors.add(msg);
+        }
+        return errors;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/GaugeTree.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,465 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.user.client.ui.Anchor;
+import com.google.gwt.user.client.ui.DecoratorPanel;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.Tree;
+import com.google.gwt.user.client.ui.TreeItem;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+
+import de.intevation.flys.client.client.FLYS;
+import de.intevation.flys.client.client.FLYSConstants;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.GaugeInfo;
+import de.intevation.flys.client.shared.model.RiverInfo;
+
+
+public class GaugeTree extends ScrollPanel {
+
+    private FLYS flys;
+    private Tree tree;
+    private DataList[] data;
+
+    /** The message class that provides i18n strings.*/
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    public GaugeTree(FLYS flys) {
+        this.flys = flys;
+        tree = new Tree();
+        setWidget(tree);
+    }
+
+    /**
+     * Resets the items of the tree.
+     * If the list of gauges is empty or null the tree will be empty.
+     */
+    public void setGauges(RiverInfo riverinfo) {
+        tree.clear();
+
+        List<GaugeInfo> gauges = riverinfo.getGauges();
+
+        if (gauges != null && !gauges.isEmpty()) {
+
+            ArrayList<GaugeInfo> emptygauges = new ArrayList<GaugeInfo>();
+
+            if (!riverinfo.isKmUp()) {
+                for (GaugeInfo gauge : gauges) {
+                    addGauge(gauge, emptygauges);
+                }
+            }
+            else {
+                for (int i = gauges.size()-1; i >= 0; i--) {
+                    GaugeInfo gauge = gauges.get(i);
+                    addGauge(gauge, emptygauges);
+                }
+            }
+
+            // put empty gauges to the end
+            for (GaugeInfo gauge : emptygauges) {
+                addGauge(gauge);
+            }
+
+            open();
+        }
+    }
+
+    private void addGauge(GaugeInfo gauge, List<GaugeInfo> empty) {
+        if (gauge.getKmStart() != null && gauge.getKmEnd() != null) {
+            addGauge(gauge);
+        }
+        else {
+            empty.add(gauge);
+        }
+    }
+
+    private void addGauge(GaugeInfo gauge) {
+        GaugeInfoItem gaugeitem = new GaugeInfoItem(flys, gauge);
+        tree.addItem(gaugeitem);
+    }
+
+    public void openAll() {
+        GWT.log("GaugeTree - openAll");
+        for (Iterator<TreeItem> it = tree.treeItemIterator(); it.hasNext();) {
+            TreeItem item = it.next();
+            item.setState(true);
+        }
+    }
+
+    public void setData(DataList[] data) {
+        this.data = data;
+        if (tree.getItemCount() > 0) {
+            open();
+        }
+    }
+
+    public void open() {
+        ArrayList<Double> locations = new ArrayList<Double>();
+
+        if (data != null && data.length > 0) {
+            for (int i = 0; i < data.length; i++) {
+                DataList dl = data[i];
+                String state = dl.getState();
+                GWT.log("GaugeTree - setData " + state);
+                if (state.equals("state.winfo.location_distance")) {
+                    Double ldfrom = null;
+                    Double ldto = null;
+
+                    for (int j = dl.size()-1; j >= 0; --j) {
+                        Data d = dl.get(j);
+                        String label = d.getLabel();
+                        GWT.log("GaugeTree - setData - label " + label + " " + d.getStringValue());
+                        if (label.equals("ld_from")) {
+                            ldfrom = getDoubleValue(d);
+                        }
+                        else if (label.equals("ld_to")) {
+                            ldto = getDoubleValue(d);
+                        }
+                        else if (label.equals("ld_locations")) {
+                            getLocationsFromData(locations, d);
+                            openOnLocations(locations);
+                            return;
+                        }
+                    }
+                    if (ldfrom != null) {
+                        openOnDistance(ldfrom, ldto);
+                        return;
+                    }
+                }
+                else if(state.equals("state.winfo.distance_only") ||
+                        state.equals("state.winfo.distance")) {
+                    Double ldfrom = null;
+                    Double ldto = null;
+
+                    for (int j = dl.size()-1; j >= 0; --j) {
+                        Data d = dl.get(j);
+                        String label = d.getLabel();
+                        GWT.log("GaugeTree - setData - label " + label + " " + d.getStringValue());
+                        if (label.equals("ld_from")) {
+                            ldfrom = getDoubleValue(d);
+                        }
+                        else if (label.equals("ld_to")) {
+                            ldto = getDoubleValue(d);
+                        }
+                    }
+
+                    if (ldfrom != null) {
+                        openOnDistance(ldfrom, ldto);
+                        return;
+                    }
+                        }
+                else if (state.equals("state.winfo.location")) {
+                    getLocations("ld_locations", locations, dl);
+                    openOnLocations(locations);
+                    return;
+                }
+                else if (state.equals("state.winfo.reference.curve.input.start")) {
+                    getLocations("reference_startpoint", locations, dl);
+                }
+                else if (state.equals("state.winfo.reference.curve.input.end")) {
+                    getLocations("reference_endpoint", locations, dl);
+                }
+                else if (state.equals("state.winfo.historicalq.reference_gauge")) {
+                    for (int j = dl.size()-1; j >= 0; --j) {
+                        Data d = dl.get(j);
+                        String label = d.getLabel();
+                        if (label.equals("reference_gauge")) {
+                            String tmp = d.getStringValue();
+                            if (tmp != null) {
+                                Long gaugereference = Long.valueOf(tmp);
+                                if (gaugereference != null) {
+                                    openOnReference(gaugereference);
+                                    return;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (!locations.isEmpty()) {
+            openOnLocations(locations);
+        }
+        else {
+            openAll();
+        }
+    }
+
+    private void getLocations(String labelname, List<Double> locations, DataList dl) {
+        for (int j = dl.size()-1; j >= 0; --j) {
+            Data d = dl.get(j);
+            String label = d.getLabel();
+            if (label.equals(labelname)) {
+                getLocationsFromData(locations, d);
+            }
+        }
+    }
+
+    private void getLocationsFromData(List<Double> locations, Data data) {
+        DataItem[] items = data.getItems();
+        for (int k = 0; k < items.length; k++) {
+            String tmp = items[k].getStringValue();
+            GWT.log("GaugeTree - getLocationsFromData " + tmp);
+            if (tmp != null) {
+                if (tmp.contains(" ")) {
+                    // string contains several values ...
+                    String[] values = tmp.split(" ");
+                    for(int i=0; i < values.length; i++) {
+                        Double value = Double.valueOf(values[i]);
+                        if (value != null) {
+                            locations.add(value);
+                        }
+                    }
+                }
+                else {
+                    Double value = Double.valueOf(tmp);
+                    if (value != null) {
+                        locations.add(value);
+                    }
+                }
+            }
+        }
+    }
+
+    private Double getDoubleValue(Data d) {
+        String tmp = d.getStringValue();
+        if (tmp != null) {
+            return Double.valueOf(tmp);
+        }
+        return null;
+    }
+
+    public void openOnReference(Long number) {
+        GWT.log("GaugeTree - openOnReference " + number);
+        for (Iterator<TreeItem> it = tree.treeItemIterator(); it.hasNext();) {
+            TreeItem item = it.next();
+            if (item instanceof GaugeInfoItem) {
+                GaugeInfoItem gitem = (GaugeInfoItem)item;
+                if (gitem.getReference().equals(number)) {
+                    item.setState(true);
+                }
+                else {
+                    item.setState(false);
+                }
+            }
+        }
+    }
+
+    public void openOnDistance(Double start, Double end) {
+        GWT.log("GaugeTree - openOnDistance " + start + " " + end + " " +
+                tree.getItemCount());
+
+        for (Iterator<TreeItem> it = tree.treeItemIterator(); it.hasNext();) {
+            TreeItem item = it.next();
+            /* Strange stuff is happening here:
+             * GWT Tree.treeItemIterator returns another TreeItem for each
+             * GaugeInfoItem */
+            if (item instanceof GaugeInfoItem) {
+                boolean setstate = false;
+                GaugeInfoItem gitem = (GaugeInfoItem)item;
+                if (end == null) {
+                    if (gitem.getStart() >= start) {
+                        setstate = true;
+                    }
+                }
+                else {
+                    GWT.log("GaugeTree - openOnDistance gitem " + gitem.getStart() + " " + gitem.getEnd());
+                    if ((start >= gitem.getStart() && start <= gitem.getEnd()) ||
+                            (end >= gitem.getStart() && end <= gitem.getEnd()) ||
+                            (start <= gitem.getStart() && end >= gitem.getEnd())) {
+                        setstate = true;
+                            }
+                }
+                item.setState(setstate);
+            }
+        }
+    }
+
+    public void openOnLocations(List<Double> locations) {
+        GWT.log("GaugeTree - openOnLocations " + locations + " " +
+                tree.getItemCount());
+
+        if (locations == null || locations.isEmpty()) {
+            return;
+        }
+
+        for (Iterator<TreeItem> it = tree.treeItemIterator(); it.hasNext();) {
+            TreeItem item = it.next();
+            if (item instanceof GaugeInfoItem) {
+                GaugeInfoItem gitem = (GaugeInfoItem)item;
+                boolean isset = false;
+                for (Double location: locations) {
+                    if (locations == null) {
+                        continue;
+                    }
+                    if (location >= gitem.getStart() &&
+                            location <= gitem.getEnd()) {
+                        isset = true;
+                        break;
+                            }
+                }
+                item.setState(isset);
+            }
+        }
+    }
+
+    class GaugeInfoItem extends TreeItem {
+
+        private GaugeInfo gauge;
+
+        public GaugeInfoItem(FLYS flys, GaugeInfo gauge) {
+            GaugeInfoHead gaugeinfohead = new GaugeInfoHead(flys, gauge);
+            GaugeInfoPanel gaugeinfopanel = new GaugeInfoPanel(gauge);
+            setWidget(gaugeinfohead);
+            addItem(gaugeinfopanel);
+            this.gauge = gauge;
+        }
+
+        public Double getStart() {
+            return gauge.getKmStart();
+        }
+
+        public Double getEnd() {
+            return gauge.getKmEnd();
+        }
+
+        public Long getReference() {
+            return gauge.getOfficialNumber();
+        }
+    }
+
+    class GaugeInfoHead extends HLayout {
+
+        public GaugeInfoHead(FLYS flys, GaugeInfo gauge) {
+            setStyleName("gaugeinfohead");
+            setAutoHeight();
+            setAutoWidth();
+
+            NumberFormat nf = NumberFormat.getDecimalFormat();
+
+            Label label = new Label(gauge.getName(), true);
+            addMember(label);
+
+            Double start;
+            Double end;
+
+            if (!gauge.isKmUp()) {
+                start = gauge.getKmStart();
+                end   = gauge.getKmEnd();
+            }
+            else {
+                start = gauge.getKmEnd();
+                end   = gauge.getKmStart();
+            }
+
+            String kmtext = "";
+            if (start != null) {
+                kmtext += nf.format(start);
+                kmtext += " - ";
+            }
+            if (end != null) {
+                kmtext += nf.format(end);
+            }
+            if (start != null || end != null) {
+                kmtext += " km";
+            }
+
+            label = new Label(kmtext);
+
+            addMember(label);
+
+            Double station = gauge.getStation();
+            if (station != null) {
+                String stext = nf.format(station);
+                stext += " km";
+                label = new Label(stext);
+                addMember(label);
+            }
+
+            Long number = gauge.getOfficialNumber();
+            String url = number != null ?
+                MSG.gauge_url() + number :
+                MSG.gauge_url();
+            Anchor anchor = new Anchor(MSG.gauge_info_link(), url);
+            addMember(anchor);
+
+            addMember(new GaugeCurveAnchor(flys, gauge));
+        }
+    }
+
+    class GaugeCurveAnchor extends Anchor implements ClickHandler {
+
+        private FLYS flys;
+        private GaugeInfo gauge;
+
+        public GaugeCurveAnchor(FLYS flys, GaugeInfo gauge) {
+            super(MSG.gauge_curve_link());
+            this.flys = flys;
+            this.gauge = gauge;
+
+            addClickHandler(this);
+        }
+
+        public void onClick(ClickEvent ev) {
+            GWT.log("GaugeCurveAnchor - onClick " + gauge.getRiverName() +
+                    " " + gauge.getOfficialNumber());
+            flys.newGaugeDischargeCurve(gauge.getRiverName(),
+                    gauge.getOfficialNumber());
+        }
+    }
+
+    class GaugeInfoPanel extends DecoratorPanel {
+
+        public GaugeInfoPanel(GaugeInfo gauge) {
+            setStyleName("gaugeinfopanel");
+            Grid grid = new Grid(4, 2);
+
+            NumberFormat nf = NumberFormat.getDecimalFormat();
+
+            Double minw = gauge.getMinW();
+            Double maxw = gauge.getMaxW();
+            if (minw != null && maxw != null) {
+                grid.setText(0, 0, MSG.wq_value_q());
+                grid.setText(0, 1, "" + nf.format(minw) +
+                        " - " + nf.format(maxw));
+            }
+
+            Double minq = gauge.getMinQ();
+            Double maxq = gauge.getMaxQ();
+            if (minq != null && maxq != null) {
+                grid.setText(1, 0, MSG.wq_value_w());
+                grid.setText(1, 1, "" + nf.format(minq) +
+                        " - " + nf.format(maxq));
+            }
+
+            Double aeo = gauge.getAeo();
+            if (aeo != null) {
+                grid.setText(2, 0, "AEO [km²]");
+                grid.setText(2, 1, "" + nf.format(aeo));
+            }
+
+            Double datum = gauge.getDatum();
+            if (datum != null) {
+                grid.setText(3, 0, MSG.gauge_zero() + " [" +
+                        gauge.getWstUnit() + "]");
+                grid.setText(3, 1, "" + nf.format(datum));
+            }
+
+            setWidget(grid);
+        }
+    }
+
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/ImgLink.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/ImgLink.java	Fri Sep 28 12:15:52 2012 +0200
@@ -6,12 +6,48 @@
 
 public class ImgLink extends HTMLPane {
 
+    private int width;
+    private int height;
+
+    private String href;
+    private String imgUrl;
+
+    private boolean newTab;
+
+
     public ImgLink(String imgUrl, String href, int width, int height) {
         super();
 
-        setContents("<a href='" + href + "'><img src='" + imgUrl + "'></a>");
+        this.width  = width;
+        this.height = height;
+        this.href   = href;
+        this.imgUrl = imgUrl;
+        this.newTab = false;
+
+        update();
+    }
+
+
+    public ImgLink(String imgUrl, String href, int w, int h, boolean newTab) {
+        this(imgUrl, href, w, h);
+        this.newTab = newTab;
+
+        update();
+    }
+
+
+    protected void update() {
+        String target = newTab ? "_blank" : "_self";
+
+        setContents("<a target='" + target + "' href='" + href + "'><img src='" + imgUrl + "'></a>");
         setWidth(width);
         setHeight(height);
         setOverflow(Overflow.VISIBLE);
     }
+
+
+    public void setSource(String href) {
+        this.href = href;
+        update();
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/IntegerRangePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,158 @@
+package de.intevation.flys.client.client.ui;
+
+import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.IntegerItem;
+import com.smartgwt.client.widgets.form.validator.IntegerRangeValidator;
+import com.smartgwt.client.widgets.form.validator.Validator;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.IntegerRangeData;
+
+
+public class IntegerRangePanel extends RangePanel {
+
+    protected Integer maxLower;
+    protected Integer maxUpper;
+
+
+    @Override
+    protected Data[] getData() {
+        Integer lo = getLowerAsInt();
+        Integer up = getUpperAsInt();
+
+        return new Data[] { new IntegerRangeData(getDataName(), null, lo, up) };
+    }
+
+
+    @Override
+    protected FormItem newFormItem(String name) {
+        IntegerItem item = new IntegerItem(name, "");
+        item.setShowTitle(false);
+
+        return item;
+    }
+
+
+    @Override
+    protected Validator[] createLowerValidators(DataList dataList) {
+        setMaxLower(dataList);
+        setMaxUpper(dataList);
+
+        Validator validator = newRangeValidator();
+
+        if (validator != null) {
+            return new Validator[] { validator };
+        }
+
+        return null;
+    }
+
+
+    @Override
+    protected Validator[] createUpperValidators(DataList dataList) {
+        setMaxLower(dataList);
+        setMaxUpper(dataList);
+
+        Validator validator = newRangeValidator();
+
+        if (validator != null) {
+            return new Validator[] { validator };
+        }
+
+        return null;
+    }
+
+
+    @Override
+    public Object getMaxLower() {
+        return maxLower;
+    }
+
+
+    @Override
+    public Object getMaxUpper() {
+        return maxUpper;
+    }
+
+
+    public Integer getLowerAsInt() {
+        String raw = getLower();
+
+        if (raw != null && raw.length() > 0) {
+            try {
+                return Integer.valueOf(raw);
+            }
+            catch (NumberFormatException nfe) {
+                // do nothing
+            }
+        }
+
+        return null;
+    }
+
+
+    public Integer getUpperAsInt() {
+        String raw = getUpper();
+
+        if (raw != null && raw.length() > 0) {
+            try {
+                return Integer.valueOf(raw);
+            }
+            catch (NumberFormatException nfe) {
+                // do nothing
+            }
+        }
+
+        return null;
+    }
+
+
+    protected Validator newRangeValidator() {
+        Integer maxLower = getMaxLowerAsInt();
+        Integer maxUpper = getMaxUpperAsInt();
+
+        if (maxLower != null && maxUpper != null) {
+            IntegerRangeValidator validator = new IntegerRangeValidator();
+            validator.setMax(maxUpper);
+            validator.setMin(maxLower);
+
+            return validator;
+        }
+
+        return null;
+    }
+
+
+    public Integer getMaxLowerAsInt() {
+        return maxLower;
+    }
+
+
+    protected void setMaxLower(DataList dataList) {
+        IntegerRangeData range = (IntegerRangeData) dataList.get(0);
+        setMaxLower((Integer) range.getLower());
+    }
+
+
+    public void setMaxLower(Integer maxLower) {
+        this.maxLower = maxLower;
+    }
+
+
+    public Integer getMaxUpperAsInt() {
+        return maxUpper;
+    }
+
+
+    protected void setMaxUpper(DataList dataList) {
+        IntegerRangeData range = (IntegerRangeData) dataList.get(0);
+        setMaxUpper((Integer) range.getUpper());
+    }
+
+
+    public void setMaxUpper(Integer maxUpper) {
+        this.maxUpper = maxUpper;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/LinkSelection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/LinkSelection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,6 +4,7 @@
 
 import com.smartgwt.client.types.VerticalAlignment;
 import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Img;
 import com.smartgwt.client.widgets.Label;
 import com.smartgwt.client.widgets.form.DynamicForm;
 import com.smartgwt.client.widgets.form.fields.LinkItem;
@@ -157,6 +158,10 @@
         }
         layout.setAlign(VerticalAlignment.TOP);
 
+        String baseUrl = GWT.getHostPageBaseURL();
+        Img map = new Img(baseUrl + messages.riverMap(), 400, 452);
+        helperContainer.addMember(map);
+
         return layout;
     }
 
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/LocationDistancePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,6 +8,10 @@
 import com.google.gwt.i18n.client.NumberFormat;
 
 import com.smartgwt.client.data.Criteria;
+import com.smartgwt.client.data.Criterion;
+import com.smartgwt.client.data.AdvancedCriteria;
+import com.smartgwt.client.types.OperatorId;
+
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.Label;
 import com.smartgwt.client.widgets.form.DynamicForm;
@@ -15,8 +19,13 @@
 import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
 import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
 import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
+import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
+
 import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
 import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
+import com.smartgwt.client.widgets.form.fields.StaticTextItem;
 import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.layout.VLayout;
 import com.smartgwt.client.widgets.grid.ListGrid;
@@ -51,6 +60,7 @@
 import de.intevation.flys.client.client.Config;
 import de.intevation.flys.client.client.event.FilterHandler;
 import de.intevation.flys.client.client.event.StringFilterEvent;
+import de.intevation.flys.client.client.event.RangeFilterEvent;
 import de.intevation.flys.client.client.ui.range.DistanceInfoDataSource;
 
 
@@ -137,7 +147,13 @@
     protected DistanceInfoObject[] tableData;
 
     /** The table filter.*/
-    protected TableFilter filter;
+    protected TableFilter filterDescription;
+    protected RangeTableFilter filterRange;
+
+    /** The Combobox for table filter criteria. */
+    protected SelectItem filterCriteria;
+    protected StaticTextItem filterResultCount;
+    protected ListGrid currentFiltered;
 
     /**
      * Creates a new LocationDistancePanel instance.
@@ -436,14 +452,14 @@
             }
         };
 
-        ListGridField addfrom = new ListGridField ("", "");
+        ListGridField addfrom = new ListGridField ("from", MESSAGES.from());
         addfrom.setType (ListGridFieldType.ICON);
-        addfrom.setWidth (20);
+        addfrom.setWidth (30);
         addfrom.setCellIcon(baseUrl + MESSAGES.markerGreen());
 
-        ListGridField addto2 = new ListGridField ("", "");
+        ListGridField addto2 = new ListGridField ("to", MESSAGES.to());
         addto2.setType (ListGridFieldType.ICON);
-        addto2.setWidth (20);
+        addto2.setWidth (30);
         addto2.setCellIcon(baseUrl + MESSAGES.markerRed());
 
         locationDistanceTable.addCellClickHandler (new CellClickHandler () {
@@ -585,7 +601,18 @@
         Data       dLocations = getData(items, "ld_locations");
         DataItem[] lItems     = dLocations.getItems();
 
-        String value = lItems[0].getStringValue();
+        String[] splitted = lItems[0].getStringValue().split(" ");
+        String value = "";
+        for (int i = 0; i < splitted.length; i++) {
+            try {
+                NumberFormat nf = NumberFormat.getDecimalFormat();
+                double dv = Double.parseDouble(splitted[i]);
+                value += nf.format(dv) + " ";
+            }
+            catch(NumberFormatException nfe) {
+                value += splitted[i] + " ";
+            }
+        }
 
         Label selected = new Label(value);
         selected.setWidth(130);
@@ -655,6 +682,7 @@
             enableDistancePanel();
             inputTables.selectTab(1);
         }
+        currentFiltered = (ListGrid)inputTables.getSelectedTab().getPane();
     }
 
 
@@ -678,7 +706,14 @@
         inputTables   = new TabSet();
         inputTables.addTabSelectedHandler(new TabSelectedHandler() {
             public void onTabSelected(TabSelectedEvent evt) {
-                filter.clear();
+                filterDescription.clear();
+                filterRange.clear();
+                filterResultCount.setValue("");
+
+                Canvas c = evt.getTabPane();
+                if(c instanceof ListGrid) {
+                    currentFiltered = (ListGrid)c;
+                }
             }
         });
 
@@ -694,19 +729,67 @@
         inputTables.addTab(locations);
         inputTables.addTab(distances);
 
-        filter = new TableFilter();
-        filter.setHeight("30px");
-        filter.addFilterHandler(this);
+        filterResultCount = new StaticTextItem(MESSAGES.resultCount());
+        filterResultCount.setTitleAlign(Alignment.LEFT);
+        filterResultCount.setTitleStyle("color: #000");
 
+        filterDescription = new TableFilter();
+        filterDescription.setHeight("30px");
+        filterDescription.addFilterHandler(this);
+
+        filterRange = new RangeTableFilter();
+        filterRange.setHeight("30px");
+        filterRange.addFilterHandler(this);
+        filterRange.setVisible(false);
+
+        filterCriteria = new SelectItem();
+        filterCriteria.setShowTitle(false);
+        filterCriteria.setWidth(100);
+        filterCriteria.addChangedHandler(new ChangedHandler() {
+            public void onChanged(ChangedEvent e) {
+                if(e.getValue().toString().equals("range")) {
+                    filterRange.setVisible(true);
+                    filterDescription.setVisible(false);
+                    filterDescription.clear();
+                    filterResultCount.setValue("");
+                }
+                else {
+                    filterRange.setVisible(false);
+                    filterRange.clear();
+                    filterDescription.setVisible(true);
+                    filterResultCount.setValue("");
+                }
+            }
+        });
+
+        LinkedHashMap<String, String> filterMap =
+            new LinkedHashMap<String, String>();
+        filterMap.put("description", MESSAGES.description());
+        filterMap.put("range", MESSAGES.range());
+        filterCriteria.setValueMap(filterMap);
+        filterCriteria.setValue("description");
+
+        DynamicForm form = new DynamicForm();
+        form.setFields(filterCriteria);
         inputTables.setHeight("*");
+        DynamicForm form2 = new DynamicForm();
+        form2.setFields(filterResultCount);
 
         VLayout helper = new VLayout();
+        HLayout filterLayout = new HLayout();
+
+        filterLayout.addMember(form);
+        filterLayout.addMember(filterDescription);
+        filterLayout.addMember(filterRange);
+        filterLayout.setHeight("30px");
         helper.addMember(inputTables);
-        helper.addMember(filter);
+        helper.addMember(filterLayout);
+        helper.addMember(form2);
         helper.setHeight100();
         helper.setWidth100();
 
         helperContainer.addMember(helper);
+        filterLayout.setWidth("200");
 
         return layout;
     }
@@ -721,15 +804,78 @@
             locationsTable.filterData(c);
             distanceTable.filterData(c);
             locationDistanceTable.filterData(c);
+            filterResultCount.setValue(currentFiltered.getRecords().length);
         }
         else {
             locationsTable.clearCriteria();
             distanceTable.clearCriteria();
             locationDistanceTable.clearCriteria();
+            filterResultCount.setValue("");
         }
     }
 
 
+    public void onFilterCriteriaChanged(RangeFilterEvent event) {
+        Float from = event.getFrom() - 0.001f;
+        Float to = event.getTo() + 0.001f;
+        GWT.log("filtering range: " + from + " to " + to);
+
+
+        Criterion combinedFilter = null;
+        Criterion locationFilter = null;
+        if (from.equals(Float.NaN) && to.equals(Float.NaN)) {
+            locationsTable.clearCriteria();
+            distanceTable.clearCriteria();
+            locationDistanceTable.clearCriteria();
+            filterResultCount.setValue("");
+            return;
+        }
+        else if (from.equals(Float.NaN)) {
+            combinedFilter = new Criterion("to", OperatorId.LESS_OR_EQUAL, to);
+            locationFilter =
+                new Criterion("from", OperatorId.LESS_OR_EQUAL, to);
+            locationsTable.filterData(locationFilter);
+            distanceTable.filterData(combinedFilter);
+            locationDistanceTable.filterData(combinedFilter);
+            filterResultCount.setValue(currentFiltered.getRecords().length);
+            return;
+        }
+        else if (to.equals(Float.NaN)) {
+            combinedFilter =
+                new Criterion("from", OperatorId.GREATER_OR_EQUAL, from);
+             locationsTable.filterData(combinedFilter);
+            distanceTable.filterData(combinedFilter);
+            locationDistanceTable.filterData(combinedFilter);
+        }
+        else {
+            AdvancedCriteria c1 =
+                new AdvancedCriteria(OperatorId.AND, new Criterion[] {
+                    new Criterion("from", OperatorId.GREATER_OR_EQUAL, from),
+                    new Criterion("from", OperatorId.LESS_OR_EQUAL, to)
+                });
+
+            AdvancedCriteria c2 =
+                new AdvancedCriteria(OperatorId.AND, new Criterion[] {
+                    new Criterion("to", OperatorId.GREATER_OR_EQUAL, from),
+                    new Criterion("to", OperatorId.LESS_OR_EQUAL, to)
+                });
+
+            AdvancedCriteria c3 =
+                new AdvancedCriteria(OperatorId.AND, new Criterion[] {
+                    new Criterion("from", OperatorId.LESS_OR_EQUAL, to),
+                    new Criterion("to", OperatorId.GREATER_OR_EQUAL, from)
+                });
+
+            combinedFilter =
+                new AdvancedCriteria(OperatorId.OR, new Criterion[] {
+                    c1, c2, c3
+                });
+        }
+        locationsTable.filterData(combinedFilter);
+        distanceTable.filterData(combinedFilter);
+        locationDistanceTable.filterData(combinedFilter);
+        filterResultCount.setValue(currentFiltered.getRecords().length);
+    }
 
 
     @Override
@@ -878,7 +1024,7 @@
             data.add(dMode);
         }
 
-        return (Data[]) data.toArray(new Data[data.size()]);
+        return data.toArray(new Data[data.size()]);
     }
 
 
@@ -1020,7 +1166,10 @@
         }
         if (value.equals(FIELD_VALUE_LOCATION)) {
             enableLocationPanel();
-            filter.clear();
+            filterDescription.clear();
+            filterRange.clear();
+            filterResultCount.setValue("");
+
             // Remove the tab containing the locationDistanceTable.
             // The 'updateTab()' avoids the tab content to be destroyed.
             inputTables.updateTab(0, null);
@@ -1036,7 +1185,10 @@
         }
         else {
             enableDistancePanel();
-            filter.clear();
+            filterDescription.clear();
+            filterRange.clear();
+            filterResultCount.setValue("");
+
             // Remove the tab containing the locationTable.
             // The 'updateTab()' avoids the tab content to be destroyed.
             inputTables.updateTab(0, null);
@@ -1182,7 +1334,7 @@
         if (data != null && data.length > 0) {
             for (int i = 0; i < data.length; i++) {
                 DataList dl = data[i];
-                if (dl.getState().equals("state.winfo.river")) {
+                if (dl.getState().endsWith("river")) {
                     for (int j = 0; j < dl.size(); j++) {
                         Data d = dl.get(j);
                         DataItem[] di = d.getItems();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/LocationPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,370 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
+import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
+import com.smartgwt.client.widgets.form.fields.FormItem;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+
+import com.smartgwt.client.data.Record;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+
+/**
+ * This UIProvider serves as base for UI Providers to enter a single location (km).
+ */
+public abstract class LocationPanel
+extends               AbstractUIProvider
+{
+    /** A container that will contain the location or the distance panel. */
+    protected HLayout inputLayout;
+
+    /** The minimal value that the user is allowed to enter. */
+    protected double min;
+
+    /** The maximal value that the user is allowed to enter. */
+    protected double max;
+
+    /** The values entered in the location mode. */
+    protected double[] values;
+
+    /** Name of the data item that keeps this location(s). */
+    protected String dataItemName;
+
+    /** The input panel for locations. */
+    protected DoubleArrayPanel locationPanel;
+
+
+    /**
+     * Creates a new LocationDistancePanel instance.
+     */
+    public LocationPanel() {
+        values = new double[0];
+    }
+
+
+    /**
+     * This method creates a widget that contains a label, a panel with
+     * checkboxes to switch the input mode between location and distance input,
+     * and a mode specific panel.
+     *
+     * @param data The data that might be inserted.
+     *
+     * @return a panel.
+     */
+    @Override
+    public Canvas create(DataList data) {
+        findDataItemName(data);
+
+        VLayout layout = new VLayout();
+        layout.setMembersMargin(10);
+
+        // Subclass uses translated data items name as label.
+        Label label   = new Label(MSG.location());
+        Canvas widget = createWidget(data);
+        Canvas submit = getNextButton();
+
+        initDefaults(data);
+
+        widget.setHeight(50);
+        label.setHeight(25);
+
+        layout.addMember(label);
+        layout.addMember(widget);
+        layout.addMember(submit);
+
+        return layout;
+    }
+
+
+    /** Store label of first data item in list. */
+    public void findDataItemName(DataList list) {
+        this.dataItemName = list.getAll().get(0).getLabel();
+    }
+
+
+    /** Get label of first data item that this uiprovider has seen. */
+    public String getDataItemName() {
+        return this.dataItemName;
+    }
+
+
+    /**
+     * This method creates a Canvas element showing the old Data objects in the
+     * DataList <i>data</i>.
+     */
+    public Canvas createOld(DataList dataList) {
+        findDataItemName(dataList);
+
+        List<Data> items = dataList.getAll();
+        Data dLocation   = getData(items, getDataItemName());
+        DataItem[] loc   = dLocation.getItems();
+
+        HLayout layout = new HLayout();
+        layout.setWidth("400px");
+
+        Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+
+        Canvas back = getBackButton(dataList.getState());
+
+        // TODO evaluate: isn't this what findDataItemName is doing?
+        Label selected = new Label(loc[0].getLabel());
+        selected.setWidth("130px");
+
+        layout.addMember(label);
+        layout.addMember(selected);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    /**
+     * This method reads the default values defined in the DataItems of the Data
+     * objects in <i>list</i>.
+     *
+     * @param list The DataList container that stores the Data objects.
+     */
+    protected void initDefaults(DataList list) {
+        Data data = list.get(0);
+
+        /*
+        // Compatibility with MinMax- DataItems:
+        RangeData rangeData = null;
+
+        for (int i = 0, n = list.size(); i < n; i++) {
+            Data tmp = list.get(i);
+
+            if (tmp instanceof RangeData) {
+                rangeData = (RangeData) tmp;
+            }
+        }
+
+        if (rangeData != null) {
+            min = Double.parseDouble(rangeData.getDefaultLower().toString());
+            max = Double.parseDouble(rangeData.getDefaultUpper().toString());
+            // catch ..?
+        }
+        */
+
+        if (false) {}
+        else {
+            DataItem[] items = data.getItems();
+            DataItem   iMin  = getDataItem(items, "min");
+            DataItem   iMax  = getDataItem(items, "max");
+
+            try {
+                min = Double.parseDouble(iMin.getStringValue());
+                max = Double.parseDouble(iMax.getStringValue());
+            }
+            catch (NumberFormatException nfe) {
+                SC.warn(MSG.error_read_minmax_values());
+                min = -Double.MAX_VALUE;
+                max = Double.MAX_VALUE;
+            }
+        }
+
+        DataItem def   = data.getDefault();
+        String   value = def.getStringValue();
+
+        try {
+            double d = Double.parseDouble(value);
+            setLocationValues(new double[] { d } );
+        }
+        catch (NumberFormatException nfe) {
+            // could not parse, dont know what to do else
+        }
+    }
+
+
+    /**
+     * This method grabs the Data with name <i>name</i> from the list and
+     * returns it.
+     *
+     * @param items A list of Data.
+     * @param name The name of the Data that we are searching for.
+     *
+     * @return the Data with the name <i>name</i>.
+     */
+    @Override
+    protected Data getData(List<Data> data, String name) {
+        for (Data d: data) {
+            if (name.equals(d.getLabel())) {
+                return d;
+            }
+        }
+
+        return null;
+    }
+
+
+    protected Canvas createWidget(DataList data) {
+        VLayout layout = new VLayout();
+        inputLayout    = new HLayout();
+
+        // The initial view will display the location input mode.
+        locationPanel = new DoubleArrayPanel(
+            MSG.unitLocation(),
+            getLocationValues(),
+            new BlurHandler(){public void onBlur(BlurEvent be) {}});
+
+        // TODO Remove picker references, refactor such that subclasses can
+        // easily use their picker if they want.
+        //picker.getLocationTable().setAutoFetchData(true);
+
+        inputLayout.addMember(locationPanel);
+
+        layout.addMember(inputLayout);
+
+        inputLayout.setMembersMargin(30);
+
+        /*
+        //picker.prepareFilter();
+        helperContainer.addMember(picker.getLocationTable());
+        helperContainer.addMember(picker.getFilterLayout());
+        helperContainer.addMember(picker.getResultCountForm());
+        */
+        return layout;
+    }
+
+
+    @Override
+    public List<String> validate() {
+        List<String> errors = new ArrayList<String>();
+        NumberFormat nf     = NumberFormat.getDecimalFormat();
+
+        saveLocationValues(locationPanel);
+
+        if (!locationPanel.validateForm()) {
+            errors.add(MSG.wrongFormat());
+            return errors;
+        }
+
+        double[] values = getLocationValues();
+        double[] good   = new double[values.length];
+        int      idx    = 0;
+
+        for (double value: values) {
+            if (value < min || value > max) {
+                String tmp = MSG.error_validate_range();
+                tmp = tmp.replace("$1", nf.format(value));
+                tmp = tmp.replace("$2", nf.format(min));
+                tmp = tmp.replace("$3", nf.format(max));
+                errors.add(tmp);
+            }
+            else {
+                good[idx++] = value;
+            }
+        }
+
+        double[] justGood = new double[idx];
+        for (int i = 0; i < justGood.length; i++) {
+            justGood[i] = good[i];
+        }
+
+        if (!errors.isEmpty()) {
+            locationPanel.setValues(justGood);
+        }
+
+        return errors;
+    }
+
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+    // TODO we are abstract because of this. Refactor to use DATA_NAME and
+    // similar fields for ld_mode .
+    public Data[] getData() {
+        saveLocationValues(locationPanel);
+        double[] values = getLocationValues();
+        Data[] data = new Data[values.length+1];
+
+        for (int i = 0; i < values.length; i++) {
+            data[i] = createDataArray(DATA_ITEM_NAME,
+                Double.valueOf(values[i]).toString());
+        }
+        data[values.length] = createDataArray("ld_mode", "locations");
+
+        return data;
+    }
+     */
+
+
+    /**
+     * Validates and stores all values entered in the location mode.
+     *
+     * @param p The DoubleArrayPanel.
+     */
+    protected void saveLocationValues(DoubleArrayPanel p) {
+        FormItem[] formItems = p.getFields();
+
+        for (FormItem item: formItems) {
+            if (item.getFieldName().equals(DoubleArrayPanel.FIELD_NAME)) {
+                saveLocationValue(p, item);
+            }
+        }
+    }
+
+
+    /**
+     * Validates and stores a value entered in the location mode.
+     *
+     * @param p The DoubleArrayPanel.
+     * @param item The item that needs to be validated.
+     */
+    protected void saveLocationValue(DoubleArrayPanel p, FormItem item) {
+        if (p.validateForm(item)) {
+            setLocationValues(p.getInputValues(item));
+        }
+    }
+
+
+    /** Get the location values. */
+    protected double[] getLocationValues() {
+        return values;
+    }
+
+
+    /** Sets Location values and updates the panel. */
+    protected void setLocationValues(double[] values) {
+        this.values = values;
+        locationPanel.setValues(values);
+    }
+
+
+    /**
+     * Callback when an item from the input helper was clicked.
+     * Set the respective km-value in the location value field.
+     * @param e event passed.
+     */
+    public void onRecordClick (RecordClickEvent e) {
+        Record record = e.getRecord();
+        double[] selected = new double[1];
+        try {
+            selected[0] =
+                Double.parseDouble(record.getAttribute("from"));
+        }
+        catch(NumberFormatException nfe) {
+            // Is there anything else to do here?
+        }
+        setLocationValues(selected);
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/ui/LocationPicker.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,254 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.LinkedHashMap;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.smartgwt.client.data.Criteria;
+import com.smartgwt.client.data.Criterion;
+import com.smartgwt.client.data.AdvancedCriteria;
+import com.smartgwt.client.types.OperatorId;
+
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
+import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
+
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.grid.CellFormatter;
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
+
+import com.smartgwt.client.types.ListGridFieldType;
+import com.smartgwt.client.types.Alignment;
+
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.event.FilterHandler;
+import de.intevation.flys.client.client.event.StringFilterEvent;
+import de.intevation.flys.client.client.event.RangeFilterEvent;
+
+/**
+ * Bundle widgets and handler for a lacation input helper.
+ *
+ * Note that the construction is weird and driven by issues that arose due to
+ * reasons not understood.
+ */
+public class LocationPicker
+implements   FilterHandler
+{
+    /** The message class that provides i18n strings.*/
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    /** The locations table. */
+    protected ListGrid locationTable;
+
+    protected HLayout filterLayout;
+
+    DynamicForm resultCountForm;
+
+    RecordClickHandler handler;
+
+    /** Text to show number of matched items when filtered. */
+    protected StaticTextItem filterResultCount;
+
+
+    public LocationPicker(RecordClickHandler handler) {
+        locationTable = new ListGrid();
+        locationTable.setShowHeaderContextMenu(false);
+        this.handler = handler;
+    }
+
+    public void prepareFilter() {
+
+        filterResultCount = new StaticTextItem(MSG.resultCount());
+        filterResultCount.setTitleAlign(Alignment.LEFT);
+        filterResultCount.setTitleStyle("color: #000");
+
+        final TableFilter filter = new TableFilter();
+        filter.setHeight("30px");
+        filter.addFilterHandler(this);
+
+        final RangeTableFilter filterRange = new RangeTableFilter();
+        filterRange.setHeight("30px");
+        filterRange.addFilterHandler(this);
+        filterRange.setVisible(false);
+
+        SelectItem filterCriteria = new SelectItem();
+        filterCriteria.setShowTitle(false);
+        filterCriteria.setWidth(100);
+        filterCriteria.addChangedHandler(new ChangedHandler() {
+            public void onChanged(ChangedEvent e) {
+                if(e.getValue().toString().equals("range")) {
+                    filterRange.setVisible(true);
+                    filter.setVisible(false);
+                    filter.clear();
+                    filterResultCount.setValue("");
+                }
+                else {
+                    filterRange.setVisible(false);
+                    filterRange.clear();
+                    filter.setVisible(true);
+                    filterResultCount.setValue("");
+                }
+            }
+        });
+
+        LinkedHashMap<String, String> filterMap =
+            new LinkedHashMap<String, String>();
+        filterMap.put("description", MSG.description());
+        filterMap.put("range", MSG.range());
+        filterCriteria.setValueMap(filterMap);
+        filterCriteria.setValue("description");
+
+        DynamicForm form = new DynamicForm();
+        form.setFields(filterCriteria);
+
+        resultCountForm = new DynamicForm();
+        resultCountForm.setFields(filterResultCount);
+
+        filterLayout = new HLayout();
+        filterLayout.addMember(form);
+        filterLayout.addMember(filter);
+        filterLayout.addMember(filterRange);
+    }
+
+
+    /** Access the main widget, a table in which locations can be chosen. */
+    public ListGrid getLocationTable() {
+        return locationTable;
+    }
+
+
+    /** Access the 'form' that shows the filter result count. */
+    public DynamicForm getResultCountForm() {
+        return resultCountForm;
+    }
+
+
+    /** Access the layout containing filter stuff. */
+    public HLayout getFilterLayout() {
+        return filterLayout;
+    }
+
+
+    /**
+     * This method creates a table that contains the location values.
+     */
+    protected void createLocationTable(/*RecordClickHandler handler*/) {
+        GWT.log("Create Location Table in LocationPicker");
+
+        String baseUrl = GWT.getHostPageBaseURL();
+
+        locationTable.setWidth100();
+        locationTable.setShowRecordComponents(true);
+        locationTable.setShowRecordComponentsByCell(true);
+        locationTable.setHeight100();
+        locationTable.setEmptyMessage(MSG.empty_filter());
+        locationTable.setCanReorderFields(false);
+
+        ListGridField addLocation = new ListGridField ("", "");
+        addLocation.setType (ListGridFieldType.ICON);
+        addLocation.setWidth (20);
+        addLocation.addRecordClickHandler (handler);
+        addLocation.setCellIcon (baseUrl + MSG.markerGreen());
+        GWT.log ("i18n: ..... "  + MSG.description());
+
+        ListGridField ldescr = new ListGridField("description",
+                MSG.description());
+        ldescr.setType(ListGridFieldType.TEXT);
+        ldescr.setWidth("*");
+        ListGridField lside = new ListGridField("riverside",
+                MSG.riverside());
+        lside.setType(ListGridFieldType.TEXT);
+        lside.setWidth("10%");
+
+        ListGridField loc = new ListGridField("from", MSG.location());
+        loc.setCellFormatter(new CellFormatter() {
+            public String format(
+                Object value,
+                ListGridRecord record,
+                int rowNum, int colNum) {
+                    if (value == null) return null;
+                    try {
+                        NumberFormat nf;
+                        double v = Double.parseDouble((String)value);
+                        nf = NumberFormat.getFormat("###0.00##");
+                        return nf.format(v);
+                    }
+                    catch (Exception e) {
+                        return value.toString();
+                    }
+                }
+            }
+        );
+        loc.setType(ListGridFieldType.FLOAT);
+
+        loc.setWidth("10%");
+
+        ListGridField bottom =
+            new ListGridField("bottom", MSG.bottom_edge());
+        bottom.setType(ListGridFieldType.TEXT);
+        bottom.setWidth("10%");
+
+        ListGridField top =
+            new ListGridField("top", MSG.top_edge());
+        top.setType(ListGridFieldType.TEXT);
+        top.setWidth("10%");
+
+
+        locationTable.setFields(
+            addLocation, ldescr, loc, lside, bottom, top);
+    }
+
+
+    @Override
+    public void onFilterCriteriaChanged(StringFilterEvent event) {
+        String search = event.getFilter();
+
+        if (search != null && search.length() > 0) {
+            Criteria c = new Criteria("description", search);
+            locationTable.filterData(c);
+            filterResultCount.setValue(locationTable.getRecords().length);
+        }
+        else {
+            locationTable.clearCriteria();
+            filterResultCount.setValue("");
+        }
+    }
+
+
+    @Override
+    public void onFilterCriteriaChanged(RangeFilterEvent event) {
+        Float from = event.getFrom() - 0.001f;
+        Float to = event.getTo() + 0.001f;
+
+        Criterion combinedFilter = null;
+        if (from.equals(Float.NaN) && to.equals(Float.NaN)) {
+            locationTable.clearCriteria();
+            filterResultCount.setValue("");
+            return;
+        }
+        else if (from.equals(Float.NaN)) {
+            combinedFilter =
+                new Criterion("from", OperatorId.LESS_OR_EQUAL, to);
+        }
+        else if (to.equals(Float.NaN)) {
+            combinedFilter =
+                new Criterion("from", OperatorId.GREATER_OR_EQUAL, from);
+        }
+        else {
+            combinedFilter =
+                new AdvancedCriteria(OperatorId.AND, new Criterion[] {
+                    new Criterion("from", OperatorId.GREATER_OR_EQUAL, from),
+                    new Criterion("from", OperatorId.LESS_OR_EQUAL, to)
+                });
+        }
+        locationTable.filterData(combinedFilter);
+        filterResultCount.setValue(locationTable.getRecords().length);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/MainMenu.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/MainMenu.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,7 +3,6 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.i18n.client.LocaleInfo;
 import com.google.gwt.user.client.Window;
-
 import com.smartgwt.client.types.Alignment;
 import com.smartgwt.client.util.BooleanCallback;
 import com.smartgwt.client.util.SC;
@@ -24,7 +23,7 @@
 public class MainMenu extends HLayout {
 
     /** The interface that provides i18n messages. */
-    private FLYSConstants messages = GWT.create(FLYSConstants.class);
+    private final FLYSConstants messages = GWT.create(FLYSConstants.class);
 
     /** An instance to FLYS.*/
     protected FLYS flys;
@@ -66,6 +65,7 @@
         info        = new Button(messages.info());
 
         newProject.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 GWT.log("Clicked 'New Project' button.");
                 createNewProject();
@@ -73,6 +73,7 @@
         });
 
         projectList.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 GWT.log("Clicked 'Open ProjectList' button.");
                 ProjectList list = getFlys().getProjectList();
@@ -84,6 +85,7 @@
         });
 
         logout.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 GWT.log("Clicked 'logout' button.");
                 GWT.log("IMPLEMENT the 'logout' function.");
@@ -91,6 +93,7 @@
         });
 
         language.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 LocaleInfo info            = LocaleInfo.getCurrentLocale();
                 final String currentLocale = info.getLocaleName();
@@ -100,6 +103,7 @@
 
                 SC.confirm(messages.warning(), messages.warning_language(),
                     new BooleanCallback() {
+                        @Override
                         public void execute(Boolean value) {
                             if (value) {
                                 switchLanguage(currentLocale, newLocale);
@@ -110,6 +114,7 @@
         });
 
         info.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 GWT.log("Clicked 'info' button.");
                 GWT.log("IMPLEMENT the 'open info panel' function.");
@@ -226,8 +231,6 @@
     protected void switchLanguage(String currentLocale, String newLocale) {
         String newLocation = Window.Location.getHref();
 
-        String oldLocation = newLocation;
-
         if (newLocation.endsWith("/")) {
             newLocation = newLocation.substring(0, newLocation.length()-1);
         }
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/ModuleSelection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/ModuleSelection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,8 +3,10 @@
 import java.util.LinkedHashMap;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.rpc.AsyncCallback;
 
 import com.smartgwt.client.types.VerticalAlignment;
+import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.Label;
 import com.smartgwt.client.widgets.form.DynamicForm;
@@ -12,12 +14,16 @@
 import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.layout.VLayout;
 
+import de.intevation.flys.client.client.services.ModuleService;
+import de.intevation.flys.client.client.services.ModuleServiceAsync;
 import de.intevation.flys.client.shared.model.Data;
 import de.intevation.flys.client.shared.model.DataItem;
 import de.intevation.flys.client.shared.model.DataList;
 import de.intevation.flys.client.shared.model.DefaultData;
 import de.intevation.flys.client.shared.model.DefaultDataItem;
+import de.intevation.flys.client.shared.model.Module;
 
+import de.intevation.flys.client.client.Config;
 import de.intevation.flys.client.client.FLYSConstants;
 
 /**
@@ -33,34 +39,21 @@
     /** The message class that provides i18n strings.*/
     protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
 
-
-    /** Constant field name for the plugin selection.*/
-    public static final String FIELD_PLUGIN = "plugin";
-
-    /** Constant value for the WINFO plugin.*/
-    public static final String FIELD_PLUGIN_WINFO = "winfo";
-
-    /** Constant value for the MINFO plugin.*/
-    public static final String FIELD_PLUGIN_MINFO = "minfo";
-
-    /** Constant value for the MAP plugin.*/
-    public static final String FIELD_PLUGIN_MAP   = "map";
-
-    /** Constant value for the CHART plugin.*/
-    public static final String FIELD_PLUGIN_CHART = "chart";
-
-    /** Constant value for the FIX plugin.*/
-    public static final String FIELD_PLUGIN_FIX   = "fix";
-
-
     /** The module checkboxes.*/
     protected RadioGroupItem radio;
 
+    /** */
+    protected Module[] modules;
+
+    /** The ModuleService used to retrieve the available modules of a user.*/
+    protected ModuleServiceAsync moduleService = GWT.create(ModuleService.class);
+
 
     /**
      * The default constructor.
      */
     public ModuleSelection() {
+        readModules();
     }
 
 
@@ -73,6 +66,7 @@
      * @return the module selection combined with the river selection.
      */
     public Canvas create(DataList data) {
+        GWT.log("ModuleSelection - create()");
         VLayout newLayout = new VLayout();
         newLayout.setMembersMargin(10);
         newLayout.setAlign(VerticalAlignment.TOP);
@@ -85,6 +79,45 @@
         return newLayout;
     }
 
+    private void readModules() {
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
+
+        moduleService.list(locale, new AsyncCallback<Module[]>() {
+            @Override
+            public void onFailure(Throwable caught) {
+                GWT.log("Could not recieve a list of modules.");
+                SC.warn(MSG.getString(caught.getMessage()));
+            }
+
+            @Override
+            public void onSuccess(Module[] newmodules) {
+                GWT.log("Retrieved " + newmodules.length + " modules.");
+                modules = newmodules;
+                setModules();
+            }
+        });
+    }
+
+    private void setModules() {
+        LinkedHashMap values = new LinkedHashMap();
+
+        if (this.modules!= null) {
+            for(Module module : this.modules) {
+                values.put(module.getName(), module.getLocalizedName());
+                if (module.isSelected()) {
+                    GWT.log("Module " + module.getName() + " is selected.");
+                    if (radio != null) {
+                        radio.setDefaultValue(module.getName());
+                        GWT.log("Setting " + module.getName() + " as selected.");
+                    }
+                }
+            }
+        }
+        if (radio != null) {
+            radio.setValueMap(values);
+        }
+    }
 
     /**
      * Creates a widget that displays a checkbox for each module.
@@ -102,22 +135,13 @@
         label.setWidth(50);
         label.setHeight(25);
 
-        LinkedHashMap values = new LinkedHashMap();
-        values.put(FIELD_PLUGIN_WINFO, messages.winfo());
-        values.put(FIELD_PLUGIN_MINFO, messages.minfo());
-        values.put(FIELD_PLUGIN_FIX, messages.fix());
-        values.put(FIELD_PLUGIN_CHART, messages.new_chart());
-        values.put(FIELD_PLUGIN_MAP, messages.map());
 
         radio.setShowTitle(false);
         radio.setVertical(true);
-        radio.setValueMap(values);
 
-        LinkedHashMap initial = new LinkedHashMap();
-        initial.put(FIELD_PLUGIN, FIELD_PLUGIN_WINFO);
+        setModules();
 
         form.setFields(radio);
-        form.setValues(initial);
 
         layout.addMember(label);
         layout.addMember(form);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/MultiPeriodPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,238 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Date;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.DateTimeFormat;
+
+import com.smartgwt.client.data.Record;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import com.smartgwt.client.types.ListGridFieldType;
+
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+
+/**
+ * This UIProvider creates a panel for location or distance input.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class MultiPeriodPanel
+extends      PeriodPanel
+{
+
+    protected ListGrid elements;
+
+    protected String values;
+
+    public MultiPeriodPanel() {
+        this("", "");
+    }
+
+    public MultiPeriodPanel(String startName, String endName) {
+        super(startName, endName);
+    }
+
+    public Canvas createWidget(DataList data) {
+        HLayout input = new HLayout();
+        VLayout root = new VLayout();
+        VLayout grid = new VLayout();
+        VLayout layout = (VLayout) super.createWidget(data);
+        Button add = new Button(MSG.add_date());
+        elements = new ListGrid();
+
+        add.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent ce) {
+                Date f = inputPanel.getFromDate();
+                Date t = inputPanel.getToDate();
+                if (f == null || t == null) {
+                    return;
+                }
+                DateRangeRecord drr = new DateRangeRecord(f, t);
+                elements.addData(drr);
+            }
+        });
+        layout.addMember(add);
+
+        Label sel = new Label(MSG.select());
+        sel.setHeight(25);
+        elements.setWidth(185);
+        elements.setHeight(120);
+        elements.setShowHeaderContextMenu(false);
+        elements.setCanReorderFields(false);
+        elements.setCanSort(false);
+        elements.setCanEdit(false);
+        ListGridField from = new ListGridField("from", MSG.from());
+        ListGridField to = new ListGridField("to", MSG.to());
+        from.setWidth(70);
+        to.setWidth(70);
+
+        final ListGridField removeField  =
+            new ListGridField("_removeRecord", "Remove Record"){{
+                setType(ListGridFieldType.ICON);
+                setIcon(GWT.getHostPageBaseURL() + MSG.removeFeature());
+                setCanEdit(false);
+                setCanFilter(false);
+                setCanSort(false);
+                setCanGroupBy(false);
+                setCanFreeze(false);
+                setWidth(25);
+        }};
+
+        elements.addRecordClickHandler(new RecordClickHandler() {
+                public void onRecordClick(final RecordClickEvent event) {
+                    // Just handle remove-clicks
+                    if(!event.getField().getName().equals(removeField.getName())) {
+                        return;
+                    }
+                    event.getViewer().removeData(event.getRecord());
+                }
+            });
+
+        elements.setFields(from, to, removeField);
+
+        grid.addMember(sel);
+        grid.addMember(elements);
+        input.addMember(layout);
+        input.addMember(grid);
+        root.addMember(input);
+
+        return root;
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        GWT.log("old............................");
+        HLayout layout = new HLayout();
+        layout.setWidth("400px");
+        VLayout vLayout = new VLayout();
+        vLayout.setWidth(130);
+        Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+        label.setHeight(25);
+
+        List<Data> items = dataList.getAll();
+        Data str = getData(items, "periods");
+        DataItem[] strItems = str.getItems();
+
+        String[] pairs = strItems[0].getLabel().split(";");
+        for (int i = 0; i < pairs.length; i++) {
+            String[] vals = pairs[i].split(",");
+            long f = Long.valueOf(vals[0]).longValue();
+            long t = Long.valueOf(vals[1]).longValue();
+            Date from = new Date(f);
+            Date to = new Date(t);
+            String fromString =
+                DateTimeFormat.getMediumDateFormat().format(from);
+            String toString =
+                DateTimeFormat.getMediumDateFormat().format(to);
+
+            Label dateLabel = new Label(fromString + " - " + toString);
+            dateLabel.setHeight(20);
+            vLayout.addMember(dateLabel);
+        }
+        Canvas back = getBackButton(dataList.getState());
+        layout.addMember(label);
+        layout.addMember(vLayout);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+     */
+    public Data[] getData() {
+        List<Data> data = new ArrayList<Data>();
+
+        boolean valid = saveDateValues();
+        if(valid) {
+            DataItem item = new DefaultDataItem("periods", null, this.values);
+            data.add(new DefaultData(
+                        "periods",
+                        null,
+                        null,
+                        new DataItem[] { item }));
+        }
+        return data.toArray(new Data[data.size()]);
+    }
+
+
+    protected boolean saveDateValues() {
+        ListGridRecord[] lgr = elements.getRecords();
+        if (lgr.length == 0) {
+            return false;
+        }
+        String data = "";
+        for (int i = 0; i < lgr.length; i++) {
+            DateRangeRecord drr = (DateRangeRecord) lgr[i];
+            data += drr.getFrom() + "," + drr.getTo();
+            data += ";";
+        }
+        values = data;
+        return true;
+    }
+
+
+    protected static class DateRangeRecord extends ListGridRecord {
+        protected Date from;
+        protected Date to;
+
+        protected final static String FROM_FIELD = "from";
+        protected final static String TO_FIELD = "to";
+
+        public DateRangeRecord (Date from, Date to) {
+            setFrom(from);
+            setTo(to);
+        }
+
+        public void setFrom(Date from) {
+            this.from = from;
+            setAttribute(
+                FROM_FIELD,
+                DateTimeFormat.getMediumDateFormat().format(from));
+        }
+
+
+        public void setTo(Date to) {
+            this.to = to;
+            setAttribute(
+                TO_FIELD,
+                DateTimeFormat.getMediumDateFormat().format(to));
+        }
+
+
+        public long getFrom() {
+            return this.from.getTime();
+        }
+
+
+        public long getTo() {
+            return this.to.getTime();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/MultipleLocationPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,350 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
+import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+
+import com.smartgwt.client.data.Record;
+
+import de.intevation.flys.client.shared.model.ArtifactDescription;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DistanceInfoObject;
+import de.intevation.flys.client.shared.DoubleUtils;
+import de.intevation.flys.client.shared.model.RangeData;
+
+import de.intevation.flys.client.client.services.DistanceInfoService;
+import de.intevation.flys.client.client.services.DistanceInfoServiceAsync;
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.ui.range.DistanceInfoDataSource;
+
+
+/**
+ * This UIProvider creates a widget to enter a single location (km).
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class MultipleLocationPanel
+extends      LocationPanel
+implements   RecordClickHandler
+{
+    /** The DistanceInfoService used to retrieve locations about rivers. */
+    protected DistanceInfoServiceAsync distanceInfoService =
+        GWT.create(DistanceInfoService.class);
+
+    /** The table data. */
+    protected DistanceInfoObject[] tableData;
+
+    /** The input helper (usually right side, table to click on, values are
+     * then entered in the texfield. */
+    protected LocationPicker picker;
+
+
+    /**
+     * Creates a new LocationDistancePanel instance.
+     */
+    public MultipleLocationPanel() {
+        picker = new LocationPicker(this);
+    }
+
+
+    /**
+     * This method creates a widget that contains a label, a panel with
+     * checkboxes to switch the input mode between location and distance input,
+     * and a mode specific panel.
+     *
+     * @param data The data that might be inserted.
+     *
+     * @return a panel.
+     */
+    @Override
+    public Canvas create(DataList data) {
+        findDataItemName(data);
+
+        VLayout layout = new VLayout();
+        layout.setMembersMargin(10);
+
+        // Take translated data item name as label, if translation available.
+        String labelString;
+        try {
+            labelString = MSG.getString(getDataItemName());
+        }
+        catch(java.util.MissingResourceException mre) {
+            GWT.log("Cannot find translation for data item name : " + getDataItemName());
+            labelString = getLabelString();
+        }
+        Label label   = new Label(labelString);
+        Canvas widget = createWidget(data);
+        Canvas submit = getNextButton();
+
+        initDefaults(data);
+
+        picker.createLocationTable();
+
+        widget.setHeight(50);
+        label.setHeight(25);
+
+        layout.addMember(label);
+        layout.addMember(widget);
+        layout.addMember(submit);
+
+        return layout;
+    }
+
+
+    /**
+     * This method reads the default values defined in the DataItems of the Data
+     * objects in <i>list</i>.
+     *
+     * @param list The DataList container that stores the Data objects.
+     */
+    protected void initDefaults(DataList list) {
+        Data data = list.get(0);
+
+        // Compatibility with MinMax- DataItems:
+        RangeData rangeData = null;
+
+        for (int i = 0, n = list.size(); i < n; i++) {
+            Data tmp = list.get(i);
+
+            if (tmp instanceof RangeData) {
+                rangeData = (RangeData) tmp;
+            }
+        }
+
+        if (rangeData != null) {
+            min = Double.parseDouble(rangeData.getDefaultLower().toString());
+            max = Double.parseDouble(rangeData.getDefaultUpper().toString());
+            // catch ..?
+        }
+        else {
+            DataItem[] items = data.getItems();
+            DataItem   iMin  = getDataItem(items, "min");
+            DataItem   iMax  = getDataItem(items, "max");
+
+            try {
+                min = Double.parseDouble(iMin.getStringValue());
+                max = Double.parseDouble(iMax.getStringValue());
+            }
+            catch (NumberFormatException nfe) {
+                SC.warn(MSG.error_read_minmax_values());
+                min = -Double.MAX_VALUE;
+                max = Double.MAX_VALUE;
+            }
+        }
+
+        DataItem def = data.getDefault();
+        if (def != null) {
+            String value = def.getStringValue();
+
+            try {
+                double d = Double.parseDouble(value);
+                setLocationValues(new double[] { d } );
+            }
+            catch (NumberFormatException nfe) {
+                // could not parse, dont know what to do else
+            }
+        }
+    }
+
+
+    protected Canvas createWidget(DataList data) {
+        VLayout layout = new VLayout();
+        inputLayout    = new HLayout();
+
+        // The initial view will display the location input mode.
+        locationPanel = new DoubleArrayPanel(
+            MSG.unitLocation(),
+            getLocationValues(),
+            new BlurHandler(){public void onBlur(BlurEvent be) {validate();}});
+
+        picker.getLocationTable().setAutoFetchData(true);
+
+        inputLayout.addMember(locationPanel);
+
+        layout.addMember(inputLayout);
+
+        inputLayout.setMembersMargin(30);
+
+        picker.prepareFilter();
+
+        helperContainer.addMember(picker.getLocationTable());
+        helperContainer.addMember(picker.getFilterLayout());
+        helperContainer.addMember(picker.getResultCountForm());
+        setPickerDataSource();
+        return layout;
+    }
+
+
+    /** Overridden to restrict to one entered value. */
+    @Override
+    public List<String> validate() {
+        List<String> errors = new ArrayList<String>();
+        NumberFormat nf     = NumberFormat.getDecimalFormat();
+
+        DataList[] ref = artifact.getArtifactDescription().getOldData();
+        String mode = ref[1].get(0).getStringValue();
+
+        saveLocationValues(locationPanel);
+
+        if (!locationPanel.validateForm()) {
+            errors.add(MSG.wrongFormat());
+            return errors;
+        }
+
+        double[] lValues = getLocationValues();
+        double[] good   = new double[lValues.length];
+        int      idx    = 0;
+
+        double reference =
+            Double.valueOf(ref[2].get(0).getStringValue()).doubleValue();
+        for (double value: lValues) {
+            if (mode.equals("calc.reference.curve") &&
+                value == reference) {
+                errors.add(MSG.error_contains_same_location());
+                return errors;
+            }
+            if (value < min || value > max) {
+                String tmp = MSG.error_validate_range();
+                tmp = tmp.replace("$1", nf.format(value));
+                tmp = tmp.replace("$2", nf.format(min));
+                tmp = tmp.replace("$3", nf.format(max));
+                errors.add(tmp);
+            }
+            else {
+                good[idx++] = value;
+            }
+        }
+
+        double[] justGood = new double[idx];
+        for (int i = 0; i < justGood.length; i++) {
+            justGood[i] = good[i];
+        }
+
+        if (!errors.isEmpty()) {
+            locationPanel.setValues(justGood);
+        }
+
+        return errors;
+    }
+
+
+    /**
+     * This method returns the selected data (to feed).
+     *
+     * @return the selected/inserted data in feedable form.
+     */
+    public Data[] getData() {
+        saveLocationValues(locationPanel);
+        double[] lValues     = getLocationValues();
+        Data[]   data        = new Data[2];
+        boolean  first       = true;
+        String   valueString = "";
+
+        for (int i = 0; i < lValues.length; i++) {
+            if (!first) valueString += " ";
+            else first = false;
+            valueString += Double.valueOf(lValues[i]).toString();
+        }
+
+        data[0] = createDataArray(getDataItemName(), valueString);
+
+        data[1] = createDataArray("ld_mode", "locations");
+
+        return data;
+    }
+
+
+    /** Hook service to the listgrid with possible input values. */
+    protected void setPickerDataSource() {
+        Config config = Config.getInstance();
+        String url    = config.getServerUrl();
+        String river  = "";
+
+        ArtifactDescription adescr = artifact.getArtifactDescription();
+        DataList[] data = adescr.getOldData();
+
+        // Try to find a "river" data item to set the source for the
+        // list grid.
+        String dataFilter = "locations";
+        if (data != null && data.length > 0) {
+            for (int i = 0; i < data.length; i++) {
+                DataList dl = data[i];
+                if (dl.getState().equals("state.minfo.river")) {
+                    dataFilter = "measuringpoint";
+                }
+                if (dl.getState().equals("state.winfo.river") ||
+                    dl.getState().equals("state.chart.river") ||
+                    dl.getState().equals("state.minfo.river")) {
+                    for (int j = 0; j < dl.size(); j++) {
+                        Data d = dl.get(j);
+                        DataItem[] di = d.getItems();
+                        if (di != null && di.length == 1) {
+                           river = d.getItems()[0].getStringValue();
+                           break;
+                        }
+                    }
+                }
+            }
+        }
+
+        picker.getLocationTable().setDataSource(new DistanceInfoDataSource(
+            url, river, dataFilter));
+    }
+
+
+    // TODO allow multiple selections here or in LocationPanel
+    /**
+     * Callback when an item from the input helper was clicked.
+     * Set the respective km-value in the location value field.
+     * @param e event passed.
+     */
+    public void onRecordClick (RecordClickEvent e) {
+        Record record     = e.getRecord();
+        double[] old      = getLocationValues();
+        double[] selected = DoubleUtils.copyOf(old, old.length + 1);
+        try {
+            selected[old.length] =
+                Double.parseDouble(record.getAttribute("from"));
+        }
+        catch(NumberFormatException nfe) {
+            // Is there anything else to do here?
+        }
+
+        // compare reference location and target location.
+        DataList[] ref = artifact.getArtifactDescription().getOldData();
+        String mode = ref[1].get(0).getStringValue();
+        if (mode.equals("calc.reference.curve") &&
+            ref[2].get(0).getStringValue().equals(record.getAttribute("from")))
+        {
+            SC.warn(MSG.error_same_location());
+            return;
+        }
+
+        setLocationValues(selected);
+    }
+
+    /**
+     * Returns the label string for the input panel.
+     */
+    protected String getLabelString() {
+        return MSG.location();
+    }
+
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/OutputTab.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/OutputTab.java	Fri Sep 28 12:15:52 2012 +0200
@@ -16,7 +16,7 @@
     /** The Collection that should be displayed in this tab.*/
     protected Collection collection;
 
-    /** The CollectionView. */
+    /** The CollectionView containing this tab. */
     protected CollectionView collectionView;
 
 
@@ -62,5 +62,10 @@
     public Collection getCollection() {
         return collection;
     }
+
+
+    public OutputMode getMode() {
+        return mode;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/ParameterList.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/ParameterList.java	Fri Sep 28 12:15:52 2012 +0200
@@ -21,6 +21,7 @@
 import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
 
 import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.WINFOArtifact;
 import de.intevation.flys.client.shared.model.ArtifactDescription;
 import de.intevation.flys.client.shared.model.Collection;
 import de.intevation.flys.client.shared.model.Data;
@@ -109,6 +110,7 @@
     protected VLayout report;
     protected VLayout helperPanel;
     protected VLayout tablePanel;
+    protected GaugePanel gaugePanel;
     protected Canvas  reportPanel;
 
     public ParameterList(FLYS flys, CollectionView cView, String title) {
@@ -207,7 +209,24 @@
         stack.setCanResizeSections(true);
         stack.setVisibilityMode(VisibilityMode.MULTIPLE);
 
-        // This canvas is used to render helper widgets
+        final SectionStackSection gaugeSection = new SectionStackSection();
+        gaugeSection.setExpanded(false);
+        gaugeSection.setTitle(MSG.gaugePanelTitle());
+        gaugePanel = new GaugePanel(flys, gaugeSection) {
+            public void addMember(Canvas component) {
+                super.addMember(component);
+                gaugeSection.setExpanded(true);
+            }
+
+            public void removeMembers(Canvas[] components) {
+                super.removeMembers(components);
+                gaugeSection.setExpanded(false);
+            }
+        };
+        gaugePanel.setWidth100();
+        gaugePanel.setHeight100();
+
+        // This canvas is used to render helper widgets.
         final SectionStackSection helperSection = new SectionStackSection();
         helperSection.setExpanded(false);
         helperSection.setTitle(MSG.helperPanelTitle());
@@ -226,7 +245,7 @@
         helperPanel.setHeight100();
         helperSection.setItems(helperPanel);
 
-        // This canvas is used to render calculation results
+        // This canvas is used to render calculation results.
         final SectionStackSection tableSection = new SectionStackSection();
         tableSection.setExpanded(false);
         tableSection.setTitle(MSG.calcTableTitle());
@@ -245,12 +264,13 @@
         tablePanel.setWidth100();
         tableSection.setItems(tablePanel);
 
-        stack.setSections(helperSection, tableSection);
+        stack.setSections(gaugeSection, helperSection, tableSection);
 
         return stack;
     }
 
 
+    /** Sets and forwards artifact. */
     protected void setArtifact(Artifact artifact) {
         setArtifact(artifact, true);
     }
@@ -322,13 +342,14 @@
             null,
             items);
 
-        LinkSelection widget         = new LinkSelection();
+        LinkSelection widget           = new LinkSelection();
         HasStepForwardHandlers handler = (HasStepForwardHandlers) widget;
 
         widget.setContainer(helperPanel);
 
         handler.addStepForwardHandler(new StepForwardHandler() {
             public void onStepForward(StepForwardEvent event) {
+                lockUI();
                 Data[] data = event.getData();
 
                 DataItem[] moduleItems = data[0].getItems();
@@ -339,6 +360,7 @@
 
                 if (module == null) {
                     // TODO throw / show error!
+                    unlockUI();
                     return;
                 }
 
@@ -346,15 +368,15 @@
                 setTitle(newTitle);
 
                 Config config       = Config.getInstance();
-                final String url    = config.getServerUrl();
                 final String locale = config.getLocale();
 
-                final Data[] feedData  = new Data[] { data[1] };
+                final Data[] feedData = new Data[] { data[1] };
 
                 artifactService.create(
                     locale, module.toLowerCase(), null,
                     new AsyncCallback<Artifact>() {
                         public void onFailure(Throwable caught) {
+                            unlockUI();
                             GWT.log("Could not create the new artifact.");
                             SC.warn(MSG.getString(caught.getMessage()));
                         }
@@ -365,6 +387,7 @@
                             forwardService.go(locale, artifact, feedData,
                             new AsyncCallback<Artifact>() {
                                 public void onFailure(Throwable caught) {
+                                    unlockUI();
                                     GWT.log("Could not feed the artifact.");
                                     SC.warn(caught.getMessage());
                                 }
@@ -374,6 +397,7 @@
                                     old.clear();
                                     cView.addArtifactToCollection(artifact);
                                     setArtifact(artifact);
+                                    unlockUI();
                                 }
                             });
                         }
@@ -540,7 +564,13 @@
 
         if (current != null && uiProvider != null) {
             Canvas c = uiProvider.create(current);
-            currentItems.addMember(c);
+            Canvas h = uiProvider.createHelpLink(current, null);
+
+            HLayout wrapper = new HLayout();
+            wrapper.addMember(h);
+            wrapper.addMember(c);
+
+            currentItems.addMember(wrapper);
         }
         else if (uiProvider != null) {
             Canvas c = uiProvider.create(null);
@@ -576,13 +606,15 @@
      */
     public void onStepForward(StepForwardEvent event) {
         GWT.log("CollectionView - onStepForward()");
+        lockUI();
 
-        Config config    = Config.getInstance();
-        String locale    = config.getLocale();
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
 
         forwardService.go(locale, artifact, event.getData(),
             new AsyncCallback<Artifact>() {
                 public void onFailure(Throwable caught) {
+                    unlockUI();
                     GWT.log("Could not feed the artifact.");
                     SC.warn(MSG.getString(caught.getMessage()));
                 }
@@ -592,6 +624,7 @@
                     old.clear();
 
                     setArtifact(artifact, true);
+                    unlockUI();
                 }
         });
     }
@@ -604,6 +637,7 @@
      * @param e The StepBackEvent that holds the identifier of the target state.
      */
     public void onStepBack(StepBackEvent e) {
+        lockUI();
         final String target    = e.getTarget();
 
         Config config          = Config.getInstance();
@@ -612,6 +646,7 @@
         advanceService.advance(locale, artifact, target,
             new AsyncCallback<Artifact>() {
                 public void onFailure(Throwable caught) {
+                    unlockUI();
                     GWT.log("Could not go back to '" + target + "'");
                     SC.warn(MSG.getString(caught.getMessage()));
                 }
@@ -622,6 +657,7 @@
                     old.clear();
 
                     setArtifact(artifact, false);
+                    unlockUI();
                 }
             }
         );
@@ -706,6 +742,15 @@
                 setCurrentData(null, null);
             }
         }
+        if (art instanceof WINFOArtifact) {
+            String river = desc.getRiver();
+            if (river != null) {
+                renderGaugeInfo(desc.getRiver(), desc.getOldData());
+            }
+            else {
+                gaugePanel.hide();
+            }
+        }
 
         addOldDatas(
             desc.getOldData(),
@@ -868,5 +913,23 @@
     public void registerCollectionViewTabHandler (TabSelectedHandler tsh) {
         this.cView.registerTabHandler (tsh);
     }
+
+
+    protected void lockUI() {
+        cView.lockUI();
+    }
+
+
+    protected void unlockUI() {
+        cView.unlockUI();
+    }
+
+
+    private void renderGaugeInfo(String river, DataList[] data) {
+        gaugePanel.setRiver(river);
+        gaugePanel.setData(data);
+        gaugePanel.show();
+    }
+
 }
 // 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-client/src/main/java/de/intevation/flys/client/client/ui/ParameterMatrix.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,244 @@
+package de.intevation.flys.client.client.ui;
+
+import java.io.Serializable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.user.client.ui.ClickListener;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.tile.TileLayout;
+
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.IntegerOptionsData;
+import de.intevation.flys.client.shared.model.StringOptionsData;
+
+
+/**
+ * Some parameters take the form of on/off options that can also be seen
+ * as a matrix.
+ *
+ * This class helps to survive the underlying objects and create a visual
+ * representation of this matrix. Later can happen in two ways to overcome
+ * shortcomings of GWT/SmartGWT combination.
+ */
+public class ParameterMatrix {
+
+    public static class Column implements Serializable {
+        protected String              name;
+        protected Map<String, String> values;
+
+        private Column() {
+            this.values = new HashMap<String, String>();
+        }
+
+        public Column(String name) {
+            this();
+            this.name = name;
+        }
+
+        public void addValue(String label, String value) {
+            values.put(label, value);
+        }
+
+        public String getValue(String label) {
+            return values.get(label);
+        }
+    } // end of class Column
+
+    /** The message class that provides i18n strings.*/
+    protected FLYSConstants MESSAGE = GWT.create(FLYSConstants.class);
+
+    public static final int CELL_HEIGHT = 25;
+
+    private Map<String, Column> columns;
+    private List<String>        columnNames;
+    private List<String>        valueNames;
+
+    private Map<String, List<String>> selected;
+
+    public ParameterMatrix() {
+        super();
+        this.columns     = new HashMap<String, Column>();
+        this.columnNames = new ArrayList<String>();
+        this.valueNames  = new ArrayList<String>();
+        this.selected    = new HashMap<String, List<String>>();
+    }
+
+
+    public void addColumn(IntegerOptionsData group) {
+        String groupTitle = group.getLabel();
+
+        Column     col   = new Column(groupTitle);
+        DataItem[] items = group.getItems();
+
+        if (items == null) {
+            GWT.log("No items found in StringOptionsData '" + groupTitle + "'");
+            return;
+        }
+
+        for (DataItem item: items) {
+            String title = item.getLabel();
+
+            if (valueNames.indexOf(title) < 0) {
+                valueNames.add(title);
+            }
+
+            col.addValue(item.getLabel(), item.getStringValue());
+        }
+
+        columnNames.add(groupTitle);
+        columns.put(groupTitle, col);
+    }
+
+
+    public void addColumn(StringOptionsData options) {
+        String groupTitle = options.getLabel();
+
+        Column     col   = new Column(groupTitle);
+        DataItem[] items = options.getItems();
+
+        if (items == null) {
+            GWT.log("No items found in StringOptionsData '" + groupTitle + "'");
+            return;
+        }
+
+        for (DataItem item: items) {
+            String title = item.getLabel();
+
+            if (valueNames.indexOf(title) < 0) {
+                valueNames.add(title);
+            }
+
+            col.addValue(item.getLabel(), item.getStringValue());
+        }
+
+        columnNames.add(groupTitle);
+        columns.put(groupTitle, col);
+    }
+
+
+    public Widget createTileLayout() {
+        TileLayout tileLayout = new TileLayout();
+        tileLayout.setTilesPerLine (columnNames.size() + 1);
+        tileLayout.setAutoWrapLines(false);
+        tileLayout.setTileMargin(1);
+
+        tileLayout.addTile(new Label(""));
+        for (int i = 0, n = columnNames.size(); i < n; i++) {
+            String columnName = columnNames.get(i);
+            Column col        = columns.get(columnName);
+
+            selected.put(columnName, new ArrayList<String>());
+
+            tileLayout.addTile(createLabel(MESSAGE.getString(columnName)));
+        }
+
+        int nVals = valueNames.size();
+
+        for (int j = 0; j < nVals; j++) {
+            for (int i = 0, n = columnNames.size(); i < n; i++) {
+                String valueName  = valueNames.get(j);
+                String columnName = columnNames.get(i);
+                Column col        = columns.get(columnName);
+                String value      = col.getValue(valueName);
+
+                if (i == 0) {
+                    tileLayout.addTile(createLabel(valueName));
+                }
+
+                if (value != null && value.length() > 0) {
+                    tileLayout.addTile(createCheckBox(columnName, value));
+                }
+            }
+        }
+
+        return tileLayout;
+    }
+
+
+    /**
+     * Returns a widget with matrix of checkboxes and labels.
+     * @param tileLayouted if true, use a TileLayout (for inclusion in SmartGWT
+     *                     containers, avoiding scrollbar-issues.
+     */
+    public Widget create(boolean tileLayouted) {
+        if (tileLayouted) {
+            return createTileLayout();
+        }
+        Grid grid = new Grid(valueNames.size() + 1, columnNames.size() + 1);
+
+        for (int i = 0, n = columnNames.size(); i < n; i++) {
+            String columnName = columnNames.get(i);
+            Column col        = columns.get(columnName);
+
+            selected.put(columnName, new ArrayList<String>());
+
+            grid.setWidget(0, i+1, createLabel(MESSAGE.getString(columnName)));
+
+            for (int j = 0, o = valueNames.size(); j < o; j++) {
+                String valueName = valueNames.get(j);
+                String value     = col.getValue(valueName);
+
+                if (i == 0) {
+                    grid.setWidget(j+1, 0, createLabel(valueName));
+                }
+
+                if (value != null && value.length() > 0) {
+                    grid.setWidget(j+1, i+1, createCheckBox(columnName, value));
+                }
+            }
+        }
+
+        return grid;
+    }
+
+
+    /** Creates label with given text. */
+    protected Label createLabel(String text) {
+        Label label = new Label(text);
+        label.setHeight(CELL_HEIGHT);
+
+        return label;
+    }
+
+
+    /** Create Checkbox for column/value. */
+    protected Canvas createCheckBox(final String colName, final String value) {
+        CheckBox box = new CheckBox();
+        box.addClickListener(new ClickListener() {
+            @Override
+            public void onClick(Widget sender) {
+                CheckBox box = (CheckBox) sender;
+                Map<String, List<String>> selection = getSelection();
+
+                List<String> values = selection.get(colName);
+                if (values.indexOf(value) >= 0) {
+                    values.remove(value);
+                }
+                else {
+                    values.add(value);
+                }
+            }
+        });
+
+        Canvas c = new Canvas();
+        c.addChild(box);
+        return c;
+    }
+
+
+    public Map<String, List<String>> getSelection() {
+        return selected;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/ui/ParameterMatrixPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,164 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.gwt.user.client.ui.HTML;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+import de.intevation.flys.client.shared.model.IntegerOptionsData;
+import de.intevation.flys.client.shared.model.StringOptionsData;
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class ParameterMatrixPanel extends AbstractUIProvider {
+
+    private ParameterMatrix matrix;
+
+    @Override
+    protected Data[] getData() {
+        Map<String, List<String>> selection = matrix.getSelection();
+        Set<Map.Entry<String, List<String>>> entries = selection.entrySet();
+
+        Data[] list = new Data[selection.size()];
+
+        int i = 0;
+
+        for (Map.Entry<String, List<String>> entry: entries) {
+            String value = buildValueString(entry.getValue());
+
+            DataItem item = new DefaultDataItem(
+                entry.getKey(),
+                null,
+                value);
+
+            list[i++] = new DefaultData(
+                entry.getKey(), null, null, new DataItem[] { item });
+        }
+
+        return list;
+    }
+
+
+    protected String buildValueString(List<String> values) {
+        StringBuilder sb = new StringBuilder();
+
+        boolean first = true;
+
+        for (String value: values) {
+            if (!first) {
+                sb.append(";");
+            }
+
+            sb.append(value);
+
+            first = false;
+        }
+
+        return sb.toString();
+    }
+
+
+    /** Canvas to show in non-edit mode. */
+    @Override
+    public Canvas createOld(DataList dataList) {
+        HLayout layout  = new HLayout();
+        VLayout vLayout = new VLayout();
+
+        layout.setWidth(300);
+        vLayout.setWidth(280);
+
+        for (int i = 0, n = dataList.size(); i < n; i++) {
+            HLayout row  = new HLayout();
+            VLayout cols = new VLayout();
+
+            row.setWidth(300);
+            cols.setWidth(100);
+
+            Data       data  = dataList.get(i);
+            DataItem[] items = data.getItems();
+
+            Label parameter = new Label(data.getDescription());
+            parameter.setWidth(200);
+
+            for (int j = 0, m = items.length; j < m; j++) {
+                DataItem item  = items[j];
+                Label    value = new Label(item.getLabel());
+
+                value.setValign(com.smartgwt.client.types.VerticalAlignment.TOP);
+                value.setWidth(130);
+                value.setHeight(20);
+
+                cols.addMember(value);
+                HTML hr = new HTML("<hr>");
+                hr.setHeight("3px");
+                cols.addMember(hr);
+            }
+
+            row.addMember(parameter);
+            row.addMember(cols);
+
+            vLayout.addMember(row);
+        }
+
+        Canvas back = getBackButton(dataList.getState());
+
+        layout.addMember(vLayout);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    /** Create the main canvas in the "editing" mode. */
+    @Override
+    public Canvas create(DataList dataList) {
+        VLayout v = new VLayout();
+        v.addMember(createTitle(dataList));
+
+        matrix = new ParameterMatrix();
+
+        for (Data data: dataList.getAll()) {
+            if (data instanceof IntegerOptionsData) {
+                matrix.addColumn((IntegerOptionsData) data);
+            }
+            else if (data instanceof StringOptionsData) {
+                matrix.addColumn((StringOptionsData) data);
+            }
+        }
+
+        // If too many items are shown, show it in the helper Panel.
+        // TODO its not about the datalist, but about the "rows" in the data.
+        if (dataList.getAll().size() > 5) {
+            v.addMember(matrix.create(false));
+        }
+        else {
+            helperContainer.addMember(matrix.create(true));
+        }
+        v.addMember(getNextButton());
+
+        return v;
+    }
+
+
+    /** Reaturns a label with description of first Data. */
+    protected Canvas createTitle(DataList dataList) {
+        Data data = dataList.get(0);
+        Label label = new Label(data.getDescription());
+        label.setHeight(35);
+
+        return label;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/ui/PeriodPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,198 @@
+package de.intevation.flys.client.client.ui;
+
+import com.google.gwt.core.client.GWT;
+
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+
+import com.smartgwt.client.util.SC;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+
+import com.smartgwt.client.widgets.form.DynamicForm;
+
+import com.smartgwt.client.widgets.form.fields.DateRangeItem;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.FLYSConstants;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * This UIProvider creates a panel for location or distance input.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class PeriodPanel
+extends      AbstractUIProvider
+{
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    DateRangeItem inputPanel;
+
+    long start;
+    long end;
+
+    protected String startName;
+    protected String endName;
+
+    public PeriodPanel() {
+        this("start", "end");
+    }
+
+    public PeriodPanel(String startName, String endName) {
+        this.startName = startName;
+        this.endName   = endName;
+    }
+
+
+    public Canvas create(DataList list) {
+        VLayout layout = new VLayout();
+
+        Canvas helper = createHelper();
+        this.helperContainer.addMember(helper);
+
+        Canvas submit = getNextButton();
+        Canvas widget = createWidget(list);
+
+        layout.addMember(widget);
+        layout.addMember(submit);
+        return layout;
+    }
+
+
+    public Canvas createWidget(DataList data) {
+        VLayout layout = new VLayout();
+
+        Label title = new Label(data.get(0).getDescription());
+        title.setHeight("25px");
+
+        DynamicForm form = new DynamicForm();
+        inputPanel = new DateRangeItem();
+        inputPanel.setToTitle(MSG.to());
+        inputPanel.setFromTitle(MSG.from());
+        inputPanel.setShowTitle(false);
+        form.setFields(inputPanel);
+
+        layout.addMember(title);
+        layout.addMember(form);
+
+        return layout;
+    }
+
+    protected Canvas createHelper() {
+        return new VLayout();
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        List<Data> items = dataList.getAll();
+
+        Data start = getData(items, startName);
+        Data end   = getData(items, endName);
+        DataItem[] startItem = start.getItems();
+        DataItem[] endItem = end.getItems();
+
+        String v1 = startItem[0].getStringValue();
+        String v2 = endItem[0].getStringValue();
+
+        long v1l = 0;
+        long v2l = 0;
+        try {
+            v1l = Long.parseLong(v1);
+            v2l = Long.parseLong(v2);
+        }
+        catch(NumberFormatException nfe) {
+            GWT.log(nfe.toString());
+        }
+        Date d1 = new Date(v1l);
+        Date d2 = new Date(v2l);
+
+        DateTimeFormat f =
+            DateTimeFormat.getFormat(
+                DateTimeFormat.PredefinedFormat.DATE_MEDIUM);
+        StringBuilder sb = new StringBuilder();
+        sb.append(f.format(d1) + " - ");
+        sb.append(f.format(d2));
+
+        Label old = new Label(sb.toString());
+        old.setWidth(130);
+
+        HLayout layout = new HLayout();
+        layout.setWidth("400px");
+
+        Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+
+        Canvas back = getBackButton(dataList.getState());
+
+        layout.addMember(label);
+        layout.addMember(old);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+     */
+    public Data[] getData() {
+        List<Data> data = new ArrayList<Data>();
+
+        boolean valid = saveDateValues();
+        if(valid) {
+            String start = Long.valueOf(this.start).toString();
+            String end   = Long.valueOf(this.end).toString();
+            DataItem startItem = new DefaultDataItem(startName, startName, start);
+            DataItem endItem   = new DefaultDataItem(endName, endName, end);
+            data.add(new DefaultData(
+                startName,
+                null,
+                null,
+                new DataItem[] { startItem }));
+            data.add(new DefaultData(
+                endName,
+                null,
+                null,
+                new DataItem[] { endItem }));
+        }
+
+        return data.toArray(new Data[data.size()]);
+    }
+
+
+    protected boolean saveDateValues() {
+        Date st = inputPanel.getFromDate();
+        Date en = inputPanel.getToDate();
+        if (st == null || en == null) {
+            SC.warn(MSG.error_wrong_date());
+            return false;
+        }
+
+        long start = st.getTime();
+        long end = en.getTime();
+
+        if (start <= end) {
+            this.start = start;
+            this.end = end;
+            return true;
+        }
+        return false;
+    }
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/ProjectList.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/ProjectList.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,22 +1,18 @@
 package de.intevation.flys.client.client.ui;
 
-import java.util.Date;
-import java.util.Map;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.MissingResourceException;
-
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.i18n.client.DateTimeFormat;
 import com.google.gwt.user.client.Timer;
 import com.google.gwt.user.client.rpc.AsyncCallback;
-
 import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.types.Autofit;
 import com.smartgwt.client.types.ListGridEditEvent;
 import com.smartgwt.client.types.ListGridFieldType;
+import com.smartgwt.client.types.Overflow;
 import com.smartgwt.client.types.SelectionStyle;
 import com.smartgwt.client.types.SortArrow;
 import com.smartgwt.client.types.SortDirection;
+import com.smartgwt.client.types.VerticalAlignment;
 import com.smartgwt.client.util.BooleanCallback;
 import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.Canvas;
@@ -32,48 +28,55 @@
 import com.smartgwt.client.widgets.grid.events.CellDoubleClickHandler;
 import com.smartgwt.client.widgets.grid.events.EditCompleteEvent;
 import com.smartgwt.client.widgets.grid.events.EditCompleteHandler;
+import com.smartgwt.client.widgets.grid.events.HeaderDoubleClickEvent;
+import com.smartgwt.client.widgets.grid.events.HeaderDoubleClickHandler;
 import com.smartgwt.client.widgets.grid.events.RowContextClickEvent;
 import com.smartgwt.client.widgets.grid.events.RowContextClickHandler;
-import com.smartgwt.client.widgets.grid.events.HeaderDoubleClickHandler;
-import com.smartgwt.client.widgets.grid.events.HeaderDoubleClickEvent;
 import com.smartgwt.client.widgets.layout.VLayout;
 import com.smartgwt.client.widgets.menu.Menu;
 import com.smartgwt.client.widgets.menu.MenuItem;
 import com.smartgwt.client.widgets.menu.MenuItemSeparator;
-import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;
 import com.smartgwt.client.widgets.menu.events.ClickHandler;
-import com.smartgwt.client.types.VerticalAlignment;
-
-import de.intevation.flys.client.shared.model.Collection;
-import de.intevation.flys.client.shared.model.CollectionRecord;
-import de.intevation.flys.client.shared.model.User;
-import de.intevation.flys.client.shared.model.Artifact;
-import de.intevation.flys.client.shared.model.Recommendation;
-
-import de.intevation.flys.client.client.event.FilterHandler;
-import de.intevation.flys.client.client.event.StringFilterEvent;
+import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;
 
 import de.intevation.flys.client.client.Config;
 import de.intevation.flys.client.client.FLYS;
 import de.intevation.flys.client.client.FLYSConstants;
 import de.intevation.flys.client.client.event.CollectionChangeEvent;
 import de.intevation.flys.client.client.event.CollectionChangeHandler;
+import de.intevation.flys.client.client.event.FilterHandler;
+import de.intevation.flys.client.client.event.RangeFilterEvent;
+import de.intevation.flys.client.client.event.StringFilterEvent;
+import de.intevation.flys.client.client.services.AddArtifactService;
+import de.intevation.flys.client.client.services.AddArtifactServiceAsync;
 import de.intevation.flys.client.client.services.ArtifactService;
 import de.intevation.flys.client.client.services.ArtifactServiceAsync;
+import de.intevation.flys.client.client.services.CreateCollectionService;
+import de.intevation.flys.client.client.services.CreateCollectionServiceAsync;
 import de.intevation.flys.client.client.services.DeleteCollectionService;
 import de.intevation.flys.client.client.services.DeleteCollectionServiceAsync;
+import de.intevation.flys.client.client.services.DescribeCollectionService;
+import de.intevation.flys.client.client.services.DescribeCollectionServiceAsync;
+import de.intevation.flys.client.client.services.GetArtifactService;
+import de.intevation.flys.client.client.services.GetArtifactServiceAsync;
 import de.intevation.flys.client.client.services.SetCollectionNameService;
 import de.intevation.flys.client.client.services.SetCollectionNameServiceAsync;
 import de.intevation.flys.client.client.services.SetCollectionTTLService;
 import de.intevation.flys.client.client.services.SetCollectionTTLServiceAsync;
 import de.intevation.flys.client.client.services.UserCollectionsService;
 import de.intevation.flys.client.client.services.UserCollectionsServiceAsync;
-import de.intevation.flys.client.client.services.DescribeCollectionService;
-import de.intevation.flys.client.client.services.DescribeCollectionServiceAsync;
-import de.intevation.flys.client.client.services.AddArtifactService;
-import de.intevation.flys.client.client.services.AddArtifactServiceAsync;
-import de.intevation.flys.client.client.services.CreateCollectionService;
-import de.intevation.flys.client.client.services.CreateCollectionServiceAsync;
+import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.CollectionItem;
+import de.intevation.flys.client.shared.model.CollectionRecord;
+import de.intevation.flys.client.shared.model.Recommendation;
+import de.intevation.flys.client.shared.model.User;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.MissingResourceException;
 
 
 /**
@@ -104,7 +107,7 @@
     public static final String COLUMN_FAVORITE_WIDTH = "75px";
 
     /** The interface that provides i18n messages. */
-    private FLYSConstants messages = GWT.create(FLYSConstants.class);
+    private final FLYSConstants messages = GWT.create(FLYSConstants.class);
 
     /** The UserService used to retrieve information about the current user. */
     protected UserCollectionsServiceAsync userCollectionsService =
@@ -138,6 +141,10 @@
     protected AddArtifactServiceAsync addArtifactService =
         GWT.create(AddArtifactService.class);
 
+    /** The GetArtifactService used to open an existing collection. */
+    protected GetArtifactServiceAsync getArtifactService =
+        GWT.create(GetArtifactService.class);
+
     /** A pointer to the FLYS instance.*/
     protected FLYS flys;
 
@@ -156,6 +163,10 @@
     /** The collection to clone*/
     protected Collection cloneCollection;
 
+    /** The message class that provides i18n strings.*/
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+
     /**
      * The default constructor that creates a new ProjectList for a specific
      * user.
@@ -163,11 +174,12 @@
      * @param user The user.
      */
     public ProjectList(FLYS flys, User user) {
+        super();
         this.flys = flys;
         this.user = user;
 
-        filteredCollections = new ArrayList();
-        collections = new ArrayList();
+        filteredCollections = new ArrayList<Collection>();
+        collections = new ArrayList<Collection>();
         grid = new ListGrid();
         initGrid();
         init();
@@ -181,7 +193,7 @@
 
     protected void initGrid() {
         grid.setWidth100();
-        grid.setHeight100();
+        grid.setAutoFitData(Autofit.VERTICAL);
         grid.setAutoFitMaxWidth(500);
         grid.setEmptyMessage(messages.no_projects());
         grid.setLoadingDataMessage(messages.load_projects());
@@ -193,6 +205,8 @@
         grid.setSortField(0);
         grid.setSelectionType(SelectionStyle.SINGLE);
         grid.setCanReorderFields(false);
+        grid.setLeaveScrollbarGap(false);
+        grid.setBorder("0px");
 
         ListGridField date = buildDateField();
         ListGridField name = buildNameField();
@@ -201,14 +215,16 @@
         grid.setFields(date, name, fav);
 
         grid.addHeaderDoubleClickHandler(new HeaderDoubleClickHandler() {
+            @Override
             public void onHeaderDoubleClick(HeaderDoubleClickEvent event) {
-                // cancel the event.
+                // Cancel the event.
                 return;
             }
         });
 
-        // add a handler to set / unset the favorite state of a project
+        // Add a handler to set / unset the favorite state of a project.
         grid.addCellClickHandler(new CellClickHandler() {
+            @Override
             public void onCellClick(CellClickEvent event) {
                 if (event.getColNum() != 2) {
                     return;
@@ -222,8 +238,9 @@
             }
         });
 
-        // add a handler to open a project
+        // Add a handler to open a project.
         grid.addCellDoubleClickHandler(new CellDoubleClickHandler() {
+            @Override
             public void onCellDoubleClick(CellDoubleClickEvent e) {
                 CollectionRecord record = (CollectionRecord) e.getRecord();
                 String uuid = record != null
@@ -233,8 +250,9 @@
             }
         });
 
-        // add a handler to open a context menu
+        // Add a handler to open a context menu.
         grid.addRowContextClickHandler(new RowContextClickHandler() {
+            @Override
             public void onRowContextClick(RowContextClickEvent event) {
                 CollectionRecord record = (CollectionRecord) event.getRecord();
 
@@ -289,6 +307,7 @@
 
         MenuItem open = new MenuItem(messages.open_project());
         open.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(MenuItemClickEvent evt) {
                 getFlys().openProject(record.getCollection().identifier());
             }
@@ -296,8 +315,10 @@
 
         MenuItem del = new MenuItem(messages.delete_project());
         del.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(MenuItemClickEvent evt) {
                 SC.ask(messages.really_delete(), new BooleanCallback() {
+                    @Override
                     public void execute(Boolean value) {
                         if (value) {
                             deleteCollection(record.getCollection());
@@ -309,6 +330,7 @@
 
         MenuItem rename = new MenuItem(messages.rename_project());
         rename.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(MenuItemClickEvent evt) {
                 int row = grid.getRecordIndex(record);
                 grid.startEditing(row, 1, false);
@@ -317,6 +339,7 @@
 
         MenuItem clone = new MenuItem(messages.clone_project());
         clone.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(MenuItemClickEvent evt) {
                 cloneProject(record.getCollection());
             }
@@ -343,6 +366,7 @@
         setShowEdges(false);
         setLayoutMargin(0);
         setLayoutAlign(VerticalAlignment.TOP);
+        setOverflow(Overflow.AUTO);
 
         Label title = new Label(messages.projects());
         title.setHeight("20");
@@ -364,6 +388,7 @@
         TableFilter filter = new TableFilter();
         filter.setHeight("30px");
         filter.addFilterHandler(this);
+        filter.setBorder("1px solid gray");
 
         addMember(titleWrapper);
         addMember(gridWrapper);
@@ -371,6 +396,7 @@
     }
 
 
+    @Override
     public void onFilterCriteriaChanged(StringFilterEvent event) {
         String search = event.getFilter();
         if (search != null && search.length() > 0) {
@@ -387,6 +413,14 @@
     }
 
 
+    @Override
+    public void onFilterCriteriaChanged(RangeFilterEvent event) {
+        //Empty. No Ranges to filter.
+    }
+
+
+    /** On collection change, update list (probably name change or similar). */
+    @Override
     public void onCollectionChange(CollectionChangeEvent event) {
         if (event.getOldValue() == null) {
             updateUserCollections();
@@ -394,6 +428,7 @@
     }
 
 
+    @Override
     public void onEditComplete(EditCompleteEvent event) {
         if (event.getColNum() != 1) {
             return;
@@ -404,7 +439,7 @@
         CollectionRecord r = (CollectionRecord) grid.getRecord(row);
         Collection       c = r.getCollection();
 
-        Map newValues = event.getNewValues();
+        Map<?, ?> newValues = event.getNewValues();
         String name   = (String) newValues.get("name");
 
         int maxLength = getMaxNameLength();
@@ -442,6 +477,7 @@
         GWT.log("=> New name = " + c.getName());
 
         nameService.setName(c, new AsyncCallback<Void>(){
+            @Override
             public void onFailure(Throwable caught) {
                 String msg = caught.getMessage();
 
@@ -453,6 +489,7 @@
                 }
             }
 
+            @Override
             public void onSuccess(Void v) {
                 updateUserCollections();
                 if(flys.getWorkspace().hasView(c.identifier())) {
@@ -478,6 +515,7 @@
         GWT.log("=> New ttl = " + c.getTTL());
 
         ttlService.setTTL(c, new AsyncCallback<Void>() {
+            @Override
             public void onFailure(Throwable caught) {
                 String msg = caught.getMessage();
 
@@ -489,6 +527,7 @@
                 }
             }
 
+            @Override
             public void onSuccess(Void v) {
                 updateUserCollections();
             }
@@ -501,7 +540,7 @@
      *
      * @param c The Collection that should be deleted.
      */
-    protected void deleteCollection(final Collection c) {
+    public void deleteCollection(final Collection c) {
         if (c == null) {
             return;
         }
@@ -509,6 +548,7 @@
         GWT.log("Delete Collection: " + c.identifier());
 
         deleteService.delete(c, new AsyncCallback<Void>(){
+            @Override
             public void onFailure(Throwable caught) {
                 String msg = caught.getMessage();
 
@@ -520,6 +560,7 @@
                 }
             }
 
+            @Override
             public void onSuccess(Void v) {
                 flys.getWorkspace().destroyProject(c.identifier());
                 updateUserCollections();
@@ -532,11 +573,11 @@
         GWT.log("==> ProjectList updates user collections!");
 
         Config config = Config.getInstance();
-        String url    = config.getServerUrl();
         String locale = config.getLocale();
 
-        userCollectionsService.getUserCollections(url, locale, user.identifier(),
+        userCollectionsService.getUserCollections(locale, user.identifier(),
             new AsyncCallback<Collection[]>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     String msg = caught.getMessage();
 
@@ -548,6 +589,7 @@
                     }
                 }
 
+                @Override
                 public void onSuccess(Collection[] collections) {
                     int num = collections != null ? collections.length : 0;
 
@@ -559,6 +601,7 @@
         );
     }
 
+
     /**
      * Delete all entries in the ListGrid.
      */
@@ -607,6 +650,7 @@
         }
     }
 
+
     /**
      * Filter for the user collections.
      *
@@ -662,6 +706,7 @@
         date.setCanEdit(false);
 
         date.setCellFormatter(new CellFormatter() {
+            @Override
             public String format(Object value, ListGridRecord rec, int r, int c) {
                 if (value == null) {
                     return null;
@@ -693,6 +738,7 @@
         name.setType(ListGridFieldType.TEXT);
         name.setShowHover(true);
         name.setHoverCustomizer(new HoverCustomizer() {
+            @Override
             public String hoverHTML(
                 Object         value,
                 ListGridRecord record,
@@ -741,22 +787,25 @@
 
         describeCollectionService.describe(c.identifier(), locale,
             new AsyncCallback<Collection>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("Could not DESCRIBE collection.");
                     SC.warn(messages.getString(caught.getMessage()));
                 }
 
 
+                @Override
                 public void onSuccess(Collection newCollection) {
                     GWT.log("Successfully DESCRIBED collection.");
                     String uuid = getMasterArtifact(newCollection);
-                    cloneArtifact(uuid);
+                    cloneArtifact(uuid, newCollection);
                 }
             }
         );
     }
 
 
+    /** Get master artifacts UUID of a collection. */
     protected String getMasterArtifact(Collection newCollection) {
         String uuid = newCollection.getItem(0).identifier();
         // The master artifact uuid.
@@ -764,13 +813,11 @@
     }
 
 
-    protected void cloneArtifact(String uuid) {
-        Config config               = Config.getInstance();
-        final String url            = config.getServerUrl();
-        final String locale         = config.getLocale();
-
+    /** Clone artifact/create collection, using the refArtifacts factory. */
+    protected void cloneArtifact(String uuid, Artifact refArtifact,
+        final String locale) {
         Recommendation recommendation = new Recommendation(
-            "winfo",
+            refArtifact.getName(),
             null,
             uuid,
             null);
@@ -779,11 +826,13 @@
         createArtifactService.create(
             locale, factory, recommendation,
             new AsyncCallback<Artifact>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("Error loading recommendations: " +
                         caught.getMessage());
                 }
 
+                @Override
                 public void onSuccess(Artifact artifact) {
                     GWT.log("Created new artifact: " + artifact.getUuid());
                     createCollection(artifact);
@@ -793,6 +842,33 @@
     }
 
 
+    /**
+     * Clone a project (collection).
+     */
+    protected void cloneArtifact(final String uuid, Collection newCollection) {
+        Config config       = Config.getInstance();
+        final String locale = config.getLocale();
+
+        // Find out which factory to use for cloning.
+        CollectionItem master = newCollection.getItem(0);
+        getArtifactService.getArtifact(
+            locale,
+            master.identifier(),
+            master.hash(),
+            new AsyncCallback<Artifact>() {
+                @Override
+                public void onFailure(Throwable caught) {
+                    SC.warn(MSG.getString(caught.getMessage()));
+                }
+
+                @Override
+                public void onSuccess(Artifact artifact) {
+                    cloneArtifact(uuid, artifact, locale);
+                }
+        });
+    }
+
+
     protected void createCollection(final Artifact artifact) {
         Config config        = Config.getInstance();
         final String locale  = config.getLocale();
@@ -802,11 +878,13 @@
             locale,
             ownerid,
             new AsyncCallback<Collection>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("Could not create the new collection.");
                     SC.warn(messages.getString(caught.getMessage()));
                 }
 
+                @Override
                 public void onSuccess(Collection collection) {
                     GWT.log("Successfully created a new collection.");
                     addArtifactToCollection(artifact, collection);
@@ -817,18 +895,19 @@
 
 
     protected void addArtifactToCollection(Artifact a, Collection c) {
-        Config config               = Config.getInstance();
-        final String url            = config.getServerUrl();
-        final String locale         = config.getLocale();
+        Config config       = Config.getInstance();
+        final String locale = config.getLocale();
 
         addArtifactService.add(
             c, a, locale,
             new AsyncCallback<Collection>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("An error occured while adding artifact.");
                     SC.warn(messages.getString(caught.getMessage()));
                 }
 
+                @Override
                 public void onSuccess(Collection newColl) {
                     String name = cloneCollection.getName();
                     if(name == null || name.equals("")) {
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/PropertyEditor.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/PropertyEditor.java	Fri Sep 28 12:15:52 2012 +0200
@@ -10,3 +10,4 @@
     String getI18NString(String name);
 
 }
+// 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-client/src/main/java/de/intevation/flys/client/client/ui/RadioPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,92 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.LinkedHashMap;
+
+import com.google.gwt.core.client.GWT;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+
+public class RadioPanel extends AbstractUIProvider {
+
+    protected String dataName;
+    protected DynamicForm form;
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        // TODO Auto-generated method stub
+        Data       data  = dataList.get(0);
+        DataItem[] items = data.getItems();
+
+        HLayout layout = new HLayout();
+        Label   label  = new Label(dataList.getLabel());
+        Label   value  = new Label(items[0].getLabel());
+
+        layout.setHeight(35);
+        layout.setWidth(400);
+        label.setWidth(200);
+
+        layout.addMember(label);
+        layout.addMember(value);
+        layout.addMember(getBackButton(dataList.getState()));
+
+        return layout;
+    }
+
+    @Override
+    public Canvas create(DataList dataList) {
+        Data       data  = dataList.get(0);
+        DataItem[] items = data.getItems();
+
+        this.dataName = data.getLabel();
+
+        VLayout layout = new VLayout();
+        Label   label  = new Label(data.getDescription());
+        RadioGroupItem rgi = new RadioGroupItem("selection");
+        rgi.setShowTitle(false);
+        GWT.log("items: " + items.length);
+        LinkedHashMap<String, String> elems = new LinkedHashMap<String, String>();
+        for (int i = 0; i < items.length; i++) {
+            GWT.log(items[i].getStringValue() + "; " + items[i].getLabel());
+            elems.put(items[i].getStringValue(), items[i].getLabel());
+        }
+        rgi.setValueMap(elems);
+        rgi.setDefaultValue(items[0].getStringValue());
+
+        form = new DynamicForm();
+        form.setFields(rgi);
+        layout.setMembersMargin(10);
+        layout.setHeight(35);
+        label.setHeight(35);
+
+        layout.addMember(label);
+        layout.addMember(form);
+        layout.addMember(getNextButton());
+        layout.setMembersMargin(10);
+
+        //initDefaultValues(dataList);
+
+        return layout;
+    }
+
+    @Override
+    protected Data[] getData() {
+        String value = form.getValueAsString("selection");
+        DataItem item = new DefaultDataItem("ye_select", "ye_select", value);
+        return new Data[] { new DefaultData(
+            "ye_select", null, null, new DataItem[]{item})};
+    }
+
+    protected String getTitle(DataItem item) {
+        return item.getLabel();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/RangePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,283 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.TextItem;
+import com.smartgwt.client.widgets.form.validator.Validator;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.RangeData;
+
+
+/**
+ * An UIProvider for inserting ranges.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public abstract class RangePanel extends AbstractUIProvider {
+
+    public static final String FIELD_LOWER = "field_lower";
+    public static final String FIELD_UPPER = "field_upper";
+
+
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    protected DynamicForm lowerForm;
+    protected DynamicForm upperForm;
+
+    protected String dataName;
+
+
+    public abstract Object getMaxLower();
+
+    public abstract Object getMaxUpper();
+
+
+
+    @Override
+    public Canvas create(DataList data) {
+        setDataName(data);
+
+        VLayout root = new VLayout();
+
+        root.addMember(createLabel(data));
+        root.addMember(createForm(data));
+        root.addMember(getNextButton());
+
+        initDefaults(data);
+
+        return root;
+    }
+
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        Data       data  = dataList.get(0);
+        DataItem[] items = data.getItems();
+
+        HLayout layout = new HLayout();
+
+        Label label = new Label(dataList.getLabel());
+        label.setWidth(200);
+        label.setHeight(20);
+
+        Label value = new Label(items[0].getLabel());
+        value.setHeight(20);
+
+        layout.addMember(label);
+        layout.addMember(value);
+        layout.addMember(getBackButton(dataList.getState()));
+
+        return layout;
+    }
+
+
+    @Override
+    public List<String> validate() {
+        List<String> errors = new ArrayList<String>();
+
+        if (!lowerForm.validate()) {
+            String msg = MSG.error_validate_range();
+            msg = msg.replace("$1", getLower());
+            msg = msg.replace("$2", String.valueOf(getMaxLower()));
+            msg = msg.replace("$3", String.valueOf(getMaxLower()));
+            errors.add(msg);
+        }
+
+        if (!upperForm.validate()) {
+            String msg = MSG.error_validate_range();
+            msg = msg.replace("$1", getUpper());
+            msg = msg.replace("$2", String.valueOf(getMaxLower()));
+            msg = msg.replace("$3", String.valueOf(getMaxUpper()));
+            errors.add(msg);
+        }
+
+        return errors;
+    }
+
+
+    @Override
+    protected Data[] getData() {
+        return new Data[0];
+    }
+
+
+    protected void initDefaults(DataList dataList) {
+        RangeData data = findRangeData(dataList);
+
+        if (data != null) {
+            setLower(String.valueOf(data.getDefaultLower()));
+            setUpper(String.valueOf(data.getDefaultUpper()));
+        }
+    }
+
+
+    protected RangeData findRangeData(DataList dataList) {
+        RangeData data = null;
+
+        for (int i = 0, n = dataList.size(); i < n; i++) {
+            Data tmp = dataList.get(i);
+
+            if (tmp instanceof RangeData) {
+                return (RangeData) tmp;
+            }
+        }
+
+        return null;
+    }
+
+
+    protected void setDataName(DataList dataList) {
+        Data data = dataList.get(0);
+
+        this.dataName = data.getLabel();
+    }
+
+
+    public String getDataName() {
+        return dataName;
+    }
+
+
+    public String getLower() {
+        return lowerForm.getValueAsString(FIELD_LOWER);
+    }
+
+
+    public void setLower(String lower) {
+        lowerForm.setValue(FIELD_LOWER, lower);
+    }
+
+
+    public String getUpper() {
+        return upperForm.getValueAsString(FIELD_UPPER);
+    }
+
+
+    public void setUpper(String upper) {
+        upperForm.setValue(FIELD_UPPER, upper);
+    }
+
+
+    protected Canvas createLabel(DataList dataList) {
+        RangeData rangeData = findRangeData(dataList);
+
+        if (rangeData == null) {
+            return new Canvas();
+        }
+
+        Label label = new Label(rangeData.getDescription());
+
+        label.setWidth100();
+        label.setHeight(25);
+
+        return label;
+    }
+
+
+    protected Canvas createForm(DataList dataList) {
+        lowerForm = createLowerForm(dataList);
+        upperForm = createUpperForm(dataList);
+
+        HLayout formLayout = new HLayout();
+        formLayout.addMember(lowerForm);
+        formLayout.addMember(createSpacer());
+        formLayout.addMember(upperForm);
+
+        return formLayout;
+    }
+
+
+    protected DynamicForm newForm() {
+        DynamicForm form = new DynamicForm();
+        form.setTitlePrefix("");
+        form.setTitleSuffix("");
+        form.setTitle("");
+        form.setTitleField("");
+
+        return form;
+    }
+
+
+    protected FormItem newFormItem(String name) {
+        TextItem item = new TextItem(name, "");
+        item.setShowTitle(false);
+
+        return item;
+    }
+
+
+    protected DynamicForm createLowerForm(DataList dataList) {
+        DynamicForm lowerForm = newForm();
+        FormItem    lower     = createLowerField(dataList);
+
+        lowerForm.setFields(lower);
+
+        return lowerForm;
+    }
+
+
+    protected DynamicForm createUpperForm(DataList dataList) {
+        DynamicForm upperForm = newForm();
+        FormItem    upper     = createUpperField(dataList);
+
+        upperForm.setFields(upper);
+
+        return upperForm;
+    }
+
+
+    protected Canvas createSpacer() {
+        Label spacer = new Label("-");
+        spacer.setWidth(25);
+        spacer.setHeight(25);
+        spacer.setAlign(Alignment.CENTER);
+
+        return spacer;
+    }
+
+
+    protected FormItem createLowerField(DataList dataList) {
+        return createField(FIELD_LOWER, createLowerValidators(dataList));
+    }
+
+
+    protected FormItem createUpperField(DataList dataList) {
+        return createField(FIELD_UPPER, createUpperValidators(dataList));
+    }
+
+
+    protected FormItem createField(String name, Validator[] validators) {
+        FormItem field = newFormItem(name);
+
+        if (validators != null && validators.length > 0) {
+            field.setValidators(validators);
+        }
+
+        return field;
+    }
+
+
+    protected Validator[] createLowerValidators(DataList dataList) {
+        return null;
+    }
+
+
+    protected Validator[] createUpperValidators(DataList dataList) {
+        return null;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/ui/RangeTableFilter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,133 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.TextItem;
+import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
+import com.smartgwt.client.widgets.form.fields.events.KeyUpEvent;
+import com.smartgwt.client.widgets.form.fields.events.KeyUpHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
+
+import de.intevation.flys.client.client.event.FilterHandler;
+import de.intevation.flys.client.client.event.RangeFilterEvent;
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.utils.DoubleValidator;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class RangeTableFilter
+extends      HLayout
+implements   ChangedHandler, KeyUpHandler
+{
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    protected List<FilterHandler> handlers;
+
+    protected TextItem fromField;
+    protected TextItem toField;
+    protected DynamicForm filterForm;
+
+    public RangeTableFilter() {
+        super();
+        fromField = new TextItem();
+        fromField.setTitle(MESSAGES.from());
+        fromField.setWidth(60);
+        toField = new TextItem();
+        toField.setTitle(MESSAGES.to());
+        toField.setWidth(60);
+
+
+        handlers    = new ArrayList<FilterHandler>();
+
+        fromField.addChangedHandler(this);
+        fromField.addKeyUpHandler(this);
+        toField.addChangedHandler(this);
+        toField.addKeyUpHandler(this);
+
+        filterForm = new DynamicForm();
+        filterForm.setNumCols(4);
+        filterForm.setFields(fromField, toField);
+
+        addMember(filterForm);
+    }
+
+
+    public void onChanged(ChangedEvent event) {
+        // This event handler is to slow...
+//        fireFilterCriteriaChanged(getSearchString());
+    }
+
+
+    public void onKeyUp(KeyUpEvent event) {
+        DoubleValidator validator = new DoubleValidator();
+        Map errors = filterForm.getErrors();
+        if(event.getItem().getValue() != null &&
+           !validator.validate(event.getItem(), errors)) {
+            filterForm.setErrors(errors, true);
+            GWT.log("no valid input!");
+            return;
+        }
+        else {
+            errors.clear();
+            filterForm.setErrors(errors, true);
+        }
+        //To deactivate "As you type" filter add
+        // ' && event.getKeyName().equals("Enter")'
+        // to the if-clause.
+        if (event != null) {
+            fireFilterCriteriaChanged(getFrom(), getTo());
+        }
+    }
+
+
+    public String getFrom() {
+        if (fromField.getValueAsString() == null) {
+            return "";
+        }
+        else {
+            return fromField.getValueAsString();
+        }
+    }
+
+
+    public String getTo() {
+        if (toField.getValueAsString() == null) {
+            return "";
+        }
+        else {
+            return toField.getValueAsString();
+        }
+    }
+
+
+    public void addFilterHandler(FilterHandler handler) {
+        if (handler != null) {
+            handlers.add(handler);
+        }
+    }
+
+
+    protected void fireFilterCriteriaChanged(String from, String to) {
+        RangeFilterEvent filter = new RangeFilterEvent(from, to);
+
+        for (FilterHandler handler: handlers) {
+            handler.onFilterCriteriaChanged(filter);
+        }
+    }
+
+
+    public void clear() {
+        fromField.clearValue();
+        toField.clearValue();
+        fireFilterCriteriaChanged("", "");
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/RecommendationPairRecord.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/RecommendationPairRecord.java	Fri Sep 28 12:15:52 2012 +0200
@@ -12,7 +12,7 @@
 
     /** First attribute-name for StringPairRecord. */
     protected static final String ATTRIBUTE_FIRST  = "first";
-    
+
     /** Second attribute-name for StringPairRecord. */
     protected static final String ATTRIBUTE_SECOND = "second";
 
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/SelectProvider.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/SelectProvider.java	Fri Sep 28 12:15:52 2012 +0200
@@ -98,7 +98,7 @@
     /**
      * This method creates the content of the widget.
      *
-     * @param data The {@link Data} object.
+     * @param data The {@link DataList} object.
      *
      * @return a combobox.
      */
@@ -139,6 +139,7 @@
                 defaultSet = true;
             }
 
+            // I was here. Me 2.
             for (DataItem item: d.getItems()) {
                 if (!defaultSet && first) {
                     initial.put(d.getLabel(), item.getStringValue());
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/SingleLocationPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,331 +1,31 @@
 package de.intevation.flys.client.client.ui;
 
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.smartgwt.client.data.Record;
+
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+
+import de.intevation.flys.client.shared.model.Data;
+
 import java.util.ArrayList;
 import java.util.List;
 
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.i18n.client.NumberFormat;
-
-import com.smartgwt.client.util.SC;
-import com.smartgwt.client.widgets.Canvas;
-import com.smartgwt.client.widgets.Label;
-import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
-import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
-import com.smartgwt.client.widgets.form.fields.FormItem;
-import com.smartgwt.client.widgets.layout.HLayout;
-import com.smartgwt.client.widgets.layout.VLayout;
-import com.smartgwt.client.widgets.grid.ListGrid;
-import com.smartgwt.client.widgets.grid.ListGridField;
-import com.smartgwt.client.widgets.grid.ListGridRecord;
-
-import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
-import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
-import com.smartgwt.client.widgets.grid.CellFormatter;
-
-import com.smartgwt.client.data.Criteria;
-import com.smartgwt.client.data.Record;
-import com.smartgwt.client.types.ListGridFieldType;
-
-import de.intevation.flys.client.shared.model.Data;
-import de.intevation.flys.client.shared.model.DataItem;
-import de.intevation.flys.client.shared.model.DataList;
-import de.intevation.flys.client.shared.model.DefaultData;
-import de.intevation.flys.client.shared.model.DefaultDataItem;
-import de.intevation.flys.client.shared.model.DistanceInfoObject;
-import de.intevation.flys.client.shared.model.ArtifactDescription;
-
-import de.intevation.flys.client.client.services.DistanceInfoService;
-import de.intevation.flys.client.client.services.DistanceInfoServiceAsync;
-import de.intevation.flys.client.client.FLYSConstants;
-import de.intevation.flys.client.client.Config;
-import de.intevation.flys.client.client.ui.range.DistanceInfoDataSource;
-import de.intevation.flys.client.client.event.FilterHandler;
-import de.intevation.flys.client.client.event.StringFilterEvent;
-
-
 /**
- * This UIProvider creates a widget to enter locations.
- *
- * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ * This UIProvider creates a widget to enter a single location (km).
  */
 public class SingleLocationPanel
-extends      AbstractUIProvider
-implements   FilterHandler
+extends      MultipleLocationPanel
 {
-    /** The message class that provides i18n strings.*/
-    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
-
-    /** The DistanceInfoService used to retrieve locations about rivers.*/
-    protected DistanceInfoServiceAsync distanceInfoService =
-        GWT.create(DistanceInfoService.class);
-
-    /** A container that will contain the location or the distance panel.*/
-    protected HLayout container;
-
-    /** The minimal value that the user is allowed to enter.*/
-    protected double min;
-
-    /** The maximal value that the user is allowed to enter.*/
-    protected double max;
-
-    /** The values entered in the location mode.*/
-    protected double[] values;
-
-    /** The input panel for locations */
-    protected DoubleArrayPanel locationPanel;
-
-    /** The locations table */
-    protected ListGrid locationTable;
-
-    /** The table data. */
-    protected DistanceInfoObject[] tableData;
-
     /**
-     * Creates a new LocationDistancePanel instance.
+     * Creates a new SingleLocationPanel instance.
      */
     public SingleLocationPanel() {
-        locationTable = new ListGrid();
-        locationTable.setShowHeaderContextMenu(false);
-    }
-
-
-    /**
-     * This method creates a widget that contains a label, a panel with
-     * checkboxes to switch the input mode between location and distance input,
-     * and a the mode specific panel.
-     *
-     * @param data The data that might be inserted.
-     *
-     * @return a panel.
-     */
-    public Canvas create(DataList data) {
-        VLayout layout = new VLayout();
-        layout.setMembersMargin(10);
-
-        Label label   = new Label(MESSAGES.location ());
-        Canvas widget = createWidget(data);
-        Canvas submit = getNextButton();
-
-        initDefaults(data);
-
-        createLocationTable();
-
-        widget.setHeight(50);
-        label.setHeight(25);
-
-        layout.addMember(label);
-        layout.addMember(widget);
-        layout.addMember(submit);
-
-        return layout;
+        picker = new LocationPicker(this);
     }
 
 
-    /**
-     * This method creates a table that contains the location values.
-     */
-    protected void createLocationTable() {
-        GWT.log("---------- I WAS HERE ---------");
-
-        String baseUrl = GWT.getHostPageBaseURL();
-
-        locationTable.setWidth100();
-        locationTable.setShowRecordComponents(true);
-        locationTable.setShowRecordComponentsByCell(true);
-        locationTable.setHeight100();
-        locationTable.setEmptyMessage(MESSAGES.empty_filter());
-        locationTable.setCanReorderFields(false);
-
-        ListGridField addLocation = new ListGridField ("", "");
-        addLocation.setType (ListGridFieldType.ICON);
-        addLocation.setWidth (20);
-        addLocation.addRecordClickHandler (new RecordClickHandler () {
-            public void onRecordClick (RecordClickEvent e) {
-                Record record = e.getRecord();
-                double[] selected = new double[1];
-                try {
-                    selected[0] =
-                        Double.parseDouble(record.getAttribute("from"));
-                }
-                catch(NumberFormatException nfe) {
-                    // Is there anything else to do here?
-                }
-                setLocationValues(selected);
-            }
-        });
-        addLocation.setCellIcon (baseUrl + MESSAGES.markerGreen());
-
-        ListGridField ldescr = new ListGridField("description",
-                MESSAGES.description());
-        ldescr.setType(ListGridFieldType.TEXT);
-        ldescr.setWidth("*");
-        ListGridField lside = new ListGridField("riverside",
-                MESSAGES.riverside());
-        lside.setType(ListGridFieldType.TEXT);
-        lside.setWidth("10%");
-
-        ListGridField loc = new ListGridField("from", MESSAGES.location());
-        loc.setCellFormatter(new CellFormatter() {
-            public String format(
-                Object value,
-                ListGridRecord record,
-                int rowNum, int colNum) {
-                    if (value == null) return null;
-                    try {
-                        NumberFormat nf;
-                        double v = Double.parseDouble((String)value);
-                        nf = NumberFormat.getFormat("###0.00##");
-                        return nf.format(v);
-                    }
-                    catch (Exception e) {
-                        return value.toString();
-                    }
-                }
-            }
-        );
-        loc.setType(ListGridFieldType.FLOAT);
-
-        loc.setWidth("10%");
-
-        ListGridField bottom =
-            new ListGridField("bottom", MESSAGES.bottom_edge());
-        bottom.setType(ListGridFieldType.TEXT);
-        bottom.setWidth("10%");
-
-        ListGridField top =
-            new ListGridField("top", MESSAGES.top_edge());
-        top.setType(ListGridFieldType.TEXT);
-        top.setWidth("10%");
-
-        locationTable.setFields(
-            addLocation, ldescr, loc, lside, bottom, top);
-    }
-
-
-    public Canvas createOld(DataList dataList) {
-        List<Data> items = dataList.getAll();
-        Data dLocation = getData(items, "ld_locations");
-        DataItem[] loc = dLocation.getItems();
-
-        HLayout layout = new HLayout();
-        layout.setWidth("400px");
-
-        Label   label  = new Label(dataList.getLabel());
-        label.setWidth("200px");
-
-        Canvas back = getBackButton(dataList.getState());
-
-        Label selected = new Label(loc[0].getLabel());
-        selected.setWidth("130px");
-
-        layout.addMember(label);
-        layout.addMember(selected);
-        layout.addMember(back);
-
-        return layout;
-    }
-
-
-    /**
-     * This method reads the default values defined in the DataItems of the Data
-     * objects in <i>list</i>.
-     *
-     * @param list The DataList container that stores the Data objects.
-     */
-    protected void initDefaults(DataList list) {
-        Data data = list.get(0);
-
-        if (data == null) {
-            return;
-        }
-
-        DataItem[] items = data.getItems();
-        DataItem   iMin  = getDataItem(items, "min");
-        DataItem   iMax  = getDataItem(items, "max");
-
-        try {
-            min = Double.parseDouble(iMin.getStringValue());
-            max = Double.parseDouble(iMax.getStringValue());
-        }
-        catch (NumberFormatException nfe) {
-            SC.warn(MESSAGES.error_read_minmax_values());
-            min = -Double.MAX_VALUE;
-            max = Double.MAX_VALUE;
-        }
-
-        DataItem def   = data.getDefault();
-        String   value = def.getStringValue();
-
-        try {
-            double d = Double.parseDouble(value);
-            setLocationValues(new double[] { d } );
-        }
-        catch (NumberFormatException nfe) {
-            // could not parse, dont know what to do else
-        }
-    }
-
-
-    /**
-     * This method greps the Data with name <i>name</i> from the list and
-     * returns it.
-     *
-     * @param items A list of Data.
-     * @param name The name of the Data that we are searching for.
-     *
-     * @return the Data with the name <i>name</i>.
-     */
-    protected Data getData(List<Data> data, String name) {
-        for (Data d: data) {
-            if (name.equals(d.getLabel())) {
-                return d;
-            }
-        }
-
-        return null;
-    }
-
-
-    protected Canvas createWidget(DataList data) {
-        VLayout layout       = new VLayout();
-        container            = new HLayout();
-
-        // the initial view will display the location input mode
-        locationPanel = new DoubleArrayPanel(
-                MESSAGES.unitLocation(),
-                getLocationValues(),
-                new BlurHandler(){public void onBlur(BlurEvent be) {}});
-
-        locationTable.setAutoFetchData(true);
-
-        container.addMember(locationPanel);
-
-        layout.addMember(container);
-
-        container.setMembersMargin(30);
-
-        TableFilter filter = new TableFilter();
-        filter.setHeight("30px");
-        filter.addFilterHandler(this);
-
-        helperContainer.addMember(locationTable);
-        helperContainer.addMember(filter);
-        createInputPanel();
-        return layout;
-    }
-
-    public void onFilterCriteriaChanged(StringFilterEvent event) {
-        String search = event.getFilter();
-
-        if (search != null && search.length() > 0) {
-            Criteria c = new Criteria("description", search);
-            locationTable.filterData(c);
-        }
-        else {
-            // TODO Remove filter
-        }
-    }
-
+    /** Overridden to restrict to one entered value. */
     @Override
     public List<String> validate() {
         List<String> errors = new ArrayList<String>();
@@ -334,7 +34,7 @@
         saveLocationValues(locationPanel);
 
         if (!locationPanel.validateForm()) {
-            errors.add(MESSAGES.wrongFormat());
+            errors.add(MSG.wrongFormat());
             return errors;
         }
 
@@ -342,13 +42,14 @@
         double[] good   = new double[values.length];
         int      idx    = 0;
 
+        // We want just one value to be allowed.
         if (values.length > 1) {
-            errors.add(MESSAGES.too_many_values());
+            errors.add(MSG.too_many_values());
         }
 
         for (double value: values) {
             if (value < min || value > max) {
-                String tmp = MESSAGES.error_validate_range();
+                String tmp = MSG.error_validate_range();
                 tmp = tmp.replace("$1", nf.format(value));
                 tmp = tmp.replace("$2", nf.format(min));
                 tmp = tmp.replace("$3", nf.format(max));
@@ -381,97 +82,41 @@
         saveLocationValues(locationPanel);
         double[] values = getLocationValues();
         Data[] data = new Data[values.length+1];
-        DataItem item = new DefaultDataItem();
+
         for (int i = 0; i < values.length; i++) {
-            item = new DefaultDataItem(
-                "ld_locations",
-                "ld_locations",
+            data[i] = createDataArray(getDataItemName(),
                 Double.valueOf(values[i]).toString());
-            data[i] = new DefaultData(
-                "ld_locations",
-                null,
-                null,
-                new DataItem[] {item});
         }
-        data[values.length] = new DefaultData(
-            "ld_mode",
-            null, null,
-            new DataItem[] {
-                new DefaultDataItem("ld_mode", "ld_mode", "locations") });
+
+        data[values.length] = createDataArray("ld_mode", "locations");
 
         return data;
     }
 
 
-
-
+    /* This is a copy of super.super.onRecordClick. Straighten out
+       this weird family. */
     /**
-     * Validates and stores all values entered in the location mode.
-     *
-     * @param p The DoubleArrayPanel.
+     * Callback when an item from the input helper was clicked.
+     * Set the respective km-value in the location value field.
+     * @param e event passed.
      */
-    protected void saveLocationValues(DoubleArrayPanel p) {
-        FormItem[] formItems = p.getFields();
-
-        for (FormItem item: formItems) {
-            if (item.getFieldName().equals(DoubleArrayPanel.FIELD_NAME)) {
-                saveLocationValue(p, item);
-            }
+    public void onRecordClick (RecordClickEvent e) {
+        Record record = e.getRecord();
+        double[] selected = new double[1];
+        try {
+            selected[0] =
+                Double.parseDouble(record.getAttribute("from"));
         }
-    }
-
-
-    /**
-     * Validates and stores a value entered in the location mode.
-     *
-     * @param p The DoubleArrayPanel.
-     * @param item The item that needs to be validated.
-     */
-    protected void saveLocationValue(DoubleArrayPanel p, FormItem item) {
-        if (p.validateForm(item)) {
-            setLocationValues(p.getInputValues(item));
+        catch(NumberFormatException nfe) {
+            // Is there anything else to do here?
         }
+        setLocationValues(selected);
     }
 
 
-    protected void createInputPanel() {
-        Config config = Config.getInstance();
-        String url    = config.getServerUrl();
-        String locale = config.getLocale ();
-        String river  = "";
-
-        ArtifactDescription adescr = artifact.getArtifactDescription();
-        DataList[] data = adescr.getOldData();
-
-        if (data != null && data.length > 0) {
-            for (int i = 0; i < data.length; i++) {
-                DataList dl = data[i];
-                if (dl.getState().equals("state.winfo.river")) {
-                    for (int j = 0; j < dl.size(); j++) {
-                        Data d = dl.get(j);
-                        DataItem[] di = d.getItems();
-                        if (di != null && di.length == 1) {
-                           river = d.getItems()[0].getStringValue();
-                           break;
-                        }
-                    }
-                }
-            }
-        }
-
-        locationTable.setDataSource(new DistanceInfoDataSource(
-            url, river, "locations"));
-    }
-
-
-    protected double[] getLocationValues() {
-        return values;
-    }
-
-
-    protected void setLocationValues(double[] values) {
-        this.values = values;
-        locationPanel.setValues(values);
+    protected String getLabelString() {
+        return MSG.single_location();
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/StyleEditorWindow.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,43 +1,52 @@
 package de.intevation.flys.client.client.ui;
 
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.rpc.AsyncCallback;
-
-import com.smartgwt.client.widgets.Window;
-import com.smartgwt.client.widgets.layout.VLayout;
-import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.Button;
-import com.smartgwt.client.widgets.form.DynamicForm;
-import com.smartgwt.client.widgets.form.fields.FormItem;
-import com.smartgwt.client.widgets.form.fields.CheckboxItem;
-import com.smartgwt.client.widgets.form.fields.ColorPickerItem;
-import com.smartgwt.client.widgets.form.fields.SelectItem;
-import com.smartgwt.client.widgets.form.fields.StaticTextItem;
-
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Window;
 import com.smartgwt.client.widgets.events.ClickEvent;
 import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.form.DynamicForm;
 import com.smartgwt.client.widgets.form.events.ItemChangedEvent;
 import com.smartgwt.client.widgets.form.events.ItemChangedHandler;
-import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.widgets.form.fields.CheckboxItem;
+import com.smartgwt.client.widgets.form.fields.ColorPickerItem;
+import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
+import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
+import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
+import com.smartgwt.client.widgets.form.validator.IsFloatValidator;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
 
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.services.CollectionItemAttributeService;
+import de.intevation.flys.client.client.services.CollectionItemAttributeServiceAsync;
+import de.intevation.flys.client.client.services.ThemeListingService;
+import de.intevation.flys.client.client.services.ThemeListingServiceAsync;
+import de.intevation.flys.client.client.utils.DoubleValidator;
 import de.intevation.flys.client.shared.model.Collection;
 import de.intevation.flys.client.shared.model.CollectionItemAttribute;
+import de.intevation.flys.client.shared.model.FacetRecord;
 import de.intevation.flys.client.shared.model.Style;
 import de.intevation.flys.client.shared.model.StyleSetting;
-import de.intevation.flys.client.shared.model.FacetRecord;
 import de.intevation.flys.client.shared.model.Theme;
 
-import de.intevation.flys.client.client.services.CollectionItemAttributeServiceAsync;
-import de.intevation.flys.client.client.services.CollectionItemAttributeService;
-import de.intevation.flys.client.client.ui.ThemePanel;
-
-import de.intevation.flys.client.client.FLYSConstants;
-import de.intevation.flys.client.client.Config;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
 
 /**
+ * Editor window for styles.
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
 public class StyleEditorWindow
@@ -62,10 +71,27 @@
     /** Main layout. */
     protected VLayout layout;
 
+    /** The form that contains all the input widgets. */
+    protected DynamicForm df;
+
+    protected VLayout properties;
+
+    protected Canvas container;
+
+    protected Map<String, Style> styleGroups;
+
+    protected Style current;
+
+    protected SelectItem styleChooser;
+
     /** The service used to set collection item attributes. */
     protected CollectionItemAttributeServiceAsync itemAttributeService =
         GWT.create(CollectionItemAttributeService.class);
 
+    /** The service used to request a list of themes. */
+    protected ThemeListingServiceAsync themeListingService =
+        GWT.create(ThemeListingService.class);
+
 
     /**
      * Setup editor dialog.
@@ -82,7 +108,39 @@
         this.attributes = attributes;
         this.facet = facet;
         this.layout = new VLayout();
+        this.properties = new VLayout();
+        this.container = new Canvas();
+        this.styleChooser = new SelectItem("style", "Style");
 
+        styleChooser.setTitleStyle("color:#000;");
+        styleChooser.setTitleAlign(Alignment.LEFT);
+        styleChooser.setValue("aktuell");
+        styleChooser.addChangedHandler(new ChangedHandler() {
+            @Override
+            public void onChanged(ChangedEvent ce) {
+                String value = ce.getValue().toString();
+                Style s = null;
+                if (value.equals("aktuell")) {
+                    s = current;
+                }
+                else if (styleGroups.containsKey(value)) {
+                    s = styleGroups.get(value);
+                }
+
+                if (s != null) {
+                    setNewStyle(s);
+                    properties.removeMember(container);
+                    container = createPropertyGrid(s);
+                    properties.addMember(container);
+                }
+            }
+        });
+
+        DynamicForm f = new DynamicForm();
+        f.setFields(styleChooser);
+        f.setColWidths("40%", "60%");
+
+        layout.addMember(f);
         init();
         initPanels();
     }
@@ -99,6 +157,47 @@
 
         layout.setWidth100();
         layout.setHeight100();
+
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
+
+        Theme theme = facet.getTheme();
+        Style style = attributes.getStyle(theme.getFacet(), theme.getIndex());
+        if(style == null) {
+            GWT.log("StyleEditorWindow.init(): style == null");
+            return;
+        }
+        String name = style.getName();
+        this.current = style;
+
+        themeListingService.list(
+            locale,
+            name,
+            new AsyncCallback<Map<String, Style> >() {
+                @Override
+                public void onFailure(Throwable caught) {
+                    GWT.log("No listloaded.");
+                }
+                @Override
+                public void onSuccess(Map<String, Style> list) {
+                    GWT.log("Successfully loaded list.");
+
+                    styleGroups = list;
+                    Set<String> keys = list.keySet();
+                    LinkedHashMap<String, String> valueMap =
+                        new LinkedHashMap<String, String>();
+                    valueMap.put("aktuell", "Aktuell");
+                    Iterator<String> iter = keys.iterator();
+                    while (iter.hasNext()) {
+                        String s = iter.next().toString();
+                        Style tmp = styleGroups.get(s);
+                        tmp.setFacet(current.getFacet());
+                        tmp.setIndex(current.getIndex());
+                        valueMap.put(s, s);
+                    }
+                    styleChooser.setValueMap(valueMap);
+                }
+            });
     }
 
 
@@ -111,8 +210,13 @@
         Button cancel = new Button(MSG.label_cancel());
         cancel.addClickHandler(this);
         accept.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent e) {
-                saveStyle();
+                // TODO Fix this, for whatever reason it doesnt work
+                // (always valid).
+                if (!df.hasErrors() && df.validate()) {
+                    saveStyle();
+                }
             }
         });
 
@@ -121,12 +225,15 @@
         buttons.setAlign(Alignment.CENTER);
         buttons.setHeight(30);
 
-        VLayout propGrid = createPropertyGrid();
+        Theme theme = facet.getTheme();
+        Style style = attributes.getStyle(theme.getFacet(), theme.getIndex());
 
-        layout.addMember(propGrid);
+        container = createPropertyGrid(style);
+        properties.addMember(container);
+        layout.addMember(properties);
         layout.addMember(buttons);
         addItem(layout);
-        setWidth(300);
+        setWidth(400);
         setHeight(410);
     }
 
@@ -144,6 +251,7 @@
      * this method is called when the user aborts theming.
      * @param event The event.
      */
+    @Override
     public void onClick(ClickEvent event) {
         this.hide();
     }
@@ -153,21 +261,27 @@
      * This method creates the property grid for available styling attributes.
      * @return The layout containing the UI elements.
      */
-    protected VLayout createPropertyGrid() {
-        VLayout properties = new VLayout();
-
-        Theme theme = facet.getTheme();
-        Style style = attributes.getStyle(theme.getFacet(), theme.getIndex());
+    protected VLayout createPropertyGrid(Style style) {
+        VLayout vl = new VLayout();
 
         StaticTextItem name = new StaticTextItem("name", "Name");
         name.setValue(facet.getName());
-        name.setTitleStyle("color:#000; width:120px");
+        name.setTitleStyle("color:#000;");
         name.setTitleAlign(Alignment.LEFT);
         name.setDisabled(true);
         name.setShowDisabled(false);
+
         DynamicForm form = new DynamicForm();
         form.setFields(name);
-        properties.addMember(form);
+        form.setColWidths("40%", "60%");
+
+
+        vl.addMember(form);
+
+        if (style == null) {
+            SC.warn("No style found.");
+            return vl;
+        }
 
         // Done via array to keep the order.
         String[] sets = {"showlines",
@@ -178,15 +292,27 @@
                          "font",
                          "textstyle",
                          "textsize",
+                         "pointcolor",
+                         "pointsize",
                          "textcolor",
+                         "backgroundcolor",
+                         "showbackground",
+                         "showlinelabel",
+                         "labelfontface",
+                         "labelfontcolor",
+                         "labelfontsize",
+                         "labelfontstyle",
                          "textorientation",
-                         "backgroundcolor",
-                         "showbackground"};
+                         "labelshowbg",
+                         "labelbgcolor",
+                         "showpointlabel",
+                         "bandwidthcolor",
+                         "bandwidth"};
 
         for (String settingName: sets) {
             StyleSetting set = style.getSetting(settingName);
 
-            if (set == null) {
+            if (set == null || set.isHidden()) {
                 continue;
             }
 
@@ -195,7 +321,7 @@
                 set.getName(),
                 set.getType(),
                 set.getDefaultValue());
-            properties.addMember(property);
+            vl.addMember(property);
         }
 
         // Add settings not in whitelist above.
@@ -210,10 +336,10 @@
                 set.getName(),
                 set.getType(),
                 set.getDefaultValue());
-            properties.addMember(property);
+            vl.addMember(property);
         }
 
-        return properties;
+        return vl;
     }
 
 
@@ -232,15 +358,17 @@
         String type,
         String value)
     {
-        DynamicForm df = new DynamicForm();
+        df = new DynamicForm();
+        df.setColWidths("40%", "60%");
 
         FormItem f;
         if(type.equals("int")) {
             f = new SelectItem(name, MSG.getString(name));
             if (name.equals("linesize")) {
                 f = createLineSizeUI(f);
+                f.setValue(value);
             }
-            else if (name.equals("textsize")) {
+            else if (name.equals("labelfontsize")) {
                 LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String>();
                 valueMap.put("3", "3");
                 valueMap.put("5", "5");
@@ -251,15 +379,52 @@
                 valueMap.put("18", "18");
                 valueMap.put("24", "24");
                 f.setValueMap(valueMap);
+                f.setValue(value);
             }
-            f.setValue(value);
+            else if (name.equals("bandwidth")) {
+                LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String>();
+                valueMap.put("0", "0");
+                valueMap.put("1", "1");
+                valueMap.put("2", "2");
+                valueMap.put("3", "3");
+                valueMap.put("4", "4");
+                valueMap.put("5", "5");
+                valueMap.put("6", "6");
+                valueMap.put("7", "7");
+                valueMap.put("8", "8");
+                valueMap.put("9", "9");
+                valueMap.put("10", "10");
+                valueMap.put("11", "11");
+                f.setValueMap(valueMap);
+                f.setValue(value);
+            }
+            else if (name.equals("pointsize")) {
+                LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String>();
+                valueMap.put("1", "1");
+                valueMap.put("2", "2");
+                valueMap.put("3", "3");
+                valueMap.put("4", "4");
+                valueMap.put("5", "5");
+                valueMap.put("6", "6");
+                valueMap.put("7", "7");
+                f.setValueMap(valueMap);
+                f.setValue(value);
+            }
+            else if (name.equals("transparency")) {
+                LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String>();
+                for (int n = 10; n < 100; n += 10) {
+                    valueMap.put(Integer.toString(n), n + "%");
+                }
+                f.setValueMap(valueMap);
+                f.setValue(value);
+            }
         }
         else if (type.equals("boolean")) {
             if(name.equals("textorientation")) {
                 f = new SelectItem(name, MSG.getString(name));
                 LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String>();
-                valueMap.put("true", "horizontal");
-                valueMap.put("false", "vertical");
+                valueMap.put("true", MSG.getString("horizontal"));
+                valueMap.put("false", MSG.getString("vertical"));
                 f.setValueMap(valueMap);
                 f.setValue(value);
             }
@@ -280,6 +445,28 @@
             c.setValue(rgbToHtml(value));
             f = c;
         }
+        else if (type.equals("double")) {
+            f = new FormItem(name);
+            IsFloatValidator fpv = new IsFloatValidator();
+
+            f.setValidators(fpv);
+            f.setValidateOnChange(true);
+            f.setTitle(MSG.getString(name));
+            f.addBlurHandler(new BlurHandler() {
+                @Override
+                public void onBlur(BlurEvent e) {
+                     DoubleValidator validator = new DoubleValidator();
+                     Map<?, ?> errors = e.getForm().getErrors();
+                     if(validator.validate(e.getItem(), errors)) {
+                         e.getForm().setErrors(errors, true);
+                     }
+                     else {
+                         e.getForm().setErrors(errors, true);
+                     }
+                }
+            });
+            f.setValue(value);
+        }
         else if (type.equals("Dash")) {
             f = new SelectItem(name, MSG.getString(name));
             LinkedHashMap<String, String> valueIcons = new LinkedHashMap<String, String>();
@@ -321,13 +508,19 @@
             f.setValueMap(valueMap);
             f.setValue(value);
         }
+        else if (type.equals("Symbol")) {
+            //create an empty element as long as this property can not be
+            //changed.
+            f = new StaticTextItem("");
+        }
         else {
             f = new FormItem();
         }
-        f.setTitleStyle("color:#000; width:120px");
+        f.setTitleStyle("color:#000;");
         f.setTitleAlign(Alignment.LEFT);
         df.setFields(f);
         df.addItemChangedHandler(new ItemChangedHandler() {
+            @Override
             public void onItemChanged(ItemChangedEvent e) {
                 String name = e.getItem().getName();
                 String newValue = e.getNewValue().toString();
@@ -430,9 +623,11 @@
             locale,
             attributes,
             new AsyncCallback<Void>() {
+                @Override
                 public void onFailure (Throwable caught) {
                     GWT.log("Could not set Collection item attributes.");
                 }
+                @Override
                 public void onSuccess(Void v) {
                     GWT.log("Successfully saved collection item attributes.");
                     panel.requestRedraw();
@@ -453,10 +648,21 @@
         Theme t = facet.getTheme();
         Style s = attributes.getStyle(t.getFacet(), t.getIndex());
         StyleSetting set = s.getSetting(name);
-        if(name.indexOf("color") != -1) {
+        String type = set.getType();
+
+        if(name.indexOf("color") != -1
+           || (type != null && type.toLowerCase().indexOf("color") > -1)) {
             value = htmlToRgb(value);
         }
         set.setDefaultValue(value);
     }
+
+
+    protected final void setNewStyle(Style style) {
+        Theme t = facet.getTheme();
+        Style s = attributes.getStyle(t.getFacet(), t.getIndex());
+        attributes.removeStyle(s.getName());
+        attributes.appendStyle(style);
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/TableFilter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/TableFilter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -40,6 +40,7 @@
 
         searchfield.addChangedHandler(this);
         searchfield.addKeyUpHandler(this);
+        searchfield.setWidth(120);
 
         DynamicForm form = new DynamicForm();
         form.setFields(searchfield);
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/ThemePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -43,8 +43,6 @@
 import de.intevation.flys.client.client.services.CollectionItemAttributeService;
 import de.intevation.flys.client.client.services.CollectionItemAttributeServiceAsync;
 
-import de.intevation.flys.client.client.ui.ThemePanel;
-
 /**
  * ThemePanel on the left in CollectionView.
  * Contains control widgets for "themes", which are plotted in a diagram (chart).
@@ -74,7 +72,6 @@
     /** List of ChartShallRedrawHandler. */
     protected List<RedrawRequestHandler> redrawRequestHandlers;
 
-    protected Collection collection;
     protected OutputMode mode;
 
     protected ThemeNavigationPanel navigation;
@@ -89,11 +86,9 @@
      * @param collection Collection for which to show themes.
      */
     public ThemePanel(
-        Collection collection,
         OutputMode mode,
         CollectionView view
     ) {
-        this.collection = collection;
         this.mode       = mode;
         this.list       = createGrid();
         this.view       = view;
@@ -126,6 +121,8 @@
         this.outHandlers = new ArrayList<OutputParameterChangeHandler>();
         this.navigation  = new ThemeNavigationPanel();
         this.navigation.addOnMoveHandler(this);
+
+        this.setShowResizeBar(true);
     }
 
 
@@ -139,19 +136,26 @@
      * @param collection The new collection object.
      */
     protected void setCollection(Collection collection) {
-        this.collection = collection;
+        // Set collection of view, but do not trigger event shooting.
+        this.view.setCollection(collection, true);
 
         updateGrid();
     }
 
 
+    /** Get Collection. */
+    public Collection getCollection() {
+        return view.getCollection();
+    }
+
+
     /**
      * Returns the ThemeList of the current collection and output mode.
      *
      * @return the current ThemeList.
      */
     public ThemeList getThemeList() {
-        return collection.getThemeList(mode.getName());
+        return getCollection().getThemeList(mode.getName());
     }
 
 
@@ -184,7 +188,7 @@
      */
     final public void requestRedraw() {
         for (RedrawRequestHandler handler: redrawRequestHandlers) {
-            handler.onRedrawRequest(new RedrawRequestEvent(Type.RESET));
+            handler.onRedrawRequest(new RedrawRequestEvent(Type.DEFAULT));
         }
     }
 
@@ -202,6 +206,7 @@
     }
 
 
+    /** Registers the CollectionView associated to this ThemePanel. */
     public void setCollectionView(CollectionView view) {
         this.view = view;
     }
@@ -230,7 +235,15 @@
         for (int i = 1; i <= count; i++) {
             Theme theme = themeList.getThemeAt(i);
 
-            if (theme == null || theme.getVisible() == 0) {
+            if (theme == null) {
+                continue;
+            }
+
+            if (theme.getFacet().equals("empty.facet")) {
+                theme.setVisible(0);
+            }
+
+            if (theme.getVisible() == 0) {
                 continue;
             }
 
@@ -284,7 +297,7 @@
         // Don't forget to enable the panel after the request has finished!
         disable();
 
-        updater.update(collection, loc, new AsyncCallback<Collection>() {
+        updater.update(getCollection(), loc, new AsyncCallback<Collection>() {
             public void onFailure(Throwable caught) {
                 GWT.log("Could not update collection attributes.");
                 SC.warn(MSG.getString(caught.getMessage()));
@@ -307,6 +320,7 @@
      */
     protected ListGrid createGrid() {
         ListGrid grid = createNewGrid();
+        grid.setLeaveScrollbarGap(false);
 
         return grid;
     }
@@ -420,6 +434,19 @@
     }
 
 
+    /** Remove given themes (not asking for confirmation). */
+    protected void removeThemes(final ListGridRecord[] records) {
+        for (ListGridRecord record: records) {
+            FacetRecord facet = (FacetRecord) record;
+            Theme theme = facet.getTheme();
+            theme.setVisible(0);
+            theme.setActive(0);
+            updateCollection();
+        }
+    }
+
+
+    /** Create menu item for removing theme(s). Will ask for confirmation. */
     protected MenuItem createRemoveItem(final ListGridRecord[] records) {
         MenuItem remove = new MenuItem(MSG.removeTheme());
 
@@ -429,14 +456,7 @@
                     @Override
                     public void execute(Boolean value) {
                         if (value) {
-                            for (ListGridRecord record: records) {
-                                FacetRecord facet = (FacetRecord) record;
-                                Theme theme = facet.getTheme();
-                                theme.setVisible(0);
-                                theme.setActive(0);
-
-                                updateCollection();
-                            }
+                            removeThemes(records);
                         }
                     }
                 });
@@ -602,7 +622,7 @@
         String artifact = record.getTheme().getArtifact();
 
         itemAttributeService.getCollectionItemAttribute(
-            this.collection,
+            this.getCollection(),
             artifact,
             locale,
             new AsyncCallback<CollectionItemAttribute>() {
@@ -622,12 +642,18 @@
         FacetRecord record)
     {
         StyleEditorWindow win = new StyleEditorWindow(
-            collection,
+            getCollection(),
             cia,
             record);
         win.setThemePanel(this);
         win.centerInPage();
         win.show();
     }
+
+
+    /** Get OutputMode of this Panel. */
+    public OutputMode getMode() {
+        return this.mode;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/Toolbar.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/Toolbar.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,7 +2,8 @@
 
 import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.events.CloseClickHandler;
-import com.smartgwt.client.widgets.events.CloseClientEvent;
+import com.smartgwt.client.widgets.events.CloseClickEvent;
+import com.smartgwt.client.types.Overflow;
 
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.shared.model.User;
@@ -17,6 +18,7 @@
 
     public Toolbar(OutputTab outputTab) {
         super();
+        setOverflow(Overflow.AUTO);
 
         this.outputTab = outputTab;
     }
@@ -47,7 +49,7 @@
             artifact, user, outs, outputTab.getCollectionView());
         dc.addRedrawRequestHandler(handler);
         dc.addCloseClickHandler(new CloseClickHandler() {
-            public void onCloseClick(CloseClientEvent event) {
+            public void onCloseClick(CloseClickEvent event) {
                 dc.destroy();
             }
         });
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/UIProvider.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/UIProvider.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,6 +5,7 @@
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.layout.VLayout;
 
+import de.intevation.flys.client.shared.model.Data;
 import de.intevation.flys.client.shared.model.DataList;
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.shared.model.Collection;
@@ -39,6 +40,9 @@
     public Canvas createOld(DataList dataList);
 
 
+    public Canvas createHelpLink(DataList dataList, Data data);
+
+
     /**
      * This method injects a container that is used to position helper widgets.
      *
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/UIProviderFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,12 +1,30 @@
 package de.intevation.flys.client.client.ui;
 
+import de.intevation.flys.client.client.ui.fixation.FixEventSelect;
+import de.intevation.flys.client.client.ui.fixation.FixFunctionSelect;
+import de.intevation.flys.client.client.ui.fixation.FixGaugeSelectPanel;
+import de.intevation.flys.client.client.ui.fixation.FixLocationPanel;
+import de.intevation.flys.client.client.ui.fixation.FixMultiPeriodPanel;
+import de.intevation.flys.client.client.ui.fixation.FixPeriodPanel;
+import de.intevation.flys.client.client.ui.fixation.FixQSelectPanel;
+import de.intevation.flys.client.client.ui.sq.SQPeriodPanel;
+import de.intevation.flys.client.client.ui.minfo.BedHeightsDatacagePanel;
+import de.intevation.flys.client.client.ui.minfo.BedMultiPeriodPanel;
+import de.intevation.flys.client.client.ui.minfo.CheckboxPanel;
 import de.intevation.flys.client.shared.model.User;
 
+/**
+ * Depending on the provider the state declared, return a UIProvider.
+ *
+ * A UIProvider provides widgets and input helpers to guide input to an
+ * artifacts state.
+ */
 public class UIProviderFactory {
 
     private UIProviderFactory() {
     }
 
+    /** @param uiProvider uiprovider demanded for by state. */
     public static UIProvider getProvider(String uiProvider, User user) {
         if (uiProvider == null || uiProvider.equals("")) {
             return new SelectProvider();
@@ -20,6 +38,9 @@
         else if (uiProvider.equals("location_panel")) {
             return new SingleLocationPanel();
         }
+        else if (uiProvider.equals("multi_location_panel")) {
+            return new MultipleLocationPanel();
+        }
         else if (uiProvider.equals("distance_panel")) {
             return new DistancePanel();
         }
@@ -62,8 +83,74 @@
         else if (uiProvider.equals("map_digitize")) {
             return new DigitizePanel();
         }
+        else if (uiProvider.equals("timerange")) {
+            return new IntegerRangePanel();
+        }
+        else if (uiProvider.equals("wq_simple_array")) {
+            return new WQSimpleArrayPanel();
+        }
+        else if (uiProvider.equals("gaugetimerange")) {
+            return new GaugeTimeRangePanel();
+        }
+        else if (uiProvider.equals("fix.location_panel")) {
+            return new FixLocationPanel();
+        }
+        else if (uiProvider.equals("fix.period_panel")) {
+            return new FixPeriodPanel();
+        }
+        else if (uiProvider.equals("fix.period_ref_panel")) {
+            return new FixPeriodPanel("ref_start", "ref_end");
+        }
+        else if (uiProvider.equals("fix.period_ana_panel")) {
+            return new FixMultiPeriodPanel();
+        }
+        else if (uiProvider.equals("fix.qselect_panel")) {
+            return new FixQSelectPanel();
+        }
+        else if (uiProvider.equals("fix.gaugeselect_panel")) {
+            return new FixGaugeSelectPanel();
+        }
+        else if (uiProvider.equals("fix.event_panel")) {
+            return new FixEventSelect();
+        }
+        else if (uiProvider.equals("fix.preprocessing_panel")) {
+            return new BooleanPanel();
+        }
+        else if (uiProvider.equals("fix.functionselect")) {
+            return new FixFunctionSelect();
+        }
+        else if (uiProvider.equals("period_select")) {
+            return new PeriodPanel();
+        }
+        else if (uiProvider.equals("periods_select")) {
+            return new MultiPeriodPanel();
+        }
+        else if (uiProvider.equals("sq.period.select")) {
+            return new SQPeriodPanel();
+        }
+        else if (uiProvider.equals("outliers_input")) {
+            return new DoubleInputPanel();
+        }
+        else if (uiProvider.equals("parameter-matrix")) {
+            return new ParameterMatrixPanel();
+        }
+        else if (uiProvider.equals("minfo.bed.year_epoch")) {
+            return new RadioPanel();
+        }
+        else if (uiProvider.equals("bedquality_periods_select")) {
+            return new BedMultiPeriodPanel();
+        }
+        else if (uiProvider.equals("bedheights_twin_panel")) {
+            return new BedHeightsDatacagePanel(user);
+        }
+        else if (uiProvider.equals("minfo.bed.char_diameter")) {
+            return new CheckboxPanel();
+        }
         else {
+            //GWT.log("Picked default provider.");
             return new SelectProvider();
         }
     }
 }
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/WQAdaptedInputPanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/WQAdaptedInputPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -9,6 +9,7 @@
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.user.client.rpc.AsyncCallback;
 
 import com.smartgwt.client.types.TitleOrientation;
 import com.smartgwt.client.types.VerticalAlignment;
@@ -23,6 +24,8 @@
 import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
 import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.layout.VLayout;
+import com.smartgwt.client.widgets.tab.TabSet;
+import com.smartgwt.client.widgets.tab.Tab;
 
 import de.intevation.flys.client.shared.model.Data;
 import de.intevation.flys.client.shared.model.DataItem;
@@ -30,8 +33,17 @@
 import de.intevation.flys.client.shared.model.DefaultData;
 import de.intevation.flys.client.shared.model.DefaultDataItem;
 import de.intevation.flys.client.shared.model.WQDataItem;
+import de.intevation.flys.client.shared.model.WQInfoObject;
+import de.intevation.flys.client.shared.model.WQInfoRecord;
+import de.intevation.flys.client.shared.model.ArtifactDescription;
+
 
 import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.services.WQInfoService;
+import de.intevation.flys.client.client.services.WQInfoServiceAsync;
+import de.intevation.flys.client.client.ui.wq.WTable;
+import de.intevation.flys.client.client.ui.wq.QDTable;
 
 
 /**
@@ -44,7 +56,7 @@
 extends      AbstractUIProvider
 implements   ChangeHandler, BlurHandler
 {
-    public static final String FIELD_WQ_MODE = "wq_mode";
+    public static final String FIELD_WQ_MODE = "wq_isq";
     public static final String FIELD_WQ_W    = "W";
     public static final String FIELD_WQ_Q    = "Q";
 
@@ -56,6 +68,17 @@
 
     public static final int ROW_HEIGHT = 20;
 
+    /** The constant field name for choosing w or q mode.*/
+    public static final String FIELD_WQ = "wq";
+
+    /** The constant field name for choosing single values or range.*/
+    public static final String FIELD_MODE = "mode";
+
+    /** The constant field value for range input mode.*/
+    public static final String FIELD_MODE_RANGE = "range";
+
+    protected WQInfoServiceAsync wqInfoService =
+        GWT.create(WQInfoService.class);
 
     /** The message class that provides i18n strings.*/
     protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
@@ -72,16 +95,25 @@
     /** The RadioGroupItem that determines the w/q input mode.*/
     protected DynamicForm modes;
 
+    protected QDTable qdTable;
+
+    protected WTable wTable;
+
+    protected TabSet tabs;
 
 
     public WQAdaptedInputPanel() {
         wqranges = new HashMap<String, DoubleArrayPanel>();
         qranges  = new HashMap<String, double[]>();
         wranges  = new HashMap<String, double[]>();
+        qdTable  = new QDTable();
+        wTable   = new WTable();
     }
 
 
     public Canvas create(DataList data) {
+        initHelperPanel();
+
         Canvas submit = getNextButton();
         Canvas widget = createWidget(data);
         Label  label  = new Label(MSG.wqadaptedTitle());
@@ -96,14 +128,37 @@
         layout.addMember(widget);
         layout.addMember(submit);
 
+
         return layout;
     }
 
 
+    protected void initHelperPanel() {
+        tabs = new TabSet();
+        tabs.setWidth100();
+        tabs.setHeight100();
+
+        // TODO i18n
+        Tab wTab = new Tab("W");
+        Tab qTab = new Tab("Q / D");
+
+        wTab.setPane(wTable);
+        qTab.setPane(qdTable);
+        qdTable.hideIconFields();
+
+        tabs.addTab(wTab, 0);
+        tabs.addTab(qTab, 1);
+
+        helperContainer.addMember(tabs);
+
+        fetchWQData();
+    }
+
+
     public Canvas createOld(DataList dataList) {
         List<Data> all = dataList.getAll();
         Data    wqData = getData(all, "wq_values");
-        Data    wqMode = getData(all, "wq_mode");
+        Data    wqMode = getData(all, "wq_isq");
 
         Canvas back = getBackButton(dataList.getState());
 
@@ -418,9 +473,6 @@
                 double[] mmQ = wq.getQRange();
                 double[] mmW = wq.getWRange();
 
-                GWT.log(title + " Q: " + mmQ[0] + " - " + mmQ[1]);
-                GWT.log(title + " W: " + mmW[0] + " - " + mmW[1]);
-
                 qranges.put(title, mmQ);
                 wranges.put(title, mmW);
             }
@@ -466,11 +518,24 @@
         modes = new DynamicForm();
         modes.setFields(wq);
         modes.setWidth(200);
+        wq.addChangeHandler(new ChangeHandler() {
+            public void onChange(ChangeEvent e) {
+                DynamicForm form = e.getForm();
+
+                if(form.getValueAsString(FIELD_WQ_MODE).contains("Q")) {
+                    tabs.selectTab(0);
+                }
+                else {
+                    tabs.selectTab(1);
+                }
+            }
+        });
+
 
         LinkedHashMap initial = new LinkedHashMap();
         initial.put(FIELD_WQ_MODE, FIELD_WQ_Q);
         modes.setValues(initial);
-
+        tabs.selectTab(1);
         return modes;
     }
 
@@ -499,9 +564,13 @@
 
     protected Data getWQMode() {
         String wqMode = modes.getValueAsString(FIELD_WQ_MODE);
-        DataItem item = new DefaultDataItem("wq_mode", "wq_mode", wqMode);
+        String value = "false";
+        if (wqMode.equals("Q")) {
+            value = "true";
+        }
+        DataItem item = new DefaultDataItem("wq_isq", "wq_isq", value);
         Data mode = new DefaultData(
-            "wq_mode", null, null, new DataItem[] { item });
+            "wq_isq", null, null, new DataItem[] { item });
 
         return mode;
     }
@@ -561,5 +630,88 @@
         DoubleArrayPanel dap = (DoubleArrayPanel) event.getForm();
         dap.validateForm(event.getItem());
     }
+
+
+    protected void fetchWQData() {
+        Config config    = Config.getInstance();
+        String locale    = config.getLocale ();
+
+        ArtifactDescription adescr = artifact.getArtifactDescription();
+        DataList[] data = adescr.getOldData();
+
+        double[]  mm = getMinMaxKM(data);
+        String river = getRiverName(data);
+
+        wqInfoService.getWQInfo(locale, river, mm[0], mm[0],
+            new AsyncCallback<WQInfoObject[]>() {
+                public void onFailure(Throwable caught) {
+                    GWT.log("Could not recieve wq informations.");
+                    SC.warn(caught.getMessage());
+                }
+
+                public void onSuccess(WQInfoObject[] wqi) {
+                    int num = wqi != null ? wqi.length :0;
+                    GWT.log("Recieved " + num + " wq informations.");
+
+                    if (num == 0) {
+                        return;
+                    }
+
+                    addWQInfo(wqi);
+
+                }
+            }
+        );
+    }
+
+
+    protected void addWQInfo (WQInfoObject[] wqi) {
+        for(WQInfoObject wi: wqi) {
+            WQInfoRecord rec = new WQInfoRecord(wi);
+
+            if (wi.getType().equals("W")) {
+                wTable.addData(rec);
+            }
+            else {
+                qdTable.addData(rec);
+            }
+        }
+    }
+
+
+    /**
+     * Determines the min and max kilometer value selected in a former state. A
+     * bit silly, but we need to run over each value of the "old data" to find
+     * such values because it is not available here.
+     *
+     * @param data The DataList which contains the whole data inserted for the
+     * current artifact.
+     *
+     * @return a double array with [min, max].
+     */
+    protected double[] getMinMaxKM(DataList[] data) {
+        ArtifactDescription adesc = artifact.getArtifactDescription();
+        return adesc.getKMRange();
+    }
+
+
+    /**
+     * Returns the name of the selected river.
+     *
+     * @param data The DataList with all data.
+     *
+     * @return the name of the current river.
+     */
+    protected String getRiverName(DataList[] data) {
+        ArtifactDescription adesc = artifact.getArtifactDescription();
+        return adesc.getRiver();
+    }
+
+
+    protected void updatePanels(boolean isQ) {
+
+    }
+
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/WQInputPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -60,6 +60,9 @@
         GWT.create(WQInfoService.class);
 
     /** The constant field name for choosing w or q mode.*/
+    public static final String FIELD_WQ_W_FREE = "WFREE";
+
+    /** The constant field name for choosing w or q mode.*/
     public static final String FIELD_WQ = "wq";
 
     /** The constant field value for W input mode.*/
@@ -69,7 +72,7 @@
     public static final String FIELD_WQ_Q = "Q";
 
     /** The constant field value for Q input mode.*/
-    public static final String FIELD_WQ_Q_GAUGE = "Q_GAUGE";
+    public static final String FIELD_WQ_Q_FREE = "QFREE";
 
     /** The constant field name for choosing single values or range.*/
     public static final String FIELD_MODE = "mode";
@@ -85,7 +88,6 @@
 
     public static final int WIDTH_LEFT_LOWER = 223;
 
-
     /** The container that manages the w and q panels.*/
     protected HLayout container;
 
@@ -101,6 +103,9 @@
     /** The min value for the 'from' property in the free Q-Range input mode.*/
     protected double minQFree;
 
+    /** The min value for the 'from' property in the free W-Range input mode.*/
+    protected double minWFree;
+
     /** The max values for the 'from' property in the W-Range input mode.*/
     protected double maxW;
 
@@ -110,6 +115,9 @@
     /** The max value for the 'from' property in the free Q-Range input mode.*/
     protected double maxQFree;
 
+    /** The max value for the 'from' property in the free W-Range input mode.*/
+    protected double maxWFree;
+
     /** The 'from' value entered in the range W mode.*/
     protected double fromW;
 
@@ -122,24 +130,36 @@
     /** The values entered in the single W mode.*/
     protected double[] valuesW;
 
+    /** The values entered in the single W mode.*/
+    protected double[] valuesWFree;
+
     /** The 'from' value entered in the range Q mode.*/
     protected double fromQ;
 
     /** The 'from' value entered in the range free Q mode.*/
     protected double fromQFree;
 
+    /** The 'from' value entered in the range free W mode.*/
+    protected double fromWFree;
+
     /** The 'to' value entered in the range Q mode.*/
     protected double toQ;
 
     /** The 'to' value entered in the range free Q mode.*/
     protected double toQFree;
 
+    /** The 'to' value entered in the range free W mode.*/
+    protected double toWFree;
+
     /** The 'step' value entered in the range Q mode.*/
     protected double stepQ;
 
     /** The 'step' value entered in the range free Q mode.*/
     protected double stepQFree;
 
+    /** The 'step' value entered in the range free W mode.*/
+    protected double stepWFree;
+
     /** The values entered in the single Q mode.*/
     protected double[] valuesQ;
 
@@ -155,6 +175,9 @@
     /** The input panel for free q values*/
     protected DoubleArrayPanel qFreeArrayPanel;
 
+    /** The input panel for free w values*/
+    protected DoubleArrayPanel wFreeArrayPanel;
+
     /** The input panel for w range*/
     protected DoubleRangePanel wRangePanel;
 
@@ -164,6 +187,9 @@
     /** The input panel for free q range*/
     protected DoubleRangePanel qFreeRangePanel;
 
+    /** The input panel for free w range*/
+    protected DoubleRangePanel wFreeRangePanel;
+
     protected QDTable qdTable;
 
     protected WTable wTable;
@@ -253,10 +279,10 @@
         tabs.setWidth100();
         tabs.setHeight100();
 
-        // TODO i18n
-        Tab wTab = new Tab("W");
-        Tab qTab = new Tab("Q / D");
+        Tab wTab = new Tab(MESSAGE.wq_table_w());
+        Tab qTab = new Tab(MESSAGE.wq_table_q());
 
+        qdTable.showSelect();
         wTab.setPane(wTable);
         qTab.setPane(qdTable);
 
@@ -272,9 +298,9 @@
     public Canvas createOld(DataList dataList) {
         List<Data> items = dataList.getAll();
 
-        Data dMode      = getData(items, "wq_mode");
-        Data dFree      = getData(items, "wq_free");
-        Data dSelection = getData(items, "wq_selection");
+        Data dMode      = getData(items, "wq_isq");
+        Data dFree      = getData(items, "wq_isfree");
+        Data dSelection = getData(items, "wq_isrange");
         Data dSingle    = getData(items, "wq_single");
         Data dFrom      = getData(items, "wq_from");
         Data dTo        = getData(items, "wq_to");
@@ -282,7 +308,7 @@
 
         DataItem[] mode = dMode.getItems();
         String strMode  = mode[0].getStringValue();
-        boolean wMode   = strMode.equals(FIELD_WQ_W);
+        boolean isQMode   = Boolean.valueOf(strMode);
 
         DataItem[] free = dFree.getItems();
         String  strFree = free[0].getStringValue();
@@ -297,14 +323,14 @@
         VLayout vLabel = null;
 
         DataItem[] selItem = dSelection.getItems();
-        String     sel     = selItem != null
-            ? selItem[0].getStringValue()
-            : "";
+        boolean    isRange = selItem != null
+            ? Boolean.valueOf(selItem[0].getStringValue())
+            : false;
 
-        if (sel.equals("single")) {
+        if (!isRange) {
             DataItem[] single = dSingle.getItems();
 
-            vLabel = wMode
+            vLabel = !isQMode
                 ? createWString(single[0])
                 : createQString(single[0]);
         }
@@ -313,7 +339,7 @@
             DataItem[] to   = dTo.getItems();
             DataItem[] step = dStep.getItems();
 
-            vLabel = wMode
+            vLabel = !isQMode
                 ? createWString(from[0], to[0], step[0])
                 : createQString(from[0], to[0], step[0]);
         }
@@ -321,8 +347,8 @@
         VLayout selectedLayout = new VLayout();
         String  wqMode         = null;
 
-        if (wMode) {
-            wqMode = MESSAGE.wqW();
+        if (!isQMode) {
+            wqMode = isFree ? MESSAGE.wqWFree() : MESSAGE.wqW();
         }
         else {
             wqMode = isFree ? MESSAGE.wqQ() : MESSAGE.wqQGauge();
@@ -366,6 +392,9 @@
         DataItem fQFItem = getDataItem(f.getItems(), "minQFree");
         DataItem tQFItem = getDataItem(t.getItems(), "maxQFree");
         DataItem sQFItem = getDataItem(s.getItems(), "stepQFree");
+        DataItem fWFItem = getDataItem(f.getItems(), "minWFree");
+        DataItem tWFItem = getDataItem(t.getItems(), "maxWFree");
+        DataItem sWFItem = getDataItem(s.getItems(), "stepWFree");
 
         minW  = Double.valueOf(fWItem.getStringValue());
         maxW  = Double.valueOf(tWItem.getStringValue());
@@ -379,6 +408,10 @@
         maxQFree  = Double.valueOf(tQFItem.getStringValue());
         stepQFree = Double.valueOf(sQFItem.getStringValue());
 
+        minWFree  = Double.valueOf(fWFItem.getStringValue());
+        maxWFree  = Double.valueOf(tWFItem.getStringValue());
+        stepWFree = Double.valueOf(sWFItem.getStringValue());
+
         this.fromW = minW;
         this.toW   = maxW;
         this.stepW = stepW;
@@ -390,6 +423,10 @@
         this.fromQFree = minQFree;
         this.toQFree   = maxQFree;
         this.stepQFree = stepQFree;
+
+        this.fromWFree = minWFree;
+        this.toWFree   = maxWFree;
+        this.stepWFree = stepWFree;
     }
 
 
@@ -401,43 +438,41 @@
     protected void initUserDefaults(DataList list) {
         List<Data> allData = list.getAll();
 
-        Data     m        = getData(allData, "wq_mode");
+        Data     m        = getData(allData, "wq_isq");
         DataItem modeItem = m != null ? m.getDefault() : null;
-        String   theMode  = modeItem != null
-            ? modeItem.getStringValue()
-            : "";
+        boolean isQ  = modeItem != null
+            ? Boolean.valueOf(modeItem.getStringValue())
+            : false;
 
-        Data     f        = getData(allData, "wq_free");
+        Data     f        = getData(allData, "wq_isfree");
         DataItem freeItem = f != null ? f.getDefault() : null;
-        String   theFree  = freeItem != null
-            ? freeItem.getStringValue()
-            : null;
+        boolean  isFree   = freeItem != null
+            ? Boolean.valueOf(freeItem.getStringValue())
+            : false;
 
-        Data     s            = getData(allData, "wq_selection");
+        Data     s            = getData(allData, "wq_isrange");
         DataItem sI           = s != null ? s.getDefault() : null;
-        String   theSelection = sI != null ? sI.getStringValue() : null;
+        boolean   isRange      = sI != null
+            ? Boolean.valueOf(sI.getStringValue())
+            : false;
 
-        if (theMode == null || theMode.length() == 0) {
-            return;
+        initUserSingleValues(list, isQ);
+        initUserRangeValues(list, isQ);
+
+        if (isQ) {
+            modes.setValue(FIELD_WQ, isQ);
+        }
+        else {
+            modes.setValue(FIELD_WQ, isFree ? FIELD_WQ_Q_FREE : FIELD_WQ_Q);
         }
 
-        boolean isW    = theMode.equals(FIELD_WQ_W);
-        boolean isFree = Boolean.valueOf(theFree);
-
-        initUserSingleValues(list, theMode);
-        initUserRangeValues(list, theMode);
-
-        if (isW) {
-            modes.setValue(FIELD_WQ, theMode);
+        if(isRange) {
+            modes.setValue(FIELD_MODE, FIELD_MODE_RANGE);
         }
         else {
-            modes.setValue(FIELD_WQ, isFree ? FIELD_WQ_Q : FIELD_WQ_Q_GAUGE);
+            modes.setValue(FIELD_MODE, FIELD_MODE_SINGLE);
         }
-
-        if (theSelection != null || theSelection.length() > 0) {
-            modes.setValue(FIELD_MODE, theSelection);
-            updatePanels(theMode, theSelection);
-        }
+        updatePanels(isQ, isFree, isRange);
     }
 
 
@@ -445,13 +480,15 @@
      * Initializes the single values of W or Q from DataList.
      *
      * @param list The DataList that contains the 'wq_single' object.
-     * @param theMode The W or Q mode.
+     * @param isQ W or Q mode?
      */
-    protected void initUserSingleValues(DataList list, String theMode) {
+    protected void initUserSingleValues(DataList list, boolean isQ) {
         List<Data> allData = list.getAll();
 
+
         Data     s = getData(allData, "wq_single");
         DataItem i = s != null ? s.getDefault() : null;
+        GWT.log("init values: " + i.getStringValue());
 
         if (i != null) {
             String   value = i.getStringValue();
@@ -470,7 +507,7 @@
                 }
             }
 
-            if (theMode.equals("W")) {
+            if (!isQ) {
                 setSingleW(values);
             }
             else {
@@ -484,9 +521,9 @@
      * Initializes the range values of W or Q from DataList.
      *
      * @param list The DataList that contains the 'wq_single' object.
-     * @param theMode The W or Q mode.
+     * @param isQ W or Q mode?
      */
-    protected void initUserRangeValues(DataList list, String theMode) {
+    protected void initUserRangeValues(DataList list, boolean isQ) {
         List<Data> allData = list.getAll();
 
         // init range mode values
@@ -508,7 +545,7 @@
                 double to   = Double.valueOf(tS);
                 double step = Double.valueOf(sS);
 
-                if (theMode.equals("W")) {
+                if (!isQ) {
                     setWRangeValues(from, to, step);
                 }
                 else {
@@ -643,7 +680,7 @@
     protected Canvas createModePanel() {
         RadioGroupItem wq = new RadioGroupItem(FIELD_WQ);
         wq.setShowTitle(false);
-        wq.setVertical(false);
+        wq.setVertical(true);
         wq.setWidth(WIDTH_LEFT_UPPER);
         wq.setWrap(false);
 
@@ -654,8 +691,9 @@
 
         LinkedHashMap wqValues = new LinkedHashMap();
         wqValues.put(FIELD_WQ_W, MESSAGE.wqW());
-        wqValues.put(FIELD_WQ_Q, MESSAGE.wqQ());
-        wqValues.put(FIELD_WQ_Q_GAUGE, MESSAGE.wqQGauge());
+        wqValues.put(FIELD_WQ_W_FREE, MESSAGE.wqWFree());
+        wqValues.put(FIELD_WQ_Q_FREE, MESSAGE.wqQ());
+        wqValues.put(FIELD_WQ_Q, MESSAGE.wqQGauge());
 
         LinkedHashMap modeValues = new LinkedHashMap();
         modeValues.put(FIELD_MODE_SINGLE, MESSAGE.wqSingle());
@@ -673,7 +711,7 @@
         modes.setNumCols(1);
 
         LinkedHashMap initial = new LinkedHashMap();
-        initial.put(FIELD_WQ, FIELD_WQ_Q_GAUGE);
+        initial.put(FIELD_WQ, FIELD_WQ_Q);
         initial.put(FIELD_MODE, FIELD_MODE_SINGLE);
         modes.setValues(initial);
 
@@ -693,21 +731,27 @@
 
 
     protected List<String> validateRangeValues() {
-        if (isWMode()) {
-            return validateRange(wRangePanel, minW, maxW);
+        if (isWFree()) {
+            return validateRange(wFreeRangePanel, minWFree, maxWFree);
         }
         else if (isQFree()) {
             return validateRange(qFreeRangePanel, minQFree, maxQFree);
         }
+        else if (isWMode()) {
+            return validateRange(wRangePanel, minW, maxW);
+        }
         else {
             return validateRange(qRangePanel, minQ, maxQ);
         }
     }
 
-
     protected List<String> validateSingleValues() {
-        if (isWMode()) {
+        if (isWFree()) {
+            return validateSingle(wFreeArrayPanel, minWFree, maxWFree);
+        }
+        else if (isWMode()) {
             return validateSingle(wArrayPanel, minW, maxW);
+            //return validateSingle(wArrayPanel, 0, 100000);
         }
         else if (isQFree()) {
             return validateSingle(qFreeArrayPanel, minQFree, maxQFree);
@@ -827,7 +871,10 @@
             Canvas member = container.getMember(0);
             if (member instanceof DoubleArrayPanel) {
                 DoubleArrayPanel form = (DoubleArrayPanel) member;
-                if (isWMode()) {
+                if (isWFree()) {
+                    saveSingleWFreeValues(form);
+                }
+                else if (isWMode()) {
                     saveSingleWValues(form);
                 }
                 else if (isQFree()) {
@@ -845,7 +892,10 @@
             if (member instanceof DoubleRangePanel) {
                 DoubleRangePanel form = (DoubleRangePanel) member;
 
-                if (isWMode()) {
+                if (isWFree()) {
+                    saveRangeWFreeValues(form);
+                }
+                else if (isWMode()) {
                     saveRangeWValues(form);
                 }
                 else if (isQFree()) {
@@ -872,7 +922,7 @@
 
         return new Data[] {
                 getDataMode(),
-                getQMode(),
+                getFree(),
                 getDataSelectionMode(),
                 getDataSingle(),
                 new DefaultData(
@@ -902,7 +952,7 @@
 
         return new Data[] {
                 getDataMode(),
-                getQMode(),
+                getFree(),
                 getDataSelectionMode(),
                 getDataFrom(),
                 getDataTo(),
@@ -924,16 +974,18 @@
         String wqMode = modes.getValueAsString(FIELD_WQ);
 
         String value = null;
-        if (wqMode.equals(FIELD_WQ_Q) || wqMode.equals(FIELD_WQ_Q_GAUGE)) {
-            value = FIELD_WQ_Q;
+        if (wqMode.equals(FIELD_WQ_Q_FREE) || wqMode.equals(FIELD_WQ_Q)) {
+            GWT.log("getData: FIELD_WQ_Q || FIELD_WQ_Q_FREE");
+            value = "true";
         }
         else {
-            value = FIELD_WQ_W;
+            GWT.log("getData: FIELD_WQ_W || FIELD_WQ_W_FREE");
+            value = "false";
         }
 
-        DataItem item = new DefaultDataItem("wq_mode", "wq_mode", value);
+        DataItem item = new DefaultDataItem("wq_isq", "wq_isq", value);
         return new DefaultData(
-            "wq_mode", null, null, new DataItem[] { item });
+            "wq_isq", null, null, new DataItem[] { item });
     }
 
 
@@ -944,12 +996,17 @@
      *
      * @return the Data object for the 'wq_free' attribute.
      */
-    protected Data getQMode() {
-        String value = isQFree() ? "true" : "false";
-
-        DataItem item = new DefaultDataItem("wq_free", "wq_free", value);
+    protected Data getFree() {
+        String value = "";
+        if(!isWMode()) {
+            value = isQFree() ? "true" : "false";
+        }
+        else {
+            value = isWFree() ? "true" : "false";
+        }
+        DataItem item = new DefaultDataItem("wq_isfree", "wq_isfree", value);
         return new DefaultData(
-            "wq_free", null, null, new DataItem[] { item });
+            "wq_isfree", null, null, new DataItem[] { item });
     }
 
 
@@ -960,11 +1017,16 @@
      */
     protected Data getDataSelectionMode() {
         String wqSelection = modes.getValueAsString(FIELD_MODE);
+
+        String isRange = "true";
+        if (wqSelection.equals(FIELD_MODE_SINGLE)) {
+            isRange = "false";
+        }
         DataItem item = new DefaultDataItem(
-            "wq_selection", "wq_selection", wqSelection);
+            "wq_isrange", "wq_isrange", isRange);
 
         return new DefaultData(
-            "wq_selection", null, null, new DataItem[] { item });
+            "wq_isrange", null, null, new DataItem[] { item });
     }
 
 
@@ -1029,9 +1091,10 @@
 
 
     protected double[] getFinalSingle() {
-        boolean wMode = isWMode();
-
-        if (isWMode()) {
+        if (isWFree()) {
+            return getSingleWFree();
+        }
+        else if (isWMode()) {
             return getSingleW();
         }
         else if (isQFree()) {
@@ -1049,11 +1112,11 @@
      * @return the value of 'from' depending on the selected input mode.
      */
     protected double getFinalFrom() {
-        boolean wMode     = isWMode();
-        boolean rangeMode = isRangeMode();
-
-        if (rangeMode) {
-            if (wMode) {
+        if (isRangeMode()) {
+            if (isWFree()) {
+                return getFromWFree();
+            }
+            else if (isWMode()) {
                 return getFromW();
             }
             else if (isQFree()) {
@@ -1066,7 +1129,10 @@
         else {
             double[] values = null;
 
-            if (wMode) {
+            if (isWFree()) {
+                values = getSingleWFree();
+            }
+            else if (isWMode()) {
                 values = getSingleW();
             }
             else if (isQFree()) {
@@ -1092,11 +1158,11 @@
      * @return the value of 'to' depending on the selected input mode.
      */
     protected double getFinalTo() {
-        boolean wMode     = isWMode();
-        boolean rangeMode = isRangeMode();
-
-        if (rangeMode) {
-            if (wMode) {
+        if (isRangeMode()) {
+            if (isWFree()) {
+                return getToWFree();
+            }
+            else if (isWMode()) {
                 return getToW();
             }
             else if (isQFree()) {
@@ -1109,7 +1175,10 @@
         else {
             double[] values = null;
 
-            if (wMode) {
+            if (isWFree()) {
+                values = getSingleWFree();
+            }
+            else if (isWMode()) {
                 values = getSingleW();
             }
             else if (isQFree()) {
@@ -1135,11 +1204,11 @@
      * @return the value of 'step' depending on the selected input mode.
      */
     protected double getFinalStep() {
-        boolean wMode     = isWMode();
-        boolean rangeMode = isRangeMode();
-
-        if (rangeMode) {
-            if (wMode) {
+        if (isRangeMode()) {
+            if (isWFree()) {
+                return getStepWFree();
+            }
+            else if (isWMode()) {
                 return getStepW();
             }
             else if (isQFree()) {
@@ -1176,13 +1245,18 @@
      */
     public boolean isWMode() {
         String wq = modes.getValueAsString(FIELD_WQ);
-        return wq.equals(FIELD_WQ_W);
+        return wq.contains("W");
     }
 
 
     public boolean isQFree() {
         String wqMode = modes.getValueAsString(FIELD_WQ);
-        return wqMode.equals(FIELD_WQ_Q);
+        return wqMode.equals(FIELD_WQ_Q_FREE);
+    }
+
+    protected boolean isWFree() {
+        String wqMode = modes.getValueAsString(FIELD_WQ);
+        return wqMode.equals(FIELD_WQ_W_FREE);
     }
 
 
@@ -1196,34 +1270,73 @@
         DynamicForm form = event.getForm();
         FormItem    item = event.getItem();
 
-        String wqMode    = null;
-        String inputMode = null;
+        boolean isQ     = false;
+        boolean isFree  = false;
+        boolean isRange = false;
 
         if (item.getFieldName().equals(FIELD_MODE)) {
-            wqMode    = form.getValueAsString(FIELD_WQ);
-            inputMode = (String) event.getValue();
+            String wq = form.getValueAsString(FIELD_WQ);
+            isQ     = wq.contains("Q");
+            isFree  = wq.contains("FREE");
+            isRange = ((String) event.getValue()).equals(FIELD_MODE_RANGE);
         }
         else {
-            wqMode    = (String) event.getValue();
-            inputMode = form.getValueAsString(FIELD_MODE);
+            String wq = ((String) event.getValue());
+            isQ       = wq.contains("Q");
+            isFree    = wq.contains("FREE");
+            isRange   =
+                form.getValueAsString(FIELD_MODE).equals(FIELD_MODE_RANGE);
         }
 
-        if (wqMode.equals("Q")) {
+        if (isQ && isFree) {
             qdTable.hideIconFields();
         }
         else {
             qdTable.showIconFields();
         }
 
-        updatePanels(wqMode, inputMode);
+        if (!isRange) {
+            qdTable.showSelect();
+        }
+        else {
+            qdTable.showIconFields();
+        }
+
+        updatePanels(isQ, isFree, isRange);
     }
 
 
-    protected void updatePanels(String wqMode, String inputMode) {
+    protected void updatePanels(boolean isQ, boolean isFree, boolean isRange) {
         container.removeMembers(container.getMembers());
 
-        if (wqMode.equals(FIELD_WQ_W)) {
-            if (inputMode.equals(FIELD_MODE_SINGLE)) {
+        if (!isQ && isFree) {
+            if (!isRange) {
+                // Single W mode
+                double[] values = getSingleWFree();
+
+                wFreeArrayPanel = new DoubleArrayPanel(
+                    MESSAGE.unitWSingle(), values, this);
+
+                container.addMember(wFreeArrayPanel);
+            }
+            else {
+                // Range W mode
+                double from = getFromWFree();
+                double to   = getToWFree();
+                double step = getStepWFree();
+
+                wFreeRangePanel = new DoubleRangePanel(
+                    MESSAGE.unitWFrom(), MESSAGE.unitWTo(), MESSAGE.unitWStep(),
+                    from, to, step,
+                    250,
+                    this);
+                container.addMember(wFreeRangePanel);
+            }
+
+            tabs.selectTab(0);
+        }
+        else if (!isQ) {
+            if (!isRange) {
                 // Single W mode
                 double[] values = getSingleW();
 
@@ -1248,8 +1361,8 @@
 
             tabs.selectTab(0);
         }
-        else if (wqMode.equals(FIELD_WQ_Q)) {
-            if (inputMode.equals(FIELD_MODE_SINGLE)) {
+        else if (isQ && isFree) {
+            if (!isRange) {
                 // Single Q mode
                 double[] values = getSingleQFree();
 
@@ -1274,7 +1387,7 @@
             tabs.selectTab(1);
         }
         else {
-            if (inputMode.equals(FIELD_MODE_SINGLE)) {
+            if (!isRange) {
                 // Single Q mode
                 double[] values = getSingleQ();
 
@@ -1323,7 +1436,17 @@
                 saveRangeWValue(p, item);
             }
         }
-        else if (wqMode.equals(FIELD_WQ_Q)) {
+        else if (wqMode.equals(FIELD_WQ_W_FREE)) {
+            if (inputMode.equals(FIELD_MODE_SINGLE)) {
+                DoubleArrayPanel p = (DoubleArrayPanel) form;
+                saveSingleWFreeValue(p, item);
+            }
+            else {
+                DoubleRangePanel p = (DoubleRangePanel) form;
+                saveRangeWFreeValue(p, item);
+            }
+        }
+        else if (wqMode.equals(FIELD_WQ_Q_FREE)) {
             if (inputMode.equals(FIELD_MODE_SINGLE)) {
                 DoubleArrayPanel p = (DoubleArrayPanel) form;
                 saveSingleQFreeValue(p, item);
@@ -1357,6 +1480,17 @@
     }
 
 
+    protected void saveSingleWFreeValues(DoubleArrayPanel p) {
+        FormItem[] formItems = p.getFields();
+
+        for (FormItem item: formItems) {
+            if (item.getFieldName().equals(DoubleArrayPanel.FIELD_NAME)) {
+                saveSingleWFreeValue(p, item);
+            }
+        }
+    }
+
+
     protected void saveSingleQValues(DoubleArrayPanel p) {
         FormItem[] formItems = p.getFields();
 
@@ -1386,6 +1520,13 @@
     }
 
 
+    protected void saveSingleWFreeValue(DoubleArrayPanel p, FormItem item) {
+        if (p.validateForm(item)) {
+            setSingleWFree(p.getInputValues(item));
+        }
+    }
+
+
     protected void saveSingleQValue(DoubleArrayPanel p, FormItem item) {
         if (p.validateForm(item)) {
             setSingleQ(p.getInputValues(item));
@@ -1409,6 +1550,15 @@
     }
 
 
+    protected void saveRangeWFreeValues(DoubleRangePanel p) {
+        FormItem[] formItems = p.getFields();
+
+        for (FormItem item: formItems) {
+            saveRangeWFreeValue(p, item);
+        }
+    }
+
+
     protected void saveRangeQValues(DoubleRangePanel p) {
         FormItem[] formItems = p.getFields();
 
@@ -1436,6 +1586,15 @@
     }
 
 
+    protected void saveRangeWFreeValue(DoubleRangePanel p, FormItem item) {
+        if (p.validateForm()) {
+            setFromWFree(p.getFrom());
+            setToWFree(p.getTo());
+            setStepWFree(p.getStep());
+        }
+    }
+
+
     protected void saveRangeQValue(DoubleRangePanel p, FormItem item) {
         if (p.validateForm()) {
             setFromQ(p.getFrom());
@@ -1533,46 +1692,69 @@
         this.stepQFree = stepQ;
     }
 
-
     protected double[] getSingleW() {
         return valuesW;
     }
 
+    protected double[] getSingleWFree() {
+        return valuesWFree;
+    }
 
     protected void setSingleW(double[] values) {
         valuesW = values;
     }
 
+    protected void setSingleWFree(double[] values) {
+        valuesWFree = values;
+    }
 
     protected double getFromW() {
         return fromW;
     }
 
+    protected double getFromWFree() {
+        return fromWFree;
+    }
 
     protected void setFromW(double fromW) {
         this.fromW = fromW;
     }
 
+    protected void setFromWFree(double fromW) {
+        this.fromW = fromW;
+    }
 
     protected double getToW() {
         return toW;
     }
 
+    protected double getToWFree() {
+        return toWFree;
+    }
 
     protected void setToW(double toW) {
         this.toW = toW;
     }
 
+    protected void setToWFree(double toW) {
+        this.toWFree = toW;
+    }
 
     protected double getStepW() {
         return stepW;
     }
 
+    protected double getStepWFree() {
+        return stepWFree;
+    }
 
     protected void setStepW(double stepW) {
         this.stepW = stepW;
     }
 
+    protected void setStepWFree(double stepW) {
+        this.stepWFree = stepW;
+    }
 
     /**
      * Determines the min and max kilometer value selected in a former state. A
@@ -1605,7 +1787,6 @@
 
     protected void fetchWQData() {
         Config config    = Config.getInstance();
-        String url       = config.getServerUrl();
         String locale    = config.getLocale ();
 
         ArtifactDescription adescr = artifact.getArtifactDescription();
@@ -1633,7 +1814,12 @@
 
                     String wq = (String) modes.getValue(FIELD_WQ);
                     String sr = (String) modes.getValue(FIELD_MODE);
-                    updatePanels(wq, sr);
+                    GWT.log("sending: " + wq + ", " + sr);
+                    boolean isQ = wq.contains("Q");
+                    boolean isFree = wq.contains("FREE");
+                    boolean isRange = sr.equals(FIELD_MODE_RANGE);
+
+                    updatePanels(isQ, isFree, isRange);
                 }
             }
         );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/WQSimpleArrayPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,453 @@
+package de.intevation.flys.client.client.ui;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
+import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
+import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
+import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+import com.smartgwt.client.widgets.tab.TabSet;
+import com.smartgwt.client.widgets.tab.Tab;
+
+import de.intevation.flys.client.shared.model.ArtifactDescription;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+import de.intevation.flys.client.shared.model.DoubleArrayData;
+import de.intevation.flys.client.shared.model.Gauge;
+import de.intevation.flys.client.shared.model.IntegerOptionsData;
+import de.intevation.flys.client.shared.model.WQInfoRecord;
+import de.intevation.flys.client.shared.model.WQInfoObject;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.services.GaugeInfoService;
+import de.intevation.flys.client.client.services.GaugeInfoServiceAsync;
+import de.intevation.flys.client.client.services.WQInfoService;
+import de.intevation.flys.client.client.services.WQInfoServiceAsync;
+import de.intevation.flys.client.client.ui.wq.WTable;
+import de.intevation.flys.client.client.ui.wq.QDTable;
+
+
+/**
+ * An UIProvider for inserting a mode for W or Q and an array of values for each
+ * mode.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class WQSimpleArrayPanel
+extends      AbstractUIProvider
+implements   BlurHandler
+{
+    public static final String FIELD_MODE   = "field_mode";
+    public static final String FIELD_VALUES = "field_values";
+
+    public static final int MODE_W = 0;
+
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    protected GaugeInfoServiceAsync gaugeService =
+        GWT.create(GaugeInfoService.class);
+
+    protected WQInfoServiceAsync wqInfoService =
+        GWT.create(WQInfoService.class);
+
+    protected String modeName;
+    protected String valuesName;
+
+    protected Canvas valuesWrapper;
+
+    protected DynamicForm      modeForm;
+    protected DoubleArrayPanel panelW;
+    protected DoubleArrayPanel panelQ;
+
+    protected WTable wTable;
+    protected QDTable qTable;
+
+
+    @Override
+    public Canvas create(DataList data) {
+        VLayout rootLayout = new VLayout();
+        rootLayout.addMember(createLabel(data));
+        rootLayout.addMember(createModeForm(data));
+        rootLayout.addMember(createValuesForm(data));
+        rootLayout.addMember(getNextButton());
+
+        initializeMode(data);
+        initializeTables();
+        initializeHelperPanel();
+
+        return rootLayout;
+    }
+
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        IntegerOptionsData modeData   = findOptionsData(dataList);
+        DoubleArrayData    valuesData = findValuesData(dataList);
+
+        DataItem[] modeItems   = modeData.getItems();
+        DataItem[] valuesItems = valuesData.getItems();
+
+        HLayout layout         = new HLayout();
+        VLayout valueContainer = new VLayout();
+
+        Label label = new Label(dataList.getLabel());
+        label.setWidth(200);
+        label.setHeight(20);
+
+        Label mode = new Label(modeItems[0].getLabel());
+        mode.setHeight(20);
+        mode.setWidth(150);
+
+        Canvas values = createOldValues(modeData, valuesData);
+        values.setWidth(150);
+
+        valueContainer.addMember(mode);
+        valueContainer.addMember(values);
+
+        layout.addMember(label);
+        layout.addMember(valueContainer);
+        layout.addMember(getBackButton(dataList.getState()));
+
+        return layout;
+    }
+
+
+    @Override
+    protected Data[] getData() {
+        Data mode = getModeAsData();
+
+        if (getMode() == MODE_W) {
+            return new Data[] { mode, getWValuesAsData() };
+        }
+        else {
+            return new Data[] { mode, getQValuesAsData() };
+        }
+    }
+
+
+    @Override
+    public List<String> validate() {
+        List<String> errors = new ArrayList<String>();
+
+        // TODO IMPLEMENT ME
+
+        return errors;
+    }
+
+
+    @Override
+    public void onBlur(BlurEvent event) {
+        // TODO TRIGGER VALIDATION HERE
+    }
+
+
+    protected void initializeMode(DataList dataList) {
+        IntegerOptionsData data  = findOptionsData(dataList);
+        DataItem[]         items = data != null ? data.getItems() : null;
+
+        if (items != null) {
+            String value = items[0].getStringValue();
+            modeForm.setValue(modeName, value);
+            switchMode(value);
+        }
+    }
+
+
+    protected void initializeTables() {
+        wTable = new WTable();
+        qTable = new QDTable();
+
+        fetchWQData();
+    }
+
+
+    protected void initializeHelperPanel() {
+        TabSet tabs = new TabSet();
+        tabs.setWidth100();
+        tabs.setHeight100();
+
+        Tab w = new Tab(MSG.wq_table_w());
+        Tab q = new Tab(MSG.wq_table_q());
+
+        w.setPane(wTable);
+        q.setPane(qTable);
+
+        tabs.addTab(w, 0);
+        tabs.addTab(q, 1);
+
+        helperContainer.addMember(tabs);
+    }
+
+
+    protected void fetchWQData() {
+        ArtifactDescription desc = artifact.getArtifactDescription();
+        DataList[]          data = desc.getOldData();
+
+        final String river    = desc.getRiver();
+        final String refGauge = desc.getReferenceGauge();
+
+        gaugeService.getGaugeInfo(river, refGauge, new AsyncCallback<List<Gauge>>() {
+            public void onFailure(Throwable throwable) {
+                GWT.log("ERROR WHILE FETCHING GAUGES!");
+            }
+
+            public void onSuccess(List<Gauge> gauges) {
+                Gauge g = gauges.get(0);
+                updateWQData(river, g.getLower(), g.getUpper());
+            }
+        });
+    }
+
+
+    protected void updateWQData(String river, double lower, double upper) {
+        GWT.log("FETCH WQ INFO FOR " + lower + " - " + upper + " now!");
+
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
+
+        wqInfoService.getWQInfo(locale, river, lower, upper,
+            new AsyncCallback<WQInfoObject[]>() {
+                public void onFailure(Throwable caught) {
+                    GWT.log("Could not recieve wq informations.");
+                }
+
+                public void onSuccess(WQInfoObject[] wqi) {
+                    int num = wqi != null ? wqi.length :0;
+                    GWT.log("Recieved " + num + " wq informations.");
+
+                    if (num == 0) {
+                        return;
+                    }
+
+                    addWQInfo(wqi);
+                }
+            }
+        );
+    }
+
+
+    protected void addWQInfo (WQInfoObject[] wqi) {
+        for(WQInfoObject wi: wqi) {
+            WQInfoRecord rec = new WQInfoRecord(wi);
+
+            if (wi.getType().equals("W")) {
+                wTable.addData(rec);
+            }
+            else {
+                qTable.addData(rec);
+            }
+        }
+    }
+
+
+    protected Canvas createLabel(DataList dataList) {
+        Label label = new Label(MSG.wqHistorical());
+        label.setWidth100();
+        label.setHeight(25);
+
+        return label;
+    }
+
+
+    protected Canvas createOldValues(
+        IntegerOptionsData modeData,
+        DoubleArrayData valuesData
+    ) {
+        NumberFormat nf = NumberFormat.getDecimalFormat();
+
+        DataItem[] items = modeData.getItems();
+        String     unit  = items[0].getStringValue().equals("0") ? "cm" : "q³/s";
+
+        VLayout layout = new VLayout();
+
+        for (double val: valuesData.getValues()) {
+            Label tmp = new Label(nf.format(val) + " " + unit);
+            tmp.setHeight(20);
+            layout.addMember(tmp);
+        }
+
+        return layout;
+    }
+
+
+    protected DoubleArrayData findValuesData(DataList dataList) {
+        DoubleArrayData data = null;
+
+        for (int i = 0, n = dataList.size(); i < n; i++) {
+            Data tmp = dataList.get(i);
+
+            if (tmp instanceof DoubleArrayData) {
+                return (DoubleArrayData) tmp;
+            }
+        }
+
+        return null;
+    }
+
+
+    protected IntegerOptionsData findOptionsData(DataList dataList) {
+        IntegerOptionsData data = null;
+
+        for (int i = 0, n = dataList.size(); i < n; i++) {
+            Data tmp = dataList.get(i);
+
+            if (tmp instanceof IntegerOptionsData) {
+                return (IntegerOptionsData) tmp;
+            }
+        }
+
+        return null;
+    }
+
+
+    protected Canvas createModeForm(DataList dataList) {
+        IntegerOptionsData data = findOptionsData(dataList);
+        DataItem[]         opts = data != null ? data.getItems() : null;
+
+        if (data == null || opts == null) {
+            return new Label("NO MODES FOUND");
+        }
+
+        modeName = data.getLabel();
+        modeForm = new DynamicForm();
+
+        RadioGroupItem items = new RadioGroupItem(data.getLabel());
+        LinkedHashMap values = new LinkedHashMap();
+
+        for (DataItem opt: opts) {
+            values.put(opt.getStringValue(), opt.getLabel());
+        }
+
+        items.setValueMap(values);
+        items.setVertical(false);
+        items.setShowTitle(false);
+        items.addChangedHandler(new ChangedHandler() {
+            @Override
+            public void onChanged(ChangedEvent event) {
+                switchMode((String) event.getValue());
+            }
+        });
+
+        modeForm.setFields(items);
+
+        return modeForm;
+    }
+
+
+    protected Canvas createValuesForm(DataList dataList) {
+        DoubleArrayData data = findValuesData(dataList);
+
+        if (data == null) {
+            return new Label("NO VALUES GIVEN!");
+        }
+
+        valuesName = data.getLabel();
+        panelW     = new DoubleArrayPanel(MSG.unitWSingle(), null, this);
+        panelQ     = new DoubleArrayPanel(MSG.unitQSingle(), null, this);
+
+        valuesWrapper = new Canvas();
+        valuesWrapper.setWidth100();
+        valuesWrapper.setHeight(35);
+
+        return valuesWrapper;
+    }
+
+
+    public void switchMode(String newMode) {
+        for (Canvas child: valuesWrapper.getChildren()) {
+            valuesWrapper.removeChild(child);
+        }
+
+        if (newMode.equals("0")) {
+            valuesWrapper.addChild(panelW);
+        }
+        else if (newMode.equals("1")) {
+            valuesWrapper.addChild(panelQ);
+        }
+    }
+
+
+    public String getModeAsString() {
+        return (String) modeForm.getValue(modeName);
+    }
+
+
+    public int getMode() {
+        String modeValue = getModeAsString();
+
+        try {
+            return Integer.valueOf(modeValue);
+        }
+        catch (NumberFormatException nfe) {
+            // do something
+        }
+        catch (NullPointerException npe) {
+            // do something
+        }
+
+        return -1;
+    }
+
+
+    public Data getModeAsData() {
+        String  value = getModeAsString();
+        DataItem item = new DefaultDataItem(value, value, value);
+
+        return new DefaultData(modeName, null, null, new DataItem[] { item });
+    }
+
+
+    public Data getWValuesAsData() {
+        double[] values = panelW.getInputValues();
+        String valueStr = getStringValue(values);
+
+        DataItem item = new DefaultDataItem(valueStr, valueStr, valueStr);
+
+        return new DefaultData(valuesName, null, null, new DataItem[] { item });
+    }
+
+
+    public Data getQValuesAsData() {
+        double[] values = panelQ.getInputValues();
+        String valueStr = getStringValue(values);
+
+        DataItem item = new DefaultDataItem(valueStr, valueStr, valueStr);
+
+        return new DefaultData(valuesName, null, null, new DataItem[] { item });
+    }
+
+
+    protected static String getStringValue(double[] values) {
+        StringBuilder sb = new StringBuilder();
+        boolean    first = true;
+
+        for (double value: values) {
+            if (first) {
+                sb.append(String.valueOf(value));
+                first = false;
+            }
+            else {
+                sb.append(";" + String.valueOf(value));
+            }
+        }
+
+        return sb.toString();
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/WspDatacagePanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/WspDatacagePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -71,7 +71,7 @@
      * we have to create a new Artifact specified by  the Datacage selection via
      * Async request.
      *
-     * @param The ClickEvent.
+     * @param e The ClickEvent.
      */
     @Override
     public void onClick(ClickEvent e) {
@@ -88,7 +88,7 @@
                 c, r, "winfo", locale,
                 new AsyncCallback<Artifact>() {
                     public void onFailure(Throwable caught) {
-                        SC.warn(MSG.getString(caught.getMessage()));
+                        SC.warn(caught.getMessage());
                     }
 
                     public void onSuccess(Artifact artifact) {
@@ -108,7 +108,7 @@
         ToLoad toLoad = widget.getSelection();
         List<Recommendation> recoms = toLoad.toRecommendations();
 
-        return recoms.get(0);
+        return recoms.size() > 0 ? recoms.get(0) : null;
     }
 
 
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/ChartOutputTab.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,47 +1,45 @@
 package de.intevation.flys.client.client.ui.chart;
 
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.types.Overflow;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Img;
+import com.smartgwt.client.widgets.events.ResizedEvent;
+import com.smartgwt.client.widgets.events.ResizedHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.event.OutputParameterChangeEvent;
+import de.intevation.flys.client.client.event.OutputParameterChangeHandler;
+import de.intevation.flys.client.client.event.PanEvent;
+import de.intevation.flys.client.client.event.PanHandler;
+import de.intevation.flys.client.client.event.RedrawRequestEvent;
+import de.intevation.flys.client.client.event.RedrawRequestEvent.Type;
+import de.intevation.flys.client.client.event.RedrawRequestHandler;
+import de.intevation.flys.client.client.event.ZoomEvent;
+import de.intevation.flys.client.client.event.ZoomHandler;
+import de.intevation.flys.client.client.services.ChartInfoService;
+import de.intevation.flys.client.client.services.ChartInfoServiceAsync;
+import de.intevation.flys.client.client.ui.CollectionView;
+import de.intevation.flys.client.client.ui.OutputTab;
+import de.intevation.flys.client.shared.Transform2D;
+import de.intevation.flys.client.shared.model.Axis;
+import de.intevation.flys.client.shared.model.ChartInfo;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.OutputMode;
+import de.intevation.flys.client.shared.model.ZoomObj;
+
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Stack;
 
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-
-import com.smartgwt.client.types.Overflow;
-
-import com.smartgwt.client.widgets.Canvas;
-import com.smartgwt.client.widgets.Img;
-
-import com.smartgwt.client.widgets.layout.HLayout;
-import com.smartgwt.client.widgets.layout.VLayout;
-
-import com.smartgwt.client.widgets.events.ResizedEvent;
-import com.smartgwt.client.widgets.events.ResizedHandler;
-
-import de.intevation.flys.client.shared.Transform2D;
-import de.intevation.flys.client.shared.model.Axis;
-import de.intevation.flys.client.shared.model.ChartInfo;
-import de.intevation.flys.client.shared.model.Collection;
-import de.intevation.flys.client.shared.model.OutputMode;
-import de.intevation.flys.client.shared.model.ZoomObj;
-import de.intevation.flys.client.client.Config;
-import de.intevation.flys.client.client.event.OutputParameterChangeEvent;
-import de.intevation.flys.client.client.event.OutputParameterChangeHandler;
-import de.intevation.flys.client.client.event.PanEvent;
-import de.intevation.flys.client.client.event.PanHandler;
-import de.intevation.flys.client.client.event.RedrawRequestHandler;
-import de.intevation.flys.client.client.event.RedrawRequestEvent;
-import de.intevation.flys.client.client.event.RedrawRequestEvent.Type;
-import de.intevation.flys.client.client.event.ZoomEvent;
-import de.intevation.flys.client.client.event.ZoomHandler;
-import de.intevation.flys.client.client.services.ChartInfoService;
-import de.intevation.flys.client.client.services.ChartInfoServiceAsync;
-import de.intevation.flys.client.client.ui.CollectionView;
-import de.intevation.flys.client.client.ui.OutputTab;
-
 
 /**
+ * Tab representing and showing one Chart-output.
+ *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class ChartOutputTab
@@ -55,7 +53,7 @@
     public static final int DEFAULT_CHART_WIDTH  = 600;
     public static final int DEFAULT_CHART_HEIGHT = 500;
 
-    public static final int THEMEPANEL_MIN_WIDTH = 200;
+    public static final int THEMEPANEL_MIN_WIDTH = 250;
 
     /** The service that is used to fetch chart information. */
     protected ChartInfoServiceAsync info = GWT.create(ChartInfoService.class);
@@ -70,10 +68,11 @@
     /** The collection view.*/
     protected CollectionView view;
 
+    /** The ThemePanel to expose control over themes (facettes). */
     protected ChartThemePanel ctp;
 
     /** The canvas that wraps the chart toolbar. */
-    protected Canvas tbarPanel;
+    protected ChartToolbar tbarPanel;
 
     /** The canvas that wraps the theme editor. */
     protected Canvas left;
@@ -87,8 +86,9 @@
     protected int[] xrange;
     protected int[] yrange;
 
+    /** Stack of ZoomObj to allow 'redo last zoom'-kind of actions. */
     protected Stack<ZoomObj> zoomStack;
-    protected double[]       zoom;
+    protected Number[]       zoom;
 
 
     /**
@@ -112,10 +112,13 @@
         right     = new Canvas();
         xrange    = new int[2];
         yrange    = new int[2];
-        zoom      = new double[4];
         zoomStack = new Stack<ZoomObj>();
 
-        left.setBorder("1px solid black");
+        zoom = new Number[] {
+            new Double(0), new Double(1),
+            new Double(0), new Double(1) };
+
+        left.setBorder("1px solid gray");
         left.setWidth(THEMEPANEL_MIN_WIDTH);
         left.setMinWidth(THEMEPANEL_MIN_WIDTH);
         right.setWidth("*");
@@ -131,27 +134,26 @@
         hLayout.addMember(left);
         hLayout.addMember(right);
 
-        // Output "cross_section" needs slightly modified ThemePanel
-        // (with action buttons).
-        if (mode.getName().equals("cross_section")) {
-            ctp = new CrossSectionChartThemePanel(collection, mode, this.view);
+        ctp = createThemePanel(mode, collectionView);
+        if (ctp != null) {
+            ctp.addRedrawRequestHandler(this);
+            ctp.addOutputParameterChangeHandler(this);
+            left.addChild(ctp);
         }
         else {
-            ctp = new ChartThemePanel(collection, mode, this.view);
+            left.setVisible(false);
         }
 
-        ctp.addRedrawRequestHandler(this);
-        ctp.addOutputParameterChangeHandler(this);
-
         chart = createChartImg();
         right.addChild(chart);
         right.setOverflow(Overflow.HIDDEN);
-        //right.addChild(createChartPanel());
-        left.addChild(ctp);
 
-        tbarPanel = new ChartToolbar(collectionView, this);
+        left.setShowResizeBar(true);
+
+        tbarPanel = createChartToolbar(this);
         vLayout.addMember(tbarPanel);
         vLayout.addMember(hLayout);
+        vLayout.setOverflow(Overflow.HIDDEN);
 
         setPane(vLayout);
 
@@ -159,18 +161,46 @@
     }
 
 
+    public ChartThemePanel createThemePanel(
+        OutputMode mode, CollectionView view
+    ) {
+        // Output "cross_section" needs slightly modified ThemePanel
+        // (with action buttons).
+        if (mode.getName().equals("cross_section")) {
+            return new CrossSectionChartThemePanel(mode, view);
+        }
+        else {
+            return new ChartThemePanel(mode, view);
+        }
+    }
+
+
+    public ChartToolbar createChartToolbar(ChartOutputTab tab) {
+        return new ChartToolbar(tab);
+    }
+
+
+    public void toggleThemePanel() {
+        this.left.setVisible(!left.isVisible());
+    }
+
+
     /**
      * This method is called after the chart panel has resized. It removes the
      * chart - if existing - and requests a new one with adjusted size.
      *
      * @param event The resize event.
      */
+    @Override
     public void onResized(ResizedEvent event) {
         updateChartPanel();
         updateChartInfo();
     }
 
 
+    /** For RESET type of events, just reset the ranges, otherwise do a
+     * complete refresh of panel, info and collection. */
+    @Override
     public void onRedrawRequest(RedrawRequestEvent event) {
         if (event.getType() == Type.RESET) {
             resetRanges();
@@ -189,7 +219,9 @@
      *
      * @param event The OutputParameterChangeEvent.
      */
+    @Override
     public void onOutputParameterChanged(OutputParameterChangeEvent event) {
+        updateChartInfo();
         updateChartPanel();
     }
 
@@ -199,6 +231,7 @@
      *
      * @param evt The ZoomEvent that stores the coordinates for zooming.
      */
+    @Override
     public void onZoom(ZoomEvent evt) {
         zoomStack.push(new ZoomObj(zoom[0], zoom[1], zoom[2], zoom[3]));
 
@@ -217,7 +250,7 @@
     }
 
 
-    protected double[] translateCoordinates() {
+    protected Number[] translateCoordinates() {
         if (xrange == null || (xrange[0] == 0 && xrange[1] == 0)) {
             zoom[0] = 0d;
             zoom[1] = 1d;
@@ -241,37 +274,38 @@
     protected void translateXCoordinates() {
         Axis xAxis = chartInfo.getXAxis(0);
 
-        double xmin   = xAxis.getMin();
-        double xmax   = xAxis.getMax();
-        double xRange = xmax - xmin;
+        Number xmin   = xAxis.getMin();
+        Number xmax   = xAxis.getMax();
+        Number xRange = subtract(xmax, xmin);
 
         Transform2D transformer = getTransformer(0);
 
         double[] start = transformer.transform(xrange[0], yrange[0]);
         double[] end   = transformer.transform(xrange[1], yrange[1]);
 
-        zoom[0] = (start[0] - xmin) / xRange;
-        zoom[1] = (end[0] - xmin) / xRange;
+        zoom[0] = divide(subtract(start[0], xmin), xRange);
+        zoom[1] = divide(subtract(end[0], xmin), xRange);
     }
 
 
     protected void translateYCoordinates() {
         Axis yAxis = chartInfo.getYAxis(0);
 
-        double ymin   = yAxis.getMin();
-        double ymax   = yAxis.getMax();
-        double yRange = ymax - ymin;
+        Number ymin   = yAxis.getMin();
+        Number ymax   = yAxis.getMax();
+        Number yRange = subtract(ymax, ymin);
 
         Transform2D transformer = getTransformer(0);
 
         double[] start = transformer.transform(xrange[0], yrange[0]);
         double[] end   = transformer.transform(xrange[1], yrange[1]);
 
-        zoom[2] = (start[1] - ymin) / yRange;
-        zoom[3] = (end[1] - ymin) / yRange;
+        zoom[2] = divide(subtract(start[1], ymin), yRange);
+        zoom[3] = divide(subtract(end[1], ymin), yRange);
     }
 
 
+    @Override
     public void onPan(PanEvent event) {
         if (chartInfo == null) {
             return;
@@ -291,9 +325,10 @@
         Axis xAxis = chartInfo.getXAxis(0);
         Axis yAxis = chartInfo.getYAxis(0);
 
-        double[] x = panAxis(xAxis, diffX);
-        double[] y = panAxis(yAxis, diffY);
+        Number[] x = panAxis(xAxis, diffX);
+        Number[] y = panAxis(yAxis, diffY);
 
+        // Set the zoom coordinates.
         zoom[0] = x[0];
         zoom[1] = x[1];
         zoom[2] = y[0];
@@ -304,12 +339,12 @@
     }
 
 
-    protected double[] panAxis(Axis axis, double diff) {
-        double min = axis.getFrom();
-        double max = axis.getTo();
+    protected Number[] panAxis(Axis axis, double diff) {
+        Number min = axis.getFrom();
+        Number max = axis.getTo();
 
-        min += diff;
-        max += diff;
+        min = add(min, diff);
+        max = add(max, diff);
 
         return computeZoom(axis, min, max);
     }
@@ -343,8 +378,8 @@
         Axis xAxis = chartInfo.getXAxis(0);
         Axis yAxis = chartInfo.getYAxis(0);
 
-        double[] x = zoomAxis(xAxis, factor);
-        double[] y = zoomAxis(yAxis, factor);
+        Number[] x = zoomAxis(xAxis, factor);
+        Number[] y = zoomAxis(yAxis, factor);
 
         zoom[0] = x[0];
         zoom[1] = x[1];
@@ -357,11 +392,10 @@
 
 
     /**
-     * This method is used to zoom out. Zooming out is realizied with a stacked
+     * This method is used to zoom out. Zooming out is realized with a stacked
      * logic. Initially, you cannot zoom out. For each time you start a zoom-in
      * action, the extent of the chart is stored and pushed onto a stack. A
-     * zoom-out will now lead you to the last extent that is poped from stack.
-     *
+     * zoom-out will now lead you to the last extent that is popped from stack.
      */
     public void zoomOut() {
         if (!zoomStack.empty()) {
@@ -373,17 +407,19 @@
     }
 
 
-    public double[] zoomAxis(Axis axis, int factor) {
+    public Number[] zoomAxis(Axis axis, int factor) {
         GWT.log("Prepare Axis for zooming (factor: " + factor + ")");
 
-        double min   = axis.getMin();
-        double max   = axis.getMax();
-        double range = max > min ? max - min : min - max;
+        Number min   = axis.getMin();
+        Number max   = axis.getMax();
+        Number range = isBigger(max, min) ? subtract(max, min) : subtract(min, max);
 
-        double curFrom = axis.getFrom();
-        double curTo   = axis.getTo();
+        Number curFrom = axis.getFrom();
+        Number curTo   = axis.getTo();
 
-        double diff = curTo > curFrom ? curTo - curFrom : curFrom - curTo;
+        Number diff = isBigger(curTo, curFrom)
+            ? subtract(curTo, curFrom)
+            : subtract(curFrom, curTo);
 
         GWT.log("    max from    : " + min);
         GWT.log("    max to      : " + max);
@@ -392,30 +428,38 @@
         GWT.log("    current to  : " + curTo);
         GWT.log("    current diff: " + diff);
 
-        double newFrom = curFrom - (diff * factor / 100);
-        double newTo   = curTo + (diff * factor / 100);
+        Number newFrom = subtract(curFrom, divide(multi(diff, factor), 100));
+        Number newTo   = add(curTo, divide(multi(diff, factor), 100));
 
         GWT.log("    new from: " + newFrom);
         GWT.log("    new to  : " + newTo);
 
-        return new double[] {
-            (newFrom - min) / range,
-            (newTo - min) / range
+        return new Number[] {
+            divide(subtract(newFrom, min), range),
+            divide(subtract(newTo, min), range)
         };
     }
 
 
-    public static double[] computeZoom(Axis axis, double min, double max) {
-        double[] zoom = new double[2];
+    public static Number[] computeZoom(Axis axis, Number min, Number max) {
+        Number[] hereZoom = new Number[2];
 
-        double absMin = axis.getMin();
-        double absMax = axis.getMax();
-        double diff   = absMax > absMin ? absMax - absMin : absMin - absMax;
+        Number absMin = axis.getMin();
+        Number absMax = axis.getMax();
+        Number diff   = isBigger(absMax, absMin)
+            ? subtract(absMax, absMin)
+            : subtract(absMin, absMax);
 
-        zoom[0] = (min - absMin) / diff;
-        zoom[1] = (max - absMin) / diff;
+        hereZoom[0] = divide(subtract(min, absMin), diff);
+        hereZoom[1] = divide(subtract(max, absMin), diff);
 
-        return zoom;
+        return hereZoom;
+    }
+
+
+    /** Get Collection from ChartThemePanel. .*/
+    public Collection getCtpCollection() {
+        return this.ctp.getCollection();
     }
 
 
@@ -432,10 +476,12 @@
             mode.getName(),
             getChartAttributes(),
             new AsyncCallback<ChartInfo>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("ChartInfo ERROR: " + caught.getMessage());
                 }
 
+                @Override
                 public void onSuccess(ChartInfo chartInfo) {
                     setChartInfo(chartInfo);
                 }
@@ -503,6 +549,20 @@
 
 
     /**
+     * Returns the Transform2D count.
+     *
+     * @return the Transformer2D count
+     */
+    public int getTransformerCount() {
+        if (chartInfo == null) {
+            return 0;
+        }
+
+        return chartInfo.getTransformerCount();
+    }
+
+
+    /**
      * Creates a new chart panel with default size.
      *
      * @return the created chart panel.
@@ -559,26 +619,26 @@
         imgUrl += "chart";
         imgUrl += "?uuid=" + collection.identifier();
         imgUrl += "&type=" + mode.getName();
-        imgUrl += "&server=" + config.getServerUrl();
         imgUrl += "&locale=" + config.getLocale();
         imgUrl += "&timestamp=" + new Date().getTime();
         imgUrl += "&width=" + Integer.toString(width);
         imgUrl += "&height=" + Integer.toString(height);
 
-        double[] zoom = getZoomValues();
+        Number[] zoom = getZoomValues();
 
         if (zoom != null) {
-            if (zoom[0] != 0 || zoom[1] != 1) {
+            if (zoom[0].intValue() != 0 || zoom[1].intValue() != 1) {
                 // a zoom range of 0-1 means displaying the whole range. In such
                 // case we don't need to zoom.
-                imgUrl += "&minx=" + Double.toString(zoom[0]);
-                imgUrl += "&maxx=" + Double.toString(zoom[1]);
+                imgUrl += "&minx=" + zoom[0];
+                imgUrl += "&maxx=" + zoom[1];
             }
-            if (zoom[2] != 0 || zoom[3] != 1) {
+
+            if (zoom[2].intValue() != 0 || zoom[3].intValue() != 1) {
                 // a zoom range of 0-1 means displaying the whole range. In such
                 // case we don't need to zoom.
-                imgUrl += "&miny=" + Double.toString(zoom[2]);
-                imgUrl += "&maxy=" + Double.toString(zoom[3]);
+                imgUrl += "&miny=" + zoom[2];
+                imgUrl += "&maxy=" + zoom[3];
             }
         }
 
@@ -586,6 +646,7 @@
     }
 
 
+    /** Get link to export image in given dimension and format. */
     public String getExportUrl(int width, int height, String format) {
         String url = getImgUrl(width, height);
         url += "&format=" + format;
@@ -595,27 +656,27 @@
     }
 
 
-    public Map getChartAttributes() {
+    public Map <String, String> getChartAttributes() {
         Map<String, String> attr = new HashMap<String, String>();
 
         Canvas chart = getChartPanel();
         attr.put("width",  chart.getWidth().toString());
         attr.put("height", chart.getHeight().toString());
 
-        double[] zoom = getZoomValues();
+        Number[] zoom = getZoomValues();
 
         if (zoom != null) {
-            if (zoom[0] != 0 || zoom[1] != 1) {
+            if (zoom[0].intValue() != 0 || zoom[1].intValue() != 1) {
                 // a zoom range of 0-1 means displaying the whole range. In such
                 // case we don't need to zoom.
-                attr.put("minx", Double.toString(zoom[0]));
-                attr.put("maxx", Double.toString(zoom[1]));
+                attr.put("minx", zoom[0].toString());
+                attr.put("maxx", zoom[1].toString());
             }
-            if (zoom[2] != 0 || zoom[3] != 1) {
+            if (zoom[2].intValue() != 0 || zoom[3].intValue() != 1) {
                 // a zoom range of 0-1 means displaying the whole range. In such
                 // case we don't need to zoom.
-                attr.put("miny", Double.toString(zoom[2]));
-                attr.put("maxy", Double.toString(zoom[3]));
+                attr.put("miny", zoom[2].toString());
+                attr.put("maxy", zoom[3].toString());
             }
         }
 
@@ -623,8 +684,81 @@
     }
 
 
-    protected double[] getZoomValues() {
+    protected Number[] getZoomValues() {
         return zoom;
     }
+
+
+    /** Return the 'parent' CollectionView. */
+    public CollectionView getView() {
+        return this.view;
+    }
+
+
+    public static Number subtract(Number left, Number right) {
+        if (left instanceof Double) {
+            return new Double(left.doubleValue() - right.doubleValue());
+        }
+        else if (left instanceof Long) {
+            return new Long(left.longValue() - right.longValue());
+        }
+        else {
+            return new Integer(left.intValue() - right.intValue());
+        }
+    }
+
+
+    /** Add two numbers, casting to Type of param left. */
+    public static Number add(Number left, Number right) {
+        if (left instanceof Double) {
+            return new Double(left.doubleValue() + right.doubleValue());
+        }
+        else if (left instanceof Long) {
+            return new Long(left.longValue() + right.longValue());
+        }
+        else {
+            return new Integer(left.intValue() + right.intValue());
+        }
+    }
+
+
+    /** Divde left by right. Note that Long will be casted to double. */
+    public static Number divide(Number left, Number right) {
+        if (left instanceof Double) {
+            return new Double(left.doubleValue() / right.doubleValue());
+        }
+        else if (left instanceof Long) {
+            return new Double(left.doubleValue() / right.doubleValue());
+        }
+        else {
+            return new Integer(left.intValue() / right.intValue());
+        }
+    }
+
+
+    public static Number multi(Number left, Number right) {
+        if (left instanceof Double) {
+            return new Double(left.doubleValue() * right.doubleValue());
+        }
+        else if (left instanceof Long) {
+            return new Long(left.longValue() * right.longValue());
+        }
+        else {
+            return new Integer(left.intValue() * right.intValue());
+        }
+    }
+
+
+    public static boolean isBigger(Number left, Number right) {
+        if (left instanceof Double) {
+            return left.doubleValue() > right.doubleValue();
+        }
+        else if (left instanceof Long) {
+            return left.longValue() > right.longValue();
+        }
+        else {
+            return left.intValue() > right.intValue();
+        }
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/ChartPropertiesEditor.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,6 +1,8 @@
 package de.intevation.flys.client.client.ui.chart;
 
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -18,17 +20,20 @@
 import com.smartgwt.client.widgets.form.DynamicForm;
 import com.smartgwt.client.widgets.form.fields.FormItem;
 import com.smartgwt.client.widgets.form.fields.CheckboxItem;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
 import com.smartgwt.client.widgets.form.fields.TextItem;
 
 import com.smartgwt.client.widgets.events.ClickEvent;
 import com.smartgwt.client.widgets.events.ClickHandler;
 import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
 import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
+import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
+import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
+
 import com.smartgwt.client.types.Alignment;
 
 import de.intevation.flys.client.client.Config;
 import de.intevation.flys.client.client.FLYSConstants;
-import de.intevation.flys.client.client.ui.OutputTab;
 import de.intevation.flys.client.shared.model.Property;
 import de.intevation.flys.client.shared.model.PropertyGroup;
 import de.intevation.flys.client.shared.model.PropertySetting;
@@ -39,39 +44,47 @@
 import de.intevation.flys.client.shared.model.Settings;
 import de.intevation.flys.client.shared.model.OutputSettings;
 import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.client.utils.IntegerValidator;
+import de.intevation.flys.client.client.utils.DoubleValidator;
 
 import de.intevation.flys.client.client.services.CollectionAttributeService;
 import de.intevation.flys.client.client.services.CollectionAttributeServiceAsync;
 
 /**
+ * Dialog for the Chart-Properties, constructed from respective xml document.
+ *
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
 public class ChartPropertiesEditor
-extends Window
-implements ClickHandler
+extends      Window
+implements   ClickHandler
 {
     /** The interface that provides i18n messages. */
     protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
 
+    /** CollectionAttribute Update Service. */
     protected CollectionAttributeServiceAsync updater =
         GWT.create(CollectionAttributeService.class);
 
     /** The tab called the editor window. */
     protected ChartOutputTab tab;
 
-    /** The tabset for chart properties */
+    /** The tabset for chart properties. */
     protected TabSet tabs;
 
-    /** The collection */
+    /** The collection. */
     protected Collection collection;
 
-    /** The output settings */
+    /** The cloned output settings. */
     protected OutputSettings settings;
 
+    /** The original output settings. */
+    protected OutputSettings origSettings;
+
 
     /**
      * Setup editor dialog.
-     * @param callerTab      The tab called the editor window.
+     * @param callerTab The tab called the editor window.
      */
     public ChartPropertiesEditor(ChartOutputTab callerTab) {
         this.tab = callerTab;
@@ -80,6 +93,7 @@
         init();
     }
 
+
     /**
      * Initialize the editor window and its components.
      */
@@ -88,11 +102,12 @@
         setCanDragReposition(true);
         setCanDragResize(true);
 
-
+        Config config = Config.getInstance();
         collection = tab.getCollectionView().getCollection();
         String outputName = tab.getOutputName();
-        settings = (OutputSettings)collection.getSettings(outputName);
+        origSettings = (OutputSettings)collection.getSettings(outputName);
 
+        settings = (OutputSettings)origSettings.clone();
         if (settings == null) {
             return;
         }
@@ -101,17 +116,20 @@
         for (int i = 0; i < list.size(); i++) {
             Tab t = new Tab(MSG.getString(list.get(i)));
             List<Property> props = settings.getSettings(list.get(i));
+            List<Property> origProps = origSettings.getSettings(list.get(i));
             VLayout layout = new VLayout();
             for (int j = 0; j < props.size(); j++) {
                 if (props.get(j) instanceof PropertyGroup) {
-                    layout.addMember(generatePropertyGroup(props.get(j)));
+                    layout.addMember(generatePropertyGroup(props.get(j),
+                                                           origProps.get(j)));
                 }
                 else if (props.get(j) instanceof PropertySetting) {
                     PropertySetting p = (PropertySetting)props.get(j);
                     if (p.getAttribute("display").equals("false")) {
                         continue;
                     }
-                    layout.addMember(generatePropertySetting(props.get(j)));
+                    layout.addMember(generatePropertySetting(props.get(j),
+                                                             origProps.get(j)));
                 }
             }
             t.setPane(layout);
@@ -123,7 +141,13 @@
         cancel.addClickHandler(this);
         accept.addClickHandler(new ClickHandler() {
             public void onClick(ClickEvent e) {
-                updateCollection();
+                if(isDialogValid()) {
+                    updateCollection();
+                }
+                else {
+                    GWT.log("Dialog not valid");
+                    SC.warn(MSG.error_dialog_not_valid());
+                }
             }
         });
 
@@ -135,26 +159,29 @@
 
         addItem(tabs);
         addItem(buttons);
-        setWidth(340);
+        setWidth(380);
         setHeight(470);
         centerInPage();
     }
 
+
     /**
      * This method is called when the user aborts theming.
      * @param event The event.
      */
     public void onClick(ClickEvent event) {
-        this.hide();
+        this.destroy();
     }
 
 
     /**
      *
      */
-    protected Canvas generatePropertyGroup(Property group) {
+    protected Canvas generatePropertyGroup(Property group, Property orig) {
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
         PropertyGroup pg = (PropertyGroup)group;
-        List<Property> list = pg.getProperties();
+        PropertyGroup origPg = (PropertyGroup)orig;
 
         if (pg.getName().equals("axis")) {
             Label scale = new Label(MSG.scale() + " :");
@@ -168,24 +195,40 @@
             StringProperty label =
                 (StringProperty)pg.getPropertyByName("label");
             FormItem title = createStringProperty(label);
+            title.setValue(
+                ((StringProperty)origPg.getPropertyByName("label")).getValue());
 
             IntegerProperty fontsize =
                 (IntegerProperty)pg.getPropertyByName("font-size");
             FormItem fs = createIntegerProperty(fontsize);
+            fs.setValue(
+                ((IntegerProperty)
+                    origPg.getPropertyByName("font-size")).getValue());
 
             DoubleProperty upper =
                 (DoubleProperty)pg.getPropertyByName("upper");
             final FormItem range1 = createDoubleProperty(upper);
-            range1.setWidth(50);
+            range1.setName("rangeupper");
+            range1.setWidth(70);
+            range1.setValue(
+                ((DoubleProperty)
+                    origPg.getPropertyByName("upper")).toUIString());
 
             DoubleProperty lower =
                 (DoubleProperty)pg.getPropertyByName("lower");
             final FormItem range2 = createDoubleProperty(lower);
-            range2.setWidth(50);
+            range2.setName("rangelower");
+            range2.setWidth(70);
+            range2.setValue(
+                ((DoubleProperty)
+                    origPg.getPropertyByName("lower")).toUIString());
 
             BooleanProperty fixation =
                 (BooleanProperty)pg.getPropertyByName("fixation");
             FormItem fix = createBooleanProperty(fixation);
+            fix.setValue(((BooleanProperty)
+                origPg.getPropertyByName("fixation")).getValue().booleanValue());
+
             fix.addChangedHandler(new ChangedHandler() {
                 public void onChanged(ChangedEvent e) {
                     if ((Boolean)e.getValue()) {
@@ -198,7 +241,7 @@
                     }
                 }
             });
-            if (fixation.getValue().equals("true")) {
+            if (fix.getValue().toString().equals("true")) {
                 range1.enable();
                 range2.enable();
             }
@@ -208,13 +251,13 @@
             }
 
             form1.setFields(title, fs);
-            form2.setFields(fix, range1, range2);
+            form2.setFields(fix, range2, range1);
 
             HLayout scaleLayout = new HLayout();
             scaleLayout.setHeight(30);
             scaleLayout.addMember(scale);
             scaleLayout.addMember(form2);
-            scaleLayout.addStyleName("property-dialog-axis");
+            scaleLayout.setStyleName("property-dialog-axis");
 
             VLayout root = new VLayout();
             root.addMember(form1);
@@ -228,49 +271,154 @@
 
 
     /**
-     *
+     * Generate a form with items for the properties/settings, preset with
+     * values.
      */
-    protected DynamicForm generatePropertySetting(Property setting) {
-        final PropertySetting s = (PropertySetting)setting;
+    protected DynamicForm generatePropertySetting(
+        Property setting,
+        Property orig)
+    {
+        PropertySetting s = (PropertySetting)setting;
         DynamicForm form = new DynamicForm();
         FormItem item = new FormItem();
         if (setting instanceof BooleanProperty) {
             item = createBooleanProperty((BooleanProperty)setting);
+            item.setValue(((BooleanProperty)orig).getValue().booleanValue());
         }
         else if (setting instanceof DoubleProperty) {
             item = createDoubleProperty((DoubleProperty)setting);
+            item.setValue(((DoubleProperty)orig).toUIString());
         }
         else if (setting instanceof IntegerProperty) {
             item = createIntegerProperty((IntegerProperty)setting);
+            item.setValue(((IntegerProperty)orig).getValue());
         }
         else if (setting instanceof StringProperty) {
-            item = createStringProperty((StringProperty)setting);
+            StringProperty property = (StringProperty) setting;
+            item = createStringProperty(property);
+            item.setValue(((StringProperty)orig).getValue());
+        }
+        else {
+            GWT.log("generatePropertySetting: unknown setting type.");
         }
         form.setFields(item);
         return form;
     }
 
 
-    /**
-     *
-     */
     protected FormItem createStringProperty(final StringProperty sp) {
         String name = sp.getName();
         if (name.contains("-")) {
             name = name.replace("-", "_");
         }
+
+        String choiceAttribute = sp.getAttribute("choice");
+
+        if (choiceAttribute != null && choiceAttribute.equals("logo")) {
+            SelectItem logoChooser = new SelectItem();
+            logoChooser.setImageURLPrefix(GWT.getHostPageBaseURL() + "images/logo-");
+            logoChooser.setValueIconHeight(50);
+            logoChooser.setValueIconWidth(100);
+
+            LinkedHashMap valueMap = new LinkedHashMap<String, String>();
+            LinkedHashMap<String, String> valueIcons = new LinkedHashMap<String, String>();
+            valueMap.put("none", MSG.getString("none"));
+            /*
+             If you want to add images, remember to change code in these places:
+             flys-artifacts:
+             XYChartGenerator.java
+             Timeseries*Generator.java and
+             in the flys-client projects Chart*Propert*Editor.java.
+             Also, these images have to be put in
+             flys-artifacts/src/main/resources/images/
+             flys-client/src/main/webapp/images/
+             */
+            valueMap.put("BfG", "");
+            valueMap.put("Intevation", "");
+            valueIcons.put("BfG", "bfg.gif");
+            valueIcons.put("Intevation", "intevation.png");
+            logoChooser.setValueIcons(valueIcons);
+            logoChooser.setValueMap(valueMap);
+            logoChooser.setTitleStyle("color:#000;");
+            logoChooser.setTitleAlign(Alignment.LEFT);
+            logoChooser.setTitle(MSG.getString(name));
+            logoChooser.setTitleAlign(Alignment.LEFT);
+            logoChooser.addBlurHandler(new BlurHandler() {
+                public void onBlur(BlurEvent e) {
+                    String val;
+                    if (e.getItem().getValue() == null) {
+                        val = "";
+                    }
+                    else {
+                        val = e.getItem().getValue().toString();
+                    }
+                    sp.setValue(val);
+                }
+            });
+            return logoChooser;
+        }
+        else if (choiceAttribute != null && choiceAttribute.equals("placeh")) {
+            SelectItem placeChooser = new SelectItem();
+            LinkedHashMap valueMap = new LinkedHashMap<String, String>();
+            valueMap.put("right", MSG.getString("right"));
+            valueMap.put("left", MSG.getString("left"));
+            valueMap.put("center", MSG.getString("center"));
+            placeChooser.setValueMap(valueMap);
+            placeChooser.setTitleStyle("color:#000;");
+            placeChooser.setTitleAlign(Alignment.LEFT);
+            placeChooser.setTitle(MSG.getString(name));
+            placeChooser.setTitleAlign(Alignment.LEFT);
+            placeChooser.addBlurHandler(new BlurHandler() {
+                public void onBlur(BlurEvent e) {
+                    String val;
+                    if (e.getItem().getValue() == null) {
+                        val = "";
+                    }
+                    else {
+                        val = e.getItem().getValue().toString();
+                    }
+                    sp.setValue(val);
+                }
+            });
+            return placeChooser;
+        }
+        else if (choiceAttribute != null && choiceAttribute.equals("placev")) {
+            SelectItem placeChooser = new SelectItem();
+            LinkedHashMap valueMap = new LinkedHashMap<String, String>();
+            valueMap.put("top", MSG.getString("top"));
+            valueMap.put("bottom", MSG.getString("bottom"));
+            valueMap.put("center", MSG.getString("center"));
+            placeChooser.setValueMap(valueMap);
+            placeChooser.setTitleStyle("color:#000;");
+            placeChooser.setTitleAlign(Alignment.LEFT);
+            placeChooser.setTitle(MSG.getString(name));
+            placeChooser.setTitleAlign(Alignment.LEFT);
+            placeChooser.addBlurHandler(new BlurHandler() {
+                public void onBlur(BlurEvent e) {
+                    String val;
+                    if (e.getItem().getValue() == null) {
+                        val = "";
+                    }
+                    else {
+                        val = e.getItem().getValue().toString();
+                    }
+                    sp.setValue(val);
+                }
+            });
+            return placeChooser;
+        }
+
         TextItem item = new TextItem();
         item.setTitle(MSG.getString(name));
         item.setTitleAlign(Alignment.LEFT);
-        item.setValue(sp.getValue());
-        item.addChangedHandler(new ChangedHandler() {
-            public void onChanged(ChangedEvent e) {
+        item.addBlurHandler(new BlurHandler() {
+            public void onBlur(BlurEvent e) {
                 String val;
-                if (e.getValue() == null) {
+                if (e.getItem().getValue() == null) {
                     val = "";
                 }
                 else {
-                    val = e.getValue().toString();
+                    val = e.getItem().getValue().toString();
                 }
                 sp.setValue(val);
             }
@@ -292,20 +440,14 @@
         item.setLabelAsTitle(true);
         item.setTitleStyle("color:#000;");
         item.setTitleAlign(Alignment.LEFT);
-        if(bp.getValue().equals("true")) {
-            item.setValue(true);
-        }
-        else {
-            item.setValue(false);
-        }
-        item.addChangedHandler(new ChangedHandler() {
-            public void onChanged(ChangedEvent e) {
+        item.addBlurHandler(new BlurHandler() {
+            public void onBlur(BlurEvent e) {
                 String val;
-                if (e.getValue() == null) {
+                if (e.getItem().getValue() == null) {
                     val = "";
                 }
                 else {
-                    val = e.getValue().toString();
+                    val = e.getItem().getValue().toString();
                 }
                 bp.setValue(val);
             }
@@ -326,17 +468,14 @@
         TextItem item = new TextItem();
         item.setTitle(MSG.getString(name));
         item.setTitleAlign(Alignment.LEFT);
-        item.setValue(dp.getValue());
-        item.addChangedHandler(new ChangedHandler() {
-            public void onChanged(ChangedEvent e) {
-                String val;
-                if (e.getValue() == null) {
-                    val = "";
-                }
-                else {
-                    val = e.getValue().toString();
-                }
-                dp.setValue(val);
+        item.addBlurHandler(new BlurHandler() {
+            public void onBlur(BlurEvent e) {
+                 DoubleValidator validator = new DoubleValidator();
+                 Map errors = e.getForm().getErrors();
+                 if(validator.validate(e.getItem(), errors)) {
+                     dp.setValueFromUI(e.getItem().getValue().toString());
+                 }
+                 e.getForm().setErrors(errors, true);
             }
         });
         return item;
@@ -355,17 +494,14 @@
         TextItem item = new TextItem();
         item.setTitle(MSG.getString(name));
         item.setTitleAlign(Alignment.LEFT);
-        item.setValue(ip.getValue());
-        item.addChangedHandler(new ChangedHandler() {
-            public void onChanged(ChangedEvent e) {
-                String val;
-                if (e.getValue() == null) {
-                    val = "";
+        item.addBlurHandler(new BlurHandler() {
+            public void onBlur(BlurEvent e) {
+                IntegerValidator validator = new IntegerValidator();
+                Map errors = e.getForm().getErrors();
+                if(validator.validate(e.getItem(), errors)) {
+                    ip.setValue(e.getItem().getValue().toString());
                 }
-                else {
-                    val = e.getValue().toString();
-                }
-                ip.setValue(val);
+                e.getForm().setErrors(errors, true);
             }
         });
         return item;
@@ -378,6 +514,8 @@
 
         GWT.log("PropertiesEditor.updateCollection via RPC now");
 
+        Settings s = settings;
+        collection.addSettings(this.tab.getOutputName(), s);
         updater.update(collection, loc, new AsyncCallback<Collection>() {
             public void onFailure(Throwable caught) {
                 GWT.log("Could not update collection attributes.");
@@ -390,8 +528,69 @@
     }
 
     protected void updateChartTab() {
-        this.hide();
         this.tab.updateChartInfo();
         this.tab.updateChartPanel();
+        this.destroy();
+    }
+
+
+    protected boolean isDialogValid() {
+        boolean valid = true;
+        for (int i = 0; i < tabs.getNumTabs(); i++) {
+            Tab t = tabs.getTab(i);
+            Canvas container = t.getPane();
+            Canvas[] children = container.getChildren();
+            for (Canvas c: children) {
+                valid = validateCanvas(c);
+                if(!valid) {
+                    return valid;
+                }
+            }
+        }
+        return valid;
+    }
+
+
+    protected boolean validateCanvas(Canvas c) {
+        boolean valid = true;
+        if(c instanceof DynamicForm) {
+            DynamicForm f = (DynamicForm) c;
+            FormItem up = f.getItem("rangeupper");
+            FormItem lo = f.getItem("rangelower");
+
+            if(up != null && lo != null &&
+               !up.isDisabled() && !lo.isDisabled())
+            {
+                validateRange(f);
+            }
+            return !f.hasErrors();
+        }
+        else if(c.getChildren().length > 0) {
+            for (Canvas child: c.getChildren()) {
+                valid = validateCanvas(child);
+                if(!valid) {
+                    return valid;
+                }
+            }
+        }
+        return valid;
+    }
+
+    protected boolean validateRange(DynamicForm form) {
+        Map errors = form.getErrors();
+        FormItem up = form.getItem("rangeupper");
+        FormItem lo = form.getItem("rangelower");
+
+        String v1 = up.getValue().toString();
+        String v2 = lo.getValue().toString();
+
+        if(v1.equals(v2)) {
+            errors.put(up.getFieldName(), MSG.wrongFormat());
+            errors.put(lo.getFieldName(), MSG.wrongFormat());
+            form.setErrors(errors, true);
+            return false;
+        }
+        return true;
     }
 }
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/ChartThemePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -18,7 +18,6 @@
 import com.smartgwt.client.util.SC;
 
 import de.intevation.flys.client.shared.model.Artifact;
-import de.intevation.flys.client.shared.model.Collection;
 import de.intevation.flys.client.shared.model.Data;
 import de.intevation.flys.client.shared.model.DefaultData;
 import de.intevation.flys.client.shared.model.DefaultArtifact;
@@ -54,9 +53,6 @@
     /** The interface that provides i18n messages. */
     protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
 
-    /** The collection */
-    protected Collection collection;
-
     public static final String GRID_FIELD_ACTIVE  = "active";
     public static final String GRID_FIELD_NAME    = "name";
     public static final String GRID_FIELD_ACTIONS = "actions";
@@ -65,13 +61,12 @@
         de.intevation.flys.client.client.services.FeedService.class);
 
 
+    /** Constructor for a ChartThemePanel. */
     public ChartThemePanel(
-        Collection collection,
         OutputMode mode,
         CollectionView view
     ) {
-        super(collection, mode, view);
-        this.collection = collection;
+        super(mode, view);
 
         initGrid();
         initLayout();
@@ -80,6 +75,7 @@
     }
 
 
+    /** Creates Layout with theme list and navigation bar inside. */
     protected VLayout createLayout() {
         VLayout layout = new VLayout();
         layout.setWidth100();
@@ -142,6 +138,13 @@
     }
 
 
+    /** Create the DataProvider ('Blackboard') key for a theme. */
+    public static String areaKey(Theme theme) {
+        return theme.getArtifact() + ":" + theme.getFacet() + ":"
+            + theme.getIndex();
+    }
+
+
     /**
      * Tell an area artifact where to get the upper and lower curve from.
      * @param artifact UUID of area-artifact.
@@ -152,15 +155,14 @@
         Theme over,
         boolean between
     ) {
-
         Data[] feedData;
 
         if (over != null && under != null) {
             feedData = new Data[] {
                 DefaultData.createSimpleStringData("area.curve_under",
-                    under.getArtifact() + under.getIndex()),
+                    areaKey(under)),
                 DefaultData.createSimpleStringData("area.curve_over",
-                    over.getArtifact() + over.getIndex()),
+                    areaKey(over)),
                 DefaultData.createSimpleStringData("area.name",
                     over.getDescription() + " / " + under.getDescription()),
                 DefaultData.createSimpleStringData("area.facet",
@@ -168,12 +170,12 @@
                 DefaultData.createSimpleStringData("area.between",
                     (between)? "true" : "false")
             };
-            GWT.log("Have over and under");
+            GWT.log("Have 'over' and 'under' curve");
         }
         else if (over == null && under != null) {
             feedData = new Data[] {
                 DefaultData.createSimpleStringData("area.curve_under",
-                    under.getArtifact() + under.getIndex()),
+                    areaKey(under)),
                 DefaultData.createSimpleStringData("area.name",
                     under.getDescription() + " / " + MSG.getString("x_axis")),
                 DefaultData.createSimpleStringData("area.facet",
@@ -181,12 +183,12 @@
                 DefaultData.createSimpleStringData("area.between",
                     (between)? "true" : "false")
             };
-            GWT.log("Have under only");
+            GWT.log("Have 'under' curve only");
         }
         else if (over != null && under == null) {
             feedData = new Data[] {
                 DefaultData.createSimpleStringData("area.curve_over",
-                    over.getArtifact() + over.getIndex()),
+                    areaKey(over)),
                 DefaultData.createSimpleStringData("area.name",
                     MSG.getString("x_axis") + " / " + over.getDescription()),
                 DefaultData.createSimpleStringData("area.facet",
@@ -194,14 +196,13 @@
                 DefaultData.createSimpleStringData("area.between",
                     (between)? "true" : "false")
             };
-            GWT.log("Have over only");
+            GWT.log("Have 'over' curve only");
         }
         else {
             GWT.log("Missing Data for area painting.");
             return;
         }
 
-
         feedService.feed(
             Config.getInstance().getLocale(),
             new DefaultArtifact(artifact, "TODO:hash"),
@@ -213,7 +214,7 @@
                     SC.warn(MSG.getString(caught.getMessage()));
                     enable();
                 }
-                public void onSuccess(Artifact artifact) {
+                public void onSuccess(Artifact fartifact) {
                     GWT.log("Successfully set area params to " + artifact);
                     requestRedraw();
                     updateCollection();
@@ -246,7 +247,7 @@
         Recommendation[] recommendations = new Recommendation[] {area};
 
         loadService.loadMany(
-            this.collection,
+            this.getCollection(),
             recommendations,
             null, //use individual factories.
             locale,
@@ -263,10 +264,10 @@
                     feedTellArea(artifacts[0].getUuid(), under, over, between);
                 }
             }
-            );
+        );
     }
 
-    
+
     /**
      * Return true if two themes are canditates for an area being
      * rendered between them.
@@ -300,8 +301,32 @@
     }
 
 
+    /** Attach menu/item to open editor for Manual Points. */
+    protected void attachManualPointsMenu(Menu menu) {
+        menu.addItem(createSeparator());
+        MenuItem editManualPoints = new MenuItem(MSG.editpoints());
+
+        editManualPoints.addClickHandler(new ClickHandler() {
+                public void onClick(MenuItemClickEvent evt) {
+                    if(mode.getName().equals("historical_discharge")) {
+                        new ManualDatePointsEditor(view.getCollection(),
+                            redrawRequestHandlers.get(0),
+                            mode.getName()).show();
+                    }
+                    else {
+                        new ManualPointsEditor(view.getCollection(),
+                            redrawRequestHandlers.get(0),
+                            mode.getName()).show();
+                    }
+                }
+            });
+        menu.addItem(editManualPoints);
+    }
+
+
     /**
-     * Include area specific menu items.
+     * Include area specific menu items and manual point editor, depending
+     * on facet.
      */
     protected Menu getSingleContextMenu(final ListGridRecord[] records) {
         Menu menu = super.getSingleContextMenu(records);
@@ -309,9 +334,15 @@
         final Theme facetTheme = ((FacetRecord)records[0]).getTheme();
         String thisItem = facetTheme.getDescription();
         if (!canArea(facetTheme)) {
-            return menu;
+            if (facetTheme.getFacet().endsWith("manualpoints")) {
+                attachManualPointsMenu(menu);
+                return menu;
+            }
+            else {
+                return menu;
+            }
         }
-        
+
         menu.addItem(createSeparator());
 
         MenuItem areaMenuItem = new MenuItem(MSG.chart_themepanel_new_area());
@@ -320,13 +351,20 @@
         ThemeList themes = getThemeList();
         int nThemes      = themes.getThemeCount();
 
+        // Create the "under..." submenu.
         MenuItem underMenuItem = new MenuItem(MSG.chart_themepanel_area_under());
         Menu underMenu = new Menu();
         for (int i = 0; i < nThemes; i++)  {
             final Theme theme = themes.getThemeAt(i+1);
+
+            if (theme.getVisible() == 0) {
+                continue;
+            }
+
             if (!areAreaCompatible(facetTheme, theme)) {
                 continue;
             }
+
             MenuItem againster = new MenuItem(theme.getDescription());
             underMenu.addItem(againster);
 
@@ -338,10 +376,14 @@
             });
         }
 
+        // Create the "over..." submenu.
         MenuItem overMenuItem = new MenuItem(MSG.chart_themepanel_area_over());
         Menu overMenu = new Menu();
         for (int i = 0; i < nThemes; i++)  {
             final Theme theme = themes.getThemeAt(i+1);
+            if (theme.getVisible() == 0) {
+                continue;
+            }
             if (!areAreaCompatible(facetTheme, theme)) {
                 continue;
             }
@@ -365,10 +407,14 @@
         });
         overMenu.addItem(againstAxis);
 
+        // Create the "between..." submenu.
         MenuItem betweenMenuItem = new MenuItem(MSG.chart_themepanel_area_between());
         Menu betweenMenu = new Menu();
         for (int i = 0; i < nThemes; i++)  {
             final Theme theme = themes.getThemeAt(i+1);
+            if (theme.getVisible() == 0) {
+                continue;
+            }
             if (!areAreaCompatible(facetTheme, theme)) {
                 continue;
             }
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/ChartToolbar.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,7 +1,7 @@
 package de.intevation.flys.client.client.ui.chart;
 
 import com.google.gwt.core.client.GWT;
-
+import com.smartgwt.client.types.Overflow;
 import com.smartgwt.client.widgets.Button;
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.ImgButton;
@@ -9,54 +9,55 @@
 import com.smartgwt.client.widgets.events.ClickEvent;
 import com.smartgwt.client.widgets.events.ClickHandler;
 
+import de.intevation.flys.client.client.Config;
 import de.intevation.flys.client.client.FLYSConstants;
-import de.intevation.flys.client.client.ui.CollectionView;
+import de.intevation.flys.client.client.event.ZoomEvent;
+import de.intevation.flys.client.client.event.ZoomHandler;
 import de.intevation.flys.client.client.ui.ImgLink;
 import de.intevation.flys.client.client.ui.Toolbar;
 
 
 /**
+ * Toolbar with buttons/icons to open datacage, switch to zoom mode, zoom out
+ * etc.
+ *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
-public class ChartToolbar extends Toolbar {
+public class ChartToolbar extends Toolbar implements ZoomHandler {
 
     protected static FLYSConstants MSG = GWT.create(FLYSConstants.class);
 
-
-    public static final int PANEL_HEIGHT = 30;
-
-
-    protected ChartOutputTab chartTab;
-
-
-    protected Button datacage;
-
-    protected Canvas downloadPNG;
-
-    protected Canvas downloadPDF;
+    public static final int PANEL_HEIGHT = 35;
 
-    protected Canvas downloadSVG;
-
+    protected Button manageThemes;
+    protected Button datacage;
+    protected ImgLink downloadPNG;
+    protected ImgLink downloadPDF;
+    protected ImgLink downloadSVG;
+    protected Canvas downloadCSV;
     protected MousePositionPanel position;
-
     protected ZoomboxControl zoombox;
-
     protected ImgButton zoomToMaxExtent;
-
     protected ImgButton historyBack;
-
     protected ImgButton zoomOut;
-
     protected ImgButton chartProperties;
-
+    protected Button addPoints;
+    protected Button addWSP;
+    protected ImgLink exportAT;
     protected PanControl panControl;
 
 
+    /** @param chartTab Output-Tab on which this toolbar is located. */
+    public ChartToolbar(ChartOutputTab chartTab) {
+        super(chartTab);
+        initTools();
+    }
 
-    public ChartToolbar(CollectionView view, ChartOutputTab chartTab) {
-        super(chartTab);
 
-        this.chartTab   = chartTab;
+    protected void initTools() {
+        ChartOutputTab chartTab = getChartOutputTab();
+
+        manageThemes    = new Button(MSG.manageThemes());
         datacage        = new Button(MSG.databasket());
         position        = new MousePositionPanel(chartTab);
         zoombox         = new ZoomboxControl(chartTab, MSG.zoom_in());
@@ -65,8 +66,38 @@
         historyBack     = new ImgButton();
         panControl      = new PanControl(chartTab, MSG.pan());
         chartProperties = new ImgButton();
+        addPoints       = new Button(MSG.points());
+
+        if (chartTab.getMode().getName().equals("cross_section")) {
+            addWSP = new Button(MSG.addWSPButton());
+            addWSP.setTooltip(MSG.addWSPTooltip());
+            final ChartOutputTab finalChartTab = chartTab;
+            addWSP.addClickHandler(new ClickHandler() {
+                @Override
+                public void onClick(ClickEvent ce) {
+                    new ManualWSPEditor(finalChartTab.getView().getCollection(),
+                        finalChartTab, finalChartTab.getMode().getName()).show();
+                    }});
+        }
+
+        addPoints.addClickHandler(new ClickHandler() {
+            @Override
+            public void onClick(ClickEvent event) {
+                openPointWindow();
+            }
+        });
+        addPoints.setTooltip(MSG.addPointsTooltip());
+
+        manageThemes.addClickHandler(new ClickHandler() {
+
+            @Override
+            public void onClick(ClickEvent event) {
+                getChartOutputTab().toggleThemePanel();
+            }
+        });
 
         datacage.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 GWT.log("Clicked 'datacage' button.");
                 openDatacageWindow((ChartOutputTab) getOutputTab());
@@ -74,105 +105,137 @@
         });
 
         String baseUrl = GWT.getHostPageBaseURL();
+        String moduleUrl = GWT.getModuleBaseURL();
+        Config config = Config.getInstance();
+
+        if (chartTab.getMode().getName().equals("fix_wq_curve")) {
+            exportAT = new ImgLink(
+                baseUrl + MSG.downloadCSV(),
+                moduleUrl + "export" +
+                   "?uuid=" + chartTab.getCollection().identifier() +
+                   "&mode=" + chartTab.getMode().getName() + "_at_export" +
+                   "&type=at" +
+                   "&server=" + config.getServerUrl() +
+                   "&locale=" + config.getLocale() +
+                   "&km=" + chartTab.getCollectionView().getCurrentKm(),
+                20,
+                20
+            );
+            exportAT.setTooltip(MSG.exportATTooltip());
+        }
 
         downloadPNG = new ImgLink(
             baseUrl + MSG.downloadPNG(),
             chartTab.getExportUrl(-1, -1, "png"),
             20,
             20);
+        downloadPNG.setTooltip(MSG.downloadPNGTooltip());
 
         downloadPDF = new ImgLink(
             baseUrl + MSG.downloadPDF(),
             chartTab.getExportUrl(1280, 1024, "pdf"),
             20,
             20);
+        downloadPDF.setTooltip(MSG.downloadPDFTooltip());
 
         downloadSVG = new ImgLink(
             baseUrl + MSG.downloadSVG(),
             chartTab.getExportUrl(1280, 1024, "svg"),
             20,
             20);
+        downloadSVG.setTooltip(MSG.downloadSVGTooltip());
+
+        downloadCSV = new ImgLink(
+            baseUrl + MSG.downloadCSV(),
+            chartTab.getExportUrl(-1, -1, "csv"),
+            20,
+            20);
+        downloadCSV.setTooltip(MSG.downloadCSVTooltip());
 
         zoomToMaxExtent.setSrc(baseUrl + MSG.zoom_all());
-        zoomToMaxExtent.setWidth(20);
-        zoomToMaxExtent.setHeight(20);
-        zoomToMaxExtent.setShowDown(false);
-        zoomToMaxExtent.setShowRollOver(false);
-        zoomToMaxExtent.setShowDisabled(false);
-        zoomToMaxExtent.setShowDisabledIcon(true);
-        zoomToMaxExtent.setShowDownIcon(false);
-        zoomToMaxExtent.setShowFocusedIcon(false);
+        adjustImageButton(zoomToMaxExtent);
         zoomToMaxExtent.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 getChartOutputTab().resetRanges();
+                // Relink the export buttons.
+                onZoom(null);
             }
         });
+        zoomToMaxExtent.setTooltip(MSG.zoomToMaxExtentTooltip());
 
         zoomOut.setSrc(baseUrl + MSG.zoom_out());
-        zoomOut.setWidth(20);
-        zoomOut.setHeight(20);
-        zoomOut.setShowDown(false);
-        zoomOut.setShowRollOver(false);
-        zoomOut.setShowDisabled(false);
-        zoomOut.setShowDisabledIcon(true);
-        zoomOut.setShowDownIcon(false);
-        zoomOut.setShowFocusedIcon(false);
+        adjustImageButton(zoomOut);
         zoomOut.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 getChartOutputTab().zoomOut(10);
+                // Relink the export buttons.
+                onZoom(null);
             }
         });
+        zoomOut.setTooltip(MSG.zoomOutTooltip());
 
         historyBack.setSrc(baseUrl + MSG.zoom_back());
-        historyBack.setWidth(20);
-        historyBack.setHeight(20);
-        historyBack.setShowDown(false);
-        historyBack.setShowRollOver(false);
-        historyBack.setShowDisabled(false);
-        historyBack.setShowDisabledIcon(true);
-        historyBack.setShowDownIcon(false);
-        historyBack.setShowFocusedIcon(false);
+        adjustImageButton(historyBack);
         historyBack.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 getChartOutputTab().zoomOut();
+                // Relink the export buttons.
+                onZoom(null);
             }
         });
+        historyBack.setTooltip(MSG.historyBackTooltip());
 
         zoombox.addZoomHandler(chartTab);
+        zoombox.addZoomHandler(this);
         zoombox.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 panControl.deselect();
             }
         });
+        zoombox.setTooltip(MSG.zoomboxTooltip());
 
         panControl.addPanHandler(chartTab);
         panControl.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 zoombox.deselect();
             }
         });
+        panControl.setTooltip(MSG.panControlTooltip());
 
         chartProperties.setSrc(baseUrl + MSG.properties_ico());
-        chartProperties.setWidth(20);
-        chartProperties.setHeight(20);
-        chartProperties.setShowDown(false);
-        chartProperties.setShowRollOver(false);
-        chartProperties.setShowDisabled(false);
-        chartProperties.setShowDisabledIcon(true);
-        chartProperties.setShowDownIcon(false);
-        chartProperties.setShowFocusedIcon(false);
+        adjustImageButton(chartProperties);
         chartProperties.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 openPropertiesEditor();
             }
         });
+        chartProperties.setTooltip(MSG.chartPropertiesTooltip());
 
         initLayout();
     }
 
+    /** Set width, height and other properties of an imagebutton. */
+    public void adjustImageButton(ImgButton imgButton) {
+        imgButton.setWidth(20);
+        imgButton.setHeight(20);
+        imgButton.setShowDown(false);
+        imgButton.setShowRollOver(false);
+        imgButton.setShowRollOverIcon(false);
+        imgButton.setShowDisabled(false);
+        imgButton.setShowDisabledIcon(true);
+        imgButton.setShowDownIcon(false);
+        imgButton.setShowFocusedIcon(false);
+    }
 
-    public ChartOutputTab getChartOutputTab() {
-        return chartTab;
+
+    protected ChartOutputTab getChartOutputTab() {
+        return (ChartOutputTab)getOutputTab();
     }
 
 
@@ -188,18 +251,31 @@
         datacage.setWidth("95px");
         position.setWidth("200px");
 
+        addMember(manageThemes);
         addMember(datacage);
         addMember(downloadPNG);
         addMember(downloadPDF);
         addMember(downloadSVG);
+        addMember(downloadCSV);
+        if (getChartOutputTab().getMode().getName().equals("fix_wq_curve")) {
+            addMember(exportAT);
+        }
         addMember(zoomToMaxExtent);
         addMember(historyBack);
         addMember(zoomOut);
         addMember(zoombox);
         addMember(panControl);
         addMember(chartProperties);
+        addMember(addPoints);
+
+        if (getChartOutputTab().getMode().getName().equals("cross_section")) {
+            addMember(addWSP);
+        }
+
         addMember(spacer);
         addMember(position);
+
+        setOverflow(Overflow.HIDDEN);
     }
 
     /**
@@ -211,5 +287,53 @@
         editor.show();
     }
 
+
+    /** Open editor for custom points. */
+    protected void openPointWindow() {
+        ChartOutputTab chartTab = getChartOutputTab();
+        if (chartTab.getMode().getName().equals("historical_discharge")) {
+            new ManualDatePointsEditor(chartTab.getView().getCollection(),
+                chartTab, chartTab.getMode().getName()).show();
+        }
+        else {
+            new ManualPointsEditor(chartTab.getView().getCollection(),
+                chartTab, chartTab.getMode().getName()).show();
+        }
+    }
+
+
+    /**
+     * Sets new sources to the export button/images, such that the
+     * correct zoom values are included in the request when clicked.
+     * @param evt ignored.
+     */
+    @Override
+    public void onZoom(ZoomEvent evt) {
+        ChartOutputTab chartTab = getChartOutputTab();
+        downloadPNG.setSource(chartTab.getExportUrl(-1, -1, "png"));
+        downloadPDF.setSource(chartTab.getExportUrl(-1, -1, "pdf"));
+        downloadSVG.setSource(chartTab.getExportUrl(-1, -1, "svg"));
+    }
+
+    public void deselectControls() {
+        zoombox.deselect();
+    }
+
+    public void updateLinks() {
+        ChartOutputTab chartTab = getChartOutputTab();
+        String moduleUrl = GWT.getModuleBaseURL();
+        Config config = Config.getInstance();
+
+        if (chartTab.getMode().getName().equals("fix_wq_curve")) {
+            exportAT.setSource(
+                   moduleUrl + "export" +
+                   "?uuid=" + chartTab.getCollection().identifier() +
+                   "&mode=" + chartTab.getMode().getName() + "_at_export" +
+                   "&type=at" +
+                   "&server=" + config.getServerUrl() +
+                   "&locale=" + config.getLocale() +
+                   "&km=" + chartTab.getCollectionView().getCurrentKm());
+        }
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,36 +1,31 @@
 package de.intevation.flys.client.client.ui.chart;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.LinkedHashMap;
-
 import com.google.gwt.core.client.GWT;
-
 import com.google.gwt.user.client.rpc.AsyncCallback;
-
+import com.smartgwt.client.types.ListGridFieldType;
 import com.smartgwt.client.util.SC;
-
-import com.smartgwt.client.types.Alignment; 
-import com.smartgwt.client.types.ListGridFieldType;
-
 import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
 import com.smartgwt.client.widgets.grid.ListGrid;
 import com.smartgwt.client.widgets.grid.ListGridField;
 import com.smartgwt.client.widgets.grid.ListGridRecord;
-import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.layout.VLayout;
-import com.smartgwt.client.widgets.form.fields.SpinnerItem;
-import com.smartgwt.client.widgets.form.DynamicForm;
-
-import com.smartgwt.client.widgets.form.fields.SelectItem;
-import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
-import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
-import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
-import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
+import com.smartgwt.client.widgets.menu.Menu;
+import com.smartgwt.client.widgets.menu.MenuItem;
+import com.smartgwt.client.widgets.menu.events.ClickHandler;
+import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;
 
 import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.services.CrossSectionKMServiceAsync;
+import de.intevation.flys.client.client.services.LoadArtifactService;
+import de.intevation.flys.client.client.services.LoadArtifactServiceAsync;
+import de.intevation.flys.client.client.ui.CollectionView;
+import de.intevation.flys.client.client.widgets.KMSpinner;
+import de.intevation.flys.client.client.widgets.KMSpinnerChangeListener;
 import de.intevation.flys.client.shared.model.Artifact;
-import de.intevation.flys.client.shared.model.Collection;
 import de.intevation.flys.client.shared.model.Data;
 import de.intevation.flys.client.shared.model.DefaultArtifact;
 import de.intevation.flys.client.shared.model.DefaultData;
@@ -39,23 +34,25 @@
 import de.intevation.flys.client.shared.model.Theme;
 import de.intevation.flys.client.shared.model.ThemeList;
 
-import de.intevation.flys.client.client.services.CrossSectionKMServiceAsync;
-import de.intevation.flys.client.client.services.FeedServiceAsync;
-import de.intevation.flys.client.client.services.LoadArtifactService;
-import de.intevation.flys.client.client.services.LoadArtifactServiceAsync;
-
-import de.intevation.flys.client.client.ui.CollectionView;
-
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
 
 
 /**
  * ThemePanel much like ChartThemePanel, but shows an "Actions" column,
  * needed for interaction in the CrossSection Charts and a selector to
- * declare which cross section profile is "master".
+ * declare which cross section profile is "master" (waterlevels refer to the
+ * chosen kilometer of that cross section profile).
  * Also can show 'area creation' context menus.
  */
 public class CrossSectionChartThemePanel
-extends      ChartThemePanel {
+extends ChartThemePanel
+implements KMSpinnerChangeListener
+{
     /** Artifact Clone/Creation service. */
     protected LoadArtifactServiceAsync loadService =
                 GWT.create(LoadArtifactService.class);
@@ -76,16 +73,24 @@
     /** Data item name for CrossSections selected km. */
     protected static String CS_IS_MASTER = "cross_section.master?";
 
+    /** List of cross-section themes through which is moved through synchronously. */
+    protected HashSet synchronCrossSectionThemes = new HashSet();
+
+    /** Data for master artifact combobox.*/
+    protected LinkedHashMap<String, String> masters;
+
+    /** Combobox for master artifacts.*/
+    protected SelectItem masterCb;
+
 
     /**
      * Trivial constructor.
      */
     public CrossSectionChartThemePanel(
-        Collection collection,
         OutputMode mode,
         CollectionView view)
     {
-        super(collection, mode, view);
+        super(mode, view);
     }
 
 
@@ -97,7 +102,13 @@
 
     /** Access data of collection item of theme. */
     public static String dataOf(Theme theme, String dataItemName) {
-        return theme.getCollectionItem().getData().get(dataItemName);
+        if (theme != null && theme.getCollectionItem() != null
+            && theme.getCollectionItem().getData() != null
+        ) {
+            return theme.getCollectionItem().getData().get(dataItemName);
+        }
+
+        return null;
     }
 
 
@@ -130,7 +141,6 @@
     }
 
 
-
     /**
      * Sets currentCSMasterUUID.
      */
@@ -152,19 +162,6 @@
                     setCurrentCSMaster(theme.getArtifact());
                     GWT.log("found a master: " + currentCSMasterUUID
                         + "/" + theme.getDescription());
-                    Theme collectionMaster = getThemeList().getTheme(
-                        view.getArtifact().getUuid());
-                    if (!dataOf(theme, CS_KM)
-                            .equals(dataOf(collectionMaster, CS_KM))
-                    ) {
-                        // Tell Collection Master which kilometer the Cross-
-                        // Section Master is at, to have consistent subtitle
-                        // in diagram.
-                        // TODO fix
-                        //sendFeed(view.getArtifact().getUuid(),
-                        //    Double.valueOf(dataOf(theme, CS_KM)));
-                    }
-
                     return theme.getDescription();
                 }
             }
@@ -173,12 +170,6 @@
         if (firstCSUuid != null) {
             setCurrentCSMaster(firstCSUuid);
             feedTellMaster(firstCSUuid);
-            // Tell Collection Master which kilometer the Cross-
-            // Section Master is at, to have consistent subtitle
-            // in diagram.
-            // TODO fix
-            //sendFeed(view.getArtifact().getUuid(),
-            //    Double.valueOf(dataOf(firstCS, CS_KM)));
         }
         return null;
     }
@@ -192,28 +183,27 @@
         layout = super.createLayout();
 
         // Create "set master" combobox.
-        SelectItem cbItem = new SelectItem();
+        masterCb = new SelectItem();
 
-        cbItem.setTitle(MSG.chart_themepanel_set_master());
-        cbItem.setType("comboBox");
-        final LinkedHashMap<String, String> valueMap =
-            getThemeList().toMapArtifactUUIDDescription("cross_section");
-        cbItem.setValueMap(valueMap);
+        masterCb.setTitle(MSG.chart_themepanel_set_master());
+        masterCb.setType("comboBox");
+        masters = getThemeList().toMapArtifactUUIDDescription("cross_section");
+        masterCb.setValueMap(masters);
 
         final DynamicForm form = new DynamicForm();
         form.setWidth(200);
-        form.setFields(cbItem);
-        layout.addMember(form);
+        form.setFields(masterCb);
+        layout.addMember(form, 0);
 
         Config config       = Config.getInstance();
         final String locale = config.getLocale();
         findCurrentCSMaster();
-        cbItem.setValue(getCurrentCSMaster());
+        masterCb.setValue(getCurrentCSMaster());
 
         // Add Change Handler to first unset the old master and then set the
         // new master.
-        cbItem.addChangeHandler(new ChangeHandler() {
-            public void onChange(ChangeEvent event) {  
+        masterCb.addChangeHandler(new ChangeHandler() {
+            public void onChange(ChangeEvent event) {
                 String selectedItem   = (String) event.getValue();
                 final String artifact = selectedItem;
 
@@ -229,7 +219,8 @@
                         feedData,
                         new AsyncCallback<Artifact>() {
                             public void onFailure(Throwable caught) {
-                                GWT.log("Could not un-master artifact ("+getCurrentCSMaster()+"): " +
+                                GWT.log("Could not un-master artifact ("
+                                    + getCurrentCSMaster() + "): " +
                                     caught.getMessage());
                                 SC.warn(MSG.getString(caught.getMessage()));
                                 enable();
@@ -243,7 +234,7 @@
                 else {
                     feedTellMaster(artifact);
                 }
-            }  
+            }
         });
 
         return layout;
@@ -251,12 +242,14 @@
 
 
     /** Disable the UI (becomes gray, inresponsive to user input). */
+    @Override
     public void disable() {
         this.layout.setDisabled(true);
     }
 
 
     /** DisDisable the UI (becomes ungray, responsive to user input). */
+    @Override
     public void enable() {
         this.layout.setDisabled(false);
     }
@@ -268,23 +261,33 @@
      * the last one is taken.
      * @param in possible return values.
      * @param to the value to be as close to as possible.
+     * @param up if true, prefer numerically higher values in case of two
+     *           values with equal distance to \param to.
      * @return value from in that is closest to to, -1 if none.
      */
-    public static double closest(Double[] in, double to) {
+    public static double closest(Double[] in, double to, boolean up) {
         if (in == null || in.length == 0) {
             return -1;
         }
         if (in[0] == to) {
             return to;
         }
+        for (int i = 0; i < in.length; i++) {
+            GWT.log ("Close? " + in[i]);
+        }
+
         double minDiff = Math.abs(to - in[0]);
         double bestMatch = in[0];
         for (int i = 1; i < in.length; i++) {
             if (in[i] == to) {
                 return to;
             }
-            double diff = Math.abs(to - in[0]);
-            if (diff < minDiff) {
+            if ((in[i] < to && up)
+                || (in[i] > to && !up)) {
+                continue;
+            }
+            double diff = Math.abs(to - in[i]);
+            if (diff <= minDiff) {
                 minDiff = diff;
                 bestMatch = in[i];
             }
@@ -293,8 +296,51 @@
     }
 
 
-    /** Feed a single artifact with the km of the crosssection to display.
-     * If its the selected master, also feed the collectionmaster. */
+    /**
+     * Feed a single artifact with the km of the crosssection to display.
+     * If its the selected master, also feed the collectionmaster.
+     *
+     * @param artifacts List of artifacts to feed.
+     * @param kmD       The km to set.
+     */
+    public void sendFeed(final List<Artifact> artifacts, final double kmD) {
+        Config config       = Config.getInstance();
+        final String locale = config.getLocale();
+
+        Data[] feedData =
+            DefaultData.createSimpleStringDataArray(CS_KM,
+                Double.valueOf(kmD).toString());
+
+        disable();
+        // TODO
+        // The ones who do not have data for this km should not show line!
+        feedService.feedMany(
+            locale,
+            artifacts,
+            feedData,
+            new AsyncCallback<List<Artifact>>() {
+                @Override
+                public void onFailure(Throwable caught) {
+                    GWT.log("Could not feed many artifacts " + caught.getMessage());
+                    SC.warn(MSG.getString(caught.getMessage()));
+                    enable();
+                }
+                @Override
+                public void onSuccess(List<Artifact> artifact) {
+                    GWT.log("Successfully fed many with km");
+                    requestRedraw();
+                    enable();
+                }
+        });
+    }
+
+
+    /**
+     * Feed a single artifact with the km of the crosssection to display.
+     * If its the selected master, also feed the collectionmaster.
+     * @param artUUID The UUID of the artifact to feed.
+     * @param kmD     The km to set.
+     */
     public void sendFeed(final String artUUID, final double kmD) {
         Config config       = Config.getInstance();
         final String locale = config.getLocale();
@@ -319,112 +365,102 @@
                 public void onSuccess(Artifact artifact) {
                     GWT.log("Successfully fed with km");
                     requestRedraw();
-                    // Also feed the winfo/masterartifact (for plot subtitle)
-                    if (artUUID.equals(getCurrentCSMaster())
-                        && !artUUID.equals(view.getArtifact().getUuid())) {
-                        sendFeed(view.getArtifact().getUuid(), kmD);
-                    }
-                    else {
-                        enable();
-                    }
+                    enable();
                 }
         });
     }
 
 
-    /**
-     * Create the handler for ChangeEvents on the Spinner in the
-     * facets that control km of cross section.
-     *
-     * @param feedService The FeedService to send (changed) data to.
-     * @param facetRecord The FacetRecord (~row in table) where this
-     *                    handler is added to (to a child, to be exact).
-     */
-    public final ChangedHandler createSpinnerHandler(
-        final FeedServiceAsync feedService,
-        final FacetRecord      facetRecord)
-    {
-        Config config          = Config.getInstance();
-        final String locale    = config.getLocale();
-
-        ChangedHandler handler = new ChangedHandler()
-            {
-                @Override
-                public void onChanged(final ChangedEvent ce) {
-                    if (ce.getValue() == null) {
-                        return;
-                    }
-
-                    // Now, query the value with the kmService.
-                    Map<Integer, Double> map = new HashMap<Integer,Double>();
-                    final double selected_km =
-                        Double.parseDouble(ce.getValue().toString());
-                    
-                    int _dbid = -1;
-                    try {
-                        _dbid = Integer.valueOf(facetRecord.getTheme()
-                            .getCollectionItem()
-                            .getData().get("cross_section.dbid"));
-                    }
-                    catch (NumberFormatException nfe) {
-                        GWT.log("Could not extract cross-section db id from data.");
-                    }
-                    final int dbid = _dbid;
-
-                    map.put(dbid, Double.parseDouble(ce.getValue().toString()));
-
-                    disable();
-    
-                    kmService.getCrossSectionKMs(locale, map, 2,
-                        new AsyncCallback<Map<Integer, Double[]>>() {
-                            @Override
-                            public void onFailure(Throwable caught) {
-                                GWT.log("Could not get single km for "
-                                    + dbid + ": "+ caught.getMessage());
-                                SC.warn(MSG.getString(caught.getMessage()));
-                                updateCollection();
-                                updateGrid();
-                                enable();
-                            }
-                            @Override
-                            public void onSuccess(Map<Integer, Double[]> obj) {
-                                Double[] kms = obj.get(dbid);
-                                double closest =
-                                    CrossSectionChartThemePanel.closest(kms,
-                                        selected_km);
-                                GWT.log("Got single km for " + dbid + ", it is "
-                                    + closest);
-                                SpinnerItem item = (SpinnerItem) ce.getItem();
-                                item.setValue(closest);
-                                sendFeed(facetRecord.getTheme().getArtifact(),
-                                         closest);
-                            }
-                            });
-                }
-            };
-        return handler;
+    /** Remove the themes, also from the master (reference) select box. */
+    @Override
+    protected void removeThemes(final ListGridRecord[] records) {
+        // TODO take care of what happens if that was the last
+        // cross section and/or the cross section currently selected as master.
+        for (ListGridRecord record: records) {
+            FacetRecord facet = (FacetRecord) record;
+            Theme theme = facet.getTheme();
+            masters.remove(theme.getArtifact());
+        }
+        masterCb.setValueMap(masters);
+        super.removeThemes(records);
     }
 
 
     /**
-     * Create a "kilometer spinner" for CrossSection Facets.
-     * @param facetRecord The respective Facet/Theme.
-     * @return label, intialized SpinnerItem.
+     * Callback for when a value has been accepted in the km-spinner
+     * of a Cross-Section Profile theme.
+     * @param item        The SpinnerItem which was manipulated.
+     * @param enteredKm   The double-parsed value that has been entered.
+     * @param facetRecord The underlying datastores record.
+     * @param up          If true, numerically higher values are preferred if
+     *                    two values in \param in are in the same distance to
+     *                    \param to.
      */
-    public SpinnerItem createSpinnerItem(FacetRecord facetRecord) {
-        SpinnerItem spinnerItem = new SpinnerItem();
-        spinnerItem.setShowTitle(false);
-        spinnerItem.setTitle("Waterlevel-Spinner");
-        spinnerItem.setWidth(45);
-        spinnerItem.setDefaultValue(facetRecord.getTheme()
-            .getCollectionItem()
-            .getData().get(CS_KM));
+    public void spinnerValueEntered(KMSpinner spinner, final double enteredKm, final FacetRecord facetRecord, final boolean up) {
+        disable();
+        Config config       = Config.getInstance();
+        final String locale = config.getLocale();
 
-        spinnerItem.setMin(0);
-        spinnerItem.setMax(2000);
-        spinnerItem.setStep(0.5f);
-        spinnerItem.setChangeOnKeypress(true);
-        return spinnerItem;
+        Map<Integer, Double> map = new HashMap<Integer,Double>();
+        int _dbid = -1;
+        try {
+            _dbid = Integer.valueOf(facetRecord.getTheme()
+                .getCollectionItem()
+                .getData().get("cross_section.dbid"));
+        }
+        catch (NumberFormatException nfe) {
+            GWT.log("Could not extract cross-section db id from data.");
+        }
+        final int dbid = _dbid;
+
+        map.put(dbid, enteredKm);
+
+        // Query the available cross section measurements.
+        kmService.getCrossSectionKMs(locale, map, 2,
+            new AsyncCallback<Map<Integer, Double[]>>() {
+                @Override
+                public void onFailure(Throwable caught) {
+                    GWT.log("Could not get single km for "
+                        + dbid + ": "+ caught.getMessage());
+                    SC.warn(MSG.getString(caught.getMessage()));
+                    updateCollection();
+                    //updateGrid();
+                    enable();
+                }
+
+                @Override
+                public void onSuccess(Map<Integer, Double[]> obj) {
+                    Double[] kms = obj.get(dbid);
+                    double closest =
+                        CrossSectionChartThemePanel.closest(kms, enteredKm, up);
+                    GWT.log("Got single km close to " + enteredKm + " for " + dbid + ", it is "
+                        + closest);
+
+                    // Do not set value, as it will trigger strange
+                    // "javascript" bugs. /*item.setValue(closest);*/
+                    if (synchronCrossSectionThemes.contains (themeHash
+                        (facetRecord.getTheme()))) {
+                        // Move all other synchrons
+                        ThemeList themes = getThemeList();
+                        int nThemes      = themes.getThemeCount();
+                        List<Artifact> artifacts = new ArrayList<Artifact>();
+                        for (int i = 0; i < nThemes; i++) {
+                            final Theme theme = themes.getThemeAt(i+1);
+                            if (theme.getFacet().equals("cross_section") &&
+                                theme.getActive() == 1 &&
+                                synchronCrossSectionThemes.contains(themeHash(theme))
+                                ) {
+                                artifacts.add(artifactReference(theme.getArtifact()));
+                            }
+                        }
+                        sendFeed(artifacts, closest);
+                    }
+                    else {
+                        sendFeed(facetRecord.getTheme().getArtifact(),
+                             closest);
+                    }
+                }
+            });
     }
 
 
@@ -434,6 +470,8 @@
      */
     @Override
     protected ListGrid createGrid() {
+        final CrossSectionChartThemePanel parent = this;
+
         ListGrid list = new ListGrid() {
             @Override
             protected Canvas createRecordComponent(
@@ -451,19 +489,11 @@
                     String fieldName = this.getFieldName(colNum);
 
                     if (fieldName.equals(GRID_FIELD_ACTIONS)) {
-                        HLayout recordCanvas = new HLayout(3);
-                        recordCanvas.setHeight(22);
-                        recordCanvas.setAlign(Alignment.CENTER);
-                        SpinnerItem spinnerItem = createSpinnerItem(facetRecord);
-                        spinnerItem.addChangedHandler(
-                            createSpinnerHandler(feedService, facetRecord));
-
-                        DynamicForm formWrap = new DynamicForm();
-                        formWrap.setFields(spinnerItem);
-                        formWrap.setTitlePrefix("");
-                        formWrap.setTitleSuffix("");
-                        recordCanvas.addMember(formWrap);
-                        return recordCanvas;
+                        double currentValue =
+                            Double.valueOf(facetRecord.getTheme().getCollectionItem().getData().get(CS_KM));
+                        KMSpinner kmSpinner = new KMSpinner(currentValue, facetRecord);
+                        kmSpinner.addChangeListener(parent);
+                        return kmSpinner;
                     }
                     else {
                         return null;
@@ -475,6 +505,7 @@
         list.setShowRecordComponentsByCell(true);
         list.setShowAllRecords(true);
         list.setShowHeaderContextMenu(false);
+        list.setLeaveScrollbarGap(false);
         return list;
     }
 
@@ -502,7 +533,7 @@
         name.setType(ListGridFieldType.TEXT);
 
         ListGridField actions = new ListGridField(GRID_FIELD_ACTIONS,
-             MSG.chart_themepanel_header_actions(), 50);
+             MSG.chart_themepanel_header_actions(), 100);
 
         list.setFields(active, name, actions);
     }
@@ -521,6 +552,7 @@
 
 
     /** Returns name of cross section area facets. */
+    @Override
     protected String getAreaFacetName() {
         return "cross_section.area";
     }
@@ -532,14 +564,15 @@
      * TODO join with canArea, generalize to allow easier modification
      *      in subclasses.
      */
+    @Override
     protected boolean areAreaCompatible(Theme a, Theme b) {
         if (a.equals(b)) {
             return false;
         }
         return (a.getFacet().equals("cross_section")
-                || a.getFacet().equals("cross_section_water_line"))
+                || a.getFacet().endsWith("line"))
             && (b.getFacet().equals("cross_section")
-                || b.getFacet().equals("cross_section_water_line"));
+                || b.getFacet().endsWith("line"));
     }
 
 
@@ -547,9 +580,135 @@
      * True if context menu should contain 'create area' submenu on
      * this theme.
      */
+    @Override
     protected boolean canArea(Theme a) {
         return a.getFacet().equals("cross_section")
-            || a.getFacet().equals("cross_section_water_line");
+            || a.getFacet().equals("cross_section_water_line")
+            || a.getFacet().endsWith("line");
+    }
+
+
+    protected String themeHash(Theme theme) {
+        return theme.getArtifact() + theme.getFacet() + theme.getIndex();
+    }
+
+
+    /**
+     * Include synchron navigation item.
+     */
+    @Override
+    protected Menu getSingleContextMenu(final ListGridRecord[] records) {
+        Menu contextMenu = super.getSingleContextMenu(records);
+
+        Theme facetTheme = ((FacetRecord)records[0]).getTheme();
+        String item = facetTheme.getFacet();
+
+        if (item.equals("cross_section")) {
+            // Synchron checking.
+            MenuItem synchronNavigationMenuItem = new MenuItem();
+            final String themeHash = themeHash(facetTheme);
+            if (synchronCrossSectionThemes.contains(themeHash)) {
+                synchronNavigationMenuItem.setTitle(MSG.chart_themepanel_asynchron());
+                synchronNavigationMenuItem.addClickHandler(new ClickHandler() {
+                    public void onClick(MenuItemClickEvent evt) {
+                        synchronCrossSectionThemes.remove (themeHash);
+                    }
+                });
+            }
+            else {
+                synchronNavigationMenuItem.setTitle(MSG.chart_themepanel_synchron());
+                synchronNavigationMenuItem.addClickHandler(new ClickHandler() {
+                    public void onClick(MenuItemClickEvent evt) {
+                        synchronCrossSectionThemes.add (themeHash);
+                    }
+                });
+            }
+            contextMenu.addItem(synchronNavigationMenuItem);
+        }
+
+        return contextMenu;
+    }
+
+
+    /**
+     * This method is used to clear the current theme grid and add new updated
+     * data.
+     */
+    @Override
+    protected void updateGrid() {
+        GWT.log("CrossSectionChartThemePanel.updateGrid");
+
+        ListGridRecord[] selected = list.getSelectedRecords();
+
+        clearGrid();
+
+        ThemeList themeList = getThemeList();
+
+        if (themeList == null) {
+            GWT.log("ERROR: No theme list.");
+            return;
+        }
+
+        int count = themeList.getThemeCount();
+
+        for (int i = 1; i <= count; i++) {
+            Theme theme = themeList.getThemeAt(i);
+
+            if (theme == null) {
+                continue;
+            }
+
+            if (theme.getFacet().equals("empty.facet")) {
+                theme.setVisible(0);
+            }
+
+            if (theme.getVisible() == 0) {
+                continue;
+            }
+
+            if (theme.getFacet().equals("cross_section")) {
+                addToReferences(theme);
+            }
+
+            FacetRecord newRecord = createRecord(theme);
+            addFacetRecord(newRecord);
+
+            String newArtifact = theme.getArtifact();
+            String newFacet    = theme.getFacet();
+            int    newIndex    = theme.getIndex();
+
+            for (ListGridRecord r: selected) {
+                FacetRecord sel = (FacetRecord) r;
+                Theme oldTheme  = sel.getTheme();
+
+                if (oldTheme.getArtifact().equals(newArtifact)
+                    && oldTheme.getFacet().equals(newFacet)
+                    && oldTheme.getIndex() == newIndex) {
+                    list.selectRecord(newRecord);
+                }
+            }
+        }
+
+        fireOutputParameterChanged();
+
+    }
+
+
+    /**
+     * Adds a cross section theme to the master artifacts combobox and finds
+     * a new master if necessary.
+     *
+     * @param theme The cross section theme.
+     */
+    protected void addToReferences(Theme theme) {
+        if (theme.getVisible() != 0) {
+            masters.put(theme.getArtifact(), theme.getDescription());
+            masterCb.setValueMap(masters);
+        }
+        findCurrentCSMaster();
+        if (masterCb.getSelectedRecord() == null) {
+            masterCb.setValue(getCurrentCSMaster());
+        }
     }
 }
 // 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-client/src/main/java/de/intevation/flys/client/client/ui/chart/ManualDatePointsEditor.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,405 @@
+package de.intevation.flys.client.client.ui.chart;
+
+import java.util.List;
+import java.util.Date;
+
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONBoolean;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.DateTimeFormat;
+
+import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.layout.VLayout;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.IButton;
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
+import com.smartgwt.client.types.ListGridFieldType;
+import com.smartgwt.client.widgets.grid.CellFormatter;
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.smartgwt.client.widgets.grid.CellEditValueParser;
+import com.smartgwt.client.widgets.grid.CellEditValueFormatter;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+
+import com.smartgwt.client.types.Alignment;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.CollectionItem;
+
+import de.intevation.flys.client.shared.model.Settings;
+import de.intevation.flys.client.shared.model.Property;
+import de.intevation.flys.client.shared.model.PropertyGroup;
+import de.intevation.flys.client.shared.model.StringProperty;
+
+import de.intevation.flys.client.client.event.RedrawRequestHandler;
+
+/**
+ * UI to enter point data and save it to an PointArtifact.
+ */
+public class ManualDatePointsEditor
+extends      ManualPointsEditor
+{
+
+    public ManualDatePointsEditor(Collection collection,
+        RedrawRequestHandler handler, String outputModeName
+    ) {
+        super (collection, handler, outputModeName);
+    }
+
+
+    /** Create and setup/add the ui. */
+    public void createUI() {
+        Config config = Config.getInstance();
+
+        Button accept = new Button(MSG.label_ok());
+        Button cancel = new Button(MSG.label_cancel());
+        cancel.addClickHandler(this);
+
+        accept.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent e) {
+                okClicked();
+            }
+        });
+
+        HLayout buttons = new HLayout();
+        buttons.addMember(accept);
+        buttons.addMember(cancel);
+        buttons.setAlign(Alignment.CENTER);
+        buttons.setHeight(30);
+
+        VLayout layout = new VLayout();
+        listGrid = new ListGrid();
+        listGrid.setWidth100();
+        listGrid.setHeight("*");
+        listGrid.setCanSort(false);
+        listGrid.setCanEdit(true);
+        listGrid.setShowHeaderContextMenu(false);
+
+        CellFormatter doubleFormat = new CellFormatter() {
+            public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
+                if(value != null) {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    try {
+                        double d = Double.valueOf(value.toString()).doubleValue();
+                        return nf.format(d);
+                    } catch (Exception e) {
+                        return value.toString();
+                    }
+                } else {
+                   return null;
+                }
+            }};
+
+        CellFormatter dateFormat = new CellFormatter() {
+            public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
+                if(value != null && !value.toString().equals("")) {
+                    try {
+                        DateTimeFormat df =
+                            DateTimeFormat.getFormat("dd.MM.yyyy");
+                        Date d = df.parse(value.toString());
+                        DateTimeFormat df2 =
+                            DateTimeFormat.getFormat(
+                                DateTimeFormat.PredefinedFormat.DATE_MEDIUM);
+                        return df2.format(d);
+
+                    }
+                    catch(IllegalArgumentException iae) {
+                        SC.warn(MSG.error_invalid_date());
+                        record.setAttribute(DatePointRecord.ATTRIBUTE_X, "");
+                        return "";
+                    }
+                }
+                else {
+                   return null;
+                }
+            }};
+
+
+        CellEditValueParser cevp = new CellEditValueParser() {
+            public Object parse(Object value, ListGridRecord record, int rowNum, int colNum) {
+                if (value == null)
+                    return null;
+                try {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    double d = nf.parse(value.toString());
+                    return (new Double(d)).toString();
+                }
+                catch(NumberFormatException nfe) {
+                    return value;
+                }
+            }
+        };
+
+        CellEditValueFormatter cevf = new CellEditValueFormatter() {
+            public Object format(Object value, ListGridRecord record, int rowNum, int colNum) {
+                if (value != null) {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    try {
+                        double d = Double.valueOf(value.toString()).doubleValue();
+                        return nf.format(d);
+                    } catch (Exception e) {
+                        return value.toString();
+                    }
+                }
+                return null;
+            }
+        };
+
+        // Use X and Y as default fallback.
+        String xAxis = "X";
+        String yAxis = "Y";
+
+        // Get header text from collection settings.
+        Settings settings = this.collection.getSettings(outputModeName);
+        List<Property> axes = settings.getSettings("axes");
+        if(axes != null) {
+            for (Property p: axes) {
+                PropertyGroup pg = (PropertyGroup)p;
+                StringProperty id =
+                    (StringProperty)pg.getPropertyByName("id");
+                if(id.getValue().equals("X")) {
+                    StringProperty name =
+                        (StringProperty)pg.getPropertyByName("label");
+                    xAxis = name.getValue();
+                }
+                else if (yAxis.equals("Y")) {
+                    StringProperty name =
+                        (StringProperty)pg.getPropertyByName("label");
+                    yAxis = name.getValue();
+                }
+            }
+        }
+        ListGridField xField =
+            new ListGridField(PointRecord.ATTRIBUTE_X, xAxis);
+        xField.setType(ListGridFieldType.TEXT);
+        xField.setCellFormatter(dateFormat);
+
+        ListGridField yField =
+            new ListGridField(PointRecord.ATTRIBUTE_Y, yAxis);
+        yField.setType(ListGridFieldType.FLOAT);
+        yField.setCellFormatter(doubleFormat);
+        yField.setEditValueParser(cevp);
+        yField.setEditValueFormatter(cevf);
+
+        ListGridField nameField = new ListGridField(PointRecord.ATTRIBUTE_NAME,
+            MSG.pointname());
+        final ListGridField removeField  =
+            new ListGridField("_removeRecord", MSG.removepoint()){{
+                setType(ListGridFieldType.ICON);
+                setIcon(GWT.getHostPageBaseURL() + MSG.removeFeature());
+                setCanEdit(false);
+                setCanFilter(false);
+                setCanSort(false);
+                setCanGroupBy(false);
+                setCanFreeze(false);
+                setWidth(25);
+        }};
+
+        ListGridField activeField = new ListGridField(
+            PointRecord.ATTRIBUTE_ACTIVE, MSG.selection());
+        activeField.setType(ListGridFieldType.BOOLEAN);
+        activeField.setDefaultValue(true);
+
+        listGrid.setFields(new ListGridField[] {activeField, xField, yField,
+            nameField, removeField});
+
+        listGrid.addRecordClickHandler(new RecordClickHandler() {
+                public void onRecordClick(final RecordClickEvent event) {
+                    // Just handle remove-clicks
+                    if(!event.getField().getName().equals(removeField.getName())) {
+                        return;
+                    }
+                    event.getViewer().removeData(event.getRecord());
+                }
+            });
+
+        // Find the artifacts uuid.
+        findManualPointsUUID();
+        CollectionItem item = collection.getItem(uuid);
+
+        // Add points to grid.
+        if (item != null) {
+            String jsonData = item.getData().get(outputModeName + "." + POINT_DATA);
+            JSONArray jsonArray = (JSONArray) JSONParser.parse(jsonData);
+            for (int i = 0; i < jsonArray.size(); i++) {
+                JSONArray point = (JSONArray) jsonArray.get(i);
+                listGrid.addData(datePointRecordFromJSON(point));
+            }
+        }
+        else {
+            // TODO proper log
+            System.out.println("No item found for " + uuid);
+        }
+
+        IButton button = new IButton(MSG.newpoint());
+        button.setTop(250);
+        button.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent event) {
+                listGrid.startEditingNew();
+            }
+        });
+
+        layout.addMember(listGrid);
+        layout.addMember(button);
+
+        addItem(layout);
+
+        addItem(buttons);
+        setWidth(380);
+        setHeight(470);
+        centerInPage();
+    }
+
+
+    /** Create JSON representation of the points present in the list grid. */
+    protected JSONArray jsonArrayFromListGrid() {
+        JSONArray list = new JSONArray();
+        int idx = 0;
+
+        for(ListGridRecord record : listGrid.getRecords()) {
+            if (record instanceof DatePointRecord) {
+                JSONArray data = new JSONArray();
+
+                DatePointRecord point = (DatePointRecord) record;
+                String dateString = point.getX();
+                DateTimeFormat df = DateTimeFormat.getFormat(
+                    DateTimeFormat.PredefinedFormat.DATE_MEDIUM);
+
+                Date d = df.parse(dateString);
+                double dv = (double)d.getTime();
+
+                data.set(0, new JSONNumber(dv));
+                data.set(1, new JSONNumber(point.getY()));
+                data.set(2, new JSONString(point.getName()));
+                data.set(3, JSONBoolean.getInstance(point.isActive()));
+
+                list.set(idx, data);
+                idx++;
+            }
+            else {
+                JSONArray data = new JSONArray();
+
+                String nameString = record.getAttributeAsString(PointRecord.ATTRIBUTE_NAME);
+                // Apply default name if none set.
+                if (nameString == null || nameString.equals("")) {
+                    String xString = record.getAttributeAsString(
+                        PointRecord.ATTRIBUTE_X);
+                    String yString = record.getAttributeAsString(
+                        PointRecord.ATTRIBUTE_Y);
+                    nameString = xString + "/" + yString;
+                }
+
+                String dateString = record.getAttributeAsString(PointRecord.ATTRIBUTE_X);
+                DateTimeFormat df = DateTimeFormat.getFormat(
+                    DateTimeFormat.PredefinedFormat.DATE_MEDIUM);
+
+                Date d = df.parse(dateString);
+                double dv = (double)d.getTime();
+                data.set(0, new JSONNumber(dv));
+                data.set(1, new JSONNumber(record.
+                    getAttributeAsDouble(PointRecord.ATTRIBUTE_Y)));
+                data.set(2, new JSONString(nameString));
+                data.set(3, JSONBoolean.getInstance(record.getAttributeAsBoolean(
+                    PointRecord.ATTRIBUTE_ACTIVE)));
+
+                list.set(idx, data);
+                idx++;
+            }
+        }
+        return list;
+    }
+
+    /** From a JSON-encoded point, create a PointRecord. */
+    public DatePointRecord datePointRecordFromJSON(JSONArray jsonArray) {
+        JSONNumber  x = (JSONNumber)  jsonArray.get(0);
+        JSONNumber  y = (JSONNumber)  jsonArray.get(1);
+        JSONString  s = (JSONString)  jsonArray.get(2);
+        JSONBoolean b = (JSONBoolean) jsonArray.get(3);
+
+        Date d = new Date (Long.valueOf(x.toString()).longValue());
+        DateTimeFormat df = DateTimeFormat.getFormat(
+            DateTimeFormat.PredefinedFormat.DATE_MEDIUM);
+
+        return new DatePointRecord(b.booleanValue(), df.format(d),
+            y.doubleValue(), s.stringValue());
+    }
+
+
+    /** Return false if x or y attribute is missing. */
+    @Override
+    protected boolean isDialogValid() {
+        boolean valid = true;
+        for (ListGridRecord record : listGrid.getRecords()) {
+            if (record.getAttributeAsString(PointRecord.ATTRIBUTE_X) == null ||
+                record.getAttributeAsString(
+                    DatePointRecord.ATTRIBUTE_X).equals("") ||
+                record.getAttributeAsDouble(PointRecord.ATTRIBUTE_Y) == null) {
+                return false;
+            }
+        }
+        if (listGrid.hasErrors()) {
+            valid = false;
+        }
+        return valid;
+    }
+
+
+    /** Simple record to store points. */
+    public class DatePointRecord extends ListGridRecord {
+        protected static final String ATTRIBUTE_X = "X";
+        protected static final String ATTRIBUTE_Y = "Y";
+        protected static final String ATTRIBUTE_NAME = "name";
+        protected static final String ATTRIBUTE_ACTIVE = "active";
+
+        private DatePointRecord() {;}
+
+        public DatePointRecord(boolean b, String x, double y, String name) {
+            setActive(b);
+            setName(name);
+            setX(x);
+            setY(y);
+        }
+
+        public void setActive(boolean b) {
+            setAttribute(ATTRIBUTE_ACTIVE, b);
+        }
+
+        public boolean isActive() {
+            return getAttributeAsBoolean(ATTRIBUTE_ACTIVE);
+        }
+
+        public void setName(String name) {
+            setAttribute(ATTRIBUTE_NAME, name);
+        }
+
+        public String getName() {
+            return getAttributeAsString(ATTRIBUTE_NAME);
+        }
+
+        public void setX(String x) {
+            setAttribute(ATTRIBUTE_X, x);
+        }
+
+        public void setY(double y) {
+            setAttribute(ATTRIBUTE_Y, y);
+        }
+
+        public String getX() {
+            return getAttributeAsString(ATTRIBUTE_X);
+        }
+
+        public double getY() {
+            return getAttributeAsDouble(ATTRIBUTE_Y);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/ManualPointsEditor.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,563 @@
+package de.intevation.flys.client.client.ui.chart;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONBoolean;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.types.ListGridFieldType;
+import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.IButton;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.Window;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.grid.CellEditValueFormatter;
+import com.smartgwt.client.widgets.grid.CellEditValueParser;
+import com.smartgwt.client.widgets.grid.CellFormatter;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.event.RedrawRequestEvent;
+import de.intevation.flys.client.client.event.RedrawRequestHandler;
+import de.intevation.flys.client.client.services.FeedServiceAsync;
+import de.intevation.flys.client.client.services.LoadArtifactServiceAsync;
+import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.CollectionItem;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DefaultArtifact;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.Property;
+import de.intevation.flys.client.shared.model.PropertyGroup;
+import de.intevation.flys.client.shared.model.Recommendation;
+import de.intevation.flys.client.shared.model.Settings;
+import de.intevation.flys.client.shared.model.StringProperty;
+
+import java.util.List;
+
+
+/**
+ * UI to enter point data and save it to an PointArtifact.
+ */
+public class ManualPointsEditor
+extends      Window
+implements   ClickHandler
+{
+    /** The interface that provides i18n messages. */
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    /** Part of name of the main data item to be fed. */
+    public static final String POINT_DATA = "manualpoints.data";
+
+    /** When we chaged something, we need a RedrawRequest(Handler). */
+    protected RedrawRequestHandler redrawRequestHandler;
+
+    /** The collection */
+    protected Collection collection;
+
+    /** The listGrid showing point entries. */
+    protected ListGrid listGrid;
+
+    protected ListGridFieldType fieldTypeX = ListGridFieldType.FLOAT;
+
+    /** Service handle to clone and add artifacts to collection. */
+    LoadArtifactServiceAsync loadArtifactService = GWT.create(
+            de.intevation.flys.client.client.services.LoadArtifactService.class);
+
+    /** Service to feed the artifact with new point-data. */
+    FeedServiceAsync feedService = GWT.create(
+        de.intevation.flys.client.client.services.FeedService.class);
+
+    /** UUID of artifact to feed. */
+    protected String uuid;
+
+    /** Name of the outputmode, important when feeding data. */
+    protected String outputModeName;
+
+    /** Name of the point data item. */
+    protected String pointDataItemName;
+
+
+    /**
+     * Setup editor dialog.
+     * @param collection The collection to use.
+     */
+    public ManualPointsEditor(Collection collection,
+        RedrawRequestHandler handler, String outputModeName
+    ) {
+        this.collection = collection;
+        this.redrawRequestHandler = handler;
+        this.outputModeName = outputModeName;
+        this.pointDataItemName = outputModeName + "." + POINT_DATA;
+        init();
+    }
+
+
+    /** Searches collection for first artifact to serve (manual) point data. */
+    public String findManualPointsUUID() {
+        // TODO Need to be more picky (different points in different diagrams)
+        int size = collection.getItemLength();
+
+        for (int i = 0; i < size; i++) {
+            CollectionItem item = collection.getItem(i);
+            String dataValue = item.getData().get(pointDataItemName);
+            if (dataValue != null) {
+                // Found it.
+                uuid = item.identifier();
+                return uuid;
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Initialize the editor window and its components.
+     */
+    protected void init() {
+        setTitle(MSG.addpoints());
+        setCanDragReposition(true);
+        setCanDragResize(true);
+
+        // If no manualpoints artifact found, create it now.
+        if(findManualPointsUUID() == null) {
+            addArtifactCreateUI();
+        }
+        else {
+            createUI();
+        }
+    }
+
+
+    /** Create and setup/add the ui. */
+    public void createUI() {
+        Config config = Config.getInstance();
+
+        Button accept = new Button(MSG.label_ok());
+        Button cancel = new Button(MSG.label_cancel());
+        cancel.addClickHandler(this);
+
+        accept.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent e) {
+                okClicked();
+            }
+        });
+
+        HLayout buttons = new HLayout();
+        buttons.addMember(accept);
+        buttons.addMember(cancel);
+        buttons.setAlign(Alignment.CENTER);
+        buttons.setHeight(30);
+
+        VLayout layout = new VLayout();
+        listGrid = new ListGrid();
+        listGrid.setWidth100();
+        listGrid.setHeight("*");
+        listGrid.setCanSort(false);
+        listGrid.setCanEdit(true);
+        listGrid.setShowHeaderContextMenu(false);
+
+        // Use X and Y as default fallback.
+        String xAxis = "X";
+        String yAxis = "Y";
+
+        // Get header text from collection settings.
+        Settings settings = this.collection.getSettings(outputModeName);
+        List<Property> axes = settings.getSettings("axes");
+        if(axes != null) {
+            for (Property p: axes) {
+                PropertyGroup pg = (PropertyGroup)p;
+                GWT.log(pg.toString());
+                StringProperty id =
+                    (StringProperty)pg.getPropertyByName("id");
+                if(id.getValue().equals("X")) {
+                    StringProperty name =
+                        (StringProperty)pg.getPropertyByName("label");
+                    xAxis = name.getValue();
+                }
+                else if (yAxis.equals("Y")) {
+                    StringProperty name =
+                        (StringProperty)pg.getPropertyByName("label");
+                    yAxis = name.getValue();
+                }
+            }
+        }
+
+        CellFormatter format = createCellFormatter();
+        CellEditValueParser cevp = createCellEditValueParser();
+        CellEditValueFormatter cevf = createCellEditValueFormatter();
+
+        ListGridField xField =
+                new ListGridField(PointRecord.ATTRIBUTE_X, xAxis);
+        if(xAxis.equalsIgnoreCase("date") || xAxis.equalsIgnoreCase("Datum")) {
+            // FIXME: This is a hack for the special axis with Date type
+            xField.setType(ListGridFieldType.DATE);
+            this.fieldTypeX = ListGridFieldType.DATE;
+        }
+        else {
+            xField.setType(ListGridFieldType.FLOAT);
+            xField.setCellFormatter(format);
+            xField.setEditValueParser(cevp);
+            xField.setEditValueFormatter(cevf);
+        }
+
+        ListGridField yField =
+            new ListGridField(PointRecord.ATTRIBUTE_Y, yAxis);
+        yField.setType(ListGridFieldType.FLOAT);
+        yField.setCellFormatter(format);
+        yField.setEditValueParser(cevp);
+        yField.setEditValueFormatter(cevf);
+
+        ListGridField nameField = new ListGridField(PointRecord.ATTRIBUTE_NAME,
+            MSG.pointname());
+        final ListGridField removeField  =
+            new ListGridField("_removeRecord", MSG.removepoint()){{
+                setType(ListGridFieldType.ICON);
+                setIcon(GWT.getHostPageBaseURL() + MSG.removeFeature());
+                setCanEdit(false);
+                setCanFilter(false);
+                setCanSort(false);
+                setCanGroupBy(false);
+                setCanFreeze(false);
+                setWidth(25);
+        }};
+
+        ListGridField activeField = new ListGridField(
+            PointRecord.ATTRIBUTE_ACTIVE, MSG.selection());
+        activeField.setType(ListGridFieldType.BOOLEAN);
+        activeField.setDefaultValue(true);
+
+        listGrid.setFields(new ListGridField[] {activeField, xField, yField,
+            nameField, removeField});
+
+        listGrid.addRecordClickHandler(new RecordClickHandler() {
+                public void onRecordClick(final RecordClickEvent event) {
+                    // Just handle remove-clicks
+                    if(!event.getField().getName().equals(removeField.getName())) {
+                        return;
+                    }
+                    event.getViewer().removeData(event.getRecord());
+                }
+            });
+
+        // Find the artifacts uuid.
+        findManualPointsUUID();
+        CollectionItem item = collection.getItem(uuid);
+
+        // Add points to grid.
+        if (item != null) {
+            // TODO store this from findPointUUID instead (we touched these).
+            String jsonData = item.getData().get(pointDataItemName);
+            JSONArray jsonArray = (JSONArray) JSONParser.parse(jsonData);
+            for (int i = 0; i < jsonArray.size(); i++) {
+                JSONArray point = (JSONArray) jsonArray.get(i);
+                listGrid.addData(pointRecordFromJSON(point));
+            }
+        }
+        else {
+            // TODO proper log
+            System.out.println("No item found for " + uuid);
+        }
+
+        IButton button = new IButton(MSG.newpoint());
+        button.setTop(250);
+        button.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent event) {
+                listGrid.startEditingNew();
+            }
+        });
+
+        layout.addMember(listGrid);
+        layout.addMember(button);
+
+        addItem(layout);
+
+        addItem(buttons);
+        setWidth(380);
+        setHeight(470);
+        centerInPage();
+    }
+
+
+    protected CellFormatter createCellFormatter() {
+        return new CellFormatter() {
+            public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
+                if(value != null) {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    try {
+                        double d = Double.valueOf(value.toString()).doubleValue();
+                        return nf.format(d);
+                    } catch (Exception e) {
+                        return value.toString();
+                    }
+                } else {
+                   return null;
+                }
+            }};
+    }
+
+
+    protected CellEditValueParser createCellEditValueParser() {
+        return new CellEditValueParser() {
+            public Object parse(Object value, ListGridRecord record, int rowNum, int colNum) {
+                if (value == null)
+                    return null;
+                try {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    double d = nf.parse(value.toString());
+                    return (new Double(d)).toString();
+                }
+                catch(NumberFormatException nfe) {
+                    return value;
+                }
+            }
+        };
+    }
+
+
+    protected CellEditValueFormatter createCellEditValueFormatter() {
+        return new CellEditValueFormatter() {
+            public Object format(Object value, ListGridRecord record, int rowNum, int colNum) {
+                if (value == null) {
+                    return "";
+                }
+                NumberFormat nf = NumberFormat.getDecimalFormat();
+                try {
+                    double d = Double.valueOf(value.toString()).doubleValue();
+                    return nf.format(d);
+                }
+                catch(NumberFormatException nfe) {
+                    return value;
+                }
+            }
+        };
+    }
+
+
+    /** Create JSON representation of the points present in the list grid. */
+    protected JSONArray jsonArrayFromListGrid() {
+        JSONArray list = new JSONArray();
+        int idx = 0;
+
+        for(ListGridRecord record : listGrid.getRecords()) {
+            if (record instanceof PointRecord) {
+                JSONArray data = new JSONArray();
+
+                PointRecord point = (PointRecord) record;
+                data.set(0, new JSONNumber(point.getX()));
+                data.set(1, new JSONNumber(point.getY()));
+                data.set(2, new JSONString(point.getName()));
+                data.set(3, JSONBoolean.getInstance(point.isActive()));
+
+                list.set(idx, data);
+                idx++;
+            }
+            else {
+                JSONArray data = new JSONArray();
+
+                String nameString = record.getAttributeAsString(PointRecord.ATTRIBUTE_NAME);
+                // Apply default name if none set.
+                if (nameString == null || nameString.equals("")) {
+                    String xString = record.getAttributeAsString(
+                        PointRecord.ATTRIBUTE_X);
+                    String yString = record.getAttributeAsString(
+                        PointRecord.ATTRIBUTE_Y);
+                    nameString = xString + "/" + yString;
+                }
+
+                if(fieldTypeX.equals(ListGridFieldType.DATE)) {
+                    data.set(0, new JSONString(record.getAttribute(PointRecord.ATTRIBUTE_X)));
+                }
+                else {
+                    data.set(0, new JSONNumber(record.
+                            getAttributeAsDouble(PointRecord.ATTRIBUTE_X)));
+                }
+                data.set(1, new JSONNumber(record.
+                    getAttributeAsDouble(PointRecord.ATTRIBUTE_Y)));
+                data.set(2, new JSONString(nameString));
+                data.set(3, JSONBoolean.getInstance(record.getAttributeAsBoolean(
+                    PointRecord.ATTRIBUTE_ACTIVE)));
+
+                list.set(idx, data);
+                idx++;
+            }
+        }
+        return list;
+    }
+
+
+    /**
+     * Called when OK Button was clicked. Then, if entered values are valid,
+     * fire a RedrawRequest and destroy.
+     */
+    protected void okClicked() {
+        if(isDialogValid()) {
+            // Feed JSON-encoded content of listgrid.
+            JSONArray list = jsonArrayFromListGrid();
+
+            Data[] feedData = new Data[] {
+                DefaultData.createSimpleStringData(pointDataItemName,
+                    list.toString())
+            };
+
+            feedService.feed(
+                Config.getInstance().getLocale(),
+                new DefaultArtifact(uuid, "TODO:hash"),
+                feedData,
+                new AsyncCallback<Artifact>() {
+                    public void onFailure(Throwable caught) {
+                        GWT.log("Could not feed artifact with points.");
+                        SC.warn(MSG.getString(caught.getMessage()));
+                        enable();
+                    }
+                    public void onSuccess(Artifact fartifact) {
+                        GWT.log("Successfully set points");
+                        redrawRequestHandler.onRedrawRequest(
+                            new RedrawRequestEvent());
+                        destroy();
+                    }
+                });
+        }
+        else {
+            GWT.log("Dialog not valid");
+            SC.warn(MSG.error_dialog_not_valid());
+        }
+    }
+
+
+    /** From a JSON-encoded point, create a PointRecord. */
+    public PointRecord pointRecordFromJSON(JSONArray jsonArray) {
+        JSONNumber  x = (JSONNumber)  jsonArray.get(0);
+        JSONNumber  y = (JSONNumber)  jsonArray.get(1);
+        JSONString  s = (JSONString)  jsonArray.get(2);
+        JSONBoolean b = (JSONBoolean) jsonArray.get(3);
+
+        return new PointRecord(b.booleanValue(), x.doubleValue(),
+            y.doubleValue(), s.stringValue());
+    }
+
+
+    /** Add a ManualPointArtifact to Collection. */
+    public void addArtifactCreateUI() {
+        final Label standByLabel = new Label(MSG.standby());
+        addItem(standByLabel);
+
+        setWidth(380);
+        setHeight(470);
+        centerInPage();
+
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
+
+        loadArtifactService.load(
+            this.collection,
+            new Recommendation("manualpoints", ""),
+            "manualpoints",
+            locale,
+            new AsyncCallback<Artifact>() {
+                public void onFailure(Throwable caught) {
+                    GWT.log("Creating manualpoint artifact failed!");
+                }
+                public void onSuccess(Artifact artifact) {
+                    GWT.log("Successfully created artifact.");
+                    removeItem(standByLabel);
+                    uuid = artifact.getUuid();
+                    createUI();
+                }
+            });
+    }
+
+
+    /**
+     * This method is called when the user aborts point editing.
+     * @param event The event.
+     */
+    public void onClick(ClickEvent event) {
+        this.destroy();
+    }
+
+
+    /** Simple record to store points. */
+    public class PointRecord extends ListGridRecord {
+        protected static final String ATTRIBUTE_X = "X";
+        protected static final String ATTRIBUTE_Y = "Y";
+        protected static final String ATTRIBUTE_NAME = "name";
+        protected static final String ATTRIBUTE_ACTIVE = "active";
+
+        public PointRecord(boolean b, double x, double y, String name) {
+            setActive(b);
+            setName(name);
+            setX(x);
+            setY(y);
+        }
+
+        public void setActive(boolean b) {
+            setAttribute(ATTRIBUTE_ACTIVE, b);
+        }
+
+        public boolean isActive() {
+            return getAttributeAsBoolean(ATTRIBUTE_ACTIVE);
+        }
+
+        public void setName(String name) {
+            setAttribute(ATTRIBUTE_NAME, name);
+        }
+
+        public String getName() {
+            return getAttributeAsString(ATTRIBUTE_NAME);
+        }
+
+        public void setX(double x) {
+            setAttribute(ATTRIBUTE_X, x);
+        }
+
+        public void setY(double y) {
+            setAttribute(ATTRIBUTE_Y, y);
+        }
+
+        public double getX() {
+            return getAttributeAsDouble(ATTRIBUTE_X);
+        }
+
+        public double getY() {
+            return getAttributeAsDouble(ATTRIBUTE_Y);
+        }
+    }
+
+
+    /** Return false if x or y attribute is missing. */
+    protected boolean isDialogValid() {
+        boolean valid = true;
+        for (ListGridRecord record : listGrid.getRecords()) {
+            try {
+                if (record.getAttribute(PointRecord.ATTRIBUTE_X) == null
+                    || record.getAttribute(PointRecord.ATTRIBUTE_Y) == null) {
+                    return false;
+                }
+            }
+            catch(IllegalArgumentException ex) {
+
+            }
+        }
+        if (listGrid.hasErrors()) {
+            valid = false;
+        }
+        return valid;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/ui/chart/ManualWSPEditor.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,367 @@
+package de.intevation.flys.client.client.ui.chart;
+
+import com.google.gwt.core.client.GWT;
+
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.json.client.JSONString;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import com.smartgwt.client.types.Alignment;
+
+import com.smartgwt.client.util.SC;
+
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.Window;
+
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+
+import com.smartgwt.client.widgets.form.DynamicForm;
+
+import com.smartgwt.client.widgets.form.fields.TextItem;
+
+import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
+import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.FLYSConstants;
+
+import de.intevation.flys.client.client.event.RedrawRequestEvent;
+import de.intevation.flys.client.client.event.RedrawRequestHandler;
+
+import de.intevation.flys.client.client.services.FeedService;
+import de.intevation.flys.client.client.services.FeedServiceAsync;
+import de.intevation.flys.client.client.services.LoadArtifactService;
+import de.intevation.flys.client.client.services.LoadArtifactServiceAsync;
+
+import de.intevation.flys.client.client.utils.DoubleValidator;
+
+import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.CollectionItem;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DefaultArtifact;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.Property;
+import de.intevation.flys.client.shared.model.PropertyGroup;
+import de.intevation.flys.client.shared.model.Recommendation;
+import de.intevation.flys.client.shared.model.Settings;
+import de.intevation.flys.client.shared.model.StringProperty;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * UI to enter point data and save it to an PointArtifact.
+ */
+public class ManualWSPEditor
+extends      Window
+implements   ClickHandler
+{
+    /** The interface that provides i18n messages. */
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    /** Name of the main data item to be fed. */
+    public static final String LINE_DATA = "manualpoints.lines";
+
+    /** When we chaged something, we need a RedrawRequest(Handler). */
+    protected RedrawRequestHandler redrawRequestHandler;
+
+    /** The collection */
+    protected Collection collection;
+
+    /** Service handle to clone and add artifacts to collection. */
+    LoadArtifactServiceAsync loadArtifactService = GWT.create(
+            de.intevation.flys.client.client.services.LoadArtifactService.class);
+
+    /** Service to feed the artifact with new point-data. */
+    FeedServiceAsync feedService = GWT.create(
+        de.intevation.flys.client.client.services.FeedService.class);
+
+    /** UUID of artifact to feed. */
+    protected String uuid;
+
+    /** Name of the outputmode, important when feeding data. */
+    protected String outputModeName;
+
+    /** Name of the data item for lines in this context. */
+    protected String dataItemName;
+
+    /** Input Field for y-coor of line. */
+    protected TextItem valueInputPanel;
+
+    /** Input Field for name of line. */
+    protected TextItem nameInputPanel;
+
+    /** Line data that is not added in this session. */
+    protected JSONArray oldLines = null;
+
+
+    /**
+     * Setup editor dialog.
+     * @param collection The collection to use.
+     */
+    public ManualWSPEditor(Collection collection,
+        RedrawRequestHandler handler, String outputModeName
+    ) {
+        this.collection = collection;
+        this.redrawRequestHandler = handler;
+        this.outputModeName = outputModeName;
+        this.dataItemName = outputModeName + "." + LINE_DATA;
+        init();
+    }
+
+
+    /** Searches collection for first artifact to serve (manual) line data. */
+    public String findManualPointsUUID() {
+        int size = collection.getItemLength();
+
+        for (int i = 0; i < size; i++) {
+            CollectionItem item = collection.getItem(i);
+            String dataValue = (String) item.getData().get(dataItemName);
+            if (dataValue != null) {
+                // Found it.
+                uuid = item.identifier();
+                return uuid;
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Initialize the editor window and its components.
+     */
+    protected void init() {
+        setTitle(MSG.addWSP());
+        setCanDragReposition(true);
+        setCanDragResize(true);
+
+        if(findManualPointsUUID() == null) {
+            addArtifactCreateUI();
+        }
+        else {
+            createUI();
+        }
+    }
+
+
+    /** Create and setup/add the ui. */
+    public void createUI() {
+        Config config = Config.getInstance();
+
+        Button accept = new Button(MSG.label_ok());
+        Button cancel = new Button(MSG.label_cancel());
+        cancel.addClickHandler(this);
+
+        accept.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent e) {
+                okClicked();
+            }
+        });
+
+        HLayout buttons = new HLayout();
+        buttons.addMember(accept);
+        buttons.addMember(cancel);
+        buttons.setAlign(Alignment.CENTER);
+        buttons.setHeight(30);
+
+        // Use X and Y as default fallback.
+        String yAxis = "Y";
+
+        // Get header text from collection settings.
+        Settings settings = this.collection.getSettings(outputModeName);
+        List<Property> axes = settings.getSettings("axes");
+        if(axes != null) {
+            for (Property p: axes) {
+                PropertyGroup pg = (PropertyGroup)p;
+                StringProperty id =
+                    (StringProperty)pg.getPropertyByName("id");
+                if (id.getValue().equals("W")) {
+                    StringProperty name =
+                        (StringProperty)pg.getPropertyByName("label");
+                    yAxis = name.getValue();
+                }
+            }
+        }
+
+        DynamicForm form = new DynamicForm();
+        valueInputPanel = new TextItem();
+        valueInputPanel.setTitle(yAxis);
+        valueInputPanel.setShowTitle(true);
+        valueInputPanel.addBlurHandler(new BlurHandler() {
+            public void onBlur(BlurEvent e) {
+                 DoubleValidator validator = new DoubleValidator();
+                 Map errors = e.getForm().getErrors();
+                 validator.validate(e.getItem(), errors);
+                 e.getForm().setErrors(errors, true);
+            }
+        });
+        nameInputPanel = new TextItem();
+        nameInputPanel.setTitle(MSG.pointname());
+        nameInputPanel.setShowTitle(true);
+        form.setFields(valueInputPanel, nameInputPanel);
+
+        VLayout layout = new VLayout();
+        layout.addMember(form);
+
+        // Find the artifacts uuid.
+        // TODO this has been called already, why call it again?
+        findManualPointsUUID();
+        CollectionItem item = collection.getItem(uuid);
+
+        // Store the old line data.
+        if (item != null) {
+            String jsonData = item.getData().get(dataItemName);
+            oldLines = (JSONArray) JSONParser.parse(jsonData);
+        }
+        else {
+            GWT.log("No old lines found for " + uuid);
+        }
+
+        addItem(layout);
+
+        addItem(buttons);
+        setWidth(360);
+        setHeight(120);
+        centerInPage();
+    }
+
+
+    /**
+     * Create JSON representation of the points present in the form.
+     * Add old data, too.
+     * @return a jsonarray with the old and the new lines.
+     */
+    protected JSONArray jsonArrayFromForm() {
+        if (oldLines == null) {
+            oldLines = new JSONArray();
+        }
+
+        int idx = 0;
+        double val;
+        if (valueInputPanel.getValue() == null)
+            return oldLines;
+        try {
+            NumberFormat nf = NumberFormat.getDecimalFormat();
+            double d = nf.parse(valueInputPanel.getValue().toString());
+            val = d;
+        }
+        catch(NumberFormatException nfe) {
+            SC.warn("fehler... nfe... TODO");
+            return oldLines;
+        }
+
+        JSONArray data = new JSONArray();
+        data.set(0, new JSONNumber(val));
+        if (nameInputPanel.getValue() == null) {
+            data.set(1, new JSONString(valueInputPanel.getValue().toString()));
+        }
+        else {
+            data.set(1, new JSONString(nameInputPanel.getValue().toString()));
+        }
+        oldLines.set(oldLines.size(), data);
+
+        return oldLines;
+    }
+
+
+    /**
+     * Called when OK Button was clicked. Then, if entered values are valid,
+     * fire a RedrawRequest and destroy.
+     */
+    protected void okClicked() {
+        if (valueInputPanel.getValue() == null) {
+            return;
+        }
+        GWT.log(valueInputPanel.getValue().toString());
+        if(isDialogValid()) {
+            // Feed JSON-encoded content of form.
+            JSONArray list = jsonArrayFromForm();
+
+            Data[] feedData = new Data[] {
+                DefaultData.createSimpleStringData(dataItemName,
+                    list.toString())
+            };
+
+            feedService.feed(
+                Config.getInstance().getLocale(),
+                new DefaultArtifact(uuid, "TODO:hash"),
+                feedData,
+                new AsyncCallback<Artifact>() {
+                    public void onFailure(Throwable caught) {
+                        GWT.log("Could not feed artifact with lines.");
+                        SC.warn(MSG.getString(caught.getMessage()));
+                        enable();
+                    }
+                    public void onSuccess(Artifact fartifact) {
+                        GWT.log("Successfully set lines ");
+                        redrawRequestHandler.onRedrawRequest(
+                            new RedrawRequestEvent());
+                        destroy();
+                    }
+                });
+        }
+        else {
+            GWT.log("Dialog not valid");
+            SC.warn(MSG.error_dialog_not_valid());
+        }
+    }
+
+
+    /** Add a ManualPointArtifact to Collection. */
+    public void addArtifactCreateUI() {
+        final Label standByLabel = new Label(MSG.standby());
+        addItem(standByLabel);
+
+        setWidth(360);
+        setHeight(120);
+        centerInPage();
+
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
+
+        loadArtifactService.load(
+            this.collection,
+            new Recommendation("manualpoints", ""),
+            "manualpoints",
+            locale,
+            new AsyncCallback<Artifact>() {
+                public void onFailure(Throwable caught) {
+                    GWT.log("Creating manualpoint artifact failed!");
+                }
+                public void onSuccess(Artifact artifact) {
+                    GWT.log("Successfully created artifact.");
+                    removeItem(standByLabel);
+                    uuid = artifact.getUuid();
+                    createUI();
+                }
+            });
+    }
+
+
+    /**
+     * This method is called when the user aborts point editing.
+     * @param event The event.
+     */
+    public void onClick(ClickEvent event) {
+        this.destroy();
+    }
+
+
+    /** Return false if x or y attribute is missing. */
+    protected boolean isDialogValid() {
+        return (DoubleValidator.isDouble(valueInputPanel.getValue()));
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/MousePositionPanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/MousePositionPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,7 @@
 package de.intevation.flys.client.client.ui.chart;
 
+import java.util.ArrayList;
+
 import com.google.gwt.i18n.client.NumberFormat;
 
 import com.smartgwt.client.widgets.Canvas;
@@ -12,6 +14,7 @@
 
 
 /**
+ * Panel showing the mouse position in data space.
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class MousePositionPanel extends HLayout implements MouseMoveHandler {
@@ -20,18 +23,14 @@
 
     protected NumberFormat nf;
 
-    protected Label x;
-    protected Label y;
-
+    protected HLayout xLayout;
+    protected ArrayList<HLayout> yLayouts;
 
     public MousePositionPanel(ChartOutputTab chartTab) {
         super();
 
         this.chartTab = chartTab;
 
-        x = new Label();
-        y = new Label();
-
         nf = NumberFormat.getDecimalFormat();
 
         chartTab.getChartPanel().addMouseMoveHandler(this);
@@ -47,46 +46,8 @@
     protected void initLayout() {
         setMembersMargin(5);
 
-        Label xDesc = new Label("Position: X = ");
-        Label yDesc  = new Label("Y = ");
-
-        HLayout xLayout = new HLayout();
-        xLayout.setWidth(125);
-        xLayout.addMember(xDesc);
-        xLayout.addMember(x);
-
-        HLayout yLayout = new HLayout();
-        yLayout.setWidth(70);
-        yLayout.addMember(yDesc);
-        yLayout.addMember(y);
-
-        xDesc.setWidth(70);
-        x.setWidth(55);
-        yDesc.setWidth(20);
-        y.setWidth(50);
-
-        addMember(xLayout);
-        addMember(yLayout);
-    }
-
-
-    /**
-     * /Updates the X value displayed in the <i>x</i> label.
-     *
-     * @param x the new x value.
-     */
-    public void setX(double x) {
-        this.x.setContents(nf.format(x));
-    }
-
-
-    /**
-     * /Updates the Y value displayed in the <i>y</i> label.
-     *
-     * @param y the new y value.
-     */
-    public void setY(double y) {
-        this.y.setContents(nf.format(y));
+        xLayout = null;
+        yLayouts = new ArrayList<HLayout>();
     }
 
 
@@ -108,11 +69,7 @@
      * @param y The y part of the pixel.
      */
     public void updateMousePosition(double x, double y) {
-        Transform2D transformer = chartTab.getTransformer();
-
-        if (transformer == null) {
-            return;
-        }
+        int transformerCount = chartTab.getTransformerCount();
 
         Canvas chart = chartTab.getChartPanel();
         int xOffset = chart.getPageLeft();
@@ -121,10 +78,66 @@
         x = x - xOffset;
         y = y - yOffset;
 
-        double[] xy = transformer.transform(x,y);
+        // Create Layout for x coordinates.
+        if (xLayout == null){
+            Label xDesc  = new Label("Position: X = ");
+            Label xLabel = new Label();
+            xLayout      = new HLayout();
+            xLayout.setWidth(125);
+            xLayout.addMember(xDesc);
+            xLayout.addMember(xLabel);
+            xDesc.setWidth(70);
+            xLabel.setWidth(55);
+            addMember(xLayout);
+        }
 
-        setX(xy[0]);
-        setY(xy[1]);
+        ArrayList<String> yCoordinates = new ArrayList<String>();
+        String xCoordinate = "";
+        for (int i = 0; i < transformerCount; i++) {
+            HLayout yLayout = null;
+            // If no layout exists for this y axis, create one.
+            // else use the existing one.
+            if (yLayouts.size() <= i) {
+                Label yDesc     = new Label("Y" + (i+1) + " = ");
+                Label yLabel    = new Label();
+                yLayout = new HLayout();
+                yLayout.setWidth(80);
+                yLayout.addMember(yDesc);
+                yLayout.addMember(yLabel);
+                yDesc.setWidth(30);
+                yLabel.setWidth(50);
+                addMember(yLayout);
+                yLayouts.add(i, yLayout);
+            }
+            else {
+                yLayout = yLayouts.get(i);
+            }
+
+            Transform2D transformer = chartTab.getTransformer(i);
+
+            if (transformer == null) {
+                return;
+            }
+
+            // Get the label for the coordinates.
+            Canvas xLabel = xLayout.getMember(1);
+            Canvas yLabel = yLayout.getMember(1);
+
+            double[] xy    = transformer.transform(x,y);
+            String[] xyStr = transformer.format(new Number[] {
+                new Double(xy[0]), new Double(xy[1]) });
+            // Set the coordinates.
+            xLabel.setContents(xyStr[0]);
+            yLabel.setContents(xyStr[1]);
+        }
+
+        // Remove y coordinates.
+        if (yLayouts.size() > transformerCount) {
+            for (int i = yLayouts.size() - 1; i >= transformerCount; i--) {
+                removeMember(yLayouts.get(i));
+                yLayouts.remove(i);
+            }
+        }
     }
 }
 // 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-client/src/main/java/de/intevation/flys/client/client/ui/chart/NaviChartOutputTab.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,294 @@
+package de.intevation.flys.client.client.ui.chart;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.smartgwt.client.types.Alignment;
+
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.Canvas;
+
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+
+import com.smartgwt.client.widgets.form.DynamicForm;
+
+import com.smartgwt.client.widgets.form.fields.TextItem;
+
+import com.smartgwt.client.widgets.form.fields.events.KeyPressEvent;
+import com.smartgwt.client.widgets.form.fields.events.KeyPressHandler;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
+import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
+
+import de.intevation.flys.client.client.Config;
+
+import de.intevation.flys.client.client.ui.CollectionView;
+
+import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.FixAnalysisArtifact;
+import de.intevation.flys.client.shared.model.OutputMode;
+
+import java.util.Date;
+
+/**
+ * Tab representing and showing one Chart-output.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class NaviChartOutputTab
+extends      ChartOutputTab
+implements   TabSelectedHandler
+{
+    protected TextItem currentkm;
+
+    public NaviChartOutputTab(
+        String         title,
+        Collection     collection,
+        OutputMode     mode,
+        CollectionView collectionView
+    ){
+        super(title, collection, mode, collectionView);
+        right.removeChild(chart);
+        right.addChild(createNaviChart());
+        collectionView.registerTabHandler(this);
+    }
+
+
+    protected Canvas createNaviChart() {
+        final Artifact art = collectionView.getArtifact();
+        VLayout root = new VLayout();
+        root.setWidth100();
+        root.setHeight100();
+
+        HLayout layout = new HLayout();
+        layout.setAlign(Alignment.CENTER);
+
+        DynamicForm form = new DynamicForm();
+        Button lower = new Button("<<");
+        lower.setWidth(30);
+        Button upper = new Button(">>");
+        upper.setWidth(30);
+        currentkm = new TextItem();
+        currentkm.setWidth(60);
+        currentkm.setShowTitle(false);
+
+        form.setFields(currentkm);
+        form.setWidth(60);
+        FixAnalysisArtifact fix = (FixAnalysisArtifact) art;
+
+        String s = fix.getArtifactDescription().getDataValueAsString("step");
+        try {
+            double ds = Double.parseDouble(s);
+            collectionView.setSteps(ds);
+        }
+        catch(NumberFormatException nfe) {
+            collectionView.setSteps(100d);
+        }
+        collectionView.setMinKm(fix.getFilter().getFromKm());
+        collectionView.setMaxKm(fix.getFilter().getToKm());
+
+        NumberFormat nf = NumberFormat.getDecimalFormat();
+        if (collectionView.getCurrentKm() == -1d) {
+            try {
+                double d = Double.valueOf(fix.getFilter().getFromKm());
+                currentkm.setValue(nf.format(d));
+            } catch (NumberFormatException e) {
+                currentkm.setValue(fix.getFilter().getFromKm());
+            }
+            collectionView.setCurrentKm(fix.getFilter().getFromKm());
+        }
+        else {
+            try {
+                double d = Double.valueOf(fix.getFilter().getFromKm());
+                currentkm.setValue(nf.format(d));
+            } catch (NumberFormatException e) {
+                currentkm.setValue(fix.getFilter().getFromKm());
+            }
+            currentkm.setValue(collectionView.getCurrentKm());
+        }
+
+        lower.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent ce) {
+                tbarPanel.deselectControls();
+                updateChartDown();
+                try {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    double d = Double.valueOf(collectionView.getCurrentKm());
+                    currentkm.setValue(nf.format(d));
+                } catch (NumberFormatException e) {
+                    currentkm.setValue(collectionView.getCurrentKm());
+                }
+            }
+        });
+
+        upper.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent ce) {
+                tbarPanel.deselectControls();
+                updateChartUp();
+                try {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    double d = Double.valueOf(collectionView.getCurrentKm());
+                    currentkm.setValue(nf.format(d));
+                } catch (NumberFormatException e) {
+                    currentkm.setValue(collectionView.getCurrentKm());
+                }
+            }
+        });
+
+        currentkm.addKeyPressHandler(new KeyPressHandler() {
+            public void onKeyPress(KeyPressEvent kpe) {
+                if (!kpe.getKeyName().equals("Enter")) {
+                    return;
+                }
+                if(kpe.getItem().getValue() != null) {
+                    tbarPanel.deselectControls();
+                    try {
+                        String s = kpe.getItem().getValue().toString();
+                        double d;
+                        try {
+                            NumberFormat nf = NumberFormat.getDecimalFormat();
+                            d = nf.parse(s);
+                            currentkm.setValue(nf.format(d));
+                        } catch (NumberFormatException e) {
+                            d = -1d;
+                        }
+                        if (d <= collectionView.getMaxKm() &&
+                            d >= collectionView.getMinKm()) {
+                            collectionView.setCurrentKm(d);
+                            tbarPanel.updateLinks();
+                            if (right != null) {
+                                updateChartPanel();
+                                updateChartInfo();
+                            }
+                        }
+                    }
+                    catch(NumberFormatException nfe) {
+                        // Do nothing.
+                    }
+                }
+            }
+        });
+        layout.addMember(lower);
+        layout.addMember(form);
+        layout.addMember(upper);
+
+        root.addMember(chart);
+        root.addMember(layout);
+        return root;
+    }
+
+
+    protected void updateChartUp() {
+        double currentKm = collectionView.getCurrentKm();
+        if (currentKm < collectionView.getMaxKm()) {
+            double newVal = currentKm * 100;
+            newVal += (collectionView.getSteps() / 10);
+            collectionView.setCurrentKm((double)Math.round(newVal) / 100);
+            tbarPanel.updateLinks();
+            updateChartPanel();
+            updateChartInfo();
+        }
+    }
+    protected void updateChartDown() {
+        double currentKm = collectionView.getCurrentKm();
+        if (currentKm > collectionView.getMinKm()) {
+            double newVal = currentKm * 100;
+            newVal -= (collectionView.getSteps() / 10);
+            collectionView.setCurrentKm((double)Math.round(newVal) / 100);
+            tbarPanel.updateLinks();
+            updateChartPanel();
+            updateChartInfo();
+        }
+
+    }
+
+   /**
+     * Returns the existing chart panel.
+     *
+     * @return the existing chart panel.
+     */
+    @Override
+    public Canvas getChartPanel() {
+        return chart;
+    }
+
+    /**
+     * Builds the URL that points to the chart image.
+     *
+     * @param width The width of the requested chart.
+     * @param height The height of the requested chart.
+     * @param xr Optional x range (used for zooming).
+     * @param yr Optional y range (used for zooming).
+     *
+     * @return the URL to the chart image.
+     */
+    @Override
+    protected String getImgUrl(int width, int height) {
+        Config config = Config.getInstance();
+
+        String imgUrl = GWT.getModuleBaseURL();
+        imgUrl += "chart";
+        imgUrl += "?uuid=" + collection.identifier();
+        imgUrl += "&type=" + mode.getName();
+        imgUrl += "&locale=" + config.getLocale();
+        imgUrl += "&timestamp=" + new Date().getTime();
+        imgUrl += "&width=" + Integer.toString(width);
+        imgUrl += "&height=" + Integer.toString(height - 40);
+
+        Number[] zoom = getZoomValues();
+
+        if (zoom != null) {
+            if (zoom[0].intValue() != 0 || zoom[1].intValue() != 1) {
+                // a zoom range of 0-1 means displaying the whole range. In such
+                // case we don't need to zoom.
+                imgUrl += "&minx=" + zoom[0];
+                imgUrl += "&maxx=" + zoom[1];
+            }
+
+            if (zoom[2].intValue() != 0 || zoom[3].intValue() != 1) {
+                // a zoom range of 0-1 means displaying the whole range. In such
+                // case we don't need to zoom.
+                imgUrl += "&miny=" + zoom[2];
+                imgUrl += "&maxy=" + zoom[3];
+            }
+        }
+
+        if(collectionView.getArtifact() instanceof FixAnalysisArtifact) {
+            if (collectionView.getCurrentKm() == -1) {
+                FixAnalysisArtifact fix =
+                    (FixAnalysisArtifact) collectionView.getArtifact();
+                collectionView.setCurrentKm(fix.getFilter().getFromKm());
+            }
+            imgUrl += "&currentKm=" + collectionView.getCurrentKm();
+        }
+
+        return imgUrl;
+    }
+
+    public void onTabSelected(TabSelectedEvent tse) {
+        if (this.equals(tse.getTab())) {
+            updateChartPanel();
+            updateChartInfo();
+            currentkm.setValue(collectionView.getCurrentKm());
+        }
+    }
+
+    @Override
+    public Map<String, String> getChartAttributes() {
+        Map<String, String> attr = new HashMap<String, String>();
+
+        attr = super.getChartAttributes();
+        attr.put("km", String.valueOf(collectionView.getCurrentKm()));
+
+        return attr;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/OverviewOutputTab.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,109 @@
+package de.intevation.flys.client.client.ui.chart;
+
+import com.google.gwt.core.client.GWT;
+
+import de.intevation.flys.client.client.event.OutputParameterChangeHandler;
+import de.intevation.flys.client.client.event.RedrawRequestHandler;
+import de.intevation.flys.client.client.ui.CollectionView;
+import de.intevation.flys.client.client.ui.ImgLink;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.OutputMode;
+import de.intevation.flys.client.shared.model.Theme;
+
+
+public class OverviewOutputTab extends ChartOutputTab  {
+
+    private class NoChartThemePanel extends ChartThemePanel {
+
+        public NoChartThemePanel(OutputMode mode, CollectionView view) {
+            super(mode, view);
+        }
+
+        @Override
+        public void activateTheme(Theme theme, boolean active) { }
+
+        @Override
+        public void feedTellArea(
+            final String artifact,
+            Theme under,
+            Theme over,
+            boolean between
+        ) { }
+
+        @Override
+        public void createAreaArtifact(
+            final Theme   over,
+            final Theme   under,
+            final boolean between
+        ) { }
+
+        @Override
+        public void addOutputParameterChangeHandler(OutputParameterChangeHandler h) { }
+
+        @Override
+        public void addRedrawRequestHandler(RedrawRequestHandler h){ }
+    }
+
+
+
+    private class MinimumChartToolbar extends ChartToolbar {
+
+        public MinimumChartToolbar(ChartOutputTab tab) {
+            super(tab);
+        }
+
+        @Override
+        protected void initTools() {
+            GWT.log("CREATE NEW MINIMALISTIC CHART TOOLBAR");
+            ChartOutputTab chartTab = getChartOutputTab();
+
+            String baseUrl = GWT.getHostPageBaseURL();
+
+            downloadPNG = new ImgLink(
+                baseUrl + MSG.downloadPNG(),
+                chartTab.getExportUrl(-1, -1, "png"),
+                20,
+                20);
+            downloadPNG.setTooltip(MSG.downloadPNGTooltip());
+
+            initLayout();
+        }
+
+
+        @Override
+        protected void initLayout() {
+            setWidth100();
+            setHeight(PANEL_HEIGHT);
+            setMembersMargin(10);
+            setPadding(5);
+            setBorder("1px solid black");
+
+            addMember(downloadPNG);
+        }
+    }
+
+
+
+    public OverviewOutputTab(
+        String         title,
+        Collection     collection,
+        OutputMode     mode,
+        CollectionView collectionView
+        ){
+        super(title, collection, mode, collectionView);
+        left.setVisible(false);
+    }
+
+
+    @Override
+    public ChartThemePanel createThemePanel(
+        OutputMode mode, CollectionView view
+        ) {
+        return new NoChartThemePanel(mode, view);
+    }
+
+    @Override
+    public ChartToolbar createChartToolbar(ChartOutputTab tab) {
+        return new MinimumChartToolbar(tab);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/fixation/FixEventSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,170 @@
+package de.intevation.flys.client.client.ui.fixation;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import com.google.gwt.core.client.GWT;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.FLYSConstants;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.IntDataItem;
+import de.intevation.flys.client.shared.model.IntegerArrayData;
+import de.intevation.flys.client.shared.model.FixingsOverviewInfo.FixEvent;
+
+import de.intevation.flys.client.client.services.FixingsOverviewService;
+import de.intevation.flys.client.client.services.FixingsOverviewServiceAsync;
+
+/**
+ * This UIProvider creates a panel for location or distance input.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixEventSelect
+extends      FixationPanel
+{
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    public static final int MAX_DISPLAYED_ITEMS = 5;
+
+    protected FixingsOverviewServiceAsync overviewService =
+        GWT.create(FixingsOverviewService.class);
+
+    protected List<String> events;
+
+    public FixEventSelect() {
+        htmlOverview = "";
+        events = new ArrayList<String>();
+    }
+
+    public Canvas createWidget(DataList data) {
+        instances.put(this.artifact.getUuid(), this);
+
+        VLayout layout = new VLayout();
+
+        Canvas title = new Label(MESSAGES.eventselect());
+        title.setHeight("25px");
+
+        layout.addMember(title);
+        return layout;
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        List<Data> list = dataList.getAll();
+
+        Data data = getData(list, "events");
+
+        VLayout dataLayout = new VLayout();
+        dataLayout.setWidth(130);
+
+        DataItem[] items = data.getItems();
+
+        if (items.length > MAX_DISPLAYED_ITEMS) {
+            for (int i = 0; i < MAX_DISPLAYED_ITEMS-2; ++i) {
+                Label l = new Label(items[i].getLabel());
+                l.setHeight(25);
+                dataLayout.addMember(l);
+            }
+            Label l = new Label("...");
+            l.setHeight(25);
+            dataLayout.addMember(l);
+            l = new Label(items[items.length-1].getLabel());
+            l.setHeight(25);
+            dataLayout.addMember(l);
+        }
+        else {
+            for (int i = 0; i < items.length; i++) {
+                Label l = new Label(items[i].getLabel());
+                l.setHeight(25);
+                dataLayout.addMember(l);
+            }
+        }
+
+        HLayout layout = new HLayout();
+        layout.setWidth("400px");
+
+        Label   label  = new Label(dataList.getLabel());
+        label.setWidth("200px");
+
+        Canvas back = getBackButton(dataList.getState());
+
+        layout.addMember(label);
+        layout.addMember(dataLayout);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+     */
+    public Data[] getData() {
+        List<Data> data = new ArrayList<Data>();
+
+        if (events.size() > 0) {
+            IntDataItem[] arr = new IntDataItem[events.size()];
+            for (int i = 0, E = events.size(); i < E; i++) {
+                try {
+                    Integer v = new Integer(events.get(i));
+                    arr[i] = new IntDataItem("id", "id", v.intValue());
+                }
+                catch (NumberFormatException nfe) {
+                    return  data.toArray(new Data[data.size()]);
+                }
+            }
+
+            IntegerArrayData iad =
+                new IntegerArrayData("events", "events", arr);
+
+            data.add(iad);
+        }
+
+        return data.toArray(new Data[data.size()]);
+    }
+
+
+    @Override
+    public void setValues(String cid, boolean checked) {
+        if (checked) {
+            events.add(cid);
+        }
+        else {
+            if (events.contains(cid)) {
+                events.remove(cid);
+            }
+        }
+    }
+
+
+    @Override
+    public boolean renderCheckboxes() {
+        return true;
+    }
+
+
+    public void success() {
+        for (FixEvent fe: fixInfo.getEvents()) {
+            events.add(fe.getCId());
+        }
+    }
+
+    public void dumpGWT(String cid) {
+        GWT.log("Setting values for cId: " + cid);
+        GWT.log("River: " + fixInfo.getRiver());
+        GWT.log("Date: " + fixInfo.getEventByCId(cid).getDate());
+        GWT.log("Name: " + fixInfo.getEventByCId(cid).getDescription());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/fixation/FixFunctionSelect.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,173 @@
+package de.intevation.flys.client.client.ui.fixation;
+
+import com.smartgwt.client.types.VerticalAlignment;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class FixFunctionSelect extends FixationPanel {
+    private static final Map<String, String> funcDesc = new HashMap<String, String>();
+
+    static {
+        funcDesc.put("log", "W(Q) = m*ln(Q + b)");
+        funcDesc.put("linear", "W(Q) = m * Q + b");
+        funcDesc.put("log-linear", "W(Q) = a*ln(m*Q+b)");
+        funcDesc.put("exp", "W(Q) = m * a^Q + b");
+        funcDesc.put("quad", "W(Q) = n*Q^2+m*Q+b");
+        funcDesc.put("pow", "W(Q) = a * Q^c + d");
+        funcDesc.put("sq-pow", "S(Q) = a * Q^b");
+    }
+
+    /** The combobox.*/
+    protected DynamicForm form;
+
+    @Override
+    public Canvas createWidget(DataList data) {
+        VLayout layout   = new VLayout();
+        layout.setAlign(VerticalAlignment.TOP);
+        layout.setHeight(25);
+
+        LinkedHashMap initial = new LinkedHashMap();
+
+        form = new DynamicForm();
+
+        int size = data.size();
+
+        for (int i = 0; i < size; i++) {
+            Data d = data.get(i);
+
+            Label label = new Label(d.getDescription());
+            label.setValign(VerticalAlignment.TOP);
+            label.setHeight(20);
+            label.setWidth(400);
+
+            SelectItem combobox = new SelectItem(d.getLabel());
+            combobox.setWidth(250);
+
+            LinkedHashMap<String, String> funcTypes = new LinkedHashMap<String, String>();
+
+            boolean  defaultSet = false;
+            boolean  first      = true;
+
+            DataItem def      = d.getDefault();
+            String   defValue = def != null ? def.getStringValue() : null;
+
+            if (defValue != null && defValue.length() > 0) {
+                initial.put(d.getLabel(), def.getStringValue());
+                defaultSet = true;
+            }
+
+            // I was here. Me 2.
+            for (DataItem item: d.getItems()) {
+                if (!defaultSet && first) {
+                    initial.put(d.getLabel(), item.getStringValue());
+                    first = false;
+                }
+
+                funcTypes.put(item.getStringValue(), item.getLabel());
+            }
+
+            label.setWidth(50);
+            combobox.setValueMap(funcTypes);
+            combobox.setShowTitle(false);
+            form.setItems(combobox);
+
+            layout.addMember(label);
+            layout.addMember(form);
+        }
+
+        form.setValues(initial);
+
+        layout.setAlign(VerticalAlignment.TOP);
+
+        return layout;
+    }
+
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        HLayout layout  = new HLayout();
+        VLayout vLayout = new VLayout();
+        layout.setWidth("400px");
+
+        Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+
+        int size = dataList.size();
+        for (int i = 0; i < size; i++) {
+            Data data        = dataList.get(i);
+            DataItem[] items = data.getItems();
+
+            for (DataItem item: items) {
+                HLayout hLayout = new HLayout();
+
+                String desc = funcDesc.containsKey(item.getLabel()) ?
+                        funcDesc.get(item.getLabel()) : item.getLabel();
+                hLayout.addMember(label);
+                hLayout.addMember(new Label(desc));
+
+                vLayout.addMember(hLayout);
+                vLayout.setWidth("130px");
+            }
+        }
+
+        Canvas back = getBackButton(dataList.getState());
+
+        layout.addMember(label);
+        layout.addMember(vLayout);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    @Override
+    public Data[] getData() {
+        Map values    = form.getValues();
+        Iterator keys = values.keySet().iterator();
+
+        Data[] list = new Data[values.size()];
+        int       i = 0;
+
+        while (keys.hasNext()) {
+            String fieldname = (String) keys.next();
+            String selection = (String) values.get(fieldname);
+
+            DataItem item    = new DefaultDataItem(fieldname, null, selection);
+
+            list[i++] = new DefaultData(
+                fieldname, null, null, new DataItem[] { item });
+        }
+
+        return list;
+    }
+
+
+    @Override
+    public void setValues(String cid, boolean checked) {
+    }
+
+    @Override
+    public boolean renderCheckboxes() {
+        return false;
+    }
+
+    @Override
+    public void success() {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/fixation/FixGaugeSelectPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,179 @@
+package de.intevation.flys.client.client.ui.fixation;
+
+import com.google.gwt.core.client.GWT;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ * This UIProvider creates a panel for location or distance input.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixGaugeSelectPanel
+extends      FixationPanel
+{
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    protected String first;
+    protected String second;
+
+    protected SelectItem from;
+    protected SelectItem to;
+
+    protected LinkedHashMap<String, String> mapValues;
+
+    public FixGaugeSelectPanel() {
+        htmlOverview = "";
+
+        mapValues = new LinkedHashMap<String, String>();
+        mapValues.put("0", MESSAGES.gauge_mnq());
+        mapValues.put("1", MESSAGES.gauge_mq());
+        mapValues.put("2", MESSAGES.gauge_mhq());
+        mapValues.put("3", MESSAGES.gauge_hq5());
+    }
+
+    @Override
+    public Canvas createWidget(DataList data) {
+        instances.put(this.artifact.getUuid(), this);
+
+        VLayout layout = new VLayout();
+
+        Label title = new Label(MESSAGES.gauge_class());
+        title.setHeight(25);
+
+        from = new SelectItem(MESSAGES.from());
+        to = new SelectItem(MESSAGES.to());
+
+        from.setShowTitle(false);
+        to.setShowTitle(false);
+        from.setValueMap(mapValues);
+        from.setDefaultValues("0");
+        from.setWidth(160);
+        to.setValueMap(mapValues);
+        to.setDefaultValues("3");
+        to.setWidth(160);
+
+        DynamicForm form = new DynamicForm();
+        StaticTextItem separator = new StaticTextItem("separator");
+        separator.setShowTitle(false);
+        separator.setValue(MESSAGES.to());
+        form.setNumCols(5);
+        form.setFields(from, separator, to);
+
+        layout.addMember(title);
+        layout.addMember(form);
+
+        return layout;
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        List<Data> items = dataList.getAll();
+
+        Data f = getData(items, "q1");
+        Data t = getData(items, "q2");
+        DataItem[] fItems = f.getItems();
+        DataItem[] tItems = t.getItems();
+
+        StringBuilder sb = new StringBuilder();
+        sb.append(mapValues.get(fItems[0].getLabel()));
+        sb.append(" " + MESSAGES.to() + " ");
+        sb.append(mapValues.get(tItems[0].getLabel()));
+
+        Label old = new Label(sb.toString());
+        old.setWidth(130);
+
+        HLayout layout = new HLayout();
+        layout.setWidth("400px");
+        Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+
+        Canvas back = getBackButton(dataList.getState());
+
+        layout.addMember(label);
+        layout.addMember(old);
+        layout.addMember(back);
+        return layout;
+    }
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+     */
+    @Override
+    public Data[] getData() {
+        List<Data> data = new ArrayList<Data>();
+
+        boolean valid = saveClassValues();
+        if (valid) {
+            DataItem firstItem = new DefaultDataItem("q1", "q1", this.first);
+            DataItem secItem = new DefaultDataItem("q2", "q2", this.second);
+            data.add(new DefaultData(
+                "q1",
+                null,
+                null,
+                new DataItem[] { firstItem }));
+            data.add(new DefaultData(
+                "q2",
+                null,
+                null,
+                new DataItem[] { secItem }));
+        }
+        return data.toArray(new Data[data.size()]);
+    }
+
+
+    @Override
+    public void setValues(String cid, boolean checked) {
+        // No user interaction, do nothing.
+    }
+
+
+    @Override
+    public boolean renderCheckboxes() {
+        // No selection, return false.
+        return false;
+    }
+
+
+    @Override
+    public void success() {}
+
+    protected boolean saveClassValues() {
+        String v1 = from.getValueAsString();
+        String v2 = to.getValueAsString();
+        try {
+            int v1i = Integer.parseInt(v1);
+            int v2i = Integer.parseInt(v2);
+            if (v1i <= v2i) {
+                this.first = v1;
+                this.second = v2;
+                return true;
+            }
+        }
+        catch(NumberFormatException nfe) {
+            return false;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/fixation/FixLocationPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,193 @@
+package de.intevation.flys.client.client.ui.fixation;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import com.google.gwt.core.client.GWT;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
+import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
+
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.ui.DoubleRangePanel;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+/**
+ * This UIProvider creates a panel for location or distance input.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixLocationPanel
+extends      FixationPanel
+implements   BlurHandler
+{
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    /** The constant name of the input field to enter locations.*/
+    public static final String FIELD_VALUE_LOCATION = "location";
+
+    /** The constant name of the input field to enter distance.*/
+    public static final String FIELD_VALUE_DISTANCE = "distance";
+
+    DoubleRangePanel inputPanel;
+
+    double from;
+    double to;
+    double step;
+
+    public FixLocationPanel() {
+        htmlOverview = "";
+    }
+
+    public Canvas createWidget(DataList data) {
+        instances.put(this.artifact.getUuid(), this);
+
+        VLayout layout = new VLayout();
+
+        Canvas title = new Label(MESSAGES.distance());
+        title.setHeight("25px");
+
+        inputPanel = new DoubleRangePanel(
+                MESSAGES.unitFrom(),
+                MESSAGES.unitTo(),
+                MESSAGES.unitWidth(),
+                0d,
+                0d,
+                0d,
+                240,
+                this);
+
+        layout.addMember(title);
+        layout.addMember(inputPanel);
+        return layout;
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        List<Data> items = dataList.getAll();
+
+        Data       f      = getData(items, "from");
+        Data       t      = getData(items, "to");
+        Data       s      = getData(items, "step");
+        DataItem[] fItems = f.getItems();
+        DataItem[] tItems = t.getItems();
+        DataItem[] sItems = s.getItems();
+
+        StringBuilder sb = new StringBuilder();
+        sb.append(fItems[0].getLabel());
+        sb.append(" " + MESSAGES.unitFrom() + " ");
+        sb.append(tItems[0].getLabel());
+        sb.append(" " + MESSAGES.unitTo() + " ");
+        sb.append(sItems[0].getLabel());
+        sb.append(" " + MESSAGES.unitWidth());
+
+        Label old = new Label(sb.toString());
+        old.setWidth(130);
+
+        HLayout layout = new HLayout();
+        layout.setWidth("400px");
+
+        Label   label  = new Label(dataList.getLabel());
+        label.setWidth("200px");
+
+        Canvas back = getBackButton(dataList.getState());
+
+        layout.addMember(label);
+        layout.addMember(old);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+     */
+    public Data[] getData() {
+        List<Data> data = new ArrayList<Data>();
+
+        boolean valid = saveRangeValues(inputPanel);
+        if (valid) {
+            String f = Double.valueOf(this.from).toString();
+            String t = Double.valueOf(this.to).toString();
+            String s = Double.valueOf(this.step).toString();
+            DataItem fi = new DefaultDataItem("from", "from", f);
+            DataItem ti = new DefaultDataItem("to", "to", t);
+            DataItem si = new DefaultDataItem("step", "step", s);
+            data.add(new DefaultData("from", null, null, new DataItem[]{ fi }));
+            data.add(new DefaultData("to", null, null, new DataItem[]{ ti }));
+            data.add(new DefaultData("step", null, null, new DataItem[]{ si }));
+        }
+        // what else?
+        return data.toArray(new Data[data.size()]);
+    }
+
+
+    protected boolean saveRangeValues(DoubleRangePanel p) {
+        FormItem[] items = p.getFields();
+        boolean valid = p.validateForm();
+
+        if(valid) {
+            this.from = p.getFrom();
+            this.to = p.getTo();
+            this.step = p.getStep();
+        }
+        return valid;
+    }
+
+
+    @Override
+    public void setValues(String cid, boolean checked) {
+        // No user interaction, do nothing.
+    }
+
+
+    @Override
+    public boolean renderCheckboxes() {
+        // No selection, return false.
+        return false;
+    }
+
+
+    public void success() {
+        inputPanel.setValues(fixInfo.getFrom(), fixInfo.getTo(), 100d);
+    }
+
+    /**
+     * This method is used to validate the inserted data in the form fields.
+     *
+     * @param event The BlurEvent that gives information about the FormItem that
+     * has been modified and its value.
+     */
+    public void onBlur(BlurEvent event) {
+        FormItem item = event.getItem();
+        String  field = item.getFieldName();
+
+        if (field == null) {
+            return;
+        }
+        DoubleRangePanel p = (DoubleRangePanel) event.getForm();
+    }
+
+
+    public void dumpGWT(String cid) {
+        GWT.log("Setting values for cId: " + cid);
+        GWT.log("River: " + fixInfo.getRiver());
+        GWT.log("Date: " + fixInfo.getEventByCId(cid).getDate());
+        GWT.log("Name: " + fixInfo.getEventByCId(cid).getDescription());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/fixation/FixMultiPeriodPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,241 @@
+package de.intevation.flys.client.client.ui.fixation;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.DateTimeFormat;
+
+import com.smartgwt.client.types.ListGridFieldType;
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * This UIProvider creates a panel for location or distance input.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixMultiPeriodPanel
+extends      FixPeriodPanel
+{
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    protected ListGrid elements;
+
+    protected String values;
+
+    public FixMultiPeriodPanel() {
+        this("", "");
+    }
+
+    public FixMultiPeriodPanel(String startName, String endName) {
+        super(startName, endName);
+    }
+
+    @Override
+    public Canvas createWidget(DataList data) {
+        HLayout input = new HLayout();
+        VLayout root = new VLayout();
+        VLayout grid = new VLayout();
+        VLayout layout = (VLayout) super.createWidget(data);
+        Button add = new Button(MESSAGES.add());
+        elements = new ListGrid();
+
+        add.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent ce) {
+                Date f = inputPanel.getFromDate();
+                Date t = inputPanel.getToDate();
+                if (f == null || t == null) {
+                    return;
+                }
+                DateRangeRecord drr = new DateRangeRecord(f, t);
+                elements.addData(drr);
+            }
+        });
+        layout.addMember(add);
+
+        Label sel = new Label("Selected");
+        sel.setHeight(25);
+        elements.setWidth(185);
+        elements.setHeight(120);
+        elements.setShowHeaderContextMenu(false);
+        elements.setCanReorderFields(false);
+        elements.setCanSort(false);
+        elements.setCanEdit(false);
+        ListGridField from = new ListGridField("from", "From");
+        ListGridField to = new ListGridField("to", "To");
+        from.setWidth(70);
+        to.setWidth(70);
+
+        final ListGridField removeField  =
+            new ListGridField("_removeRecord", "Remove Record"){{
+                setType(ListGridFieldType.ICON);
+                setIcon(GWT.getHostPageBaseURL() + MSG.removeFeature());
+                setCanEdit(false);
+                setCanFilter(false);
+                setCanSort(false);
+                setCanGroupBy(false);
+                setCanFreeze(false);
+                setWidth(25);
+        }};
+
+        elements.addRecordClickHandler(new RecordClickHandler() {
+                public void onRecordClick(final RecordClickEvent event) {
+                    // Just handle remove-clicks
+                    if(!event.getField().getName().equals(removeField.getName())) {
+                        return;
+                    }
+                    event.getViewer().removeData(event.getRecord());
+                }
+            });
+
+        elements.setFields(from, to, removeField);
+
+        grid.addMember(sel);
+        grid.addMember(elements);
+        input.addMember(layout);
+        input.addMember(grid);
+        root.addMember(input);
+
+        return root;
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        HLayout layout = new HLayout();
+        layout.setWidth("400px");
+        VLayout vLayout = new VLayout();
+        vLayout.setWidth(130);
+        Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+        label.setHeight(25);
+
+        List<Data> items = dataList.getAll();
+        Data str = getData(items, "ana_data");
+        DataItem[] strItems = str.getItems();
+
+        String[] pairs = strItems[0].getLabel().split(";");
+        for (int i = 0; i < pairs.length; i++) {
+            String[] vals = pairs[i].split(",");
+            try {
+                long f = Long.valueOf(vals[0]).longValue();
+                long t = Long.valueOf(vals[1]).longValue();
+                Date from = new Date(f);
+                Date to = new Date(t);
+                String fromString =
+                    DateTimeFormat.getMediumDateFormat().format(from);
+                String toString =
+                    DateTimeFormat.getMediumDateFormat().format(to);
+
+                Label dateLabel = new Label(fromString + " - " + toString);
+                dateLabel.setHeight(20);
+                vLayout.addMember(dateLabel);
+            }
+            catch(NumberFormatException nfe) {
+            }
+        }
+        Canvas back = getBackButton(dataList.getState());
+        layout.addMember(label);
+        layout.addMember(vLayout);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+     */
+    @Override
+    public Data[] getData() {
+        List<Data> data = new ArrayList<Data>();
+
+        boolean valid = saveDateValues();
+        if(valid) {
+            DataItem item = new DefaultDataItem("ana_data", null, this.values);
+            data.add(new DefaultData(
+                        "ana_data",
+                        null,
+                        null,
+                        new DataItem[] { item }));
+        }
+        return data.toArray(new Data[data.size()]);
+    }
+
+
+    @Override
+    protected boolean saveDateValues() {
+        ListGridRecord[] lgr = elements.getRecords();
+        if (lgr.length == 0) {
+            return false;
+        }
+        String data = "";
+        for (int i = 0; i < lgr.length; i++) {
+            DateRangeRecord drr = (DateRangeRecord) lgr[i];
+            data += drr.getFrom() + "," + drr.getTo();
+            data += ";";
+        }
+        values = data;
+        return true;
+    }
+
+
+    protected static class DateRangeRecord extends ListGridRecord {
+        protected Date from;
+        protected Date to;
+
+        protected final static String FROM_FIELD = "from";
+        protected final static String TO_FIELD = "to";
+
+        public DateRangeRecord (Date from, Date to) {
+            setFrom(from);
+            setTo(to);
+        }
+
+        public void setFrom(Date from) {
+            this.from = from;
+            setAttribute(
+                FROM_FIELD,
+                DateTimeFormat.getMediumDateFormat().format(from));
+        }
+
+
+        public void setTo(Date to) {
+            this.to = to;
+            setAttribute(
+                TO_FIELD,
+                DateTimeFormat.getMediumDateFormat().format(to));
+        }
+
+
+        public long getFrom() {
+            return this.from.getTime();
+        }
+
+
+        public long getTo() {
+            return this.to.getTime();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/fixation/FixPeriodPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,242 @@
+package de.intevation.flys.client.client.ui.fixation;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.DateTimeFormat;
+
+import com.smartgwt.client.util.SC;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.DateRangeItem;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+import de.intevation.flys.client.shared.model.FixingsOverviewInfo.FixEvent;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * This UIProvider creates a panel for location or distance input.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixPeriodPanel
+extends      FixationPanel
+{
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    DateRangeItem inputPanel;
+
+    long start;
+    long end;
+
+    protected String startName;
+    protected String endName;
+
+    public FixPeriodPanel() {
+        this("start", "end");
+    }
+
+    public FixPeriodPanel(String startName, String endName) {
+        this.startName = startName;
+        this.endName   = endName;
+        htmlOverview = "";
+    }
+
+    @Override
+    public Canvas createWidget(DataList data) {
+        instances.put(this.artifact.getUuid(), this);
+
+        VLayout layout = new VLayout();
+
+        Label title = new Label(data.get(0).getDescription());
+        title.setHeight("25px");
+
+        DynamicForm form = new DynamicForm();
+        inputPanel = new DateRangeItem();
+        inputPanel.setToTitle(MESSAGES.to());
+        inputPanel.setFromTitle(MESSAGES.from());
+        inputPanel.setShowTitle(false);
+        form.setFields(inputPanel);
+
+        layout.addMember(title);
+        layout.addMember(form);
+
+        return layout;
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        List<Data> items = dataList.getAll();
+
+        Data start = getData(items, startName);
+        Data end   = getData(items, endName);
+        DataItem[] startItem = start.getItems();
+        DataItem[] endItem = end.getItems();
+
+        String v1 = startItem[0].getStringValue();
+        String v2 = endItem[0].getStringValue();
+
+        long v1l = 0;
+        long v2l = 0;
+        try {
+            v1l = Long.parseLong(v1);
+            v2l = Long.parseLong(v2);
+        }
+        catch(NumberFormatException nfe) {
+            GWT.log(nfe.toString());
+        }
+        Date d1 = new Date(v1l);
+        Date d2 = new Date(v2l);
+
+        DateTimeFormat f =
+            DateTimeFormat.getFormat(
+                DateTimeFormat.PredefinedFormat.DATE_MEDIUM);
+        StringBuilder sb = new StringBuilder();
+        sb.append(f.format(d1) + " - ");
+        sb.append(f.format(d2));
+
+        Label old = new Label(sb.toString());
+        old.setWidth(130);
+
+        HLayout layout = new HLayout();
+        layout.setWidth("400px");
+
+        Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+
+        Canvas back = getBackButton(dataList.getState());
+
+        layout.addMember(label);
+        layout.addMember(old);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+     */
+    @Override
+    public Data[] getData() {
+        List<Data> data = new ArrayList<Data>();
+
+        boolean valid = saveDateValues();
+        if(valid) {
+            String start = Long.valueOf(this.start).toString();
+            String end   = Long.valueOf(this.end).toString();
+            DataItem startItem = new DefaultDataItem(startName, startName, start);
+            DataItem endItem   = new DefaultDataItem(endName, endName, end);
+            data.add(new DefaultData(
+                startName,
+                null,
+                null,
+                new DataItem[] { startItem }));
+            data.add(new DefaultData(
+                endName,
+                null,
+                null,
+                new DataItem[] { endItem }));
+        }
+
+        return data.toArray(new Data[data.size()]);
+    }
+
+
+    @Override
+    public void setValues(String cid, boolean checked) {
+        // No user interaction, do nothing.
+    }
+
+
+    @Override
+    public boolean renderCheckboxes() {
+        // No selection, return false.
+        return false;
+    }
+
+    protected String getLocaleDateFormat() {
+        String loc = Config.getInstance().getLocale();
+        if ("de".equals(loc)) {
+            return "yy.MM.yyyy";
+        }
+        else {
+            return "MM/dd/yyyy";
+        }
+    }
+
+    @Override
+    public void success() {
+        List<FixEvent> list = fixInfo.getEvents();
+
+        // The date in FixEvent is always "de" locale, so it seems...
+        DateTimeFormat df = DateTimeFormat.getFormat("yy.MM.yyyy");
+
+        if (!setFromAndToDate(list, df)) {
+            // or perhaps "en"?
+            df = DateTimeFormat.getFormat("MM/dd/yyyy");
+
+            if (!setFromAndToDate(list, df)) {
+                GWT.log("FixPeriodPanel::success(): could not set from and to dates!");
+            }
+        }
+    }
+
+    protected boolean setFromAndToDate(List<FixEvent> list, DateTimeFormat df) {
+        try {
+            setFromDate(list.get(0).getDate(), df);
+            setToDate(list.get(list.size() - 1).getDate(), df);
+            return true;
+        }
+        catch(IllegalArgumentException ex) {
+            GWT.log("FixPeriodPanel::setFromAndToDate(): " + ex.toString());
+            return false;
+        }
+    }
+
+    protected void setFromDate(String date, DateTimeFormat df)
+        throws IllegalArgumentException
+    {
+        Date from = df.parse(date);
+        this.inputPanel.setFromDate(from);
+    }
+
+    protected void setToDate(String date, DateTimeFormat df)
+        throws IllegalArgumentException
+    {
+        Date to = df.parse(date);
+        this.inputPanel.setToDate(to);
+    }
+
+    protected boolean saveDateValues() {
+        Date st = inputPanel.getFromDate();
+        Date en = inputPanel.getToDate();
+        if (st == null || en == null) {
+            SC.warn(MESSAGES.error_wrong_date());
+            return false;
+        }
+
+        long start = st.getTime();
+        long end = en.getTime();
+
+        if (start <= end) {
+            this.start = start;
+            this.end = end;
+            return true;
+        }
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/fixation/FixQSelectPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,63 @@
+package de.intevation.flys.client.client.ui.fixation;
+
+import com.google.gwt.core.client.GWT;
+
+import com.smartgwt.client.widgets.Canvas;
+
+import de.intevation.flys.client.client.FLYSConstants;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataList;
+
+/**
+ * This UIProvider creates a panel for location or distance input.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixQSelectPanel
+extends      FixationPanel
+{
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    public FixQSelectPanel() {
+        htmlOverview = "";
+    }
+
+    public Canvas createWidget(DataList data) {
+        instances.put(this.artifact.getUuid(), this);
+
+        return new Canvas();
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        return new Canvas();
+    }
+
+
+    /**
+     * This method returns the selected data.
+     *
+     * @return the selected/inserted data.
+     */
+    public Data[] getData() {
+        return new Data[0];
+    }
+
+
+    @Override
+    public void setValues(String cid, boolean checked) {
+        // No user interaction, do nothing.
+    }
+
+
+    @Override
+    public boolean renderCheckboxes() {
+        // No selection, return false.
+        return false;
+    }
+
+
+    public void success() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/fixation/FixationPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,482 @@
+package de.intevation.flys.client.client.ui.fixation;
+
+import com.google.gwt.core.client.GWT;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import com.smartgwt.client.types.Alignment;
+
+import com.smartgwt.client.util.SC;
+
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.HTMLPane;
+import com.smartgwt.client.widgets.Img;
+
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.events.ResizedEvent;
+import com.smartgwt.client.widgets.events.ResizedHandler;
+
+import com.smartgwt.client.widgets.form.DynamicForm;
+
+import com.smartgwt.client.widgets.form.fields.TextItem;
+
+import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import com.smartgwt.client.widgets.tab.Tab;
+import com.smartgwt.client.widgets.tab.TabSet;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.FLYSConstants;
+
+import de.intevation.flys.client.client.services.FixingsOverviewService;
+import de.intevation.flys.client.client.services.FixingsOverviewServiceAsync;
+
+import de.intevation.flys.client.client.ui.AbstractUIProvider;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.FixAnalysisArtifact;
+import de.intevation.flys.client.shared.model.FixFilter;
+import de.intevation.flys.client.shared.model.FixingsOverviewInfo;
+
+import java.util.Date;
+import java.util.HashMap;
+
+
+/**
+ * This UIProvider creates helper panel for fixation analysis without input
+ * elements.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public abstract class FixationPanel
+extends               AbstractUIProvider
+implements            ResizedHandler
+{
+    protected static HashMap<String, FixationPanel> instances = new HashMap<String, FixationPanel>();
+
+    /** The message class that provides i18n strings. */
+    protected FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    protected FixingsOverviewServiceAsync overviewService =
+        GWT.create(FixingsOverviewService.class);
+
+    protected String htmlOverview;
+    protected FixingsOverviewInfo fixInfo;
+    protected TabSet tabs;
+    protected Tab events;
+    protected Tab chart;
+    protected VLayout chartContainer;
+    protected Img chartImg;
+    protected TextItem kmText;
+
+    public static final DateTimeFormat DTF = DateTimeFormat.getFormat("dd.MM.yyyy");
+
+
+    public FixationPanel() {
+        chartImg = new Img();
+        htmlOverview = "";
+    }
+
+    
+    /** Get the (master) artifact UUID. */
+    protected String getArtifactUuid() {
+        return this.artifact.getUuid();
+    }
+
+    protected void init() {
+    }
+
+    public Data[] getData() {
+        return null;
+    }
+
+    public Canvas create(DataList list) {
+        VLayout layout = new VLayout();
+
+        Canvas helper = createHelper();
+        this.helperContainer.addMember(helper);
+
+        Canvas submit = getNextButton();
+        Canvas widget = createWidget(list);
+
+        layout.addMember(widget);
+        layout.addMember(submit);
+        return layout;
+    }
+
+    public Canvas createOld(DataList list) {
+        return new DynamicForm();
+    }
+
+    protected Canvas createHelper() {
+        Config config    = Config.getInstance();
+        String locale    = config.getLocale ();
+
+        tabs = new TabSet();
+        events = new Tab(MESSAGES.events());
+        chart = new Tab(MESSAGES.kmchart());
+
+        chartContainer = new VLayout();
+        Canvas scroll = createChartHelper();
+
+        VLayout layout = new VLayout();
+        layout.addResizedHandler(this);
+        layout.addMember(chartContainer);
+        layout.addMember(scroll);
+        layout.setAlign(Alignment.CENTER);
+        chart.setPane(layout);
+
+        final HTMLPane eventPane = new HTMLPane();
+
+        String river = artifact.getArtifactDescription().getRiver();
+        createCallback();
+
+        String callBack = "fixationCallback(this.checked, this.name)";
+        FixAnalysisArtifact art = (FixAnalysisArtifact) this.artifact;
+
+        overviewService.generateOverview(
+            locale,
+            artifact.getUuid(),
+            getOverviewFilter(art.getFilter()),
+            renderCheckboxes(),
+            callBack,
+            new AsyncCallback<FixingsOverviewInfo>() {
+                public void onFailure(Throwable caught) {
+                    GWT.log("Could not receive overview.");
+                    SC.warn(caught.getMessage());
+                }
+                public void onSuccess(FixingsOverviewInfo info) {
+                    GWT.log("Successfully loaded overview.");
+                    fixInfo = info;
+                    htmlOverview = info.getHTML();
+                    FixAnalysisArtifact art = (FixAnalysisArtifact)artifact;
+                    FixFilter filter = art.getFilter();
+                    filter.setRiver(info.getRiver());
+                    if (filter.getCurrentKm() == -Double.MAX_VALUE ||
+                        filter.getCurrentKm() == -1d) {
+                        filter.setCurrentKm(info.getFrom());
+                        filter.setToKm(info.getTo());
+                    }
+                    if (kmText != null) {
+                        NumberFormat nf = NumberFormat.getDecimalFormat();
+                        try {
+                            double d = Double.valueOf(filter.getCurrentKm());
+                            kmText.setValue(nf.format(d));
+                        } catch (NumberFormatException e) {
+                            kmText.setValue(filter.getCurrentKm());
+                        }
+                    }
+                    eventPane.setContents(htmlOverview);
+                    updateChartTab(fixInfo.getFrom());
+                    events.setPane(eventPane);
+                    success();
+                }
+            });
+
+        tabs.addTab(events);
+        tabs.addTab(chart);
+
+        return tabs;
+    }
+
+
+    protected Canvas createChartHelper() {
+        DynamicForm form = new DynamicForm();
+        Button lower = new Button("<<");
+        lower.setWidth(30);
+        Button upper = new Button(">>");
+        upper.setWidth(30);
+        kmText = new TextItem();
+        kmText.setWidth(60);
+        kmText.setShowTitle(false);
+
+
+        form.setFields(kmText);
+        form.setWidth(60);
+        lower.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent ce) {
+                FixFilter filter = updateChartTabLow();
+                NumberFormat nf = NumberFormat.getDecimalFormat();
+                try {
+                    double d = Double.valueOf(filter.getCurrentKm());
+                    kmText.setValue(nf.format(d));
+                } catch (NumberFormatException e) {
+                    kmText.setValue(filter.getCurrentKm());
+                }
+            }
+        });
+
+        upper.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent ce) {
+                FixFilter filter = updateChartTabUp();
+                NumberFormat nf = NumberFormat.getDecimalFormat();
+                try {
+                    double d = Double.valueOf(filter.getCurrentKm());
+                    kmText.setValue(nf.format(d));
+                } catch (NumberFormatException e) {
+                    kmText.setValue(filter.getCurrentKm());
+                }
+            }
+        });
+
+        kmText.addChangedHandler(new ChangedHandler() {
+            public void onChanged(ChangedEvent ce) {
+                //TODO: get current value.
+                if(ce.getItem().getValue() != null) {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    try {
+                        double d = nf.parse(ce.getItem().getValue().toString());
+                        updateChartTab(d);
+                    }
+                    catch(NumberFormatException nfe) {
+                        // Do nothing.
+                    }
+                }
+            }
+        });
+
+        HLayout layout = new HLayout();
+        layout.setAlign(Alignment.CENTER);
+
+        layout.addMember(lower);
+        layout.addMember(form);
+        layout.addMember(upper);
+        return layout;
+    }
+
+    protected void updateChartTab(double km) {
+        Config config    = Config.getInstance();
+        String locale    = config.getLocale ();
+
+        FixAnalysisArtifact art = (FixAnalysisArtifact) this.artifact;
+
+        if (fixInfo != null) {
+            if (km < fixInfo.getFrom()) km = fixInfo.getFrom();
+            if (km > fixInfo.getTo())   km = fixInfo.getTo();
+        }
+
+        FixFilter filter = art.getFilter();
+
+        if (km < filter.getFromKm()) km = filter.getFromKm();
+        if (km > filter.getToKm())   km = filter.getToKm();
+
+        filter.setCurrentKm(km);
+
+        int hWidth = helperContainer.getWidth() - 12;
+        int hHeight = helperContainer.getHeight() - 62;
+
+        if ((int)(hHeight *4f/3) < hWidth) {
+            hWidth = (int)(hHeight * 4f/3);
+        }
+        else {
+            hHeight = (int)(hWidth *3f/4);
+        }
+
+        String imgUrl = GWT.getModuleBaseURL();
+        imgUrl += "fixings-km-chart";
+        imgUrl += "?locale=" + locale;
+        imgUrl += "&filter=" + getChartFilter(filter, hWidth, hHeight);
+
+        if (chartContainer.hasMember(chartImg)) {
+            chartImg.setWidth(hWidth);
+            chartImg.setHeight(hHeight);
+            chartImg.setSrc(imgUrl);
+        }
+        else {
+            chartImg = new Img(imgUrl, hWidth, hHeight);
+            chartContainer.addMember(chartImg);
+        }
+    }
+
+
+    protected FixFilter updateChartTabLow() {
+        FixAnalysisArtifact art = (FixAnalysisArtifact) this.artifact;
+
+        FixFilter filter = art.getFilter();
+
+        double curr = filter.getCurrentKm();
+        if (curr > filter.getFromKm()) {
+            double newVal = (curr - 0.1) * 10;
+            long round = Math.round(newVal);
+            updateChartTab(((double)round) / 10);
+        }
+        return filter;
+    }
+
+
+    protected FixFilter updateChartTabUp() {
+        FixAnalysisArtifact art = (FixAnalysisArtifact) this.artifact;
+
+        FixFilter filter = art.getFilter();
+
+        double curr = filter.getCurrentKm();
+        if (curr < filter.getToKm()) {
+            double newVal = (curr + 0.1) * 10;
+            long round = Math.round(newVal);
+            updateChartTab(((double)round) / 10);
+        }
+        return filter;
+    }
+
+
+    public void onResized(ResizedEvent re) {
+        FixAnalysisArtifact art = (FixAnalysisArtifact) this.artifact;
+
+        updateChartTab(art.getFilter().getCurrentKm());
+    }
+
+
+    private native void createCallback() /*-{
+        $wnd.fixationCallback = @de.intevation.flys.client.client.ui.fixation.FixationPanel::helperCallback(ZLjava/lang/String;);
+    }-*/;
+
+    private static void helperCallback(boolean checked, String name) {
+        String[] parts = name.split(":");
+        String uuid = parts[0];
+        String cid = parts[1];
+
+        FixationPanel p = FixationPanel.getInstance(uuid);
+        if (p != null) {
+            p.setValues(cid, checked);
+        }
+    }
+
+    private static FixationPanel getInstance(String uuid) {
+        return instances.get(uuid);
+    }
+
+    public abstract Canvas createWidget(DataList data);
+    public abstract void setValues(String cid, boolean checked);
+    public abstract boolean renderCheckboxes();
+    public abstract void success();
+
+
+    public static String getOverviewFilter(FixFilter filter) {
+        String river = filter.getRiver();
+
+        if (river != null && river.length() > 0) {
+            JSONObject jfix = new JSONObject();
+            JSONObject jfilter = new JSONObject();
+            JSONObject jrName = new JSONObject();
+            JSONString jrValue = new JSONString(river);
+            jrName.put("name", jrValue);
+            jfilter.put("river", jrName);
+            jfix.put("fixings", createFilter(filter, jfilter));
+            return jfix.toString();
+        }
+        return "";
+    }
+
+    public String getChartFilter(FixFilter filter, int width, int height) {
+        String river     = filter.getRiver();
+        double currentKm = filter.getCurrentKm();
+        double fromKm    = filter.getFromKm();
+        double toKm      = filter.getToKm();
+
+        if (river != null && river.length() > 0 &&
+            currentKm >= fromKm && currentKm <= toKm)
+        {
+            JSONObject jfix = new JSONObject();
+            JSONObject jfilter = new JSONObject();
+            JSONObject jrName = new JSONObject();
+            JSONString jrValue = new JSONString(river);
+            JSONObject jkm = new JSONObject();
+            JSONNumber jkmValue = new JSONNumber(currentKm);
+            JSONObject jextent = new JSONObject();
+            JSONNumber jwidth = new JSONNumber(width);
+            JSONNumber jheight = new JSONNumber(height);
+
+            jkm.put("value", jkmValue);
+            jrName.put("name", jrValue);
+            jfilter.put("river", jrName);
+            jfilter.put("km", jkm);
+            jextent.put("width", jwidth);
+            jextent.put("height", jheight);
+            jfilter.put("extent", jextent);
+            jfix.put("fixings", createFilter(filter, jfilter));
+            return jfix.toString();
+        }
+        return "";
+    }
+
+    protected static JSONObject createFilter(FixFilter filter, JSONObject root) {
+        double fromKm = filter.getFromKm();
+        double toKm   = filter.getToKm();
+        boolean hasDate = filter.getFromDate() > 0 && filter.getToDate() > 0;
+
+        if (fromKm >= 0 && toKm >= 0 && fromKm <= toKm) {
+            JSONObject range = new JSONObject();
+            JSONObject fromtokm = new JSONObject();
+            JSONNumber f = new JSONNumber(fromKm);
+            JSONNumber t = new JSONNumber(toKm);
+            fromtokm.put("from", f);
+            fromtokm.put("to", t);
+            root.put("range", fromtokm);
+        }
+
+        JSONObject and = new JSONObject();
+        if (hasDate) {
+            long fromDate = filter.getFromDate();
+            long toDate   = filter.getToDate();
+
+            Date df = new Date(fromDate);
+            Date dt = new Date(toDate);
+
+            JSONObject daterange = new JSONObject();
+            JSONString f = new JSONString(DTF.format(df));
+            JSONString t = new JSONString(DTF.format(dt));
+
+            daterange.put("from", f);
+            daterange.put("to", t);
+            and.put("date-range", daterange);
+        }
+
+        int fromClass = filter.getFromClass();
+        int toClass   = filter.getToClass();
+
+        if (fromClass >= 0 && toClass >= 0 && fromClass <= toClass) {
+            JSONObject classrange = new JSONObject();
+            JSONNumber f = new JSONNumber(fromClass);
+            JSONNumber t = new JSONNumber(toClass);
+
+            classrange.put("from", f);
+            classrange.put("to", t);
+            and.put("sector-range", classrange);
+        }
+
+        int[] events = filter.getEvents();
+
+        if (events.length > 0) {
+            StringBuilder cids = new StringBuilder();
+
+            for (int i = 0; i < events.length; i++) {
+                if (i > 0) cids.append(' ');
+                cids.append(events[i]);
+            }
+            JSONObject columns = new JSONObject();
+            columns.put("cids", new JSONString(cids.toString()));
+            and.put("columns", columns);
+        }
+        if (and.size() > 0) {
+            JSONObject jFilter = new JSONObject();
+            jFilter.put("and", and);
+            root.put("filter", jFilter);
+        }
+        return root;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/ElevationWindow.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/ElevationWindow.java	Fri Sep 28 12:15:52 2012 +0200
@@ -13,7 +13,7 @@
 import com.smartgwt.client.widgets.Window;
 import com.smartgwt.client.widgets.events.ClickEvent;
 import com.smartgwt.client.widgets.events.ClickHandler;
-import com.smartgwt.client.widgets.events.CloseClientEvent;
+import com.smartgwt.client.widgets.events.CloseClickEvent;
 import com.smartgwt.client.widgets.events.CloseClickHandler;
 import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.layout.VLayout;
@@ -85,7 +85,7 @@
 
     protected void init() {
         addCloseClickHandler(new CloseClickHandler() {
-            public void onCloseClick(CloseClientEvent evt) {
+            public void onCloseClick(CloseClickEvent evt) {
                 doClose();
             }
         });
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/ExternalWMSWindow.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/ExternalWMSWindow.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,15 +2,18 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.LinkedHashMap;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.TextBox;
 
 import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.Button;
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.Window;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.ComboBoxItem;
 import com.smartgwt.client.widgets.events.ClickEvent;
 import com.smartgwt.client.widgets.events.ClickHandler;
 import com.smartgwt.client.widgets.grid.ListGridRecord;
@@ -23,6 +26,8 @@
 import de.intevation.flys.client.client.FLYSConstants;
 import de.intevation.flys.client.client.services.GCService;
 import de.intevation.flys.client.client.services.GCServiceAsync;
+import de.intevation.flys.client.client.services.MapUrlService;
+import de.intevation.flys.client.client.services.MapUrlServiceAsync;
 
 
 public class ExternalWMSWindow extends Window {
@@ -33,6 +38,7 @@
 
 
     protected GCServiceAsync gcService = GWT.create(GCService.class);
+    protected MapUrlServiceAsync muService = GWT.create(MapUrlService.class);
     protected FLYSConstants  MSG       = GWT.create(FLYSConstants.class);
 
     protected Layout inputPanel;
@@ -43,6 +49,7 @@
 
     protected String srs;
 
+    protected LinkedHashMap<String, String> urls;
     protected String url;
 
     protected LayerLoader loader;
@@ -50,6 +57,7 @@
 
     public ExternalWMSWindow(LayerLoader loader) {
         super();
+        this.urls = new LinkedHashMap<String, String>();
         this.loader = loader;
     }
 
@@ -146,12 +154,32 @@
     }
 
 
+    protected void setUrls(Map<String, String> urls) {
+        this.urls.putAll(urls);
+    }
+
+    protected void readUrls() {
+    }
+
+
     protected Layout createInputPanel() {
         setTitle(MSG.addwmsInputTitle());
 
-        final TextBox url = new TextBox();
-        url.setHeight("25px");
-        url.setWidth("326px");
+        readUrls();
+
+        DynamicForm form = new DynamicForm();
+        final ComboBoxItem url = new ComboBoxItem("Url:");
+        url.setRedrawOnChange(true);
+        muService.getUrls(new AsyncCallback<Map<String, String> >() {
+            public void onFailure(Throwable caught) {
+                GWT.log("Error reading WMS-Services" + caught.getMessage());
+            }
+            public void onSuccess(Map<String, String> wms) {
+                urls.putAll(wms);
+                url.setValueMap(urls);
+
+            }
+        });
 
         String oldUrl = getUrl();
         if (oldUrl != null && oldUrl.length() > 0) {
@@ -161,14 +189,14 @@
         ClickHandler goHandler = new ClickHandler() {
             @Override
             public void onClick(ClickEvent e) {
-                String newUrl = url.getValue();
+                String newUrl = url.getValue().toString();
 
                 if (!isUrlValid(newUrl)) {
                     SC.warn(MSG.addwmsInvalidURL());
                     return;
                 }
 
-                setUrl(url.getValue());
+                setUrl(newUrl);
 
                 doCapabilitesRequest();
             }
@@ -186,7 +214,8 @@
         root.setMargin(10);
         root.setLayoutMargin(10);
 
-        root.addMember(url);
+        form.setFields(url);
+        root.addMember(form);
         root.addMember(createButtonPanel(null, goHandler, cancelHandler));
 
         return root;
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/FloodMap.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/FloodMap.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,7 +1,7 @@
 package de.intevation.flys.client.client.ui.map;
 
-
 import org.gwtopenmaps.openlayers.client.Bounds;
+import org.gwtopenmaps.openlayers.client.LonLat;
 import org.gwtopenmaps.openlayers.client.Map;
 import org.gwtopenmaps.openlayers.client.MapOptions;
 import org.gwtopenmaps.openlayers.client.MapWidget;
@@ -9,7 +9,6 @@
 import org.gwtopenmaps.openlayers.client.control.ScaleLine;
 import org.gwtopenmaps.openlayers.client.control.ScaleLineOptions;
 import org.gwtopenmaps.openlayers.client.event.VectorFeatureAddedListener;
-import org.gwtopenmaps.openlayers.client.event.VectorFeatureAddedListener.FeatureAddedEvent;
 import org.gwtopenmaps.openlayers.client.feature.VectorFeature;
 import org.gwtopenmaps.openlayers.client.format.GeoJSON;
 import org.gwtopenmaps.openlayers.client.layer.Layer;
@@ -18,7 +17,6 @@
 import org.gwtopenmaps.openlayers.client.util.Attributes;
 import org.gwtopenmaps.openlayers.client.util.JObjectArray;
 import org.gwtopenmaps.openlayers.client.util.JSObject;
-import org.gwtopenmaps.openlayers.client.LonLat;
 
 
 public class FloodMap implements VectorFeatureAddedListener {
@@ -34,12 +32,17 @@
     protected Vector    barrierLayer;
     protected String    srid;
     protected Bounds    maxExtent;
-
+    protected ScaleLine scaleLine;
 
     public FloodMap(String srid, Bounds maxExtent) {
         this.srid      = srid;
         this.maxExtent = maxExtent;
+        recreateWidget("100%", "99px");
+        getBarrierLayer();
+    }
 
+
+    public void recreateWidget(String width, String height) {
         MapOptions opts = new MapOptions();
         opts.setControls(new JObjectArray(new JSObject[] {}));
         opts.setNumZoomLevels(16);
@@ -48,18 +51,8 @@
         opts.setUnits("m");
         opts.setMaxResolution(500); // TODO DO THIS ON THE FLY
 
-        mapWidget = new MapWidget("510px", "635px", opts);
+        mapWidget = new MapWidget(width, height, opts);
         map       = mapWidget.getMap();
-
-        ScaleLineOptions slOpts = new ScaleLineOptions();
-        slOpts.setBottomInUnits("m");
-        slOpts.setBottomOutUnits("km");
-        slOpts.setTopInUnits("");
-        slOpts.setTopOutUnits("");
-
-        map.addControl(new ScaleLine(slOpts));
-
-        getBarrierLayer();
     }
 
 
@@ -305,5 +298,22 @@
             l.redraw();
         }
     }
+
+
+    public void activateScaleLine(boolean activate) {
+        if (activate) {
+            ScaleLineOptions slOpts = new ScaleLineOptions();
+            slOpts.setBottomInUnits("m");
+            slOpts.setBottomOutUnits("km");
+            slOpts.setTopInUnits("");
+            slOpts.setTopOutUnits("");
+
+            scaleLine = new ScaleLine(slOpts);
+            this.map.addControl(scaleLine);
+        }
+        else if (!activate && scaleLine != null){
+            this.map.removeControl(scaleLine);
+        }
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfo.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -26,6 +26,8 @@
 
     protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
 
+    protected GetFeatureInfoWindow gfiWindow;
+
     protected Map        map;
     protected ThemePanel themePanel;
     protected String     infoFormat;
@@ -54,13 +56,23 @@
     }
 
 
+    protected void newGetFeatureInfoWindow(List<FeatureInfo> features) {
+        if (gfiWindow != null) {
+            gfiWindow.destroy();
+        }
+
+        gfiWindow = new GetFeatureInfoWindow(features);
+        gfiWindow.show();
+    }
+
+
     @Override
     public void onClick(MapClickListener.MapClickEvent e) {
         LonLat lonlat = e.getLonLat();
         Pixel  pixel  = map.getPixelFromLonLat(lonlat);
 
         gfiService.query(
-            themePanel.getThemeList().getThemes(),
+            themePanel.getThemeList().getActiveThemes(),
             infoFormat,
             map.getExtent().toString(),
             map.getProjection(),
@@ -73,7 +85,7 @@
             }
 
             public void onSuccess(List<FeatureInfo> features) {
-                new GetFeatureInfoWindow(features).show();
+                newGetFeatureInfoWindow(features);
             }
         });
     }
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfoWindow.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/GetFeatureInfoWindow.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,24 +1,22 @@
 package de.intevation.flys.client.client.ui.map;
 
+import com.google.gwt.core.client.GWT;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.Window;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.shared.model.FeatureInfo;
+
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import com.google.gwt.core.client.GWT;
-
-import com.smartgwt.client.widgets.Label;
-import com.smartgwt.client.widgets.Window;
-import com.smartgwt.client.widgets.layout.HLayout;
-import com.smartgwt.client.widgets.layout.VLayout;
-
 import org.gwtopenmaps.openlayers.client.feature.VectorFeature;
 import org.gwtopenmaps.openlayers.client.util.Attributes;
 import org.gwtopenmaps.openlayers.client.util.JSObject;
 
-import de.intevation.flys.client.shared.model.FeatureInfo;
-
-import de.intevation.flys.client.client.FLYSConstants;
-
 
 public class GetFeatureInfoWindow extends Window {
 
@@ -50,10 +48,13 @@
 
         addItem(root);
 
-        setWidth(400);
-        setHeight(50 + rows * ROW_HEIGHT);
+        setWidth(500);
+        setHeight(500); // + rows * ROW_HEIGHT);
         setTitle(MSG.getFeatureInfoWindowTitle());
 
+        setIsModal(true);
+        setShowModalMask(true);
+
         centerInPage();
     }
 
@@ -62,16 +63,17 @@
         HLayout r = new HLayout();
         r.setHeight(ROW_HEIGHT);
         r.setStyleName("featureinfo-row");
+        r.setMembersMargin(5);
 
         Label l = new Label("Layer: " + feature.getLayername());
         l.setHeight(ROW_HEIGHT);
-
+        l.setWrap(false);
         r.addMember(l);
 
         Map<String, String> attrs = feature.getAttrs();
         Set<Map.Entry<String, String>> entries = attrs.entrySet();
 
-        for (Map.Entry entry: entries) {
+        for (Map.Entry<String, String> entry: entries) {
             Label attr = new Label(entry.getKey() + ": " + entry.getValue());
             attr.setHeight(ROW_HEIGHT);
 
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapOutputTab.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapOutputTab.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,33 +1,30 @@
 package de.intevation.flys.client.client.ui.map;
 
-import java.util.List;
-
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.HorizontalPanel;
 import com.google.gwt.user.client.ui.Widget;
-
 import com.smartgwt.client.util.SC;
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.events.ResizedEvent;
 import com.smartgwt.client.widgets.events.ResizedHandler;
 import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.layout.VLayout;
+import com.smartgwt.client.widgets.tab.events.TabSelectedEvent;
+import com.smartgwt.client.widgets.tab.events.TabSelectedHandler;
 
-import org.gwtopenmaps.openlayers.client.Bounds;
-import org.gwtopenmaps.openlayers.client.Map;
-import org.gwtopenmaps.openlayers.client.event.VectorFeatureAddedListener;
-import org.gwtopenmaps.openlayers.client.event.VectorFeatureAddedListener.FeatureAddedEvent;
-import org.gwtopenmaps.openlayers.client.event.VectorFeatureRemovedListener;
-import org.gwtopenmaps.openlayers.client.event.VectorFeatureRemovedListener.FeatureRemovedEvent;
-import org.gwtopenmaps.openlayers.client.feature.VectorFeature;
-import org.gwtopenmaps.openlayers.client.format.GeoJSON;
-import org.gwtopenmaps.openlayers.client.layer.Layer;
-import org.gwtopenmaps.openlayers.client.layer.Vector;
-import org.gwtopenmaps.openlayers.client.layer.WMS;
-import org.gwtopenmaps.openlayers.client.layer.WMSParams;
-import org.gwtopenmaps.openlayers.client.layer.WMSOptions;
-
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.event.RedrawRequestEvent;
+import de.intevation.flys.client.client.event.RedrawRequestHandler;
+import de.intevation.flys.client.client.services.LoadArtifactService;
+import de.intevation.flys.client.client.services.LoadArtifactServiceAsync;
+import de.intevation.flys.client.client.services.MapOutputService;
+import de.intevation.flys.client.client.services.MapOutputServiceAsync;
+import de.intevation.flys.client.client.services.StepForwardService;
+import de.intevation.flys.client.client.services.StepForwardServiceAsync;
+import de.intevation.flys.client.client.ui.CollectionView;
+import de.intevation.flys.client.client.ui.OutputTab;
+import de.intevation.flys.client.client.ui.ThemePanel;
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.shared.model.ArtifactDescription;
 import de.intevation.flys.client.shared.model.AttributedTheme;
@@ -38,30 +35,30 @@
 import de.intevation.flys.client.shared.model.DefaultData;
 import de.intevation.flys.client.shared.model.DefaultDataItem;
 import de.intevation.flys.client.shared.model.MapConfig;
+import de.intevation.flys.client.shared.model.OutputMode;
 import de.intevation.flys.client.shared.model.Recommendation;
 import de.intevation.flys.client.shared.model.Theme;
 import de.intevation.flys.client.shared.model.ThemeList;
-import de.intevation.flys.client.shared.model.OutputMode;
 import de.intevation.flys.client.shared.model.WMSLayer;
 
-import de.intevation.flys.client.client.Config;
-import de.intevation.flys.client.client.FLYSConstants;
-import de.intevation.flys.client.client.services.LoadArtifactService;
-import de.intevation.flys.client.client.services.LoadArtifactServiceAsync;
-import de.intevation.flys.client.client.services.StepForwardService;
-import de.intevation.flys.client.client.services.StepForwardServiceAsync;
-import de.intevation.flys.client.client.services.MapOutputService;
-import de.intevation.flys.client.client.services.MapOutputServiceAsync;
-import de.intevation.flys.client.client.event.RedrawRequestHandler;
-import de.intevation.flys.client.client.event.RedrawRequestEvent;
-import de.intevation.flys.client.client.ui.CollectionView;
-import de.intevation.flys.client.client.ui.OutputTab;
-import de.intevation.flys.client.client.ui.ThemePanel;
+import java.util.List;
+
+import org.gwtopenmaps.openlayers.client.Bounds;
+import org.gwtopenmaps.openlayers.client.Map;
+import org.gwtopenmaps.openlayers.client.event.VectorFeatureAddedListener;
+import org.gwtopenmaps.openlayers.client.event.VectorFeatureRemovedListener;
+import org.gwtopenmaps.openlayers.client.feature.VectorFeature;
+import org.gwtopenmaps.openlayers.client.format.GeoJSON;
+import org.gwtopenmaps.openlayers.client.layer.Layer;
+import org.gwtopenmaps.openlayers.client.layer.Vector;
+import org.gwtopenmaps.openlayers.client.layer.WMS;
+import org.gwtopenmaps.openlayers.client.layer.WMSOptions;
+import org.gwtopenmaps.openlayers.client.layer.WMSParams;
 
 
 public class MapOutputTab
 extends      OutputTab
-implements   RedrawRequestHandler, ExternalWMSWindow.LayerLoader {
+implements   RedrawRequestHandler, ExternalWMSWindow.LayerLoader, TabSelectedHandler {
 
     public static final String DEFAULT_SRID = "4326";
 
@@ -86,7 +83,9 @@
 
     protected MapToolbar controlPanel;
     protected ThemePanel themePanel;
+    protected Canvas     themePanelCanvas;
     protected Widget     mapPanel;
+    protected Canvas mapPanelCanvas;
 
     protected FloodMap floodMap;
 
@@ -99,11 +98,15 @@
     ){
         super(title, collection, collectionView, mode);
 
+        collectionView.registerTabHandler(this);
+
         mapService.doOut(collection, new AsyncCallback<MapConfig>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("MAP ERROR: " + caught.getMessage());
                 }
 
+                @Override
                 public void onSuccess(MapConfig c) {
                     GWT.log("MAP SUCCESS!");
 
@@ -136,29 +139,26 @@
         rootLayout.setMembersMargin(2);
 
         final HLayout hlayout = new HLayout();
-        hlayout.setHeight("*");
-        hlayout.setWidth100();
         hlayout.setMembersMargin(2);
 
-        final Canvas themePanelWrapper = createThemePanel();
+        this.themePanelCanvas = createThemePanel();
 
         controlPanel = createControlPanel();
-        mapPanel     = floodMap.getMapWidget();
-        final HorizontalPanel layout = new HorizontalPanel();
-        layout.setWidth("99%");
-        layout.setHeight("99%");
-        layout.add(mapPanel);
-
-        hlayout.addMember(themePanelWrapper);
-        hlayout.addMember(layout);
+        //mapPanel     = new Image();
+        //((Image)mapPanel).setUrl("http://www.hedweb.com/animimag/cool-pony.jpg");
+        mapPanel = floodMap.getMapWidget();
+        hlayout.addMember(themePanelCanvas);
+        hlayout.addMember(mapPanel);
 
         rootLayout.addMember(controlPanel);
         rootLayout.addMember(hlayout);
 
         hlayout.addResizedHandler(new ResizedHandler() {
+            @Override
             public void onResized(ResizedEvent e) {
-                Integer height = hlayout.getHeight();
-                Integer width  = hlayout.getWidth() - themePanelWrapper.getWidth();
+                int height = hlayout.getHeight();
+                int width  = hlayout.getWidth() -
+                        (themePanelCanvas.isVisible() ? themePanelCanvas.getWidth() : 0);
 
                 height = height * 99 / 100;
                 width  = width  * 99 / 100;
@@ -166,7 +166,7 @@
                 String w = String.valueOf(width) + "px";
                 String h = String.valueOf(height) + "px";
 
-                floodMap.setSize(w, h);
+                mapPanel.setSize(w, h);
             }
         });
 
@@ -178,6 +178,7 @@
         Vector vector = floodMap.getBarrierLayer();
         vector.addVectorFeatureAddedListener(
             new VectorFeatureAddedListener() {
+                @Override
                 public void onFeatureAdded(FeatureAddedEvent e) {
                     saveBarriers();
                 }
@@ -186,6 +187,7 @@
 
         vector.addVectorFeatureRemovedListener(
             new VectorFeatureRemovedListener() {
+                @Override
                 public void onFeatureRemoved(FeatureRemovedEvent e) {
                     saveBarriers();
                 }
@@ -242,10 +244,12 @@
     @Override
     public void onRedrawRequest(RedrawRequestEvent event) {
         mapService.doOut(collection, new AsyncCallback<MapConfig>() {
+            @Override
             public void onFailure(Throwable caught) {
                 GWT.log("MAP ERROR: " + caught.getMessage());
             }
 
+            @Override
             public void onSuccess(MapConfig c) {
                 GWT.log("We want to refresh the map now!");
                 themePanel.updateCollection();
@@ -403,8 +407,8 @@
 
         AttributedTheme at = (AttributedTheme) theme;
 
-        String type      = at.getAttr("name");
-        String desc      = at.getAttr("description");
+        //String type      = at.getAttr("name");
+        //String desc      = at.getAttr("description");
         String url       = at.getAttr("url");
         String layers    = at.getAttr("layers");
 
@@ -446,15 +450,17 @@
         c.setBorder("1px solid black");
 
         themePanel = new MapThemePanel(
-            collection,
+            this.getCollectionView(),
             mode,
             this,
             new MapThemePanel.ActivateCallback() {
+                @Override
                 public void activate(Theme theme, boolean active) {
                     activateTheme(theme, active);
                 }
             },
             new MapThemePanel.ThemeMovedCallback() {
+                @Override
                 public void onThemeMoved(Theme theme, int oldIdx, int newIdx) {
                     // this code synchronizes the ThemePanel and the OpenLayers
                     // internal order of layers.
@@ -475,6 +481,7 @@
                 }
             },
             new MapThemePanel.LayerZoomCallback() {
+                @Override
                 public void onLayerZoom(Theme theme, String extent) {
                     Bounds zoomTo = boundsFromString(extent);
 
@@ -526,16 +533,39 @@
 
         feedService.go(locale, getArtifact(), new Data[] { data },
             new AsyncCallback<Artifact>() {
+                @Override
                 public void onFailure(Throwable caught) {
                     GWT.log("Could not save barrier geometries: " +
                         caught.getMessage());
                 }
 
+                @Override
                 public void onSuccess(Artifact artifact) {
                     GWT.log("Successfully saved barrier geometries.");
                 }
             }
         );
     }
+
+
+    @Override
+    public void onTabSelected(TabSelectedEvent tse) {
+        if(floodMap == null) {
+            return;
+        }
+        if(this.equals(tse.getTab())) {
+            floodMap.activateScaleLine(true);
+        }
+        else {
+            controlPanel.activateMeasureControl(false);
+            floodMap.activateScaleLine(false);
+        }
+    }
+
+    public void toogleThemePanel() {
+        this.themePanelCanvas.setVisible(!themePanelCanvas.isVisible());
+        this.themePanelCanvas.setSize(themePanelCanvas.getWidthAsString(),
+                                      themePanelCanvas.getHeightAsString());
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapPanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,15 +1,14 @@
 package de.intevation.flys.client.client.ui.map;
 
 import com.google.gwt.user.client.ui.HorizontalPanel;
-
 import com.smartgwt.client.widgets.Canvas;
 import com.smartgwt.client.widgets.layout.VLayout;
 
-import org.gwtopenmaps.openlayers.client.Bounds;
-
 import de.intevation.flys.client.shared.model.BBox;
 import de.intevation.flys.client.shared.model.MapInfo;
 
+import org.gwtopenmaps.openlayers.client.Bounds;
+
 
 public class MapPanel extends VLayout {
 
@@ -55,7 +54,7 @@
         toolbar = new MapToolbar(floodMap, digitizeEnabled);
 
         addMember(toolbar);
-        addMember(mapArea);
+        addMember(wrapper);
     }
 
 
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapPositionPanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapPositionPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,7 @@
 package de.intevation.flys.client.client.ui.map;
 
+import com.google.gwt.i18n.client.NumberFormat;
+
 import com.smartgwt.client.types.Alignment;
 import com.smartgwt.client.widgets.Label;
 import com.smartgwt.client.widgets.layout.HLayout;
@@ -62,12 +64,14 @@
 
 
     protected void setX(double x) {
-        this.x.setContents(String.valueOf(x));
+        NumberFormat f = NumberFormat.getFormat("#0.0000");
+        this.x.setContents(f.format(x).toString());
     }
 
 
     protected void setY(double y) {
-        this.y.setContents(String.valueOf(y));
+        NumberFormat f = NumberFormat.getFormat("#0.0000");
+        this.y.setContents(f.format(y).toString());
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapThemePanel.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapThemePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -18,15 +18,17 @@
 import com.smartgwt.client.widgets.menu.MenuItem;
 import com.smartgwt.client.widgets.menu.events.ClickHandler;
 import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;
+import com.smartgwt.client.widgets.grid.events.HeaderDoubleClickHandler;
+import com.smartgwt.client.widgets.grid.events.HeaderDoubleClickEvent;
 
 import de.intevation.flys.client.shared.MapUtils;
 import de.intevation.flys.client.shared.model.AttributedTheme;
-import de.intevation.flys.client.shared.model.Collection;
 import de.intevation.flys.client.shared.model.FacetRecord;
 import de.intevation.flys.client.shared.model.Theme;
 import de.intevation.flys.client.shared.model.OutputMode;
 
 import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.ui.CollectionView;
 import de.intevation.flys.client.client.ui.ThemePanel;
 
 
@@ -36,7 +38,7 @@
 public class MapThemePanel extends ThemePanel {
 
     public static final int CELL_HEIGHT      = 75;
-    public static final int STYLE_CELL_WIDTH = 125;
+    public static final int STYLE_CELL_WIDTH = 150;
 
 
     public interface ActivateCallback {
@@ -73,24 +75,14 @@
 
 
     public MapThemePanel(
-        Collection         collection,
-        MapOutputTab       mapOut,
-        OutputMode         mode,
-        ActivateCallback   activateCallback
-    ) {
-        this(collection, mode, mapOut, activateCallback, null, null);
-    }
-
-
-    public MapThemePanel(
-        Collection         collection,
+        CollectionView     view,
         OutputMode         mode,
         MapOutputTab       mapOut,
         ActivateCallback   activateCallback,
         ThemeMovedCallback themeMovedCallback,
         LayerZoomCallback  layerZoomCallback
     ) {
-        super(collection, mode, null);
+        super(mode, view);
 
         this.mapOut             = mapOut;
         this.activateCallback   = activateCallback;
@@ -126,9 +118,17 @@
         list.setShowRecordComponentsByCell(true);
         list.setShowHeader(true);
         list.setShowHeaderContextMenu(false);
+        list.setCanReorderFields(false);
         list.setWidth100();
         list.setHeight100();
 
+        list.addHeaderDoubleClickHandler(new HeaderDoubleClickHandler() {
+            public void onHeaderDoubleClick(HeaderDoubleClickEvent event) {
+                // cancel the event.
+                return;
+            }
+        });
+
         list.setCellHeight(CELL_HEIGHT);
         list.setShowRecordComponents(true);
         list.setShowRecordComponentsByCell(true);
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MapToolbar.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,7 +1,6 @@
 package de.intevation.flys.client.client.ui.map;
 
 import com.google.gwt.core.client.GWT;
-
 import com.smartgwt.client.types.Alignment;
 import com.smartgwt.client.types.SelectionType;
 import com.smartgwt.client.util.SC;
@@ -11,28 +10,35 @@
 import com.smartgwt.client.widgets.Label;
 import com.smartgwt.client.widgets.events.ClickEvent;
 import com.smartgwt.client.widgets.events.ClickHandler;
+import com.smartgwt.client.widgets.events.ResizedEvent;
+import com.smartgwt.client.widgets.events.ResizedHandler;
 import com.smartgwt.client.widgets.layout.HLayout;
 
+import de.intevation.flys.client.client.FLYSConstants;
+import de.intevation.flys.client.client.ui.ImgLink;
+import de.intevation.flys.client.client.ui.Toolbar;
+import de.intevation.flys.client.client.utils.EnableDisableCmd;
+import de.intevation.flys.client.shared.model.Collection;
+
+import org.gwtopenmaps.openlayers.client.Bounds;
 import org.gwtopenmaps.openlayers.client.Map;
 import org.gwtopenmaps.openlayers.client.control.DragPan;
 import org.gwtopenmaps.openlayers.client.control.SelectFeature;
 import org.gwtopenmaps.openlayers.client.control.SelectFeatureOptions;
 import org.gwtopenmaps.openlayers.client.control.ZoomBox;
+import org.gwtopenmaps.openlayers.client.event.MapZoomListener;
 import org.gwtopenmaps.openlayers.client.feature.VectorFeature;
 import org.gwtopenmaps.openlayers.client.layer.Vector;
 import org.gwtopenmaps.openlayers.client.util.Attributes;
 
-import de.intevation.flys.client.client.FLYSConstants;
-import de.intevation.flys.client.client.ui.Toolbar;
-import de.intevation.flys.client.client.utils.EnableDisableCmd;
-import de.intevation.flys.client.shared.model.ThemeList;
-
 
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
-public class MapToolbar extends Toolbar {
-
+public class MapToolbar
+extends      Toolbar
+implements   MapZoomListener
+{
     protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
 
     protected FloodMap       floodMap;
@@ -41,6 +47,7 @@
     protected SelectFeature  selectFeature;
     protected GetFeatureInfo getFeatureInfo;
 
+    protected Button manageThemesButton;
     protected Button datacageButton;
 
     protected ImgButton addWMSButton;
@@ -52,6 +59,7 @@
     protected ImgButton infoButton;
     protected ImgButton removeButton;
     protected ImgButton elevationButton;
+    protected ImgLink   printMapLink;
 
     protected Label epsgLabel;
 
@@ -79,11 +87,10 @@
         super(mapTab);
 
         setWidth100();
-        setHeight(30);
+        setHeight(38);
         setMembersMargin(10);
         setPadding(5);
         setBorder("1px solid black");
-
         this.floodMap = floodMap;
 
         zoomToMaxButton = createMaxExtentControl();
@@ -100,11 +107,17 @@
         epsgLabel       = createEPSGLabel();
 
         if (mapTab != null) {
+            manageThemesButton = createManageThemesControl();
+            addMember(manageThemesButton);
+
             datacageButton = createDatacageControl();
             addMember(datacageButton);
 
             addWMSButton = createWMSControl();
             addMember(addWMSButton);
+
+            printMapLink = createPrintMapLink();
+            addMember(printMapLink);
         }
 
         addMember(zoomToMaxButton);
@@ -125,6 +138,19 @@
 
         addMember(measureControl);
         addMember(createRightPanel());
+
+        addResizedHandler(new ResizedHandler() {
+            @Override
+            public void onResized(ResizedEvent e) {
+                if (getVisibleWidth() < 656) {
+                    setHeight(55);
+                }
+                else {
+                    setHeight(38);
+                }
+            }
+        });
+
     }
 
 
@@ -191,6 +217,17 @@
 
 
     protected void activateGetFeatureInfo(boolean activate) {
+        if (infoButton == null) {
+            return;
+        }
+
+        if (activate) {
+            infoButton.select();
+        }
+        else {
+            infoButton.deselect();
+        }
+
         getFeatureInfo.activate(activate);
     }
 
@@ -204,6 +241,7 @@
         btn.setHeight(20);
         btn.setShowDown(false);
         btn.setShowRollOver(false);
+        btn.setShowRollOverIcon(false);
         btn.setShowDisabled(false);
         btn.setShowDisabledIcon(true);
         btn.setShowDownIcon(false);
@@ -228,8 +266,10 @@
         btn.setActionType(SelectionType.CHECKBOX);
         btn.setSize(20);
         btn.setShowRollOver(false);
+        btn.setShowRollOverIcon(false);
         btn.setSelected(false);
         btn.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent e) {
                 if (btn.isSelected()) {
                     cmd.enable();
@@ -243,9 +283,22 @@
         return btn;
     }
 
+    protected ImgLink createPrintMapLink() {
+        String baseUrl = GWT.getHostPageBaseURL();
+
+        getMap().addMapZoomListener(this);
+
+        return new ImgLink(
+            baseUrl + MSG.downloadPDF(),
+            getPrintUrl(),
+            20, 20,
+            true);
+    }
+
 
     protected ImgButton createMaxExtentControl() {
         ImgButton zoomToMax = createButton(MSG.zoom_all(), new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 floodMap.getMap().zoomToMaxExtent();
             }
@@ -261,14 +314,17 @@
         zoomBox = new ZoomBox();
 
         EnableDisableCmd cmd = new EnableDisableCmd() {
+            @Override
             public void enable() {
-                activateZoomBox(true);
                 activatePan(false);
                 activateDrawFeature(false);
                 activateSelectFeature(false);
                 activateMeasureControl(false);
+                activateGetFeatureInfo(false);
+                activateZoomBox(true);
             }
 
+            @Override
             public void disable() {
                 activateZoomBox(false);
             }
@@ -286,6 +342,7 @@
 
     protected ImgButton createZoomOutControl() {
         ImgButton zoomOut = createButton(MSG.zoom_out(), new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 Map map   = floodMap.getMap();
                 int level = map.getZoom();
@@ -307,14 +364,17 @@
         getMap().addControl(pan);
 
         EnableDisableCmd cmd = new EnableDisableCmd() {
+            @Override
             public void enable() {
                 activateZoomBox(false);
-                activatePan(true);
                 activateDrawFeature(false);
                 activateSelectFeature(false);
                 activateMeasureControl(false);
+                activateGetFeatureInfo(false);
+                activatePan(true);
             }
 
+            @Override
             public void disable() {
                 activatePan(false);
             }
@@ -329,6 +389,7 @@
 
     protected DrawControl createDrawControl() {
         EnableDisableCmd cmd = new EnableDisableCmd() {
+            @Override
             public void enable() {
                 activateZoomBox(false);
                 activatePan(false);
@@ -337,6 +398,7 @@
                 activateMeasureControl(false);
             }
 
+            @Override
             public void disable() {
                 activateDrawFeature(false);
             }
@@ -357,12 +419,14 @@
         // this doesn't work here. After a feature has been selected, the layer
         // still has no selected features.
         opts.onSelect(new SelectFeature.SelectFeatureListener() {
+            @Override
             public void onFeatureSelected(VectorFeature feature) {
                 floodMap.selectFeature(feature);
             }
         });
 
         opts.onUnSelect(new SelectFeature.UnselectFeatureListener() {
+            @Override
             public void onFeatureUnselected(VectorFeature feature) {
                 floodMap.disableFeature(feature);
             }
@@ -372,6 +436,7 @@
         getMap().addControl(selectFeature);
 
         EnableDisableCmd cmd = new EnableDisableCmd() {
+            @Override
             public void enable() {
                 activateDrawFeature(false);
                 activatePan(false);
@@ -380,6 +445,7 @@
                 activateMeasureControl(false);
             }
 
+            @Override
             public void disable() {
                 activateSelectFeature(false);
                 floodMap.disableFeatures();
@@ -395,6 +461,7 @@
 
     protected ImgButton createRemoveFeatureControl() {
         ImgButton remove = createButton(MSG.removeFeature(),new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 Vector          barriers = floodMap.getBarrierLayer();
                 VectorFeature[] features = barriers.getFeatures();
@@ -425,6 +492,7 @@
 
     protected ImgButton createElevationControl() {
         ImgButton btn = createButton(MSG.adjustElevation(), new ClickHandler() {
+            @Override
             public void onClick(ClickEvent evt) {
                 Vector          barriers = floodMap.getBarrierLayer();
                 VectorFeature[] features = barriers.getFeatures();
@@ -476,13 +544,16 @@
 
     protected MeasureControl createMeasureControl() {
         EnableDisableCmd cmd = new EnableDisableCmd() {
+            @Override
             public void enable() {
                 activateDrawFeature(false);
                 activatePan(false);
                 activateZoomBox(false);
                 activateSelectFeature(false);
+                activateGetFeatureInfo(false);
             }
 
+            @Override
             public void disable() {
                 // do nothing
             }
@@ -495,6 +566,7 @@
     protected Button createDatacageControl() {
         Button btn = new Button(MSG.databasket());
         btn.addClickHandler(new ClickHandler() {
+            @Override
             public void onClick(ClickEvent evt) {
                 openDatacageWindow((MapOutputTab) getOutputTab());
             }
@@ -510,7 +582,7 @@
             return null;
         }
 
-        ThemeList tl = ot.getCollection().getThemeList("floodmap");
+        //ThemeList tl = ot.getCollection().getThemeList("floodmap");
 
         getFeatureInfo = new GetFeatureInfo(
             getMap(),
@@ -518,14 +590,17 @@
             "gml");
 
         EnableDisableCmd cmd = new EnableDisableCmd() {
+            @Override
             public void enable() {
                 activateDrawFeature(false);
                 activatePan(false);
                 activateZoomBox(false);
                 activateSelectFeature(false);
+                activateMeasureControl(false);
                 activateGetFeatureInfo(true);
             }
 
+            @Override
             public void disable() {
                 activateGetFeatureInfo(false);
             }
@@ -538,10 +613,24 @@
     }
 
 
+    protected Button createManageThemesControl() {
+        Button btn = new Button(MSG.manageThemes());
+        btn.addClickHandler(new ClickHandler() {
+
+            @Override
+            public void onClick(ClickEvent event) {
+                ((MapOutputTab)getOutputTab()).toogleThemePanel();
+            }
+        });
+        return btn;
+    }
+
+
     protected ImgButton createWMSControl() {
         final String srs = floodMap.getRiverProjection();
 
         ImgButton add = createButton(MSG.addWMS(), new ClickHandler() {
+            @Override
             public void onClick(ClickEvent event) {
                 MapOutputTab ot = (MapOutputTab) getOutputTab();
                 new ExternalWMSWindow(ot, srs).start();
@@ -562,5 +651,46 @@
 
         return epsgLabel;
     }
+
+    @Override
+    public void onMapZoom(MapZoomListener.MapZoomEvent e) {
+        printMapLink.setSource(getPrintUrl());
+    }
+
+    public String getPrintUrl() {
+        MapOutputTab ot = (MapOutputTab)getOutputTab();
+        Collection collection = ot.getCollection();
+        String uuid = collection.identifier();
+
+        String mapType = collection.getOutputModes().containsKey("floodmap")
+            ? "floodmap"
+            : "map";
+
+        String url = GWT.getModuleBaseURL() + "map-print?";
+
+        Map map = getMap();
+        Bounds bounds = map.getExtent();
+
+        if (bounds != null) {
+            try {
+                double minX = bounds.getLowerLeftX();
+                double maxX = bounds.getUpperRightX();
+                double minY = bounds.getLowerLeftY();
+                double maxY = bounds.getUpperRightY();
+                url += "minx=" + minX + "&";
+                url += "maxx=" + maxX + "&";
+                url += "miny=" + minY + "&";
+                url += "maxy=" + maxY + "&";
+            }
+            catch (Exception e) {
+                // XXX: Ignore it. bounds.getXXX() throw
+                // exceptions when bound is invalid. :-/
+            }
+        }
+
+        url += "uuid=" + uuid + "&maptype=" + mapType;
+
+        return url;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MeasureControl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/MeasureControl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -91,6 +91,7 @@
         btn.setActionType(SelectionType.CHECKBOX);
         btn.setSize(20);
         btn.setShowRollOver(false);
+        btn.setShowRollOverIcon(false);
         btn.setSelected(false);
         btn.setTooltip(MSG.measureDistance());
         btn.addClickHandler(new ClickHandler() {
@@ -133,6 +134,7 @@
         btn.setActionType(SelectionType.CHECKBOX);
         btn.setSize(20);
         btn.setShowRollOver(false);
+        btn.setShowRollOverIcon(false);
         btn.setSelected(false);
         btn.setTooltip(MSG.measureArea());
         btn.addClickHandler(new ClickHandler() {
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/WMSLayersTree.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/map/WMSLayersTree.java	Fri Sep 28 12:15:52 2012 +0200
@@ -106,7 +106,7 @@
             }
         }
 
-        return (TreeNode[]) layerNodes.toArray(new TreeNode[layerNodes.size()]);
+        return layerNodes.toArray(new TreeNode[layerNodes.size()]);
     }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/minfo/BedCampaignChart.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,78 @@
+package de.intevation.flys.client.client.ui.minfo;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.widgets.Img;
+import com.smartgwt.client.widgets.events.ResizedHandler;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.shared.model.Artifact;
+
+public class BedCampaignChart extends VLayout {
+
+    private final Artifact artifact;
+
+    protected Img chartImg;
+
+    public BedCampaignChart(Artifact artifact, ResizedHandler resizeHandler) {
+        super();
+
+        this.artifact = artifact;
+        this.chartImg = new Img();
+
+        addResizedHandler(resizeHandler);
+        setAlign(Alignment.CENTER);
+    }
+
+    public void update() {
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
+
+        int hWidth = getWidth() - 12;
+        int hHeight = getHeight() - 12;
+
+        if ((int) (hHeight * 4f / 3) < hWidth) {
+            hWidth = (int) (hHeight * 4f / 3);
+        }
+        else {
+            hHeight = (int) (hWidth * 3f / 4);
+        }
+
+        String river = artifact.getArtifactDescription().getRiver();
+
+        JSONObject jfix = new JSONObject();
+        JSONObject jfilter = new JSONObject();
+        JSONObject jrName = new JSONObject();
+        JSONString jrValue = new JSONString(river);
+        JSONObject jextent = new JSONObject();
+        JSONNumber jwidth = new JSONNumber(hWidth);
+        JSONNumber jheight = new JSONNumber(hHeight);
+
+        jrName.put("name", jrValue);
+        jfilter.put("river", jrName);
+        jextent.put("width", jwidth);
+        jextent.put("height", jheight);
+        jfilter.put("extent", jextent);
+        jfix.put("bed", jfilter);
+        String filter = jfix.toString();
+
+        String imgUrl = GWT.getModuleBaseURL();
+        imgUrl += "bed-km-chart";
+        imgUrl += "?locale=" + locale;
+        imgUrl += "&filter=" + filter;
+
+        if (chartImg != null && hasMember(chartImg)) {
+            chartImg.setWidth(hWidth);
+            chartImg.setHeight(hHeight);
+            chartImg.setSrc(imgUrl);
+        }
+        else {
+            chartImg = new Img(imgUrl, hWidth, hHeight);
+            addMember(chartImg);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/minfo/BedHeightsDatacagePanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,310 @@
+package de.intevation.flys.client.client.ui.minfo;
+
+import com.google.gwt.core.client.GWT;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import com.smartgwt.client.data.Record;
+
+import com.smartgwt.client.widgets.Canvas;
+
+import com.smartgwt.client.widgets.events.ClickEvent;
+
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.client.FLYSConstants;
+
+import de.intevation.flys.client.client.event.StepForwardEvent;
+
+import de.intevation.flys.client.client.services.LoadArtifactService;
+import de.intevation.flys.client.client.services.LoadArtifactServiceAsync;
+import de.intevation.flys.client.client.services.RemoveArtifactService;
+import de.intevation.flys.client.client.services.RemoveArtifactServiceAsync;
+
+import de.intevation.flys.client.client.ui.DatacagePairWidget;
+import de.intevation.flys.client.client.ui.DatacageTwinPanel;
+import de.intevation.flys.client.client.ui.RecommendationPairRecord;
+
+import de.intevation.flys.client.shared.model.Artifact;
+import de.intevation.flys.client.shared.model.Collection;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+
+import de.intevation.flys.client.shared.model.Recommendation.Facet;
+import de.intevation.flys.client.shared.model.Recommendation.Filter;
+
+import de.intevation.flys.client.shared.model.Recommendation;
+import de.intevation.flys.client.shared.model.User;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+// TODO Probably better to branch off AbstractUIProvider.
+// TODO Merge with other datacage-widget impls.
+/**
+ * Panel containing a Grid and a "next" button. The Grid is fed by a
+ * DatacagePairWidget which is put in the input-helper area.
+ */
+public class BedHeightsDatacagePanel
+extends      DatacageTwinPanel {
+
+    protected static FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    /**
+     * List to track previously selected but now removed pairs. (Needed to
+     * be able to identify artifacts that can be removed from the collection.
+     */
+    protected List<RecommendationPairRecord> removedPairs =
+        new ArrayList<RecommendationPairRecord>();
+
+    /** Service handle to clone and add artifacts to collection. */
+    LoadArtifactServiceAsync loadArtifactService = GWT.create(
+            de.intevation.flys.client.client.services.LoadArtifactService.class);
+
+    /** Service to remove artifacts from collection. */
+    RemoveArtifactServiceAsync removeArtifactService = GWT.create(
+            de.intevation.flys.client.client.services.RemoveArtifactService.class);
+
+
+    public BedHeightsDatacagePanel(User user) {
+        super(user);
+    }
+
+
+    /**
+     * Create a recommendation from a string representation of it.
+     * @TODO describe format of input string
+     * @param from string in format as shown above.
+     * @return recommendation from input string.
+     */
+    public Recommendation createRecommendationFromString(String from) {
+        // TODO Construct "real" filter.
+        String[] parts = unbracket(from).split(";");
+        Recommendation.Filter filter = new Recommendation.Filter();
+        Recommendation.Facet  facet  = new Recommendation.Facet(
+                parts[1],
+                parts[2]);
+
+        List<Recommendation.Facet> facets = new ArrayList<Recommendation.Facet>
+            ();
+        facets.add(facet);
+        filter.add("longitudinal_section", facets);
+        Recommendation r = new Recommendation("bedheight", parts[0],
+            this.artifact.getUuid(), filter);
+        r.setDisplayName(parts[3]);
+        return r;
+    }
+
+
+    /**
+     * Creates the graphical representation and interaction widgets for the data.
+     * @param dataList the data.
+     * @return graphical representation and interaction widgets for data.
+     */
+    @Override
+    public Canvas create(DataList dataList) {
+        GWT.log("createData()");
+
+        Data       data  = dataList.get(0);
+        DataItem[] items = data.getItems();
+
+        String value = items[0].getStringValue();
+
+        String filter = "minfo-heights";
+        if (value.equals("epoch")) {
+            filter = "minfo-heights-epoch";
+        }
+        Canvas widget = createWidget();
+        Canvas submit = getNextButton();
+
+        VLayout layout       = new VLayout();
+        HLayout helperLayout = new HLayout();
+        helperLayout.addMember(new DatacagePairWidget(this.artifact,
+            user, filter, differencesList));
+
+        layout.addMember(widget);
+        layout.addMember(submit);
+        layout.setMembersMargin(10);
+        this.helperContainer.addMember(helperLayout);
+
+        this.dataName = "diffids";
+
+        return layout;
+    }
+
+
+    /**
+     * Add record to list of removed records.
+     */
+    public void trackRemoved(Record r) {
+        RecommendationPairRecord pr = (RecommendationPairRecord) r;
+        this.removedPairs.add(pr);
+    }
+
+
+    /**
+     * Validates data, does nothing if invalid, otherwise clones new selected
+     * waterlevels and add them to collection, forward the artifact.
+     */
+    @Override
+    public void onClick(ClickEvent e) {
+        GWT.log("DatacageTwinPanel.onClick");
+
+        List<String> errors = validate();
+        if (errors != null && !errors.isEmpty()) {
+            showErrors(errors);
+            return;
+        }
+
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
+
+        ListGridRecord[] records = differencesList.getRecords();
+
+        List<Recommendation> ar  = new ArrayList<Recommendation>();
+        List<Recommendation> all = new ArrayList<Recommendation>();
+
+        for (ListGridRecord record : records) {
+            RecommendationPairRecord r =
+                (RecommendationPairRecord) record;
+            // Do not add "old" recommendations.
+            if (!r.isAlreadyLoaded()) {
+                // Check whether one of those is a dike or similar.
+                // TODO differentiate and merge: new clones, new, old.
+                Recommendation firstR = r.getFirst();
+                if(firstR.getIDs() != null) {
+                    GWT.log("First IDs: " + firstR.getIDs() + " factory: "
+                            + firstR.getFactory());
+                }
+                firstR.setFactory("bedheight");
+                Recommendation secondR = r.getSecond();
+                if(secondR.getIDs() != null) {
+                    GWT.log("Second IDs: " + secondR.getIDs() + " factory: "
+                            + secondR.getFactory());
+                }
+                secondR.setFactory("bedheight");
+
+                ar.add(firstR);
+                ar.add(secondR);
+            }
+            else {
+                all.add(r.getFirst());
+                all.add(r.getSecond());
+            }
+        }
+
+        final Recommendation[] toClone = ar.toArray(new Recommendation[ar.size()]);
+        final Recommendation[] toUse   = all.toArray(new Recommendation[all.size()]);
+
+        // Find out whether "old" artifacts have to be removed.
+        List<String> artifactIdsToRemove = new ArrayList<String>();
+        for (RecommendationPairRecord rp: this.removedPairs) {
+            Recommendation first  = rp.getFirst();
+            Recommendation second = rp.getSecond();
+
+            for (Recommendation recommendation: toUse) {
+                if (first != null && first.getIDs().equals(recommendation.getIDs())) {
+                    first = null;
+                }
+                if (second != null && second.getIDs().equals(recommendation.getIDs())) {
+                    second = null;
+                }
+
+                if (first == null && second == null) {
+                    break;
+                }
+            }
+            if (first != null) {
+                artifactIdsToRemove.add(first.getIDs());
+            }
+            if (second != null) {
+                artifactIdsToRemove.add(second.getIDs());
+            }
+        }
+
+        // Remove old artifacts, if any. Do this asychronously without much
+        // feedback.
+        for(final String uuid: artifactIdsToRemove) {
+            removeArtifactService.remove(this.collection,
+                uuid,
+                locale,
+                new AsyncCallback<Collection>() {
+                    public void onFailure(Throwable caught) {
+                        GWT.log("RemoveArtifact (" + uuid + ") failed.");
+                    }
+                    public void onSuccess(Collection collection) {
+                        GWT.log("RemoveArtifact succeeded");
+                    }
+                });
+        }
+
+        // Clone new ones (and spawn statics), go forward.
+        loadArtifactService.loadMany(
+            this.collection,
+            toClone,
+            //"staticwkms" and "waterlevel"
+            null,
+            locale,
+            new AsyncCallback<Artifact[]>() {
+                public void onFailure(Throwable caught) {
+                    GWT.log("Failure of cloning with factories!");
+                }
+                public void onSuccess(Artifact[] artifacts) {
+                    GWT.log("Successfully cloned " + toClone.length +
+                        " with factories.");
+
+                    fireStepForwardEvent(new StepForwardEvent(
+                        getData(toClone, artifacts, toUse)));
+                }
+            });
+    }
+
+
+    /**
+     * Creates part of the String that encodes minuend or subtrahend.
+     * @param artifact Artifacts UUID.
+     * @param recommendation Recommendation to wrap in string.
+     */
+    protected String createDataString(
+        String artifact,
+        Recommendation recommendation)
+    {
+        Filter filter = recommendation.getFilter();
+        Facet  f      = null;
+
+        if(filter != null) {
+            Map<String, List<Facet>>               outs = filter.getOuts();
+            Set<Map.Entry<String, List<Facet>>> entries = outs.entrySet();
+
+            for (Map.Entry<String, List<Facet>> entry: entries) {
+                List<Facet> fs = entry.getValue();
+
+                f = fs.get(0);
+                if (f != null) {
+                    break;
+                }
+            }
+
+            return "[" + artifact + ";"
+                + f.getName()
+                + ";"
+                + f.getIndex()
+                + ";"
+                + recommendation.getDisplayName() + "]";
+        }
+        else {
+            return "["
+                + artifact
+                + ";bedheight;0;"
+                + recommendation.getDisplayName() + "]";
+        }
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/ui/minfo/BedMultiPeriodPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,34 @@
+package de.intevation.flys.client.client.ui.minfo;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.events.ResizedEvent;
+import com.smartgwt.client.widgets.events.ResizedHandler;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.ui.MultiPeriodPanel;
+
+public class BedMultiPeriodPanel
+extends MultiPeriodPanel
+implements ResizedHandler {
+    protected BedCampaignChart chartContainer1;
+    protected BedloadCampaignChart chartContainer2;
+
+    public BedMultiPeriodPanel() {
+    }
+
+    @Override
+    protected Canvas createHelper() {
+        chartContainer1 = new BedCampaignChart(artifact, this);
+        chartContainer2 = new BedloadCampaignChart(artifact, this);
+        VLayout layout = new VLayout();
+        layout.addMember(chartContainer1);
+        layout.addMember(chartContainer2);
+        return layout;
+    }
+
+    @Override
+    public void onResized(ResizedEvent re) {
+        chartContainer1.update();
+        chartContainer2.update();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/minfo/BedloadCampaignChart.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,78 @@
+package de.intevation.flys.client.client.ui.minfo;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.widgets.Img;
+import com.smartgwt.client.widgets.events.ResizedHandler;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.shared.model.Artifact;
+
+public class BedloadCampaignChart extends VLayout {
+
+    private final Artifact artifact;
+
+    protected Img chartImg;
+
+    public BedloadCampaignChart(Artifact artifact, ResizedHandler resizeHandler) {
+        super();
+
+        this.artifact = artifact;
+        this.chartImg = new Img();
+
+        addResizedHandler(resizeHandler);
+        setAlign(Alignment.CENTER);
+    }
+
+    public void update() {
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
+
+        int hWidth = getWidth() - 12;
+        int hHeight = getHeight() - 12;
+
+        if ((int) (hHeight * 4f / 3) < hWidth) {
+            hWidth = (int) (hHeight * 4f / 3);
+        }
+        else {
+            hHeight = (int) (hWidth * 3f / 4);
+        }
+
+        String river = artifact.getArtifactDescription().getRiver();
+
+        JSONObject jfix = new JSONObject();
+        JSONObject jfilter = new JSONObject();
+        JSONObject jrName = new JSONObject();
+        JSONString jrValue = new JSONString(river);
+        JSONObject jextent = new JSONObject();
+        JSONNumber jwidth = new JSONNumber(hWidth);
+        JSONNumber jheight = new JSONNumber(hHeight);
+
+        jrName.put("name", jrValue);
+        jfilter.put("river", jrName);
+        jextent.put("width", jwidth);
+        jextent.put("height", jheight);
+        jfilter.put("extent", jextent);
+        jfix.put("bedload", jfilter);
+        String filter = jfix.toString();
+
+        String imgUrl = GWT.getModuleBaseURL();
+        imgUrl += "bedload-km-chart";
+        imgUrl += "?locale=" + locale;
+        imgUrl += "&filter=" + filter;
+
+        if (chartImg != null && hasMember(chartImg)) {
+            chartImg.setWidth(hWidth);
+            chartImg.setHeight(hHeight);
+            chartImg.setSrc(imgUrl);
+        }
+        else {
+            chartImg = new Img(imgUrl, hWidth, hHeight);
+            addMember(chartImg);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/minfo/CheckboxPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,117 @@
+package de.intevation.flys.client.client.ui.minfo;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Set;
+
+import com.google.gwt.core.client.GWT;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.CheckboxItem;
+import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.ui.AbstractUIProvider;
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DataList;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+
+public class CheckboxPanel extends AbstractUIProvider {
+
+    private String dataName;
+    HashMap<String, Boolean> values;
+
+    protected DynamicForm form;
+
+    public CheckboxPanel() {
+        super();
+        values = new HashMap<String, Boolean>();
+    }
+
+    @Override
+    public Canvas createOld(DataList dataList) {
+        Data       data  = dataList.get(0);
+        DataItem[] items = data.getItems();
+
+        HLayout layout = new HLayout();
+        Label   label  = new Label(dataList.getLabel());
+        Label   value  = new Label(items[0].getLabel());
+
+        layout.setHeight(35);
+        layout.setWidth(400);
+        label.setWidth(200);
+
+        layout.addMember(label);
+        layout.addMember(value);
+        layout.addMember(getBackButton(dataList.getState()));
+
+        return layout;
+    }
+
+    @Override
+    public Canvas create(DataList dataList) {
+        Data       data  = dataList.get(0);
+        DataItem[] items = data.getItems();
+
+        this.dataName = data.getLabel();
+        form = new DynamicForm();
+
+        VLayout layout = new VLayout();
+        Label   label  = new Label(data.getDescription());
+        LinkedList<CheckboxItem> cbItems = new LinkedList<CheckboxItem>();
+        for (int i = 0; i < items.length; i++) {
+            CheckboxItem item = new CheckboxItem(items[i].getLabel());
+            GWT.log(items[i].getStringValue() + "; " + items[i].getLabel());
+            item.addChangedHandler(new ChangedHandler() {
+                @Override
+                public void onChanged(ChangedEvent event) {
+                    values.put(
+                        event.getItem().getName(),
+                        (Boolean)event.getItem().getValue());
+                }
+            });
+            cbItems.add(item);
+        }
+
+        form.setFields(cbItems.toArray(new CheckboxItem[cbItems.size()]));
+        layout.setMembersMargin(10);
+        layout.setHeight(35);
+        label.setHeight(35);
+
+        layout.addMember(label);
+        layout.addMember(form);
+        layout.addMember(getNextButton());
+        layout.setMembersMargin(10);
+
+        return layout;
+    }
+
+    @Override
+    protected Data[] getData() {
+        String value = "";
+        Set<String> entries = values.keySet();
+        boolean first = true;
+        for (String s: values.keySet()) {
+            if (!first) {
+                value += ";";
+            }
+            if ((Boolean)values.get(s) == true) {
+                value += s;
+            }
+            first = false;
+        }
+        DataItem item = new DefaultDataItem("diameter", "diameter", value);
+
+        return new Data[] {new DefaultData(
+            "diameter",
+            null,
+            null,
+            new DataItem[]{item})};
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/range/DischargeInfoDataSource.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,43 @@
+package de.intevation.flys.client.client.ui.range;
+
+import com.google.gwt.core.client.GWT;
+
+import com.smartgwt.client.data.DataSource;
+import com.smartgwt.client.data.DataSourceField;
+import com.smartgwt.client.types.DSDataFormat;
+import com.smartgwt.client.types.FieldType;
+
+
+public class DischargeInfoDataSource extends DataSource {
+
+    public static final String XPATH_DISCHARGE_DEFAULT = "/discharges/discharge";
+
+
+    public DischargeInfoDataSource(String url, long gauge) {
+        setDataFormat(DSDataFormat.XML);
+        setRecordXPath(XPATH_DISCHARGE_DEFAULT);
+
+        DataSourceField desc = new DataSourceField(
+            "description", FieldType.TEXT, "description");
+
+        DataSourceField start = new DataSourceField(
+            "start", FieldType.INTEGER, "start");
+
+        DataSourceField end = new DataSourceField(
+            "end", FieldType.INTEGER, "end");
+
+        setFields(desc, start, end);
+        setDataURL(getServiceURL(url, gauge));
+    }
+
+
+    protected String getServiceURL(String server, long gauge) {
+        String url = GWT.getModuleBaseURL();
+        url += "dischargeinfoxml";
+        url += "?server=" + server;
+        url += "&gauge=" + String.valueOf(gauge);
+
+        return url;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/range/LocationsTable.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/range/LocationsTable.java	Fri Sep 28 12:15:52 2012 +0200
@@ -24,7 +24,6 @@
 
 
     public LocationsTable() {
-
         String baseUrl = GWT.getHostPageBaseURL();
 
         setWidth100();
@@ -37,14 +36,14 @@
         setEmptyMessage(MSG.empty_filter());
         setCanReorderFields(false);
 
-        ListGridField addfrom = new ListGridField ("", "");
+        ListGridField addfrom = new ListGridField ("from", MSG.from());
         addfrom.setType(ListGridFieldType.ICON);
-        addfrom.setWidth(20);
+        addfrom.setWidth(30);
         addfrom.setCellIcon(baseUrl + MSG.markerGreen());
 
-        ListGridField addto = new ListGridField("", "");
+        ListGridField addto = new ListGridField("to", MSG.to());
         addto.setType(ListGridFieldType.ICON);
-        addto.setWidth(20);
+        addto.setWidth(30);
         addto.setCellIcon(baseUrl + MSG.markerRed());
 
         ListGridField ldescr = new ListGridField(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/sq/SQCampaignChart.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,79 @@
+package de.intevation.flys.client.client.ui.sq;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.json.client.JSONNumber;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.widgets.Img;
+import com.smartgwt.client.widgets.events.ResizedHandler;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+import de.intevation.flys.client.client.Config;
+import de.intevation.flys.client.shared.model.Artifact;
+
+
+public class SQCampaignChart extends VLayout {
+
+    private final Artifact artifact;
+
+    protected Img chartImg;
+
+    public SQCampaignChart(Artifact artifact, ResizedHandler resizeHandler) {
+        super();
+
+        this.artifact = artifact;
+        this.chartImg = new Img();
+
+        addResizedHandler(resizeHandler);
+        setAlign(Alignment.CENTER);
+    }
+
+    public void update() {
+        Config config = Config.getInstance();
+        String locale = config.getLocale();
+
+        int hWidth = getWidth() - 12;
+        int hHeight = getHeight() - 12;
+
+        if ((int) (hHeight * 4f / 3) < hWidth) {
+            hWidth = (int) (hHeight * 4f / 3);
+        }
+        else {
+            hHeight = (int) (hWidth * 3f / 4);
+        }
+
+        String river = artifact.getArtifactDescription().getRiver();
+
+        JSONObject jfix = new JSONObject();
+        JSONObject jfilter = new JSONObject();
+        JSONObject jrName = new JSONObject();
+        JSONString jrValue = new JSONString(river);
+        JSONObject jextent = new JSONObject();
+        JSONNumber jwidth = new JSONNumber(hWidth);
+        JSONNumber jheight = new JSONNumber(hHeight);
+
+        jrName.put("name", jrValue);
+        jfilter.put("river", jrName);
+        jextent.put("width", jwidth);
+        jextent.put("height", jheight);
+        jfilter.put("extent", jextent);
+        jfix.put("sq", jfilter);
+        String filter = jfix.toString();
+
+        String imgUrl = GWT.getModuleBaseURL();
+        imgUrl += "sq-km-chart";
+        imgUrl += "?locale=" + locale;
+        imgUrl += "&filter=" + filter;
+
+        if (chartImg != null && hasMember(chartImg)) {
+            chartImg.setWidth(hWidth);
+            chartImg.setHeight(hHeight);
+            chartImg.setSrc(imgUrl);
+        }
+        else {
+            chartImg = new Img(imgUrl, hWidth, hHeight);
+            addMember(chartImg);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/sq/SQMultiPeriodPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,32 @@
+package de.intevation.flys.client.client.ui.sq;
+
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.events.ResizedEvent;
+import com.smartgwt.client.widgets.events.ResizedHandler;
+
+import de.intevation.flys.client.client.ui.MultiPeriodPanel;
+
+
+/**
+ * This UIProvider creates helper panel for sq relation.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class SQMultiPeriodPanel extends MultiPeriodPanel implements
+    ResizedHandler {
+    protected SQCampaignChart chartContainer;
+
+    public SQMultiPeriodPanel() {
+    }
+
+    @Override
+    protected Canvas createHelper() {
+        chartContainer = new SQCampaignChart(artifact, this);
+        return chartContainer;
+    }
+
+    @Override
+    public void onResized(ResizedEvent re) {
+        chartContainer.update();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/sq/SQPeriodPanel.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,26 @@
+package de.intevation.flys.client.client.ui.sq;
+
+import com.google.gwt.core.client.GWT;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.events.ResizedEvent;
+import com.smartgwt.client.widgets.events.ResizedHandler;
+
+import de.intevation.flys.client.client.ui.PeriodPanel;
+
+public class SQPeriodPanel extends PeriodPanel implements ResizedHandler {
+
+    private SQCampaignChart chartLayout;
+
+    @Override
+    protected Canvas createHelper() {
+        GWT.log("Create new SQCampaignChart as Helper Widget");
+        chartLayout = new SQCampaignChart(artifact, this);
+        return chartLayout;
+    }
+
+
+    @Override
+    public void onResized(ResizedEvent re) {
+        chartLayout.update();
+    }
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/wq/QDTable.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/wq/QDTable.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,11 +1,14 @@
 package de.intevation.flys.client.client.ui.wq;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
 
 import com.smartgwt.client.types.ListGridFieldType;
 import com.smartgwt.client.types.SelectionStyle;
+import com.smartgwt.client.widgets.grid.CellFormatter;
 import com.smartgwt.client.widgets.grid.ListGrid;
 import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
 
 import de.intevation.flys.client.client.FLYSConstants;
 
@@ -33,16 +36,21 @@
         setShowRecordComponentsByCell(true);
         setEmptyMessage(MESSAGE.empty_table());
 
-        ListGridField addMax = new ListGridField("max", "");
+        ListGridField addMax = new ListGridField("max", MESSAGE.from());
         addMax.setType(ListGridFieldType.ICON);
         addMax.setWidth(30);
         addMax.setCellIcon(baseUrl + MESSAGE.markerRed());
 
-        ListGridField addMin = new ListGridField("min", "");
+        ListGridField addMin = new ListGridField("min", MESSAGE.to());
         addMin.setType(ListGridFieldType.ICON);
         addMin.setWidth(30);
         addMin.setCellIcon(baseUrl + MESSAGE.markerGreen());
 
+        ListGridField select = new ListGridField("select", MESSAGE.selection());
+        select.setType(ListGridFieldType.ICON);
+        select.setWidth(70);
+        select.setCellIcon(baseUrl + MESSAGE.markerGreen());
+
         ListGridField name = new ListGridField("name", MESSAGE.discharge());
         name.setType(ListGridFieldType.TEXT);
         name.setWidth("*");
@@ -51,16 +59,35 @@
         type.setType(ListGridFieldType.TEXT);
         type.setWidth("20%");
 
-        ListGridField value = new ListGridField("value", MESSAGE.wq_value());
+        final NumberFormat nf = NumberFormat.getDecimalFormat();
+
+        ListGridField value = new ListGridField("value", MESSAGE.wq_value_q());
         value.setType(ListGridFieldType.FLOAT);
+        value.setCellFormatter(new CellFormatter() {
+            @Override
+            public String format(Object v, ListGridRecord r, int row, int col) {
+                if (v == null) {
+                    return null;
+                }
+
+                try {
+                    double value = Double.valueOf(v.toString());
+                    return nf.format(value);
+                }
+                catch (NumberFormatException nfe) {
+                    return v.toString();
+                }
+            }
+        });
         value.setWidth("20%");
 
-        setFields(addMax, addMin, name, type, value);
+        setFields(addMax, addMin, select, name, type, value);
     }
 
     public void hideIconFields () {
         hideField("max");
         hideField("min");
+        hideField("select");
         lockClick = true;
     }
 
@@ -68,9 +95,16 @@
     public void showIconFields() {
         showField("max");
         showField("min");
+        hideField("select");
         lockClick = false;
     }
 
+    public void showSelect() {
+        showField("select");
+        hideField("max");
+        hideField("min");
+    }
+
     public boolean isLocked() {
         return lockClick;
     }
--- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/wq/WTable.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/wq/WTable.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,11 +1,14 @@
 package de.intevation.flys.client.client.ui.wq;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
 
 import com.smartgwt.client.types.ListGridFieldType;
 import com.smartgwt.client.types.SelectionStyle;
+import com.smartgwt.client.widgets.grid.CellFormatter;
 import com.smartgwt.client.widgets.grid.ListGrid;
 import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
 
 import de.intevation.flys.client.client.FLYSConstants;
 
@@ -36,9 +39,26 @@
         type.setType(ListGridFieldType.TEXT);
         type.setWidth("50");
 
-        ListGridField value = new ListGridField("value", MESSAGE.wq_value());
+        final NumberFormat nf = NumberFormat.getDecimalFormat();
+
+        ListGridField value = new ListGridField("value", MESSAGE.wq_value_w());
         value.setType(ListGridFieldType.FLOAT);
-        type.setWidth("50");
+        value.setCellFormatter(new CellFormatter() {
+            @Override
+            public String format(Object v, ListGridRecord r, int row, int col) {
+                if (v == null) {
+                    return null;
+                }
+
+                try {
+                    double value = Double.valueOf(v.toString());
+                    return nf.format(value);
+                }
+                catch (NumberFormatException nfe) {
+                    return v.toString();
+                }
+            }
+        });
 
         setFields(name, type, value);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/utils/DoubleValidator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,81 @@
+package de.intevation.flys.client.client.utils;
+
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.smartgwt.client.widgets.form.fields.FormItem;
+
+import de.intevation.flys.client.client.FLYSConstants;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class DoubleValidator implements Validator {
+
+    /** The interface that provides i18n messages. */
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+
+    /** Statically determine doubility of String value. */
+    public static boolean isDouble(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        boolean valid = true;
+        String v = obj.toString();
+
+        NumberFormat f = NumberFormat.getDecimalFormat();
+
+        try {
+            if (v == null) {
+                throw new NumberFormatException("empty");
+            }
+
+            double value = f.parse(v);
+        }
+        catch (NumberFormatException nfe) {
+            valid = false;
+        }
+        return valid;
+
+    }
+
+
+    /**
+     * @return true if items value can be converted to double, if false,
+     *         expect error message in \param errors map.
+     */
+    public boolean validate(FormItem item, Map errors) {
+        boolean valid = true;
+
+        if(item.getValue() == null) {
+            return false;
+        }
+        String v = item.getValue().toString();
+
+        NumberFormat f = NumberFormat.getDecimalFormat();
+
+        try {
+            if (v == null) {
+                throw new NumberFormatException("empty");
+            }
+
+            double value = f.parse(v);
+
+            errors.remove(item.getFieldName());
+        }
+        catch (NumberFormatException nfe) {
+            errors.put(item.getFieldName(), MSG.wrongFormat());
+
+            item.focusInItem();
+
+            valid = false;
+        }
+        return valid;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/client/utils/IntegerValidator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,45 @@
+package de.intevation.flys.client.client.utils;
+
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+
+import com.smartgwt.client.widgets.form.fields.FormItem;
+
+import de.intevation.flys.client.client.FLYSConstants;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class IntegerValidator implements Validator {
+
+    /** The interface that provides i18n messages. */
+    protected FLYSConstants MSG = GWT.create(FLYSConstants.class);
+
+    /**
+     *
+     */
+    public boolean validate(FormItem item, Map errors) {
+        boolean valid = true;
+
+        String v = item.getValue().toString();
+
+        try {
+            if (v == null) {
+                throw new NumberFormatException("empty");
+            }
+
+            int value = Integer.parseInt(v);
+
+            errors.remove(item.getFieldName());
+        }
+        catch (NumberFormatException nfe) {
+            errors.put(item.getFieldName(), MSG.wrongFormat());
+
+            item.focusInItem();
+
+            valid = false;
+        }
+        return valid;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/utils/Validator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,16 @@
+package de.intevation.flys.client.client.utils;
+
+import java.util.Map;
+
+import com.smartgwt.client.widgets.form.fields.FormItem;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ *
+ * This validator is used for SmartGWT FormItems.
+ */
+public interface Validator {
+
+    boolean validate(FormItem item, Map errors);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/widgets/KMSpinner.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,176 @@
+package de.intevation.flys.client.client.widgets;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+
+import com.smartgwt.client.data.Record;
+import com.smartgwt.client.widgets.Button;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.FormItemValueFormatter;
+import com.smartgwt.client.widgets.form.FormItemValueParser;
+import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.TextItem;
+import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
+import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
+import com.smartgwt.client.widgets.form.fields.events.KeyPressEvent;
+import com.smartgwt.client.widgets.form.fields.events.KeyPressHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
+
+import de.intevation.flys.client.shared.model.FacetRecord;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * SpinnerItem-like element with text label and up/down buttons.
+ */
+public class KMSpinner extends HLayout {
+    protected List<KMSpinnerChangeListener> listeners = new ArrayList<KMSpinnerChangeListener>();
+
+    protected Label label;
+    protected FacetRecord facetRecord;
+    protected double value;
+
+    public KMSpinner(double initialValue, FacetRecord facetRecord) {
+        super(2);
+        this.facetRecord = facetRecord;
+        this.value = initialValue;
+
+        setWidth("99%");
+        setHeight(18);
+
+        // minusButton shall ask service for previous available cs.
+        Button minusButton = new Button("-");
+        minusButton.setWidth(18);
+        minusButton.setHeight(18);
+        minusButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
+            public void onClick(ClickEvent evt) {
+                fireChangedEvent(value - 0.1d, false);
+            }
+        });
+
+        DynamicForm form = new DynamicForm();
+        final TextItem kmField = new TextItem();
+        kmField.setValue(initialValue);
+        kmField.setWidth("*");
+        kmField.setTitle("");
+        kmField.setHeight(16);
+
+        FormItemValueFormatter doubleFormat = new FormItemValueFormatter() {
+            public String formatValue(Object value, Record record, DynamicForm form, FormItem item) {
+                if (value != null) {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    try {
+                        double d = Double.valueOf(value.toString()).doubleValue();
+                        return nf.format(d);
+                    }
+                    catch (Exception e) {
+                        GWT.log("EditorValueFormatter exception: " + e.toString());
+
+                        // Remove junk chars from input string
+                        return doublefyString(value.toString());
+                    }
+                }
+                else {
+                    return null;
+                }
+            }
+        };
+        kmField.setEditorValueFormatter(doubleFormat);
+
+        FormItemValueParser doubleParser = new FormItemValueParser() {
+            public Object parseValue(String value, DynamicForm form, FormItem item) {
+                if (value == null)
+                    return null;
+                try {
+                    NumberFormat nf = NumberFormat.getDecimalFormat();
+                    double d = nf.parse(value.toString());
+                    return Double.toString(d);
+                }
+                catch(NumberFormatException nfe) {
+                    return value;
+                }
+            }
+        };
+        kmField.setEditorValueParser(doubleParser);
+
+        // Update on focus lost and enter-pressed.
+        kmField.addBlurHandler(new BlurHandler() {
+            @Override
+            public void onBlur(BlurEvent be) {
+                if (kmField.getValue() != null) {
+                    try {
+                        fireChangedEvent(Double.parseDouble(kmField.getValue().toString()), true);
+                    }
+                    catch(NumberFormatException nfe) {
+                        GWT.log("entered string cannot be parsed to double.");
+                    }
+                }
+            }
+        });
+        kmField.addKeyPressHandler(new KeyPressHandler() {
+            @Override
+            public void onKeyPress(KeyPressEvent kpe) {
+                if (kpe.getKeyName().equals("Enter")) {
+                    kmField.blurItem();
+                }
+            }
+        });
+
+        // TODO: i18n Now add all the validators, formatters, editors/parsers  etc.
+        form.setFields(kmField);
+        form.setTitle("");
+        form.setTitlePrefix("");
+        form.setTitleSuffix("");
+        form.setTitleWidth(0);
+        form.setWidth(50);
+        form.setHeight(18);
+
+        // PlusButton shall ask service for next available cs.
+        Button plusButton = new Button("+");
+        plusButton.setWidth(18);
+        plusButton.setHeight(18);
+        plusButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
+            public void onClick(ClickEvent evt) {
+                fireChangedEvent(value + 0.1d, true);
+            }
+        });
+
+        this.addMember(minusButton);
+        this.addMember(form);
+        this.addMember(plusButton);
+    }
+
+    public void addChangeListener(KMSpinnerChangeListener listener) {
+        this.listeners.add(listener);
+    }
+
+    protected void fireChangedEvent(double val, boolean up) {
+        for(KMSpinnerChangeListener listener : listeners) {
+            listener.spinnerValueEntered(this, val, facetRecord, up);
+        }
+    }
+
+    /**
+     * Remove junk chars from double string.
+     * This method should work for most locales, but not for
+     * exotic ones that do not use "." or "," as decimal
+     * separator.
+     * @return
+     */
+    protected String doublefyString(String str) {
+        StringBuilder buf = new StringBuilder(str.length());
+
+        for (int n = 0; n < str.length(); n++) {
+            char c = str.charAt(n);
+            if ((c >= '0' && c <= '9') || c == '.' || c == ',') {
+                buf.append(c);
+            }
+        }
+
+        return buf.toString();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/client/widgets/KMSpinnerChangeListener.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,9 @@
+package de.intevation.flys.client.client.widgets;
+
+import de.intevation.flys.client.client.widgets.KMSpinner;
+
+import de.intevation.flys.client.shared.model.FacetRecord;
+
+public interface KMSpinnerChangeListener {
+    public void spinnerValueEntered(KMSpinner spinner, double km, FacetRecord facetRecord, boolean up);
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/server/AdvanceServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/AdvanceServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -31,7 +31,6 @@
 {
     private static final Logger logger = Logger.getLogger(AdvanceService.class);
 
-
     public static final String XPATH_RESULT = "/art:result/text()";
 
     public static final String OPERATION_FAILURE = "FAILED";
@@ -47,7 +46,7 @@
     {
         logger.info("AdvanceServiceImpl.advance");
 
-        String url  = getServletContext().getInitParameter("server-url");
+        String url = getServletContext().getInitParameter("server-url");
 
         Document advance = ClientProtocolUtils.newAdvanceDocument(
             artifact.getUuid(),
--- a/flys-client/src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ArtifactDescriptionFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -23,6 +23,11 @@
 import de.intevation.flys.client.shared.model.DefaultData;
 import de.intevation.flys.client.shared.model.DefaultDataItem;
 import de.intevation.flys.client.shared.model.DefaultOutputMode;
+import de.intevation.flys.client.shared.model.DoubleArrayData;
+import de.intevation.flys.client.shared.model.DoubleRangeData;
+import de.intevation.flys.client.shared.model.IntegerArrayData;
+import de.intevation.flys.client.shared.model.IntegerRangeData;
+import de.intevation.flys.client.shared.model.IntegerOptionsData;
 import de.intevation.flys.client.shared.model.OutputMode;
 import de.intevation.flys.client.shared.model.Recommendation;
 import de.intevation.flys.client.shared.model.WQDataItem;
@@ -46,6 +51,8 @@
 
     public static final String XPATH_UIPROVIDER = "@art:uiprovider";
 
+    public static final String XPATH_HELP_TEXT = "@art:helpText";
+
     public static final String XPATH_REACHABLE_STATE = "art:state";
 
     public static final String XPATH_STATIC_STATE_NODE = "art:state";
@@ -113,27 +120,99 @@
         logger.debug("ArtifactDescriptionFactory.extractCurrentData");
 
         NodeList data     = ClientProtocolUtils.getSelectNode(dynamicNode);
+        String help       = extractHelpText(dynamicNode);
         String uiProvider = extractUIProvider(dynamicNode);
 
         if (data == null || data.getLength() == 0) {
             return null;
         }
 
-        int dataNum   = data.getLength();
-        DataList list = new DataList(state, dataNum, uiProvider);
+        int      dataNum = data.getLength();
+        DataList list    = new DataList(state, dataNum, uiProvider, null, help);
 
         for (int i = 0; i < dataNum; i++) {
-            Node d = data.item(i);
+            Element   d  = (Element) data.item(i);
+            String label = ClientProtocolUtils.getLabel(d);
+            String name  = XMLUtils.xpathString(
+                d, "@art:name", ArtifactNamespaceContext.INSTANCE);
+            String type  = XMLUtils.xpathString(
+                d, "@art:type", ArtifactNamespaceContext.INSTANCE);
 
-            NodeList choices  = ClientProtocolUtils.getItemNodes(d);
-            String   label    = ClientProtocolUtils.getLabel(d);
-            String   name     = XMLUtils.xpathString(
-                d, "@art:name", ArtifactNamespaceContext.INSTANCE);
+            logger.debug("Create new IntegerRangeData object for: " + name);
+            logger.debug("New Data is from type: " + type);
 
-            DataItem[] dataItems = extractCurrentDataItems(choices);
-            DataItem   def       = extractDefaultDataItem(d);
+            // TODO replace with DataFactory.
 
-            list.add(new DefaultData(name, label, null, dataItems, def));
+            if (type == null || type.length() == 0) {
+                NodeList   choices   = ClientProtocolUtils.getItemNodes(d);
+                DataItem[] dataItems = extractCurrentDataItems(choices);
+                DataItem   def       = extractDefaultDataItem(d);
+
+                list.add(new DefaultData(name, label, null, dataItems, def));
+            }
+            else if (type.equals("intrange")) {
+                String min = ClientProtocolUtils.getMinNode(d);
+                String max = ClientProtocolUtils.getMaxNode(d);
+
+                String defMin = ClientProtocolUtils.getDefMin(d);
+                String defMax = ClientProtocolUtils.getDefMax(d);
+
+                try {
+                    int lower = Integer.parseInt(min);
+                    int upper = Integer.parseInt(max);
+
+                    if (defMin != null && defMax != null) {
+                        list.add(new IntegerRangeData(
+                                name, label,
+                                lower, upper,
+                                Integer.parseInt(defMin),
+                                Integer.parseInt(defMax)));
+                    }
+                    else {
+                        list.add(
+                            new IntegerRangeData(name, label, lower, upper));
+                    }
+                }
+                catch (NumberFormatException nfe) {
+                    logger.warn("NumberFormatException: ", nfe);
+                }
+            }
+            else if (type.equals("intarray")) {
+                list.add(new IntegerArrayData(name, label, null));
+            }
+            else if (type.equals("intoptions") && uiProvider.equals("parameter-matrix")) {
+                list.add(DataFactory.createIntegerOptionsData(d, name, label));
+            }
+            else if (type.equals("options")) {
+                list.add(DataFactory.createStringOptionsData(d, name, label));
+            }
+            else if (type.equals("intoptions")) {
+                NodeList   choices = ClientProtocolUtils.getItemNodes(d);
+                DataItem[] opts    = extractCurrentDataItems(choices);
+
+                list.add(new IntegerOptionsData(name, label, opts));
+            }
+            else if (type.equals("doublearray")) {
+                list.add(new DoubleArrayData(name, label, null));
+            }
+            else {
+                logger.warn("Unrecognized Dynamic data type.");
+                NodeList   choices   = ClientProtocolUtils.getItemNodes(d);
+                DataItem[] dataItems = extractCurrentDataItems(choices);
+                DataItem   def       = extractDefaultDataItem(d);
+
+                String min = ClientProtocolUtils.getMinNode(d);
+                String max = ClientProtocolUtils.getMaxNode(d);
+                if (min != null && max != null) {
+                    list.add(new DoubleRangeData(
+                        name, label,
+                        Double.valueOf(min), Double.valueOf(max),
+                        Double.valueOf(min), Double.valueOf(max)));
+                }
+
+                list.add(new DefaultData(name, label, null, dataItems, def));
+            }
+
         }
 
         return list;
@@ -199,7 +278,7 @@
             }
         }
 
-        return (DataItem[]) dataItems.toArray(new DataItem[count]);
+        return dataItems.toArray(new DataItem[count]);
     }
 
 
@@ -311,6 +390,8 @@
                 tmp, "@art:uiprovider", ArtifactNamespaceContext.INSTANCE);
             String label = XMLUtils.xpathString(
                 tmp, "@art:label", ArtifactNamespaceContext.INSTANCE);
+            String help = XMLUtils.xpathString(
+                tmp, "@art:helpText", ArtifactNamespaceContext.INSTANCE);
 
             NodeList dataNodes = (NodeList) XMLUtils.xpath(
                 tmp,
@@ -323,19 +404,12 @@
             }
 
             int size      = dataNodes.getLength();
-            DataList list = new DataList(name, size, uiprovider, label);
+            DataList list = new DataList(name, size, uiprovider, label, help);
 
             for (int j = 0; j < size; j++) {
                 Node dataNode = dataNodes.item(j);
 
-                String dName = XMLUtils.xpathString(
-                    dataNode, "@art:name", ArtifactNamespaceContext.INSTANCE);
-                String dType = XMLUtils.xpathString(
-                    dataNode, "@art:type", ArtifactNamespaceContext.INSTANCE);
-
-                DataItem[] items = extractOldDataItems(dataNode);
-
-                list.add(new DefaultData(dName, dName, dType, items));
+                list.add(DataFactory.createDataFromElement((Element) dataNode));
 
                 data[i] = list;
             }
@@ -346,45 +420,6 @@
 
 
     /**
-     * This method extracts the data items from the data nodes that are placed
-     * in the static ui part of the DESCRIBE document.
-     *
-     * @param dataNode A data node that contains items.
-     *
-     * @return a list of DataItems.
-     */
-    protected static DataItem[] extractOldDataItems(Node dataNode) {
-        NodeList itemList = (NodeList) XMLUtils.xpath(
-            dataNode,
-            XPATH_STATIC_ITEM_NODE,
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
-
-        if (itemList == null || itemList.getLength() == 0) {
-            logger.debug("No old data items found.");
-            return null;
-        }
-
-        int count = itemList.getLength();
-
-        DataItem[] items = new DataItem[count];
-
-        for (int i = 0; i < count; i++) {
-            Node tmp = itemList.item(i);
-
-            String value = XMLUtils.xpathString(
-                tmp, "@art:value", ArtifactNamespaceContext.INSTANCE);
-            String label = XMLUtils.xpathString(
-                tmp, "@art:label", ArtifactNamespaceContext.INSTANCE);
-
-            items[i] = new DefaultDataItem(label, label, value);
-        }
-
-        return items;
-    }
-
-
-    /**
      * This method extracts the UIProvider specified by the data node.
      *
      * @param data The data node.
@@ -401,6 +436,22 @@
 
 
     /**
+     * This method extracts the help text specified by the data node.
+     *
+     * @param ui The data node.
+     *
+     * @return the help text.
+     */
+    protected static String extractHelpText(Node ui) {
+        return (String) XMLUtils.xpath(
+            ui,
+            XPATH_HELP_TEXT,
+            XPathConstants.STRING,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+
+    /**
      * This method extracts the reachable states of the current artifact.
      *
      * @param reachable The reachable states node.
--- a/flys-client/src/main/java/de/intevation/flys/client/server/ArtifactHelper.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ArtifactHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,6 +1,7 @@
 package de.intevation.flys.client.server;
 
 import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import org.apache.log4j.Logger;
 
@@ -14,13 +15,14 @@
 import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
 import de.intevation.artifacts.httpclient.http.HttpClient;
 import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+import de.intevation.artifacts.httpclient.utils.ArtifactNamespaceContext;
+import de.intevation.artifacts.httpclient.utils.XMLUtils;
 
 import de.intevation.flys.client.shared.exceptions.ServerException;
 import de.intevation.flys.client.shared.model.Artifact;
 
 import de.intevation.flys.client.shared.model.Recommendation;
 
-
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
@@ -33,6 +35,11 @@
      * creation.*/
     public static final String ERROR_CREATE_ARTIFACT = "error_create_artifact";
 
+    /**
+     * Name of the factory to generate a GaugeDischargeCurveArtifact
+     */
+    private static final String GAUGE_DISCHARGE_CURVE_ARTIFACT = "gaugedischargecurve";
+
 
     private ArtifactHelper() {
     }
@@ -68,10 +75,58 @@
         Document create = ClientProtocolUtils.newCreateDocument(
             factory, uuid, ids, filter);
 
+        return sendCreate(serverUrl, locale, create);
+
+    }
+
+    /**
+     * Creates a new GaugeDischargeCurverArtifact
+     *
+     * @param river the name of the river
+     * @param reference the reference id of the gauge (official number)
+     */
+    public static Artifact createGaugeDischargeCurveArtifact(
+            String serverUrl,
+            String locale,
+            String river,
+            Long   reference)
+    throws ServerException
+    {
+        Document create = ClientProtocolUtils.newCreateDocument(
+                GAUGE_DISCHARGE_CURVE_ARTIFACT);
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            create,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element root = create.getDocumentElement();
+
+        Element eriver = ec.create("river");
+        ec.addAttr(eriver, "name", river);
+
+        Element egauge = ec.create("gauge");
+        ec.addAttr(egauge, "reference", reference.toString());
+
+        root.appendChild(eriver);
+        root.appendChild(egauge);
+
+        return sendCreate(serverUrl, locale, create);
+    }
+
+    /**
+     * Sends a create document to the artifact server
+     */
+    private static Artifact sendCreate(
+            String   serverUrl,
+            String   locale,
+            Document doc)
+    throws ServerException
+    {
         HttpClient client = new HttpClientImpl(serverUrl, locale);
 
         try {
-            return (Artifact) client.create(create, new FLYSArtifactCreator());
+            return (Artifact) client.create(doc, new FLYSArtifactCreator());
         }
         catch (ConnectionException ce) {
             logger.error(ce, ce);
--- a/flys-client/src/main/java/de/intevation/flys/client/server/ArtifactServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ArtifactServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,6 +8,7 @@
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.client.services.ArtifactService;
 
+import de.intevation.flys.client.shared.model.Collection;
 import de.intevation.flys.client.shared.model.Recommendation;
 
 /**
@@ -20,6 +21,7 @@
 extends      RemoteServiceServlet
 implements   ArtifactService
 {
+    /** Private logger. */
     private static final Logger logger =
         Logger.getLogger(ArtifactServiceImpl.class);
 
@@ -30,6 +32,7 @@
      *
      * @param locale The locale used for HTTP request.
      * @param factory The factory that is used to create the new Artifact.
+     * @param recom Recommendation with details of the artifact to create.
      *
      * @return a new Artifact.
      */
@@ -46,5 +49,34 @@
 
         return ArtifactHelper.createArtifact(url, locale, factory, recom);
     }
+
+    /**
+     * Create a new GaugeDischageCurveArtifact
+     *
+     * @param river    the river
+     * @param gaugeref reference id of the gauge
+     */
+    public Artifact createGaugeDischargeCurveArtifact(
+            Collection collection,
+            String locale,
+            String river,
+            Long   gaugeref)
+    throws ServerException
+    {
+        logger.info("ArtifactServiceImpl.createGaugeDischargeCurverArtifact");
+        String url  = getServletContext().getInitParameter("server-url");
+
+        Artifact artifact = ArtifactHelper.createGaugeDischargeCurveArtifact(url,
+                locale, river, gaugeref);
+        if (artifact == null) {
+            return null;
+        }
+        logger.info("GaugeDischargeCurveArtifact created successfully");
+
+        CollectionHelper.addArtifact(collection, artifact, url, locale);
+
+        return artifact;
+    }
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/BaseServlet.java	Fri Sep 28 12:14:57 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-package de.intevation.flys.client.server;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-
-import org.apache.log4j.Logger;
-
-
-public class BaseServlet extends HttpServlet {
-
-    private static Logger logger = Logger.getLogger(BaseServlet.class);
-
-
-    public static final String LOG4J_PROPERTIES = "FLYS_CLIENT_LOG4J_PROPERIES";
-
-
-    @Override
-    public void init()
-    throws ServletException
-    {
-        System.out.println("BaseServlet.init");
-
-        initLogging();
-        initConfigParameters();
-    }
-
-
-    protected void initLogging() {
-        String log4jProperties = System.getenv(LOG4J_PROPERTIES);
-
-        if (log4jProperties == null || log4jProperties.length() == 0) {
-            String file = getInitParameter("log4j-properties");
-
-            if (file != null && file.length() > 0) {
-                log4jProperties = getServletContext().getRealPath(file);
-            }
-        }
-
-        LoggingConfigurator.init(log4jProperties);
-    }
-
-
-    protected void initConfigParameters() {
-        String url = getInitParameter("server-url");
-        logger.debug("Found server url: " + url);
-
-        getServletContext().setAttribute("server-url", url);
-    }
-}
-// 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-client/src/main/java/de/intevation/flys/client/server/BaseServletContextListener.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,62 @@
+package de.intevation.flys.client.server;
+
+import java.io.IOException;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.client.server.LoggingConfigurator;
+import de.intevation.flys.client.server.features.Features;
+import de.intevation.flys.client.server.features.XMLFileFeatures;
+
+/**
+ * ServletContextListenter to initalize the Features globally for
+ * all Servlets
+ */
+public class BaseServletContextListener implements ServletContextListener {
+
+    public static final String LOG4J_PROPERTIES = "FLYS_CLIENT_LOG4J_PROPERIES";
+
+    public static final Logger logger = Logger.getLogger(BaseServletContextListener.class);
+
+    @Override
+    public void  contextInitialized(ServletContextEvent sce) {
+        ServletContext sc = sce.getServletContext();
+
+        this.initLogging(sc);
+
+        String filename = sc.getInitParameter("features-file");
+
+        logger.debug("Initializing ServletContext");
+        try {
+            XMLFileFeatures features = new XMLFileFeatures(sc.getRealPath(filename));
+            sc.setAttribute(Features.CONTEXT_ATTRIBUTE, features);
+        } catch(IOException e) {
+            logger.error(e);
+        }
+    }
+
+    @Override
+    public void contextDestroyed(ServletContextEvent sce) {
+        //DO NOTHING
+    }
+
+
+    private void initLogging(ServletContext sc) {
+        String log4jProperties = System.getenv(LOG4J_PROPERTIES);
+
+        if (log4jProperties == null || log4jProperties.length() == 0) {
+            String file = sc.getInitParameter("log4j-properties");
+
+            if (file != null && file.length() > 0) {
+                log4jProperties = sc.getRealPath(file);
+            }
+        }
+        System.out.println(log4jProperties);
+
+        LoggingConfigurator.init(log4jProperties);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/BedKMChartServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,106 @@
+package de.intevation.flys.client.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+import de.intevation.artifacts.httpclient.http.response.StreamResponseHandler;
+
+public class BedKMChartServiceImpl extends HttpServlet {
+    private static final Logger log =
+        Logger.getLogger(FixingsKMChartServiceImpl.class);
+
+    public static final String SERVICE_NAME = "bed-km-chart";
+
+    public BedKMChartServiceImpl() {
+    }
+
+    public void doGet(HttpServletRequest req, HttpServletResponse resp) {
+
+        log.info("BedKMChartServiceImpl.doGet");
+
+        String url    = getServletContext().getInitParameter("server-url");
+        String locale = req.getParameter("locale");
+        String filter = req.getParameter("filter");
+
+        if (filter == null || filter.length() == 0) {
+            log.warn("Missing 'filter' parameter.");
+            return;
+        }
+
+        if (locale == null || locale.length() == 0) {
+            locale = "de";
+        }
+
+        Document filterDoc = XMLUtils.jsonToXML(filter);
+
+        if (filterDoc == null) {
+            log.warn("Creating filter document failed.");
+            return;
+        }
+
+        InputStream in;
+
+        try {
+            HttpClient client = new HttpClientImpl(url, locale);
+            in = (InputStream)client.callService(
+                url, // XXX: Why? The URL is passed by construction already.
+                SERVICE_NAME,
+                filterDoc,
+                new StreamResponseHandler());
+        }
+        catch (ConnectionException ce) {
+            log.error(ce);
+            return;
+        }
+
+        resp.setHeader("Content-Type", guessMIMEType(filterDoc));
+
+        try {
+            OutputStream out = resp.getOutputStream();
+
+            byte [] buf = new byte[4096];
+            int i = -1;
+            while ((i = in.read(buf)) >= 0) {
+                out.write(buf, 0, i);
+            }
+            out.flush();
+        }
+        catch (IOException ioe) {
+            log.error(ioe);
+        }
+        finally {
+            try { in.close(); }
+            catch (IOException ioe) { /* ignored */ }
+        }
+    }
+
+    protected static String guessMIMEType(Document document) {
+
+        NodeList formats = document.getElementsByTagName("format");
+
+        String format = "png";
+
+        if (formats.getLength() > 0) {
+            String type = ((Element)formats.item(0)).getAttribute("type");
+            if (type.length() > 0) {
+                format = type;
+            }
+        }
+
+        return "image/" + format;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/BedloadKMChartServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,106 @@
+package de.intevation.flys.client.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+import de.intevation.artifacts.httpclient.http.response.StreamResponseHandler;
+
+public class BedloadKMChartServiceImpl extends HttpServlet {
+   private static final Logger log =
+        Logger.getLogger(FixingsKMChartServiceImpl.class);
+
+    public static final String SERVICE_NAME = "bedload-km-chart";
+
+    public BedloadKMChartServiceImpl() {
+    }
+
+    public void doGet(HttpServletRequest req, HttpServletResponse resp) {
+
+        log.info("BedloadKMChartServiceImpl.doGet");
+
+        String url    = getServletContext().getInitParameter("server-url");
+        String locale = req.getParameter("locale");
+        String filter = req.getParameter("filter");
+
+        if (filter == null || filter.length() == 0) {
+            log.warn("Missing 'filter' parameter.");
+            return;
+        }
+
+        if (locale == null || locale.length() == 0) {
+            locale = "de";
+        }
+
+        Document filterDoc = XMLUtils.jsonToXML(filter);
+
+        if (filterDoc == null) {
+            log.warn("Creating filter document failed.");
+            return;
+        }
+
+        InputStream in;
+
+        try {
+            HttpClient client = new HttpClientImpl(url, locale);
+            in = (InputStream)client.callService(
+                url, // XXX: Why? The URL is passed by construction already.
+                SERVICE_NAME,
+                filterDoc,
+                new StreamResponseHandler());
+        }
+        catch (ConnectionException ce) {
+            log.error(ce);
+            return;
+        }
+
+        resp.setHeader("Content-Type", guessMIMEType(filterDoc));
+
+        try {
+            OutputStream out = resp.getOutputStream();
+
+            byte [] buf = new byte[4096];
+            int i = -1;
+            while ((i = in.read(buf)) >= 0) {
+                out.write(buf, 0, i);
+            }
+            out.flush();
+        }
+        catch (IOException ioe) {
+            log.error(ioe);
+        }
+        finally {
+            try { in.close(); }
+            catch (IOException ioe) { /* ignored */ }
+        }
+    }
+
+    protected static String guessMIMEType(Document document) {
+
+        NodeList formats = document.getElementsByTagName("format");
+
+        String format = "png";
+
+        if (formats.getLength() > 0) {
+            String type = ((Element)formats.item(0)).getAttribute("type");
+            if (type.length() > 0) {
+                format = type;
+            }
+        }
+
+        return "image/" + format;
+    }
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/server/CapabilitiesParser.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/CapabilitiesParser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -98,7 +98,7 @@
     public static void main(String[] args) {
         logger.info("Do static Capabilities request/parsing.");
 
-        String log4jProperties = System.getenv(BaseServlet.LOG4J_PROPERTIES);
+        String log4jProperties = System.getenv(BaseServletContextListener.LOG4J_PROPERTIES);
         LoggingConfigurator.init(log4jProperties);
 
         try {
--- a/flys-client/src/main/java/de/intevation/flys/client/server/ChartInfoServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ChartInfoServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,13 +3,14 @@
 import java.io.InputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
 import javax.xml.xpath.XPathConstants;
 
 import org.w3c.dom.Document;
-import org.w3c.dom.Node;
+import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
 import org.apache.log4j.Logger;
@@ -26,6 +27,8 @@
 import de.intevation.flys.client.shared.Transform2D;
 import de.intevation.flys.client.shared.exceptions.ServerException;
 import de.intevation.flys.client.shared.model.Axis;
+import de.intevation.flys.client.shared.model.DateAxis;
+import de.intevation.flys.client.shared.model.NumberAxis;
 import de.intevation.flys.client.shared.model.ChartInfo;
 import de.intevation.flys.client.shared.model.Collection;
 
@@ -147,30 +150,20 @@
 
         Axis[] result = new Axis[count];
 
-        for (int i = 0; i < count; i++) {
-            Node node = axes.item(i);
-
-            String posStr = XMLUtils.xpathString(
-                node, "@art:pos", ArtifactNamespaceContext.INSTANCE);
+        String ns = ArtifactNamespaceContext.NAMESPACE_URI;
 
-            String fromStr = XMLUtils.xpathString(
-                node, "@art:from", ArtifactNamespaceContext.INSTANCE);
+        for (int i = 0; i < count; i++) {
+            Element node = (Element) axes.item(i);
 
-            String toStr = XMLUtils.xpathString(
-                node, "@art:to", ArtifactNamespaceContext.INSTANCE);
-
-            String minStr = XMLUtils.xpathString(
-                node, "@art:min", ArtifactNamespaceContext.INSTANCE);
-
-            String maxStr = XMLUtils.xpathString(
-                node, "@art:max", ArtifactNamespaceContext.INSTANCE);
+            String posStr   = node.getAttributeNS(ns, "pos");
+            String fromStr  = node.getAttributeNS(ns, "from");
+            String toStr    = node.getAttributeNS(ns, "to");
+            String minStr   = node.getAttributeNS(ns, "min");
+            String maxStr   = node.getAttributeNS(ns, "max");
+            String axisType = node.getAttributeNS(ns, "axistype");
 
             try {
                 int    pos  = Integer.parseInt(posStr);
-                double from = Double.parseDouble(fromStr);
-                double to   = Double.parseDouble(toStr);
-                double min  = Double.parseDouble(minStr);
-                double max  = Double.parseDouble(maxStr);
 
                 if (pos >= result.length) {
                     // this should never happen
@@ -178,7 +171,29 @@
                     continue;
                 }
 
-                result[pos] = new Axis(pos, from, to, min, max);
+                if (axisType != null && axisType.equals(DateAxis.TYPE)) {
+                    long from = Long.parseLong(fromStr);
+                    long to   = Long.parseLong(toStr);
+                    long min  = Long.parseLong(minStr);
+                    long max  = Long.parseLong(maxStr);
+
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("date axis from: " + new Date(from));
+                        logger.debug("date axis to  : " + new Date(to));
+                        logger.debug("date axis min : " + new Date(min));
+                        logger.debug("date axis max : " + new Date(max));
+                    }
+
+                    result[pos] = new DateAxis(pos, from, to, min, max);
+                }
+                else {
+                    double from = Double.parseDouble(fromStr);
+                    double to   = Double.parseDouble(toStr);
+                    double min  = Double.parseDouble(minStr);
+                    double max  = Double.parseDouble(maxStr);
+
+                    result[pos] = new NumberAxis(pos, from, to, min, max);
+                }
             }
             catch (NumberFormatException nfe) {
                 nfe.printStackTrace();
@@ -213,7 +228,7 @@
         List<Transform2D> transformer = new ArrayList<Transform2D>(num);
 
         for (int i = 0; i < num; i++) {
-            Transform2D t = createTransformer(matrix.item(i));
+            Transform2D t = createTransformer((Element) matrix.item(i));
 
             if (t == null) {
                 logger.warn("Broken transformation matrix at pos: " + i);
@@ -223,30 +238,34 @@
             transformer.add(t);
         }
 
-        return (Transform2D[]) transformer.toArray(new Transform2D[num]);
+        return transformer.toArray(new Transform2D[num]);
     }
 
 
-    protected Transform2D createTransformer(Node matrix) {
-        String sx = XMLUtils.xpathString(
-            matrix, "@art:sx", ArtifactNamespaceContext.INSTANCE);
+    protected Transform2D createTransformer(Element matrix) {
+        String ns = ArtifactNamespaceContext.NAMESPACE_URI;
 
-        String sy = XMLUtils.xpathString(
-            matrix, "@art:sy", ArtifactNamespaceContext.INSTANCE);
+        String sx    = matrix.getAttributeNS(ns, "sx");
+        String sy    = matrix.getAttributeNS(ns, "sy");
+        String tx    = matrix.getAttributeNS(ns, "tx");
+        String ty    = matrix.getAttributeNS(ns, "ty");
+        String xType = matrix.getAttributeNS(ns, "xtype");
+        String yType = matrix.getAttributeNS(ns, "ytype");
 
-        String tx = XMLUtils.xpathString(
-            matrix, "@art:tx", ArtifactNamespaceContext.INSTANCE);
-
-        String ty = XMLUtils.xpathString(
-            matrix, "@art:ty", ArtifactNamespaceContext.INSTANCE);
+        xType = xType == null || xType.length() == 0 ? "number" : xType;
+        yType = yType == null || yType.length() == 0 ? "number" : yType;
 
         if (sx != null && sy != null && tx != null && ty != null) {
             try {
+                logger.debug("Create new Transform2D with x format: " + xType);
+                logger.debug("Create new Transform2D with y format: " + yType);
+
                 return new Transform2D(
                     Double.parseDouble(sx),
                     Double.parseDouble(sy),
                     Double.parseDouble(tx),
-                    Double.parseDouble(ty));
+                    Double.parseDouble(ty),
+                    xType, yType);
             }
             catch (NumberFormatException nfe) {
                 logger.warn("Error while parsing matrix values.");
--- a/flys-client/src/main/java/de/intevation/flys/client/server/ChartOutputServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ChartOutputServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -39,11 +39,11 @@
         try {
             OutputStream out = resp.getOutputStream();
 
-            String url  = getServletContext().getInitParameter("server-url");
+            String url = getServletContext().getInitParameter("server-url");
 
-            String uuid      = req.getParameter("uuid");
-            String type      = req.getParameter("type");
-            String locale    = req.getParameter("locale");
+            String uuid   = req.getParameter("uuid");
+            String type   = req.getParameter("type");
+            String locale = req.getParameter("locale");
 
             prepareHeader(req, resp);
 
@@ -78,6 +78,15 @@
         attr.put("miny", req.getParameter("miny"));
         attr.put("maxy", req.getParameter("maxy"));
         attr.put("format", req.getParameter("format"));
+        attr.put("km", req.getParameter("currentKm"));
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("====== ZOOM VALUES =======");
+            logger.debug("  min x: " + req.getParameter("minx"));
+            logger.debug("  max x: " + req.getParameter("maxx"));
+            logger.debug("  min y: " + req.getParameter("miny"));
+            logger.debug("  max y: " + req.getParameter("maxy"));
+        }
 
         return attr;
     }
@@ -114,6 +123,9 @@
         else if (format.equals("svg")) {
             return ".svg";
         }
+        else if (format.equals("csv")) {
+            return ".csv";
+        }
 
         return ".png";
     }
@@ -129,6 +141,9 @@
         else if (format.equals("svg")) {
             return "svg+xml";
         }
+        else if (format.equals("csv")) {
+            return "text/plain";
+        }
 
         return "image/png";
     }
--- a/flys-client/src/main/java/de/intevation/flys/client/server/ChartServiceHelper.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ChartServiceHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -56,6 +56,7 @@
         appendFormat(req, attributes, ec);
         appendXRange(req, attributes, ec);
         appendYRange(req, attributes, ec);
+        appendCurrentKm(req, attributes, ec);
 
         doc.appendChild(attributes);
 
@@ -183,5 +184,34 @@
 
         attributes.appendChild(format);
     }
+
+
+    /**
+     * This method extracts the current km for the chart from request object and
+     * appends this km - if it exists - to the attribute document used to
+     * adjust the chart settings.
+     *
+     * @param req The request object that might contain the chart size.
+     * @param doc The attribute document used to adjust chart settings.
+     * @param ec The ElementCreator that might be used to create new Elements.
+     */
+    protected static void appendCurrentKm(
+        Map<String, String> req,
+        Element             attributes,
+        ElementCreator      ec)
+    {
+        logger.debug("ChartServiceHelper.appendCurrentKm");
+
+        Element currentKm = ec.create("currentKm");
+
+        String km = req.get("km");
+
+        if (km != null) {
+            ec.addAttr(currentKm, "km", km, true);
+
+            attributes.appendChild(currentKm);
+        }
+    }
+
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/CollectionHelper.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/CollectionHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -39,6 +39,7 @@
 import de.intevation.flys.client.shared.model.Facet;
 import de.intevation.flys.client.shared.model.MapMode;
 import de.intevation.flys.client.shared.model.OutputMode;
+import de.intevation.flys.client.shared.model.OverviewMode;
 import de.intevation.flys.client.shared.model.ReportMode;
 import de.intevation.flys.client.shared.model.Recommendation;
 import de.intevation.flys.client.shared.model.Theme;
@@ -187,11 +188,12 @@
             settings.getCategories().size() == 0)
         {
             logger.debug("No settings for output mode: " + mode.getName());
-            return null;
         }
-        Element s = createSettingsElement(settingscr, collection, settings);
-        if (s != null) {
-            out.appendChild(s);
+        else {
+            Element s = createSettingsElement(settingscr, collection, settings);
+            if (s != null) {
+                out.appendChild(s);
+            }
         }
         logger.info(XMLUtils.toString(out));
         return out;
@@ -374,7 +376,7 @@
             cr.addAttr(e, "type", "string", false);
         }
 
-        e.setTextContent(p.getValue());
+        e.setTextContent(p.getValue().toString());
         cr.addAttr(e, "display", p.getAttribute("display"), false);
         return e;
     }
@@ -605,7 +607,8 @@
 
 
     /**
-     *
+     * From a document, parse the settings for an output and create an
+     * OutputSettings object.
      */
     protected static Settings parseSettings(String outName, Element node) {
         OutputSettings set = new OutputSettings(outName);
@@ -618,7 +621,7 @@
 
         Element settings = (Element)elements.item(0);
 
-        // get the categories
+        // Get the categories
         NodeList catNodes = settings.getChildNodes();
         for (int i = 0; i < catNodes.getLength(); i++) {
             Element catNode = (Element)catNodes.item(i);
@@ -632,7 +635,7 @@
             // iterate through all properties or groups.
             List<Property> props = new ArrayList<Property> ();
             for (int j = 0; j < list.getLength(); j++) {
-                Property p = new PropertySetting();
+                Property p;
                 Element e = (Element)list.item(j);
                 if (e.hasChildNodes() &&
                     e.getFirstChild().getNodeType() != Node.TEXT_NODE) {
@@ -667,7 +670,7 @@
 
 
     /**
-     *
+     * From a property element create a Property object.
      */
     protected static Property parseSetting(Element property){
         NamedNodeMap attrMap = property.getAttributes();
@@ -718,7 +721,7 @@
         Element node,
         boolean outs
     ) {
-        logger.debug("AddArtifactServiceImpl.parseCollectionItem");
+        logger.debug("CollectionHelper.parseCollectionItem");
 
         if (node == null) {
             logger.debug("The node for parsing CollectionItem is null!");
@@ -814,11 +817,14 @@
                 outmode = new ReportMode(name, desc, mime, fs);
             }
             else if (type.equals("chart")){
-                outmode = new ChartMode(name, desc, mime, fs);
+                outmode = new ChartMode(name, desc, mime, fs, type);
             }
             else if (type.equals("map")){
                 outmode = new MapMode(name, desc, mime, fs);
             }
+            else if (type.equals("overview")) {
+                outmode = new OverviewMode(name, desc, mime, fs, type);
+            }
             else {
                 logger.warn("Broken Output mode without type found.");
                 continue;
--- a/flys-client/src/main/java/de/intevation/flys/client/server/CollectionItemAttributeServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/CollectionItemAttributeServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -137,7 +137,7 @@
         NodeList items = e.getElementsByTagName("theme");
 
         for (int i = 0; i < items.getLength(); i++) {
-            Style s = getStyle ((Element) items.item(i));
+            Style s = StyleHelper.getStyle ((Element) items.item(i));
             if(s == null) {
                 throw new ServerException(ERROR_NO_STYLES_FOUND);
             }
@@ -198,37 +198,5 @@
         styles.appendChild(action);
         return styles;
     }
-
-
-    protected Style getStyle (Element element) {
-
-        if (!element.getTagName().equals("theme")) {
-            return null;
-        }
-
-        NodeList list = element.getElementsByTagName("field");
-        Style style = new Style();
-
-        style.setName (element.getAttribute("name"));
-        style.setFacet (element.getAttribute("facet"));
-        try {
-            int ndx = Integer.parseInt(element.getAttribute("index"));
-            style.setIndex (ndx);
-        }
-        catch(NumberFormatException nfe) {
-            return null;
-        }
-        for(int i = 0; i < list.getLength(); i++) {
-            Element e = (Element) list.item(i);
-            StyleSetting set = new StyleSetting (
-                e.getAttribute("name"),
-                e.getAttribute("default"),
-                e.getAttribute("display"),
-                e.getAttribute("hints"),
-                e.getAttribute("type"));
-            style.appendStyleSetting(set);
-        }
-        return style;
-    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/CreateCollectionServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/CreateCollectionServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -31,10 +31,10 @@
 extends      RemoteServiceServlet
 implements   CreateCollectionService
 {
+    /** Private logger. */
     private static final Logger logger =
         Logger.getLogger(CreateCollectionServiceImpl.class);
 
-
     /** XPath to figure out the uuid of the created collection.*/
     public static final String XPATH_COLLECTION_UUID =
         "/art:result/art:artifact-collection/@art:uuid";
@@ -49,6 +49,7 @@
         "error_create_collection";
 
 
+    /** Attempt creation of Collection. */
     public Collection create(String locale, String ownerId)
     throws ServerException
     {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/DataFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,341 @@
+package de.intevation.flys.client.server;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.flys.client.shared.model.Data;
+import de.intevation.flys.client.shared.model.DataItem;
+import de.intevation.flys.client.shared.model.DefaultData;
+import de.intevation.flys.client.shared.model.DefaultDataItem;
+import de.intevation.flys.client.shared.model.DoubleArrayData;
+import de.intevation.flys.client.shared.model.IntegerArrayData;
+import de.intevation.flys.client.shared.model.IntegerData;
+import de.intevation.flys.client.shared.model.IntegerOptionsData;
+import de.intevation.flys.client.shared.model.IntegerRangeData;
+import de.intevation.flys.client.shared.model.StringData;
+import de.intevation.flys.client.shared.model.StringOptionsData;
+import de.intevation.flys.client.shared.model.LongRangeData;
+
+import de.intevation.flys.client.shared.model.IntDataItem;
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DataFactory {
+
+    private static final Logger logger = Logger.getLogger(DataFactory.class);
+
+    public static final String NS_URI = ArtifactNamespaceContext.NAMESPACE_URI;
+
+
+    /**
+     * Creates a new Data instance based on the <i>art:type</i> attribute of
+     * <i>element</i>.
+     *
+     * @param element The Data element.
+     *
+     * @return a Data instance.
+     */
+    public static Data createDataFromElement(Element element) {
+        String name  = element.getAttributeNS(NS_URI, "name");
+        String type  = element.getAttributeNS(NS_URI, "type");
+        String label = element.getAttributeNS(NS_URI, "label");
+
+        label = label != null && label.length() > 0 ? label : name;
+
+        try {
+            logger.debug("Create Data instance for: " + name + " | " + type);
+
+            if (type == null || type.length() == 0) {
+                return createDefaultData(element, name, label);
+            }
+
+            type = type.toLowerCase();
+
+            if (type.equals(StringData.TYPE)) {
+                return createStringData(element, name, label);
+            }
+            else if (type.equals(IntegerData.TYPE)) {
+                return createIntegerData(element, name, label);
+            }
+            else if (type.equals(StringOptionsData.TYPE)) {
+                return createStringOptionsData(element, name, label);
+            }
+            else if (type.equals(IntegerOptionsData.TYPE)) {
+                return createIntegerOptionsData(element, name, label);
+            }
+            else if (type.equals(IntegerRangeData.TYPE)) {
+                return createIntegerRangeData(element, name, label);
+            }
+            else if (type.equals(IntegerArrayData.TYPE)) {
+                return createIntegerArrayData(element, name, label);
+            }
+            else if (type.equals(DoubleArrayData.TYPE)) {
+                return createDoubleArrayData(element, name, label);
+            }
+            else if (type.equals(LongRangeData.TYPE)) {
+                return createLongRangeData(element, name, label);
+            }
+            else {
+                return createDefaultData(element, name, label);
+            }
+        }
+        catch (Exception e) {
+            logger.error("Error while data creation for: " + name);
+        }
+
+        return null;
+    }
+
+
+    /**
+     * This method creates a new instance of DefaultData which has no real type
+     * set.
+     *
+     * @param ele The Data element.
+     * @param name The name of the Data instance.
+     *
+     * @return an instance of DefaultData.
+     */
+    protected static Data createDefaultData(Element ele, String name, String label) {
+        logger.debug("Create new DefaultData");
+        return new DefaultData(name, label, "default", extractDataItems(ele));
+    }
+
+
+    /**
+     * This method creates a new instance of StringData which has a type
+     * "string" set.
+     *
+     * @param ele The Data element.
+     * @param name The name of the Data instance.
+     *
+     * @return an instance of StringData.
+     */
+    protected static Data createStringData(Element ele, String name, String label) {
+        return new StringData(name, label, extractDataItems(ele));
+    }
+
+
+    /**
+     * This method creates a new instance of DefaultData which has a type
+     * "integer" set.
+     *
+     * @param ele The Data element.
+     * @param name The name of the Data instance.
+     *
+     * @return an instance of IntegerData.
+     */
+    protected static Data createIntegerData(Element ele, String name, String label) {
+        return new IntegerData(name, label, extractDataItems(ele));
+    }
+
+
+    /**
+     * This method creates a new instance of StringOptionsData which has a type
+     * "options" set.
+     *
+     * @param ele The Data element.
+     * @param name The name of the Data instance.
+     *
+     * @return an instance of StringOptionsData.
+     */
+    protected static Data createStringOptionsData(Element ele, String name, String label) {
+        return new StringOptionsData(name, label, extractDataItems(ele));
+    }
+
+
+    /**
+     * This method creates a new instance of DefaultData which has a type
+     * "intoptions" set.
+     *
+     * @param ele The Data element.
+     * @param name The name of the Data instance.
+     *
+     * @return an instance of IntegerOptionsData.
+     */
+    protected static Data createIntegerOptionsData(Element ele, String name, String label) {
+        return new IntegerOptionsData(name, label, extractDataItems(ele));
+    }
+
+
+    /**
+     * This method creates a new instance of DefaultData which has a type
+     * "intrange" set.
+     *
+     * @param ele The Data element.
+     * @param name The name of the Data instance.
+     *
+     * @return an instance of IntegerRangeData.
+     */
+    protected static Data createIntegerRangeData(Element ele, String name, String label) {
+        DataItem[] items    = extractDataItems(ele);
+        String     rawValue = items[0].getStringValue();
+
+        String[] minmax = rawValue.split(";");
+
+        return new IntegerRangeData(
+            name,
+            label,
+            Integer.valueOf(minmax[0]),
+            Integer.valueOf(minmax[1]));
+    }
+
+
+    /**
+     * This method creates a new instance of DefaultData which has a type
+     * "integerarray" set.
+     *
+     * @param ele The Data element.
+     * @param name The name of the Data instance.
+     *
+     * @return an instance of IntegerArrayData.
+     */
+    protected static Data createIntegerArrayData(Element ele, String name, String label) {
+        IntDataItem[] items    = extractIntDataItems(ele);
+        return new IntegerArrayData(name, label, items);
+    }
+
+
+    /**
+     * This method creates a new instance of DefaultData which has a type
+     * "doublearray" set.
+     *
+     * @param ele The Data element.
+     * @param name The name of the Data instance.
+     *
+     * @return an instance of DoubleArrayData.
+     */
+    protected static Data createDoubleArrayData(Element ele, String name, String label) {
+        DataItem[] items    = extractDataItems(ele);
+        String     rawValue = items[0].getStringValue();
+
+        String[] values  = rawValue.split(";");
+        double[] doubles = new double[values.length];
+
+        for (int i = 0; i < values.length; i++) {
+            try {
+                doubles[i] = Double.valueOf(values[i]);
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("Error while parsing DoubleArrayData: " + nfe);
+            }
+        }
+
+        return new DoubleArrayData(name, label, doubles);
+    }
+
+
+    /**
+     * This method extracts the art:item elements placed under <i>elements</i>.
+     *
+     * @param element A data node that contains items.
+     *
+     * @return a list of DataItems.
+     */
+    protected static DataItem[] extractDataItems(Element element) {
+        NodeList itemList = (NodeList) XMLUtils.xpath(
+            element,
+            "art:item",
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (itemList == null || itemList.getLength() == 0) {
+            logger.debug("No data items found.");
+            return null;
+        }
+
+        int count = itemList.getLength();
+
+        DataItem[] items = new DataItem[count];
+
+        logger.debug("There are " + count + " data items in element.");
+
+        for (int i = 0; i < count; i++) {
+            Element tmp = (Element) itemList.item(i);
+
+            String value = tmp.getAttributeNS(NS_URI, "value");
+            String label = tmp.getAttributeNS(NS_URI, "label");
+
+            logger.debug("Found data item:");
+            logger.debug("   label: " + label);
+            logger.debug("   value: " + value);
+
+            items[i] = new DefaultDataItem(label, label, value);
+        }
+
+        return items;
+    }
+
+
+    /**
+     * This method extracts the art:item elements placed under <i>elements</i>.
+     *
+     * @param element A data node that contains items.
+     *
+     * @return a list of DataItems.
+     */
+    protected static IntDataItem[] extractIntDataItems(Element element) {
+        NodeList itemList = (NodeList) XMLUtils.xpath(
+            element,
+            "art:item",
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (itemList == null || itemList.getLength() == 0) {
+            logger.debug("No old data items found.");
+            return null;
+        }
+
+        int count = itemList.getLength();
+
+        IntDataItem[] items = new IntDataItem[count];
+
+         for (int i = 0; i < count; i++) {
+             Element tmp = (Element) itemList.item(i);
+
+             String value = tmp.getAttributeNS(NS_URI, "value");
+             String label = tmp.getAttributeNS(NS_URI, "label");
+
+             try {
+                 int data = Integer.parseInt(value);
+                 items[i] = new IntDataItem(label, label, data);
+             }
+             catch(NumberFormatException nfe) {
+                 logger.debug(nfe, nfe);
+             }
+         }
+         return items;
+    }
+
+    /**
+     * This method creates a new instance of LongRangeData which has a type
+     * "longrange" set.
+     *
+     * @param ele The Data element.
+     * @param name The name of the Data instance.
+     *
+     * @return an instance of IntegerRangeData.
+     */
+    protected static Data createLongRangeData(Element ele, String name, String label) {
+        DataItem[] items    = extractDataItems(ele);
+        String     rawValue = items[0].getStringValue();
+
+        String[] minmax = rawValue.split(";");
+
+        return new LongRangeData(
+            name,
+            label,
+            Long.valueOf(minmax[0]),
+            Long.valueOf(minmax[1]));
+    }
+
+}
+// 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-client/src/main/java/de/intevation/flys/client/server/DischargeInfoServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,138 @@
+package de.intevation.flys.client.server;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.apache.log4j.Logger;
+
+import com.google.gwt.user.server.rpc.RemoteServiceServlet;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.client.services.DischargeInfoService;
+import de.intevation.flys.client.shared.model.DischargeInfoObject;
+import de.intevation.flys.client.shared.model.DischargeInfoObjectImpl;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class DischargeInfoServiceImpl
+extends      RemoteServiceServlet
+implements   DischargeInfoService
+{
+    private static final Logger logger =
+        Logger.getLogger(DischargeInfoServiceImpl.class);
+
+    public static final String ERROR_NO_DISCHARGEINFO_FOUND =
+        "error_no_dischargeinfo_found";
+
+    public static final String XPATH_DISTANCES = "art:discharges/art:discharge";
+
+
+    public DischargeInfoObject[] getDischargeInfo(
+        String locale,
+        long gauge)
+    throws ServerException
+    {
+        logger.info("DichargeInfoServiceImpl.getDischargeInfo");
+
+        String url  = getServletContext().getInitParameter("server-url");
+
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element gaugeEl = ec.create("gauge");
+        gaugeEl.setTextContent(String.valueOf(gauge));
+
+        doc.appendChild(gaugeEl);
+
+        HttpClient client = new HttpClientImpl(url, locale);
+
+        try {
+            Document result = client.callService(url, "dischargeinfo", doc);
+
+            logger.debug("Extract discharge info objects now.");
+            DischargeInfoObject[] objects = extractDischargeInfoObjects(result);
+
+            if (objects != null && objects.length > 0) {
+                return objects;
+            }
+        }
+        catch (ConnectionException ce) {
+            logger.error(ce, ce);
+        }
+
+        throw new ServerException(ERROR_NO_DISCHARGEINFO_FOUND);
+    }
+
+    protected DischargeInfoObject[] extractDischargeInfoObjects(
+        Document result
+    )
+    throws ServerException {
+        NodeList list = result.getElementsByTagName("discharge");
+
+        if (list == null || list.getLength() == 0) {
+            logger.warn("No discharge info found.");
+            throw new ServerException(ERROR_NO_DISCHARGEINFO_FOUND);
+        }
+
+        int num = list.getLength();
+        logger.debug("Response contains " + num + " objects.");
+
+        List<DischargeInfoObject> objects =
+            new ArrayList<DischargeInfoObject>(num);
+
+        for (int i = 0; i < num; i++) {
+            DischargeInfoObject obj = buildDischargeInfoObject(
+                (Element)list.item(i));
+
+            if (obj != null) {
+                objects.add(obj);
+            }
+        }
+
+        logger.debug("Retrieved " + objects.size() + " discharges.");
+
+        return (DischargeInfoObject[])
+            objects.toArray(new DischargeInfoObject[num]);
+
+    }
+
+    protected DischargeInfoObject buildDischargeInfoObject(Element node) {
+
+        String desc      = node.getAttribute("description").trim();
+        String start     = node.getAttribute("start").trim();
+        String end       = node.getAttribute("end").trim();
+
+        if (start.length() > 0 && end.length() > 0) {
+            try {
+                Integer startYear  = new Integer(start);
+                Integer endYear    = new Integer(end);
+                return new DischargeInfoObjectImpl(desc, startYear, endYear);
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn(nfe.getLocalizedMessage());
+            }
+        }
+
+        logger.warn("Invalid distance info object found.");
+
+        return null;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/server/DischargeInfoXML.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,82 @@
+package de.intevation.flys.client.server;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Logger;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+import de.intevation.artifacts.httpclient.http.response.StreamResponseHandler;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class DischargeInfoXML
+extends      HttpServlet
+{
+    private static final Logger logger = Logger.getLogger(DischargeInfoXML.class);
+
+
+    public static final String ERROR_NO_DISTANCEINFO_FOUND =
+        "error_no_dischargeinfo_found";
+
+
+    public void doGet(HttpServletRequest req, HttpServletResponse resp) {
+        logger.info("DischargeInfoXML.doGet");
+
+        String url  = getServletContext().getInitParameter("server-url");
+
+        String gauge = req.getParameter("gauge");
+
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element gaugeEl = ec.create("gauge");
+        gaugeEl.setTextContent(gauge);
+
+        doc.appendChild(gaugeEl);
+
+        HttpClient client = new HttpClientImpl(url);
+
+        try {
+            InputStream in = (InputStream) client.callService(
+                url, "dischargeinfo", doc, new StreamResponseHandler());
+
+            OutputStream out = resp.getOutputStream();
+
+            byte[] b = new byte[4096];
+            int i;
+            while ((i = in.read(b)) >= 0) {
+                out.write(b, 0, i);
+            }
+
+            out.flush();
+            out.close();
+        }
+        catch (ConnectionException ce) {
+            logger.error(ce, ce);
+        }
+        catch (IOException ioe) {
+            logger.error(ioe, ioe);
+        }
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/ExportServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ExportServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -4,6 +4,7 @@
 import java.io.IOException;
 
 import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import org.apache.log4j.Logger;
 
@@ -12,6 +13,7 @@
 import javax.servlet.http.HttpServletResponse;
 
 import de.intevation.artifacts.common.utils.ClientProtocolUtils;
+import de.intevation.artifacts.common.utils.XMLUtils;
 
 import de.intevation.artifacts.httpclient.http.HttpClient;
 import de.intevation.artifacts.httpclient.http.HttpClientImpl;
@@ -37,20 +39,31 @@
         try {
             OutputStream out = resp.getOutputStream();
 
-            String url  = getServletContext().getInitParameter("server-url");
-
-            String uuid      = req.getParameter("uuid");
-            String mode      = req.getParameter("mode");
-            String type      = req.getParameter("type");
-            String locale    = req.getParameter("locale");
-            String fn        = mode + "." + type;
+            String url    = getServletContext().getInitParameter("server-url");
+            String uuid   = req.getParameter("uuid");
+            String mode   = req.getParameter("mode");
+            String type   = req.getParameter("type");
+            String locale = req.getParameter("locale");
+            String km     = req.getParameter("km");
+            String fn     = mode + "." + type;
 
             resp.setHeader("Content-Disposition", "attachment;filename=" + fn);
 
-            logger.debug("Request " + type + " export.");
+            if (logger.isDebugEnabled()) {
+                logger.debug("Request " + type + " export.");
+            }
+
+            Document attr = null;
+            if (km != null && km.length() > 0) {
+                attr = XMLUtils.newDocument();
+                XMLUtils.ElementCreator ec =
+                        new XMLUtils.ElementCreator(attr, null, null);
+                Element e = ec.create("km");
+                e.setTextContent(km);
+                attr.appendChild(e);
+            }
             Document request = ClientProtocolUtils.newOutCollectionDocument(
-                uuid, mode, type);
-
+                uuid, mode, type, attr);
             HttpClient client = new HttpClientImpl(url, locale);
             client.collectionOut(request, uuid, mode, out);
 
--- a/flys-client/src/main/java/de/intevation/flys/client/server/FLYSArtifactCreator.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/FLYSArtifactCreator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -18,7 +18,12 @@
 
 import de.intevation.flys.client.shared.model.Artifact;
 import de.intevation.flys.client.shared.model.CalculationMessage;
+import de.intevation.flys.client.shared.model.ChartArtifact;
 import de.intevation.flys.client.shared.model.DefaultArtifact;
+import de.intevation.flys.client.shared.model.FixAnalysisArtifact;
+import de.intevation.flys.client.shared.model.GaugeDischargeCurveArtifact;
+import de.intevation.flys.client.shared.model.MapArtifact;
+import de.intevation.flys.client.shared.model.MINFOArtifact;
 import de.intevation.flys.client.shared.model.WINFOArtifact;
 
 
@@ -124,6 +129,26 @@
             logger.debug("+++++ NEW WINFO ARTIFACT.");
             return new WINFOArtifact(uuid, hash, background, msg);
         }
+        else if (name.length() > 0 && name.equals("new_map")) {
+            logger.debug("+++++ NEW MAP ARTIFACT.");
+            return new MapArtifact(uuid, hash, background, msg);
+        }
+        else if (name.length() > 0 && name.equals("new_chart")) {
+            logger.debug("+++++ NEW CHART ARTIFACT.");
+            return new ChartArtifact(uuid, hash, background, msg);
+        }
+        else if (name.length() > 0 && name.equals("minfo")) {
+            logger.debug("+++++ NEW MINFO ARTIFACT.");
+            return new MINFOArtifact(uuid, hash, background, msg);
+        }
+        else if (name.length() > 0 && name.equals("fixanalysis")) {
+            logger.debug("+++++ NEW FIXANALYSIS ARTIFACT.");
+            return new FixAnalysisArtifact(uuid, hash, background, msg);
+        }
+        else if (name.length() > 0 && name.equals("gaugedischargecurve")) {
+            logger.debug("+++++ NEW WINFO ARTIFACT.");
+            return new GaugeDischargeCurveArtifact(uuid, hash, background, msg);
+        }
 
         return new DefaultArtifact(uuid, hash, background, msg);
     }
--- a/flys-client/src/main/java/de/intevation/flys/client/server/FeedServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/FeedServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,8 @@
 package de.intevation.flys.client.server;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.w3c.dom.Document;
 
 import org.apache.log4j.Logger;
@@ -112,6 +115,37 @@
 
 
     /**
+     * Triggers FEED operation, many artifacts, same data item(s).
+     *
+     * @param artifacts Artifacts that shall be fed.
+     * @param data An array of Data objects that contain the information that
+     * are used for the FEED operation.
+     *
+     * @return a new artifact parsed from the description of FEED.
+     */
+    public List<Artifact> feedMany(
+        String         locale,
+        List<Artifact> artifacts,
+        Data[]         data)
+    throws    ServerException
+    {
+        logger.info("StepForwardServiceImpl.feedMany");
+
+        String url = getServletContext().getInitParameter("server-url");
+
+        List<Artifact> resultArtifacts = new ArrayList<Artifact>();
+
+        for (Artifact artifact: artifacts) {
+            logger.info("feedMany: Relay to StepForwardServiceImpl.feed");
+            Artifact fedArtifact = feed(locale, artifact, data);
+            resultArtifacts.add(fedArtifact);
+        }
+
+        return resultArtifacts;
+    }
+
+
+    /**
      * This method creates an array of key/value pairs from an array of Data
      * objects. The string array is used as parameter for the feed() operation.
      *
@@ -127,7 +161,7 @@
         for (Data d: data) {
             DataItem[] items = d.getItems();
             String key       = d.getLabel();
-            String value     = items[0].getStringValue();
+            String value     = d.getStringValue();
 
             kvp[i++] = new String[] { key, value };
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/FileUploadServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,108 @@
+package de.intevation.flys.client.server;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class FileUploadServiceImpl
+extends      HttpServlet
+{
+    private static final Logger logger = Logger.getLogger(FileUploadServiceImpl.class);
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
+        processPost(req, resp);
+    }
+
+
+    protected void processPost(HttpServletRequest req, HttpServletResponse resp) {
+        logger.debug("handling post request.");
+
+        String url  = getServletContext().getInitParameter("server-url");
+
+        Document request = createFileXML(req);;
+
+        if (request == null) {
+            return;
+        }
+        HttpClient client = new HttpClientImpl(url);
+
+        try {
+            Document result = client.callService(url, "fileupload", request);
+
+            if (result == null) {
+                logger.warn("FileUpload service returned no result.");
+            }
+
+            return;
+        }
+        catch (ConnectionException ce) {
+            logger.error(ce, ce);
+        }
+    }
+
+
+    protected Document createFileXML(HttpServletRequest req) {
+           ServletFileUpload upload = new ServletFileUpload();
+
+        try{
+            FileItemIterator iter = upload.getItemIterator(req);
+
+            while (iter.hasNext()) {
+                FileItemStream item = iter.next();
+
+                String name = item.getFieldName();
+                InputStream stream = item.openStream();
+
+                // Process the input stream
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                int len;
+                byte[] buffer = new byte[stream.available()];
+                while ((len = stream.read(buffer, 0, buffer.length)) != -1) {
+                    out.write(buffer, 0, len);
+                }
+
+                buffer = Base64.encodeBase64(buffer);
+                String b64File = new String(buffer);
+
+                Document fileDoc = XMLUtils.newDocument();
+
+                ElementCreator ec = new ElementCreator(fileDoc, null, null);
+                Element root = ec.create("upload");
+                Element id = ec.create("artifact-uuid");
+                id.setTextContent(req.getParameter("uuid"));
+
+                Element data = ec.create("data");
+                data.setTextContent(b64File);
+
+                fileDoc.appendChild(root);
+                root.appendChild(id);
+                root.appendChild(data);
+
+                return fileDoc;
+            }
+        }
+        catch(Exception e){
+            logger.debug("Failed to create xml document containing the file.");
+            logger.debug(e, e);
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/FixingsKMChartServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,113 @@
+package de.intevation.flys.client.server;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+
+import de.intevation.artifacts.httpclient.http.response.StreamResponseHandler;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class FixingsKMChartServiceImpl
+extends      HttpServlet
+{
+    private static final Logger log =
+        Logger.getLogger(FixingsKMChartServiceImpl.class);
+
+    public static final String SERVICE_NAME = "fixings-km-chart";
+
+    public FixingsKMChartServiceImpl() {
+    }
+
+    public void doGet(HttpServletRequest req, HttpServletResponse resp) {
+
+        log.info("FixingsKMChartServiceImpl.doGet");
+
+        String url    = getServletContext().getInitParameter("server-url");
+        String locale = req.getParameter("locale");
+        String filter = req.getParameter("filter");
+
+        if (filter == null || filter.length() == 0) {
+            log.warn("Missing 'filter' parameter.");
+            return;
+        }
+
+        if (locale == null || locale.length() == 0) {
+            locale = "de";
+        }
+
+        Document filterDoc = XMLUtils.jsonToXML(filter);
+
+        if (filterDoc == null) {
+            log.warn("Creating filter document failed.");
+            return;
+        }
+
+        InputStream in;
+
+        try {
+            HttpClient client = new HttpClientImpl(url, locale);
+            in = (InputStream)client.callService(
+                url, // XXX: Why? The URL is passed by construction already.
+                SERVICE_NAME,
+                filterDoc,
+                new StreamResponseHandler());
+        }
+        catch (ConnectionException ce) {
+            log.error(ce);
+            return;
+        }
+
+        resp.setHeader("Content-Type", guessMIMEType(filterDoc));
+
+        try {
+            OutputStream out = resp.getOutputStream();
+
+            byte [] buf = new byte[4096];
+            int i = -1;
+            while ((i = in.read(buf)) >= 0) {
+                out.write(buf, 0, i);
+            }
+            out.flush();
+        }
+        catch (IOException ioe) {
+            log.error(ioe);
+        }
+        finally {
+            try { in.close(); }
+            catch (IOException ioe) { /* ignored */ }
+        }
+    }
+
+    protected static String guessMIMEType(Document document) {
+
+        NodeList formats = document.getElementsByTagName("format");
+
+        String format = "png";
+
+        if (formats.getLength() > 0) {
+            String type = ((Element)formats.item(0)).getAttribute("type");
+            if (type.length() > 0) {
+                format = type;
+            }
+        }
+
+        return "image/" + format;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/server/FixingsOverviewServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,240 @@
+package de.intevation.flys.client.server;
+
+import com.google.gwt.user.server.rpc.RemoteServiceServlet;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.common.utils.XSLTransformer;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import de.intevation.flys.client.client.services.FixingsOverviewService;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+
+import de.intevation.flys.client.shared.model.FixingsOverviewInfo.FixEvent;
+import de.intevation.flys.client.shared.model.FixingsOverviewInfo.Sector;
+
+import de.intevation.flys.client.shared.model.FixingsOverviewInfo;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class FixingsOverviewServiceImpl
+extends      RemoteServiceServlet
+implements   FixingsOverviewService
+{
+    private static final Logger log =
+        Logger.getLogger(FixingsOverviewServiceImpl.class);
+
+    public static final String SERVICE_NAME = "fixings-overview";
+
+    public static final String XSL_TRANSFORM =
+        "/WEB-INF/stylesheets/fixoverview2html.xsl";
+
+    protected static final String XPATH_RID = "/fixings/river/@rid";
+    protected static final String XPATH_RIVER = "/fixings/river/@name";
+    protected static final String XPATH_RFROM = "/fixings/river/@from";
+    protected static final String XPATH_RTO = "/fixings/river/@to";
+
+    protected static final String XPATH_EVENT = "/fixings/events/event";
+
+
+    @Override
+    public FixingsOverviewInfo generateOverview(
+        String  locale,
+        String  uuid,
+        String  filter,
+        boolean checkboxes,
+        String  callback
+    )
+    throws ServerException
+    {
+        log.info("FixingsOverviewServiceImpl.doGet");
+
+        if (filter == null || filter.length() == 0) {
+            log.warn("Missing 'filter' parameter.");
+            return null;
+        }
+
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("JSON filter: ------------------");
+            log.debug(filter);
+        }
+
+        Document filterDoc = XMLUtils.jsonToXML(filter);
+
+        if (filterDoc == null) {
+            log.warn("Creating filter document failed.");
+            return null;
+        }
+
+        if (debug) {
+            log.debug("XML filter: ------------------");
+            log.debug(XMLUtils.toString(filterDoc));
+        }
+
+        try {
+            String url = getServletContext().getInitParameter("server-url");
+            HttpClient client = new HttpClientImpl(url, locale);
+            Document resultDoc =
+                client.callService(url, SERVICE_NAME, filterDoc);
+
+            if (debug) {
+                log.debug("Result XML: -----------");
+                log.debug(XMLUtils.toString(resultDoc));
+            }
+
+            FixingsOverviewInfo i = getInfo(
+                locale, resultDoc, uuid, checkboxes, callback);
+            return i;
+        }
+        catch (ConnectionException ce) {
+            log.error(ce);
+        }
+        return null;
+    }
+
+
+    protected FixingsOverviewInfo getInfo(
+        String   locale,
+        Document doc,
+        String   uuid,
+        boolean  checkboxes,
+        String   callback
+    ) {
+        // TODO: Find a more general solution.
+        locale = locale == null || locale.toLowerCase().startsWith("de")
+            ? "de"
+            : "en";
+
+        InputStream transform = getServletContext()
+            .getResourceAsStream(XSL_TRANSFORM);
+
+        if (transform == null) {
+            log.warn("transform not found");
+            return null;
+        }
+
+        String result = null;
+        try {
+            XSLTransformer xformer = new XSLTransformer();
+            xformer.addParameter("locale", locale);
+            xformer.addParameter("project-uuid", uuid);
+            xformer.addParameter(
+                "render-checkboxes",
+                checkboxes ? Boolean.TRUE : Boolean.FALSE);
+            xformer.addParameter("callback", callback);
+            result = xformer.transform(doc, transform);
+        }
+        finally {
+            try { transform.close(); }
+            catch (IOException ioe) {}
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("--------------------------------------");
+            log.debug(result);
+            log.debug("--------------------------------------");
+        }
+
+        int    rid  = -1;
+        double from = -1;
+        double to   = -1;
+
+        String rid_str  = XMLUtils.xpathString(doc, XPATH_RID, null);
+        String river    = XMLUtils.xpathString(doc, XPATH_RIVER, null);
+        String from_str = XMLUtils.xpathString(doc, XPATH_RFROM, null);
+        String to_str   = XMLUtils.xpathString(doc, XPATH_RTO, null);
+
+        try {
+            rid = Integer.parseInt(rid_str);
+            from = Double.parseDouble(from_str);
+            to = Double.parseDouble(to_str);
+        }
+        catch(NumberFormatException nfe) {
+            log.warn(nfe, nfe);
+        }
+
+        List<FixEvent> fixEvents = getFixEvents(doc);
+        return new FixingsOverviewInfo(
+            rid,
+            river,
+            from,
+            to,
+            fixEvents,
+            result);
+    }
+
+
+    protected List<FixEvent> getFixEvents(Document doc) {
+        List<FixEvent> list = new ArrayList<FixEvent>();
+
+        NodeList events = (NodeList) XMLUtils.xpath(
+            doc,
+            XPATH_EVENT,
+            XPathConstants.NODESET,
+            null);
+
+        if (events == null || events.getLength() == 0) {
+            log.warn("No events in Overview!");
+            return list;
+        }
+
+        for (int i = 0, E = events.getLength(); i < E; i++) {
+            Element n = (Element)events.item(i);
+            List<Sector> sectors = getSectors(n);
+            String cid  = n.getAttribute("cid");
+            String date = n.getAttribute("date");;
+            String name = n.getAttribute("description");
+            list.add(new FixEvent( cid, date, name, sectors));
+        }
+        return list;
+    }
+
+    protected List<Sector> getSectors(Element event) {
+        NodeList sectors = event.getElementsByTagName("sector");
+
+        if (sectors.getLength() == 0) {
+            log.warn("No Sectors in Event!");
+            return null;
+        }
+
+        List<Sector> list = new ArrayList<Sector>();
+        for (int i = 0, S = sectors.getLength(); i < S; i++) {
+            Element n = (Element)sectors.item(i);
+            int    cls  = -1;
+            double from = -1;
+            double to   = -1;
+            String cls_str  = n.getAttribute("class");
+            String from_str = n.getAttribute("from");
+            String to_str   = n.getAttribute("to");
+            try {
+                cls  = Integer.parseInt(cls_str);
+                from = Double.parseDouble(from_str);
+                to   = Double.parseDouble(to_str);
+            }
+            catch(NumberFormatException nfe) {
+                log.warn(nfe, nfe);
+            }
+            list.add(new Sector(cls, from, to));
+        }
+        return list;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/GFIServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/GFIServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -167,12 +167,12 @@
         boolean first = true;
 
         for (Theme theme: themes) {
-            if (!first) {
-                sb.append(",");
-            }
-
             AttributedTheme layer = (AttributedTheme) theme;
             if (layer.getAttrAsBoolean("queryable")) {
+                if (!first) {
+                    sb.append(",");
+                }
+
                 sb.append(layer.getAttr("layers"));
                 first = false;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/GGInAFilter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,156 @@
+package de.intevation.flys.client.server;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.client.server.auth.Authentication;
+import de.intevation.flys.client.server.auth.AuthenticationException;
+import de.intevation.flys.client.server.auth.AuthenticationFactory;
+import de.intevation.flys.client.server.auth.User;
+import de.intevation.flys.client.server.features.Features;
+
+
+/** ServletFilter used for GGInA authentification and certain authorisation. */
+public class GGInAFilter implements Filter {
+
+    /** Private logger. */
+    private static Logger logger = Logger.getLogger(GGInAFilter.class);
+
+    private boolean deactivate = false;
+    private String authmethod;
+    private ServletContext sc;
+
+    public static final String LOGIN_JSP     = "/login.jsp";
+    public static final String LOGIN_SERVLET = "/flys/login";
+    public static final String FLYS_CSS      = "/FLYS.css";
+
+
+    /**
+     * Initialize.
+     *
+     * Read FilterConfig parameter deactivate
+     */
+    @Override
+    public void init(FilterConfig config)
+    throws ServletException
+    {
+        String deactivate = config.getInitParameter("deactivate");
+        this.sc = config.getServletContext();
+        logger.debug("GGInAFilter context " + this.sc.getContextPath());
+        this.authmethod = sc.getInitParameter("authentication");
+        if (deactivate != null && deactivate.equalsIgnoreCase("true")) {
+            this.deactivate = true;
+        }
+
+    }
+
+
+    /**
+     * Called when filter in chain invoked.
+     * @param req request to servlet
+     * @param resp response of servlet
+     * @param chain the filter chain
+     */
+    @Override
+    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
+    throws IOException, ServletException
+    {
+        if (this.deactivate) {
+            logger.debug("GGinAFilter is deactivated");
+            chain.doFilter(req, resp);
+            return;
+        }
+
+        HttpServletRequest sreq = (HttpServletRequest) req;
+
+        String requesturi = sreq.getRequestURI();
+        for (Enumeration e = req.getAttributeNames() ; e.hasMoreElements() ;) {
+            logger.debug(e.nextElement());
+        }
+
+        logger.debug("Request for: " + requesturi);
+
+        // Allow access to login pages
+        // TODO Maybe replace with Filter <url-pattern>
+        String path = this.sc.getContextPath();
+        if (requesturi.equals(path + "/login.jsp") ||
+                requesturi.equals(path + "/flys/login")
+                || requesturi.equals(path + "/FLYS.css")) {
+            logger.debug("Request for login " + requesturi);
+            chain.doFilter(req, resp);
+            return;
+        }
+
+        HttpSession session = sreq.getSession();
+
+        String uri = requesturi;
+        if (sreq.getQueryString() != null) {
+            uri = uri + "?" + sreq.getQueryString();
+        }
+        session.setAttribute("requesturi", uri);
+
+        User user = (User)session.getAttribute("user");
+        if (user == null) {
+            logger.debug("No user in session: " + requesturi);
+            this.redirect(resp);
+            return;
+        }
+        if (user.hasExpired()) {
+            // try to re-authenticate the user
+            logger.debug("User ticket has expired: " + requesturi);
+            String encoding = sreq.getCharacterEncoding();
+            try {
+                Authentication auth = this.auth(user, encoding);
+                if (auth == null || !auth.isSuccess()) {
+                    logger.debug("Re-athentication not successful");
+                    this.redirect(resp);
+                }
+            }
+            catch(AuthenticationException e) {
+                logger.error("Failure during re-authentication", e);
+                this.redirect(resp);
+                return;
+            }
+        }
+
+        logger.debug("GGInAFilter.doFilter");
+        chain.doFilter(req, resp);
+        return;
+    }
+
+    private void redirect(ServletResponse resp) throws IOException {
+        logger.debug("Redirect to login");
+        ((HttpServletResponse) resp).sendRedirect(this.sc.getContextPath() +
+            "/login.jsp");
+    }
+
+
+    /**
+     * Do nothing at destruction.
+     */
+    @Override
+    public void destroy() {
+    }
+
+    private Authentication auth(User user, String encoding)
+        throws AuthenticationException, IOException {
+        Features features = (Features)sc.getAttribute(Features.CONTEXT_ATTRIBUTE);
+        return AuthenticationFactory.getInstance(this.authmethod).auth(
+                user.getName(), user.getPassword(), encoding, features);
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/server/GGInATrustStrategy.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,20 @@
+package de.intevation.flys.client.server;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import org.apache.http.conn.ssl.TrustStrategy;
+
+public class GGInATrustStrategy implements TrustStrategy {
+
+    /**
+     * Tempoary class to accept all certificates for GGinA Authentication
+     */
+
+    @Override
+    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+        // FIXME validate Certificate
+        return true;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/GaugeInfoServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,155 @@
+package de.intevation.flys.client.server;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.apache.log4j.Logger;
+
+import com.google.gwt.user.server.rpc.RemoteServiceServlet;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.client.services.GaugeInfoService;
+import de.intevation.flys.client.shared.model.Gauge;
+import de.intevation.flys.client.shared.model.GaugeImpl;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class GaugeInfoServiceImpl
+extends      RemoteServiceServlet
+implements   GaugeInfoService
+{
+    private static final Logger logger =
+        Logger.getLogger(GaugeInfoServiceImpl.class);
+
+
+    public static final String ERROR_NO_GAUGES_FOUND =
+        "error_no_gaugeinfo_found";
+
+    public static final String XPATH_GAUGES = "art:service/art:gauge";
+
+
+    public List<Gauge> getGaugeInfo(String rivername, String refnumber)
+    throws ServerException
+    {
+        logger.info("GaugeInfoServiceImpl.getGaugeInfo");
+
+        String url = getServletContext().getInitParameter("server-url");
+
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element river = ec.create("river");
+        ec.addAttr(river, "name", rivername);
+
+        if (refnumber != null && refnumber.length() > 0) {
+            Element filter = ec.create("filter");
+            Element gauge  = ec.create("gauge");
+            gauge.setTextContent(refnumber);
+
+            filter.appendChild(gauge);
+            river.appendChild(filter);
+        }
+
+        doc.appendChild(river);
+
+        HttpClient client = new HttpClientImpl(url);
+
+        try {
+            Document result = client.callService(url, "gaugeinfo", doc);
+
+            logger.debug("Extract gauge info now.");
+            List<Gauge> gauges = extractGauges(result);
+
+            if (gauges != null && gauges.size() > 0) {
+                return gauges;
+            }
+        }
+        catch (ConnectionException ce) {
+            logger.error(ce, ce);
+        }
+
+        throw new ServerException(ERROR_NO_GAUGES_FOUND);
+    }
+
+
+    /**
+     * Extracts all wq info objects from <i>result</i> document.
+     *
+     * @param result The document retrieved by the server.
+     *
+     * @return a list of WQInfoObjects.
+     */
+    protected List<Gauge> extractGauges(Document result)
+    throws    ServerException
+    {
+        List<Gauge> gauges = new ArrayList<Gauge>();
+
+        NodeList list = (NodeList) XMLUtils.xpath(
+            result,
+            XPATH_GAUGES,
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+
+        if (list == null || list.getLength() == 0) {
+            logger.warn("No gauges found.");
+
+            throw new ServerException(ERROR_NO_GAUGES_FOUND);
+        }
+
+        int num = list.getLength();
+        logger.debug("Response contains " + num + " objects.");
+
+        for (int i = 0; i < num; i++) {
+            Gauge obj = buildGauge((Element) list.item(i));
+
+            if (obj != null) {
+                gauges.add(obj);
+            }
+        }
+
+        logger.debug("Retrieved " + gauges.size() + " gauges.");
+
+        return gauges;
+    }
+
+
+    protected Gauge buildGauge(Element ele) {
+        String name     = ele.getAttribute("name");
+        String lowerStr = ele.getAttribute("lower");
+        String upperStr = ele.getAttribute("upper");
+
+        if (lowerStr != null && upperStr != null) {
+            try {
+                return new GaugeImpl(
+                    name,
+                    Double.valueOf(lowerStr),
+                    Double.valueOf(upperStr));
+            }
+            catch (NumberFormatException nfe) {
+                logger.warn("Error while Gauge creation: " + nfe.getMessage());
+            }
+        }
+
+        return null;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/server/GaugeOverviewInfoServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,207 @@
+package de.intevation.flys.client.server;
+
+import java.util.ArrayList;
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import de.intevation.flys.client.client.services.GaugeOverviewInfoService;
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.DefaultGaugeInfo;
+import de.intevation.flys.client.shared.model.DefaultRiverInfo;
+import de.intevation.flys.client.shared.model.GaugeInfo;
+import de.intevation.flys.client.shared.model.RiverInfo;
+
+/**
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public class GaugeOverviewInfoServiceImpl
+extends      RemoteServiceServlet
+implements   GaugeOverviewInfoService
+{
+    private static final Logger logger =
+        Logger.getLogger(GaugeOverviewInfoServiceImpl.class);
+
+    public static final String ERROR_NO_RIVERINFO_FOUND =
+        "error_no_gaugeoverviewinfo_found";
+
+    private static final String XPATH_RIVER = "/art:gauge-info/art:river";
+
+    private static final String XPATH_GAUGES = "/art:gauge-info/art:gauges/art:gauge";
+
+    public RiverInfo getRiverInfo(String river) throws ServerException {
+        logger.info("RiverInfoServiceImpl.getRiverInfo");
+
+        String url = getServletContext().getInitParameter("server-url");
+
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element riverele = ec.create("river");
+        riverele.setTextContent(river);
+
+        doc.appendChild(riverele);
+
+        HttpClient client = new HttpClientImpl(url);
+
+        try {
+            Document result = client.callService(url, "gaugeoverviewinfo", doc);
+
+            Element riverresp = (Element) XMLUtils.xpath(
+                    result,
+                    XPATH_RIVER,
+                    XPathConstants.NODE,
+                    ArtifactNamespaceContext.INSTANCE);
+
+            String rname = riverresp.getAttributeNS(
+                    ArtifactNamespaceContext.NAMESPACE_URI, "name");
+            String rkmup = riverresp.getAttributeNS(
+                    ArtifactNamespaceContext.NAMESPACE_URI, "kmup");
+            String rstart = riverresp.getAttributeNS(
+                    ArtifactNamespaceContext.NAMESPACE_URI, "start");
+            String rend = riverresp.getAttributeNS(
+                    ArtifactNamespaceContext.NAMESPACE_URI, "end");
+            String rwstunit = riverresp.getAttributeNS(
+                    ArtifactNamespaceContext.NAMESPACE_URI, "wstunit");
+            String rminq = riverresp.getAttributeNS(
+                    ArtifactNamespaceContext.NAMESPACE_URI, "minq");
+            String rmaxq = riverresp.getAttributeNS(
+                    ArtifactNamespaceContext.NAMESPACE_URI, "maxq");
+            String rofficial = riverresp.getAttributeNS(
+                    ArtifactNamespaceContext.NAMESPACE_URI, "official");
+
+            logger.debug("River is " + rname);
+
+            boolean kmup = rkmup.equalsIgnoreCase("true");
+
+            NodeList gaugenodes = (NodeList) XMLUtils.xpath(
+                result,
+                XPATH_GAUGES,
+                XPathConstants.NODESET,
+                ArtifactNamespaceContext.INSTANCE);
+
+            int num = gaugenodes == null ? 0 : gaugenodes.getLength();
+
+            ArrayList<GaugeInfo> gauges = new ArrayList<GaugeInfo>(num);
+
+            if (num == 0) {
+                logger.warn("No gauge info found.");
+            }
+            else {
+                logger.debug("Found " + num + " gauges.");
+
+                for (int i = 0; i < num; i++) {
+                    Element gaugeele = (Element)gaugenodes.item(i);
+
+                    String gname = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "name");
+                    String gstart = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "start");
+                    String gend = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "end");
+                    String gdatum = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "datum");
+                    String gaeo = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "aeo");
+                    String gminq = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "minq");
+                    String gminw = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "minw");
+                    String gmaxq = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "maxq");
+                    String gmaxw = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "maxw");
+                    String gstation = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "station");
+                    String gofficial = gaugeele.getAttributeNS(
+                            ArtifactNamespaceContext.NAMESPACE_URI, "official");
+
+                    logger.debug("Found gauge with name " + gname);
+
+                    GaugeInfo gaugeinfo = new DefaultGaugeInfo(
+                            rname,
+                            gname,
+                            kmup,
+                            parseDouble(gstation),
+                            parseDouble(gstart),
+                            parseDouble(gend),
+                            parseDouble(gdatum),
+                            parseDouble(gaeo),
+                            parseDouble(gminq),
+                            parseDouble(gmaxq),
+                            parseDouble(gminw),
+                            parseDouble(gmaxw),
+                            rwstunit,
+                            parseLong(gofficial)
+                            );
+
+                    gauges.add(gaugeinfo);
+                }
+            }
+
+            RiverInfo riverinfo = new DefaultRiverInfo(
+                    rname,
+                    kmup,
+                    parseDouble(rstart),
+                    parseDouble(rend),
+                    rwstunit,
+                    parseDouble(rminq),
+                    parseDouble(rmaxq),
+                    parseLong(rofficial),
+                    gauges);
+
+            logger.debug("Finished RiverInfoService.");
+
+            return riverinfo;
+        }
+        catch (ConnectionException ce) {
+            logger.error(ce, ce);
+        }
+
+        logger.warn("No gauge found");
+        throw new ServerException(ERROR_NO_RIVERINFO_FOUND);
+    }
+
+    /**
+     * Avoids NullPointerException when parsing double value
+     */
+    private Double parseDouble(String value) {
+        if (value == null || value.isEmpty()) {
+            return null;
+        }
+        try {
+            return Double.valueOf(value);
+        }
+        catch(NumberFormatException e) {
+            logger.error(e, e);
+            return null;
+        }
+    }
+
+    private Long parseLong(String value) {
+        if (value == null || value.isEmpty()) {
+            return null;
+        }
+        try {
+            return Long.valueOf(value);
+        }
+        catch(NumberFormatException e) {
+            logger.error(e, e);
+            return null;
+        }
+    }
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/server/LoadArtifactServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/LoadArtifactServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -123,13 +123,13 @@
 
                 Artifact clone = ArtifactHelper.createArtifact(
                     url, locale, realFactory, recom);
-        
+
                 if (clone != null) {
                     logger.debug("LoadArtifactServiceImple: Successfully "
                         + "loaded Artifact Clone.");
                     Collection c = CollectionHelper.addArtifact(
                         parent, clone, url, locale);
-        
+
                     if (c != null) {
                         artifacts.add(clone);
                         // Remember we cloned a recommendation like this.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/LoginServlet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,110 @@
+package de.intevation.flys.client.server;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.client.server.auth.Authentication;
+import de.intevation.flys.client.server.auth.AuthenticationException;
+import de.intevation.flys.client.server.auth.AuthenticationFactory;
+import de.intevation.flys.client.server.auth.User;
+import de.intevation.flys.client.server.auth.UserClient;
+import de.intevation.flys.client.server.features.Features;
+
+public class LoginServlet extends HttpServlet {
+
+    private static Logger logger = Logger.getLogger(LoginServlet.class);
+
+    private void redirectFailure(HttpServletResponse resp, String path)
+        throws IOException {
+        resp.sendRedirect(path + "/login.jsp");
+    }
+
+    private void redirectFailure(HttpServletResponse resp, String path,
+            Exception e) throws IOException {
+        this.redirectFailure(resp, path, e.getMessage());
+    }
+
+    private void redirectFailure(HttpServletResponse resp, String path,
+            String message) throws IOException {
+        resp.sendRedirect(path + "/login.jsp?error=" + message);
+    }
+
+    private void redirectSuccess(HttpServletResponse resp, String path,
+            String uri) throws IOException {
+        if (uri == null) {
+            uri = path + "/FLYS.html";
+        }
+        resp.sendRedirect(uri);
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+    throws ServletException, IOException {
+        logger.debug("Processing get request");
+        this.redirectFailure(resp, req.getContextPath());
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+    throws ServletException, IOException
+    {
+        String encoding = req.getCharacterEncoding();
+        String username = req.getParameter("username");
+        String password = req.getParameter("password");
+
+        logger.debug("Processing post request");
+
+        if (username == null || password == null) {
+            logger.debug("No username or password provided");
+            this.redirectFailure(resp, req.getContextPath());
+            return;
+        }
+
+        try {
+            Authentication aresp = this.auth(username, password, encoding);
+            if (aresp == null || !aresp.isSuccess()) {
+                logger.debug("Authentication not successful");
+                this.redirectFailure(resp, req.getContextPath());
+            }
+            User user = aresp.getUser();
+
+            String url = getServletContext().getInitParameter("server-url");
+            UserClient client = new UserClient(url);
+            if (!client.userExists(user)) {
+                logger.debug("Creating db user");
+                if (!client.createUser(user)) {
+                    this.redirectFailure(resp, req.getContextPath(),
+                            "Could not create new user");
+                }
+            }
+
+            HttpSession session = req.getSession();
+            session.setAttribute("user", user);
+
+            String uri = (String)session.getAttribute("requesturi");
+
+            this.redirectSuccess(resp, req.getContextPath(), uri);
+        }
+        catch(AuthenticationException e) {
+            logger.error(e);
+            this.redirectFailure(resp, req.getContextPath(), e);
+        }
+    }
+
+    private Authentication auth(String username, String password, String encoding)
+        throws AuthenticationException, IOException
+    {
+        ServletContext sc = this.getServletContext();
+        Features features = (Features)sc.getAttribute(Features.CONTEXT_ATTRIBUTE);
+        String auth = sc.getInitParameter("authentication");
+        return AuthenticationFactory.getInstance(auth).auth(username, password, encoding, features);
+    }
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/server/MapHelper.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/MapHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -32,7 +32,9 @@
     public static MapConfig parseConfig(Document raw) {
         logger.debug("MapHelper.parseConfig");
 
-        logger.debug(XMLUtils.toString(raw));
+        if (logger.isDebugEnabled()) {
+            logger.debug(XMLUtils.toString(raw));
+        }
 
         MapConfig config = new MapConfig();
 
--- a/flys-client/src/main/java/de/intevation/flys/client/server/MapOutputServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/MapOutputServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -3,6 +3,8 @@
 import java.io.InputStream;
 import java.io.IOException;
 
+import java.util.Map;
+
 import org.w3c.dom.Document;
 
 import org.apache.log4j.Logger;
@@ -19,7 +21,7 @@
 import de.intevation.flys.client.shared.exceptions.ServerException;
 import de.intevation.flys.client.shared.model.Collection;
 import de.intevation.flys.client.shared.model.MapConfig;
-
+import de.intevation.flys.client.shared.model.OutputMode;
 import de.intevation.flys.client.client.services.MapOutputService;
 
 
@@ -34,6 +36,7 @@
 
     public static final String ERROR_NO_MAP_CONFIG = "error_no_map_config";
 
+    public static final String ERROR_NO_MAP_OUTPUT_TYPE = "error_no_map_output_type";
 
     public MapConfig doOut(Collection collection)
     throws ServerException
@@ -43,12 +46,24 @@
         String url  = getServletContext().getInitParameter("server-url");
         String uuid = collection.identifier();
 
+        Map<String, OutputMode> modes = collection.getOutputModes();
+        String requestMode = "";
+        if (modes.containsKey("floodmap")) {
+            requestMode = "floodmap";
+        }
+        else if (modes.containsKey("map")) {
+            requestMode = "map";
+        }
+        else {
+           throw new ServerException(ERROR_NO_MAP_OUTPUT_TYPE);
+        }
+
         try {
             Document request = ClientProtocolUtils.newOutCollectionDocument(
-                uuid, "floodmap", "floodmap");
+                uuid, requestMode, requestMode);
 
             HttpClient client = new HttpClientImpl(url);
-            InputStream    is = client.collectionOut(request, uuid, "floodmap");
+            InputStream    is = client.collectionOut(request, uuid, requestMode);
 
             Document response = XMLUtils.parseDocument(is);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/MapPrintServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,477 @@
+package de.intevation.flys.client.server;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+
+import de.intevation.artifacts.common.utils.ClientProtocolUtils;
+import de.intevation.artifacts.common.utils.JSON;
+import de.intevation.artifacts.common.utils.StringUtils;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import de.intevation.artifacts.httpclient.http.response.DocumentResponseHandler;
+
+import de.intevation.flys.client.shared.model.MapConfig;
+import de.intevation.flys.client.shared.MapUtils;
+
+/*
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+*/
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+import java.net.URLEncoder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+
+import org.apache.log4j.Logger;
+
+/* Used by direct API call. -> Enforce GPLv3
+import org.mapfish.print.MapPrinter;
+import org.mapfish.print.output.OutputFactory;
+import org.mapfish.print.output.OutputFormat;
+
+import org.mapfish.print.utils.PJsonObject;
+*/
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class MapPrintServiceImpl
+extends      HttpServlet
+{
+    private static final Logger log =
+        Logger.getLogger(MapPrintServiceImpl.class);
+
+    protected static class Layer implements Comparable<Layer> {
+
+        protected int    pos;
+        protected String url;
+        protected String layers;
+        protected String description;
+
+        public Layer() {
+        }
+
+        public boolean setup(Element element) {
+
+            Element parent = (Element)element.getParentNode();
+            String parentName = parent.getAttribute("name");
+            if (!(parentName.equals("map")
+            ||    parentName.equals("floodmap"))) {
+                return false;
+            }
+
+            String ns = ArtifactNamespaceContext.NAMESPACE_URI;
+
+            String visible = element.getAttributeNS(ns, "visible");
+            String active  = element.getAttributeNS(ns, "active");
+
+            if (visible.equals("0") || active.equals("0")) {
+                return false;
+            }
+
+            url         = element.getAttributeNS(ns, "url");
+            layers      = element.getAttributeNS(ns, "layers");
+            description = element.getAttributeNS(ns, "description");
+
+            try {
+                pos = Integer.parseInt(element.getAttributeNS(ns, "pos"));
+            }
+            catch (NumberFormatException nfe) {
+                return false;
+            }
+
+            return true;
+        }
+
+        public Map<String, Object> toMap() {
+            Map<String, Object> layer = new LinkedHashMap<String, Object>();
+
+            layer.put("type", "WMS");
+            List<Object> subLayers = new ArrayList<Object>(1);
+            subLayers.add(layers);
+            layer.put("layers", subLayers);
+            layer.put("baseURL", url);
+            layer.put("format", "image/png"); // TODO: Make configurable.
+
+            return layer;
+        }
+
+        @Override
+        public int compareTo(Layer other) {
+            int d = pos - other.pos;
+            if (d < 0) return -1;
+            return d > 0 ? +1 : 0;
+        }
+    } // class Layer
+
+    protected static String generateSpec(
+        Document descDocument,
+        MapConfig mapConfig,
+        Double minX, Double minY,
+        Double maxX, Double maxY
+    ) {
+        Map<String, Object> spec = new LinkedHashMap<String, Object>();
+        spec.put("layout",       "A4 portrait");
+        spec.put("title",        "FLYS Druck");
+        spec.put("srs",          "EPSG:" + mapConfig.getSrid());
+        spec.put("dpi",          Integer.valueOf(254));
+        spec.put("units",        "m");
+        spec.put("geodaetic",    "true");
+        spec.put("outputFormat", "pdf");
+
+        String ns = ArtifactNamespaceContext.NAMESPACE_URI;
+
+        List<Layer> ls = new ArrayList<Layer>();
+        {   Layer l = new Layer();
+
+            NodeList facets = descDocument.getElementsByTagNameNS(ns, "facet");
+
+            for (int i = 0, N = facets.getLength(); i < N; ++i) {
+                Element element = (Element)facets.item(i);
+                if (l.setup(element)) {
+                    ls.add(l);
+                    l = new Layer();
+                }
+            }
+        }
+
+        // Establish Z order.
+        Collections.sort(ls);
+
+        List<Object> layers = new ArrayList<Object>(ls.size());
+
+        for (int i = ls.size()-1; i >= 0; --i) {
+            layers.add(ls.get(i).toMap());
+        }
+
+        spec.put("layers", layers);
+        spec.put("name", "Name");
+
+        List<Object> pages = new ArrayList<Object>(1);
+
+
+        Map<String, Object> page = new LinkedHashMap<String, Object>();
+
+        List<Object> bounds = new ArrayList<Object>(4);
+        bounds.add(minX);
+        bounds.add(minY);
+        bounds.add(maxX);
+        bounds.add(maxY);
+        page.put("bbox", bounds);
+
+        /*
+        bounds.add(Double.valueOf((minX+maxX)*0.5));
+        bounds.add(Double.valueOf((minY+maxY)*0.5));
+
+        page.put("center", bounds);
+        page.put("scale", Integer.valueOf(50000));
+        */
+
+        page.put("mapTitle", "FLYS Karte");
+        page.put("comment", "Eine mit FLYS gedruckte Karte.");
+        page.put("rotation", Integer.valueOf(0));
+
+        pages.add(page);
+        spec.put("pages", pages);
+
+        List<Object> legends = new ArrayList<Object>(layers.size());
+
+        for (Layer layer: ls) {
+            Map<String, Object> legend = new LinkedHashMap<String, Object>();
+            List<Object> classes = new ArrayList<Object>(1);
+            Map<String, Object> clazz = new LinkedHashMap<String, Object>();
+            String lgu = MapUtils.getLegendGraphicUrl(layer.url, layer.layers);
+            clazz.put("icon", lgu);
+            clazz.put("name", layer.description);
+            classes.add(clazz);
+            legend.put("classes", classes);
+            legend.put("name", layer.description);
+            legends.add(legend);
+        }
+
+        spec.put("legends", legends);
+
+        return JSON.toJSONString(spec);
+    }
+
+
+    @Override
+    public void doGet(HttpServletRequest req, HttpServletResponse resp)
+    throws  ServletException, IOException
+    {
+        log.info("MapPrintServiceImpl.doGet");
+
+        String uuid = req.getParameter("uuid");
+
+        if (uuid == null || !StringUtils.checkUUID(uuid)) {
+            throw new ServletException("Missing or misspelled UUID");
+        }
+
+        String minXS = req.getParameter("minx");
+        String maxXS = req.getParameter("maxx");
+        String minYS = req.getParameter("miny");
+        String maxYS = req.getParameter("maxy");
+
+        Double minX = null;
+        Double maxX = null;
+        Double minY = null;
+        Double maxY = null;
+
+        if (minXS != null && maxXS != null
+        &&  minYS != null && maxYS != null) {
+            log.debug("all parameters found -> parsing");
+            try {
+                minX = Double.parseDouble(minXS);
+                minY = Double.parseDouble(minYS);
+                maxX = Double.parseDouble(maxXS);
+                maxY = Double.parseDouble(maxYS);
+            }
+            catch (NumberFormatException nfe) {
+                throw new ServletException("Misspelled minX, minY, maxX or maxY");
+            }
+        }
+
+        String mapType = req.getParameter("maptype");
+
+        if (mapType == null || !mapType.equals("floodmap")) {
+            mapType = "map";
+        }
+
+        String url = getURL();
+
+        Document requestOut =
+            ClientProtocolUtils.newOutCollectionDocument(
+                uuid, mapType, mapType);
+        Document requestDesc =
+            ClientProtocolUtils.newDescribeCollectionDocument(uuid);
+
+        Document outDocument;
+        Document descDocument;
+
+        try {
+            HttpClient client = new HttpClientImpl(url);
+
+            descDocument = (Document)client.doCollectionAction(
+                requestDesc, uuid, new DocumentResponseHandler());
+
+            InputStream is = client.collectionOut(
+                requestOut, uuid, mapType);
+
+            try {
+                outDocument = XMLUtils.parseDocument(is);
+            }
+            finally {
+                is.close();
+                is = null;
+            }
+
+        }
+        catch (ConnectionException ce) {
+            log.error(ce);
+            throw new ServletException(ce);
+        }
+
+        MapConfig mapConfig = MapHelper.parseConfig(outDocument);
+
+        if (minX == null) {
+            log.debug("parameters missing -> fallback to max extent");
+            String [] parts = mapConfig.getMaxExtent().split("\\s+");
+            if (parts.length < 4) {
+                throw new ServletException(
+                    "Max extent has less than 4 values");
+            }
+            try {
+                minX = Double.valueOf(parts[0]);
+                minY = Double.valueOf(parts[1]);
+                maxX = Double.valueOf(parts[2]);
+                maxY = Double.valueOf(parts[3]);
+            }
+            catch (NumberFormatException nfe) {
+                throw new ServletException(nfe);
+            }
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("minX: " + minX);
+            log.debug("maxX: " + maxX);
+            log.debug("minY: " + minY);
+            log.debug("maxY: " + maxY);
+        }
+
+        String spec = generateSpec(
+            descDocument,
+            mapConfig,
+            minX, minY,
+            maxX, maxY);
+
+        if (log.isDebugEnabled()) {
+            log.debug("Generated spec:");
+            log.debug(spec);
+            //System.err.println(spec);
+        }
+
+        producePDF(spec, resp);
+    }
+
+    protected String getURL() throws ServletException {
+        String url = getServletContext().getInitParameter("server-url");
+        if (url == null) {
+            throw new ServletException("Missing server-url");
+        }
+        return url;
+    }
+
+    private static final String encode(String s) {
+        try {
+            return URLEncoder.encode(s, "UTF-8");
+        }
+        catch (UnsupportedEncodingException usee) {
+            // Should not happen.
+            return s;
+        }
+    }
+
+    protected void producePDF(String json, HttpServletResponse resp)
+    throws ServletException, IOException
+    {
+        String printUrl = getInitParameter("print-url");
+
+        if (printUrl == null) {
+            throw new ServletException("Missing 'print-url' in web.xml");
+        }
+
+        String url = printUrl + "/print.pdf?spec=" + encode(json);
+
+        org.apache.commons.httpclient.HttpClient client =
+            new org.apache.commons.httpclient.HttpClient(
+                new MultiThreadedHttpConnectionManager());
+
+        GetMethod get = new GetMethod(url);
+        int result = client.executeMethod(get);
+        InputStream in = get.getResponseBodyAsStream();
+
+        if (in != null) {
+            try {
+                OutputStream out = resp.getOutputStream();
+                try {
+                    byte [] buf = new byte[4096];
+                    int r;
+                    while ((r = in.read(buf)) >= 0) {
+                        out.write(buf, 0, r);
+                    }
+                    out.flush();
+                }
+                finally {
+                    out.close();
+                }
+            }
+            finally {
+                in.close();
+            }
+        }
+    }
+
+    /* Use this if you want directly call the MapPrinter. Enforces GPLv3!
+
+    protected MapPrinter getMapPrinter() throws ServletException, IOException {
+        String configPath = getInitParameter("config");
+        if (configPath == null) {
+            throw new ServletException("Missing configuration in web.xml");
+        }
+
+        File configFile = new File(configPath);
+        if (!configFile.isAbsolute()) {
+            configFile = new File(getServletContext().getRealPath(configPath));
+        }
+
+        if (!configFile.isFile() || !configFile.canRead()) {
+            throw new ServletException("Cannot read '" + configFile + "'");
+        }
+
+        return new MapPrinter(configFile);
+    }
+
+    protected void producePDF(String json, HttpServletResponse resp)
+    throws ServletException, IOException
+    {
+        PJsonObject jsonSpec = MapPrinter.parseSpec(json);
+
+        MapPrinter printer = getMapPrinter();
+
+        OutputFormat outputFormat = OutputFactory.create(
+            printer.getConfig(), jsonSpec);
+
+        resp.setHeader("Content-Disposition", "attachment;filename=print.pdf");
+        resp.setHeader("Content-Type", "application/pdf");
+
+        // XXX: Streaming the generated PDF directly
+        // to the request out does not work. :-/
+        File tmpFile = File.createTempFile("map-printing", null);
+
+        try {
+            OutputStream out =
+                new BufferedOutputStream(
+                new FileOutputStream(tmpFile));
+            try {
+                outputFormat.print(printer, jsonSpec, out, "");
+                out.flush();
+            }
+            catch (Exception e) {
+                log.error(e);
+                throw new ServletException(e);
+            }
+            finally {
+                printer.stop();
+                out.close();
+            }
+            InputStream in =
+                new BufferedInputStream(
+                new FileInputStream(tmpFile));
+            out = resp.getOutputStream();
+            try {
+                byte [] buf = new byte[4096];
+                int r;
+                while ((r = in.read(buf)) >= 0) {
+                    out.write(buf, 0, r);
+                }
+                out.flush();
+            }
+            finally {
+                in.close();
+                out.close();
+            }
+        }
+        finally {
+            if (tmpFile.exists()) {
+                tmpFile.delete();
+            }
+        }
+    }
+    */
+}
+// 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-client/src/main/java/de/intevation/flys/client/server/MapUrlServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,50 @@
+package de.intevation.flys.client.server;
+
+import java.io.InputStream;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Logger;
+
+import com.google.gwt.user.server.rpc.RemoteServiceServlet;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.client.services.MapUrlService;
+
+
+public class MapUrlServiceImpl
+extends      RemoteServiceServlet
+implements   MapUrlService
+{
+
+    private static final Logger logger =
+        Logger.getLogger(MapUrlServiceImpl.class);
+
+
+    public Map<String, String> getUrls()
+    throws ServerException
+    {
+        logger.info("MapUrlServiceImpl.getUrls");
+        Map<String, String> urls = new HashMap<String, String>();
+
+        InputStream in = getServletContext().getResourceAsStream("/WEB-INF/wms-services.xml");
+
+        Document doc = XMLUtils.parseDocument(in);
+
+        NodeList list = doc.getElementsByTagName("wms");
+        for (int i = 0; i < list.getLength(); i++) {
+            Element e = (Element) list.item(i);
+            urls.put(e.getAttribute("url"), e.getAttribute("name"));
+        }
+
+        return urls;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/MetaDataServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/MetaDataServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -24,17 +24,29 @@
 
 import de.intevation.flys.client.server.meta.Converter;
 
+/**
+ * Service that returns certain meta-data from the backends data, polished to
+ * inclusion into current project.
+ */
 public class MetaDataServiceImpl
 extends      RemoteServiceServlet
 implements   MetaDataService
 {
+    /** Our very own logger. */
     private static final Logger logger =
         Logger.getLogger(MetaDataServiceImpl.class);
 
-
     public static final String ERROR_NO_META_DATA_FOUND =
         "error_no_meta_data_found";
 
+
+    /**
+     * @param locale needed for i18n.
+     * @param artifactId ID of masterartifact (can be null)
+     * @param userId can be null
+     * @param outs can be null
+     * @param parameters can be null
+     */
     @Override
     public DataCageTree getMetaData(
         String locale,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ModuleServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,99 @@
+package de.intevation.flys.client.server;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+import de.intevation.flys.client.client.services.ModuleService;
+import de.intevation.flys.client.server.auth.User;
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.DefaultModule;
+import de.intevation.flys.client.shared.model.Module;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class ModuleServiceImpl
+extends      RemoteServiceServlet
+implements   ModuleService
+{
+    private static final Logger logger =
+        Logger.getLogger(ModuleServiceImpl.class);
+
+    public static final String XPATH_MODULES = "/art:modules/art:module";
+
+    public static final String ERROR_NO_MODULES_FOUND =
+        "error_no_module_found";
+
+    @Override
+    public Module[] list(String locale) throws ServerException {
+        User user = this.getUser();
+
+        logger.info("ModuleService.list");
+
+        String url = getServletContext().getInitParameter("server-url");
+
+        // create dummy xml
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX);
+
+        Element dummy = ec.create("modules");
+        doc.appendChild(dummy);
+
+        HttpClient client = new HttpClientImpl(url, locale);
+        try {
+            Document result = client.callService(url, "modules", doc);
+
+            NodeList list = (NodeList) XMLUtils.xpath(
+                result,
+                XPATH_MODULES,
+                XPathConstants.NODESET,
+                ArtifactNamespaceContext.INSTANCE);
+
+            if (list == null) {
+                logger.warn("No modules found.");
+
+                throw new ServerException(ERROR_NO_MODULES_FOUND);
+            }
+
+            int num = list.getLength();
+
+            List<Module> modules = new ArrayList<Module>(list.getLength());
+            for(int i =0; i < num; i++) {
+                Element em = (Element)list.item(i);
+                String name = em.getAttributeNS(
+                        ArtifactNamespaceContext.NAMESPACE_URI, "name");
+                String localname = em.getAttributeNS(
+                        ArtifactNamespaceContext.NAMESPACE_URI, "localname");
+                String strselected = em.getAttributeNS(
+                        ArtifactNamespaceContext.NAMESPACE_URI, "selected");
+                boolean selected = strselected == null ? false :
+                        strselected.equalsIgnoreCase("true");
+                logger.debug("Found module " + name + " " + localname);
+                if (user == null || user.canUseFeature("module:" + name)) {
+                    modules.add(new DefaultModule(name, localname, selected));
+                }
+            }
+            return modules.toArray(new Module[modules.size()]);
+        }
+        catch (ConnectionException ce) {
+            logger.error(ce, ce);
+        }
+
+        throw new ServerException(ERROR_NO_MODULES_FOUND);
+    }
+}
+
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ProxyServlet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,113 @@
+package de.intevation.flys.client.server;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Enumeration;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.client.server.auth.User;
+
+/**
+ * Implements a Proxy for HTTP Requests
+ */
+public class ProxyServlet
+extends HttpServlet
+{
+    private static Logger logger = Logger.getLogger(ProxyServlet.class);
+    private String remoteurl;
+
+    @Override
+    public void init(ServletConfig config) {
+        this.remoteurl = config.getInitParameter("remoteurl");
+    }
+
+    @Override
+    public void doPost(HttpServletRequest req, HttpServletResponse resp) {
+    }
+
+    @Override
+    public void doGet(HttpServletRequest req, HttpServletResponse resp)
+    throws IOException {
+        HttpClient httpclient = new DefaultHttpClient();
+
+        String requesturi = req.getRequestURI();
+        String query = req.getQueryString();
+
+        HttpGet httpget = new HttpGet(this.remoteurl + "?" + query);
+
+        boolean debug = logger.isDebugEnabled();
+
+        for (Enumeration e = req.getHeaderNames(); e.hasMoreElements();) {
+            String name = (String)e.nextElement();
+            for (Enumeration f = req.getHeaders(name); f.hasMoreElements();) {
+                String value = (String)f.nextElement();
+                if (debug) {
+                    logger.debug(
+                        "Adding request header " + name + " : " + value);
+                }
+                httpget.addHeader(name, value);
+            }
+        }
+
+        HttpResponse response = httpclient.execute(httpget);
+
+        StatusLine statusline = response.getStatusLine();
+        if (debug) {
+            logger.debug("Response statuscode " + statusline.getStatusCode());
+        }
+        resp.setStatus(statusline.getStatusCode());
+
+        Header[] headers = response.getAllHeaders();
+        for(Header header : headers) {
+            if (debug) {
+                logger.debug(
+                    "Adding response header " + header.getName() +
+                    " : " + header.getValue());
+            }
+            resp.setHeader(header.getName(), header.getValue());
+        }
+
+        HttpEntity entity = response.getEntity();
+        if (entity != null) {
+            InputStream instream = entity.getContent();
+            byte [] buf = new byte[4096];
+            try {
+                OutputStream outstream = resp.getOutputStream();
+                try {
+                    int read;
+                    while ((read = instream.read(buf)) >= 0) {
+                        outstream.write(buf, 0, read);
+                    }
+                    outstream.flush();
+                }
+                finally {
+                    outstream.close();
+                }
+            }
+            finally {
+                instream.close();
+            }
+        }
+    }
+
+    private User getUser(HttpServletRequest req) {
+            HttpSession session = req.getSession();
+            return (User)session.getAttribute("user");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/RemoteServiceServlet.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,18 @@
+package de.intevation.flys.client.server;
+
+import de.intevation.flys.client.server.auth.User;
+
+import javax.servlet.http.HttpSession;
+
+public class RemoteServiceServlet
+extends      com.google.gwt.user.server.rpc.RemoteServiceServlet
+{
+    /**
+     * Return the current logged in user from the HTTP Session
+     */
+    public User getUser() {
+        HttpSession session = this.getThreadLocalRequest().getSession();
+        return (User)session.getAttribute("user");
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/ReportServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/ReportServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -92,7 +92,7 @@
             String msg = element.getTextContent();
 
             if (km.length() > 0) {
-                kms.append("<li><strong>")
+                kms.append("<li><strong>KM ")
                    .append(StringEscapeUtils.escapeHtml(km))
                    .append("</strong>: ")
                    .append(StringEscapeUtils.escapeHtml(msg))
--- a/flys-client/src/main/java/de/intevation/flys/client/server/RiverServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/RiverServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,29 +1,25 @@
 package de.intevation.flys.client.server;
 
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+import de.intevation.flys.client.client.services.RiverService;
+import de.intevation.flys.client.server.auth.User;
+import de.intevation.flys.client.shared.exceptions.ServerException;
+import de.intevation.flys.client.shared.model.DefaultRiver;
+import de.intevation.flys.client.shared.model.River;
+
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.xml.xpath.XPathConstants;
 
-import org.w3c.dom.Document;
-import org.w3c.dom.NodeList;
-import org.w3c.dom.Node;
-
 import org.apache.log4j.Logger;
-
-import com.google.gwt.user.server.rpc.RemoteServiceServlet;
-
-import de.intevation.artifacts.common.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
-
-import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
-import de.intevation.artifacts.httpclient.http.HttpClient;
-import de.intevation.artifacts.httpclient.http.HttpClientImpl;
-
-import de.intevation.flys.client.shared.exceptions.ServerException;
-import de.intevation.flys.client.shared.model.DefaultRiver;
-import de.intevation.flys.client.shared.model.River;
-import de.intevation.flys.client.client.services.RiverService;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
 
 
 /**
@@ -36,10 +32,10 @@
 extends      RemoteServiceServlet
 implements   RiverService
 {
+    /** Private logger. */
     private static final Logger logger =
         Logger.getLogger(RiverServiceImpl.class);
 
-
     /** The XPath string that points to the rivers in the resulting document.*/
     public static final String XPATH_RIVERS = "/art:rivers/art:river";
 
@@ -48,12 +44,14 @@
     public static final String ERROR_NO_RIVERS_FOUND = "error_no_rivers_found";
 
 
+    /** Get river list. */
+    @Override
     public River[] list(String locale)
     throws ServerException
     {
         String url = getServletContext().getInitParameter("server-url");
 
-        Document doc      = XMLUtils.newDocument();
+        Document doc = XMLUtils.newDocument();
 
         XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
             doc,
@@ -80,17 +78,21 @@
             int count = rivers.getLength();
 
             List<River> theRivers = new ArrayList<River>(count);
+            User user = this.getUser();
 
             for (int i = 0; i < count; i++) {
-                Node tmp = rivers.item(i);
+                Element tmp = (Element)rivers.item(i);
 
-                String name = XMLUtils.xpathString(
-                    tmp, "@art:name", ArtifactNamespaceContext.INSTANCE);
+                String name = tmp.getAttributeNS(
+                    ArtifactNamespaceContext.NAMESPACE_URI, "name");
 
-                theRivers.add(new DefaultRiver(name));
+                if (name.length() > 0
+                && (user == null || user.canUseFeature("river:" + name))) {
+                    theRivers.add(new DefaultRiver(name));
+                }
             }
 
-            return (River[]) theRivers.toArray(new River[count]);
+            return theRivers.toArray(new River[theRivers.size()]);
         }
         catch (ConnectionException ce) {
             logger.error(ce, ce);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/SQKMChartServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,111 @@
+package de.intevation.flys.client.server;
+
+import org.apache.log4j.Logger;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import de.intevation.artifacts.httpclient.http.response.StreamResponseHandler;
+
+public class SQKMChartServiceImpl
+extends HttpServlet
+{
+    private static final Logger log =
+        Logger.getLogger(FixingsKMChartServiceImpl.class);
+
+    public static final String SERVICE_NAME = "sq-km-chart";
+
+    public SQKMChartServiceImpl() {
+    }
+
+    public void doGet(HttpServletRequest req, HttpServletResponse resp) {
+
+        log.info("SQKMChartServiceImpl.doGet");
+
+        String url    = getServletContext().getInitParameter("server-url");
+        String locale = req.getParameter("locale");
+        String filter = req.getParameter("filter");
+
+        if (filter == null || filter.length() == 0) {
+            log.warn("Missing 'filter' parameter.");
+            return;
+        }
+
+        if (locale == null || locale.length() == 0) {
+            locale = "de";
+        }
+
+        Document filterDoc = XMLUtils.jsonToXML(filter);
+
+        if (filterDoc == null) {
+            log.warn("Creating filter document failed.");
+            return;
+        }
+
+        InputStream in;
+
+        try {
+            HttpClient client = new HttpClientImpl(url, locale);
+            in = (InputStream)client.callService(
+                url, // XXX: Why? The URL is passed by construction already.
+                SERVICE_NAME,
+                filterDoc,
+                new StreamResponseHandler());
+        }
+        catch (ConnectionException ce) {
+            log.error(ce);
+            return;
+        }
+
+        resp.setHeader("Content-Type", guessMIMEType(filterDoc));
+
+        try {
+            OutputStream out = resp.getOutputStream();
+
+            byte [] buf = new byte[4096];
+            int i = -1;
+            while ((i = in.read(buf)) >= 0) {
+                out.write(buf, 0, i);
+            }
+            out.flush();
+        }
+        catch (IOException ioe) {
+            log.error(ioe);
+        }
+        finally {
+            try { in.close(); }
+            catch (IOException ioe) { /* ignored */ }
+        }
+    }
+
+    protected static String guessMIMEType(Document document) {
+
+        NodeList formats = document.getElementsByTagName("format");
+
+        String format = "png";
+
+        if (formats.getLength() > 0) {
+            String type = ((Element)formats.item(0)).getAttribute("type");
+            if (type.length() > 0) {
+                format = type;
+            }
+        }
+
+        return "image/" + format;
+    }
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/server/StepForwardServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/StepForwardServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -168,7 +168,7 @@
         for (Data d: data) {
             DataItem[] items = d.getItems();
             String key       = d.getLabel();
-            String value     = items[0].getStringValue();
+            String value     = d.getStringValue();
 
             kvp[i++] = new String[] { key, value };
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/StyleHelper.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,48 @@
+package de.intevation.flys.client.server;
+
+import de.intevation.flys.client.shared.model.Style;
+import de.intevation.flys.client.shared.model.StyleSetting;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+
+public class StyleHelper {
+
+    public static Style getStyle (Element element) {
+        if (!element.getTagName().equals("theme")) {
+            return null;
+        }
+
+        NodeList list = element.getElementsByTagName("field");
+        Style style = new Style();
+
+        style.setName (element.getAttribute("name"));
+        style.setFacet (element.getAttribute("facet"));
+
+        try {
+            int ndx = Integer.parseInt(element.getAttribute("index"));
+            style.setIndex (ndx);
+        }
+        catch(NumberFormatException nfe) {
+            return null;
+        }
+
+        for(int i = 0; i < list.getLength(); i++) {
+            Element     e = (Element) list.item(i);
+            String hidden = e.getAttribute("hidden");
+
+            StyleSetting set = new StyleSetting (
+                e.getAttribute("name"),
+                e.getAttribute("default"),
+                e.getAttribute("display"),
+                e.getAttribute("hints"),
+                e.getAttribute("type"),
+                (hidden != null ? Boolean.valueOf(hidden) : false)
+            );
+            style.appendStyleSetting(set);
+        }
+        return style;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/server/ThemeListingServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,107 @@
+package de.intevation.flys.client.server;
+
+import com.google.gwt.user.server.rpc.RemoteServiceServlet;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+import de.intevation.flys.client.client.services.ThemeListingService;
+
+import de.intevation.flys.client.shared.exceptions.ServerException;
+
+import de.intevation.flys.client.shared.model.Style;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * This interface provides a method to list themes filtered by name.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class ThemeListingServiceImpl
+extends      RemoteServiceServlet
+implements   ThemeListingService
+{
+    private static final Logger logger =
+        Logger.getLogger(ThemeListingServiceImpl.class);
+
+
+    private static final String XPATH_THEME_GROUPS = "/themes/themegroup";
+    /** The error message key that is thrown if an error occured while reading
+     * the supported rivers from server.*/
+    public static final String ERROR_NO_GROUPS_FOUND = "error_no_groups_found";
+
+
+    public Map<String, Style> list(String locale, String name)
+    throws ServerException
+    {
+        String url = getServletContext().getInitParameter("server-url");
+
+        Document doc = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
+            doc,
+            null,
+            null);
+
+        Element e = ec.create("theme");
+        ec.addAttr(e, "name", name);
+        doc.appendChild(e);
+        HttpClient client = new HttpClientImpl(url, locale);
+
+        try {
+            Document res = client.callService(url, "themelisting", doc);
+
+            NodeList themeGroups = (NodeList) XMLUtils.xpath(
+                res,
+                XPATH_THEME_GROUPS,
+                XPathConstants.NODESET,
+                null);
+
+            if (themeGroups == null || themeGroups.getLength() == 0) {
+                throw new ServerException(ERROR_NO_GROUPS_FOUND);
+            }
+
+            int count = themeGroups.getLength();
+
+            Map<String, Style> theStyles = new HashMap<String, Style>(count);
+
+            for (int i = 0; i < count; i++) {
+                Element tmp = (Element)themeGroups.item(i);
+
+                String groupName = tmp.getAttribute("name");
+                NodeList theTheme = (NodeList) XMLUtils.xpath(
+                    tmp,
+                    "theme",
+                    XPathConstants.NODESET,
+                    null);
+
+                for (int j = 0; j < theTheme.getLength(); j++) {
+                    Element elem = (Element) theTheme.item(j);
+                    theStyles.put(groupName, StyleHelper.getStyle(elem));
+                }
+            }
+
+            return theStyles;
+        }
+        catch (ConnectionException ce) {
+            logger.error(ce, ce);
+        }
+
+        throw new ServerException(ERROR_NO_GROUPS_FOUND);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/server/UserCollectionsServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/UserCollectionsServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -42,13 +42,10 @@
         UserCollectionsServiceImpl.class);
 
 
-    public Collection[] getUserCollections(
-        String serverUrl,
-        String locale,
-        String userid)
-    {
+    public Collection[] getUserCollections(String locale, String userid) {
         logger.info("UserCollectionsServiceImpl.getUserCollections");
 
+        String serverUrl  = getServletContext().getInitParameter("server-url");
         HttpClient client = new HttpClientImpl(serverUrl, locale);
 
         try {
@@ -79,7 +76,7 @@
 
             logger.debug("User has " + all.size() + " collections.");
 
-            return (Collection[]) all.toArray(new Collection[all.size()]);
+            return all.toArray(new Collection[all.size()]);
         }
         catch (ConnectionException ce) {
             logger.error(ce, ce);
--- a/flys-client/src/main/java/de/intevation/flys/client/server/UserServiceImpl.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/UserServiceImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,28 +1,19 @@
 package de.intevation.flys.client.server;
 
-import javax.xml.xpath.XPathConstants;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
+import org.w3c.dom.Element;
 
 import org.apache.log4j.Logger;
 
-import com.google.gwt.user.server.rpc.RemoteServiceServlet;
-
 import de.intevation.artifacts.common.ArtifactNamespaceContext;
-import de.intevation.artifacts.common.utils.XMLUtils;
 
 import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
-import de.intevation.artifacts.httpclient.http.HttpClient;
-import de.intevation.artifacts.httpclient.http.HttpClientImpl;
 
 import de.intevation.flys.client.client.services.UserService;
+import de.intevation.flys.client.server.auth.UserClient;
 import de.intevation.flys.client.shared.exceptions.AuthenticationException;
 import de.intevation.flys.client.shared.model.DefaultUser;
 import de.intevation.flys.client.shared.model.User;
 
-
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
@@ -30,36 +21,34 @@
 extends      RemoteServiceServlet
 implements   UserService
 {
+    /** Private logger. */
     private static final Logger logger = Logger.getLogger(UserServiceImpl.class);
 
+    public static final String ERROR_NO_SUCH_USER = "error_no_such_user";
 
-    public static final String ERROR_NO_SUCH_USER = "error_no_such_user";
+    public static final String ERROR_NO_USERS = "error_no_users";
 
     public User getCurrentUser(String locale)
     throws AuthenticationException
     {
         String url = getServletContext().getInitParameter("server-url");
 
-        HttpClient client = new HttpClientImpl(url);
+        UserClient client = new UserClient(url);
+        de.intevation.flys.client.server.auth.User loginuser = getUser();
+
+        if (loginuser == null) {
+            logger.debug("no session user");
+            throw new AuthenticationException(ERROR_NO_SUCH_USER);
+        }
 
         try {
-            Document users = (Document) client.listUsers();
-
-            String XPATH_USERS = "/art:users/art:user";
+            Element user = client.findUser(loginuser);
 
-            NodeList theUsers = (NodeList) XMLUtils.xpath(
-                users,
-                XPATH_USERS,
-                XPathConstants.NODESET,
-                ArtifactNamespaceContext.INSTANCE);
-
-            if (theUsers != null && theUsers.getLength() > 0) {
-                Node user = theUsers.item(0);
-
-                String uuid = XMLUtils.xpathString(
-                    user, "@art:uuid", ArtifactNamespaceContext.INSTANCE);
-                String name = XMLUtils.xpathString(
-                    user, "@art:name", ArtifactNamespaceContext.INSTANCE);
+            if (user != null) {
+                String uuid = user.getAttributeNS(
+                        ArtifactNamespaceContext.NAMESPACE_URI, "uuid");
+                String name = user.getAttributeNS(
+                        ArtifactNamespaceContext.NAMESPACE_URI, "name");
 
                 return new DefaultUser(uuid, name);
             }
@@ -69,7 +58,7 @@
         }
 
         logger.error("No users existing in the server.");
-        throw new AuthenticationException(ERROR_NO_SUCH_USER);
+        throw new AuthenticationException(ERROR_NO_USERS);
     }
 }
 // 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-client/src/main/java/de/intevation/flys/client/server/auth/Authentication.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.client.server.auth;
+
+/** Interface to represent user authentications
+ */
+public interface Authentication {
+
+    /** Returns true if the authentication was successfull
+     */
+    public boolean isSuccess();
+
+    /** Returns a new User object
+     */
+    public User getUser() throws AuthenticationException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/AuthenticationException.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.client.server.auth;
+
+/**
+ * Base class for Authentication related Exceptions
+ */
+public class AuthenticationException extends Exception {
+
+    public AuthenticationException(String message) {
+        super(message);
+    }
+
+    public AuthenticationException(Exception e) {
+        super(e);
+    }
+}
+// vim: set fileencoding=utf-8 ts=4 sw=4 tw=80:
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/AuthenticationFactory.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,31 @@
+package de.intevation.flys.client.server.auth;
+
+import org.apache.log4j.Logger;
+
+public class AuthenticationFactory {
+
+    private static final Logger log =
+        Logger.getLogger(AuthenticationFactory.class);
+
+    public static Authenticator getInstance(String name)
+        throws IllegalArgumentException
+    {
+        if (name == null) {
+            throw new IllegalArgumentException("Authentication type name is null");
+        }
+
+        if (name.equalsIgnoreCase("was") ||
+            name.equalsIgnoreCase("ggina")) {
+            log.debug("Using GGinA authenticator.");
+            return
+                new de.intevation.flys.client.server.auth.was.Authenticator();
+        }
+        else if (name.equalsIgnoreCase("plain")) {
+            log.debug("Using plain authenticator.");
+            return
+                new de.intevation.flys.client.server.auth.plain.Authenticator();
+        }
+
+        throw new IllegalArgumentException("Unkown Authentication " + name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/Authenticator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,12 @@
+package de.intevation.flys.client.server.auth;
+
+import java.io.IOException;
+
+import de.intevation.flys.client.server.features.Features;
+
+public interface Authenticator {
+
+    public Authentication auth(String username, String password, String encoding, Features features)
+        throws AuthenticationException, IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/DefaultUser.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,88 @@
+package de.intevation.flys.client.server.auth;
+
+import java.util.List;
+
+public class DefaultUser
+implements   User
+{
+    protected String  name;
+    protected String  account;
+    protected String  password;
+    protected boolean expired;
+    protected List<String> roles;
+    protected List<String> features;
+
+    public DefaultUser() {
+    }
+
+    public DefaultUser(
+        String       name,
+        String       password,
+        boolean      expired,
+        List<String> roles,
+        List<String> features
+    ) {
+        this.name     = name;
+        this.password = password;
+        this.expired  = expired;
+        this.roles    = roles;
+        this.features = features;
+        this.account  = name;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    @Override
+    public boolean hasExpired() {
+        return expired;
+    }
+
+    public void setExpired(boolean expired) {
+        this.expired = expired;
+    }
+
+    @Override
+    public List<String> getRoles() {
+        // XXX: return clone of the list?
+        return this.roles;
+    }
+
+    public void setRoles(List<String> roles) {
+        this.roles = roles;
+    }
+
+    @Override
+    public boolean canUseFeature(String feature) {
+        return this.features.contains(feature);
+    }
+
+    public void setAllowedFeatures(List<String> features) {
+        this.features = features;
+    }
+
+    @Override
+    public String getAccount() {
+        return this.account;
+    }
+
+    public void setAccount(String account) {
+        this.account = account;
+    }
+}
+// vim:set ts=4 sw=4 si et fenc=utf8 tw=80:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/User.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,42 @@
+package de.intevation.flys.client.server.auth;
+
+import java.util.List;
+
+/**
+ * User representation after a succesfull login
+ */
+public interface User {
+
+    /**
+     * Returns the username as String
+     */
+    public String getName();
+
+    /**
+     * Returns the password of the user as String
+     */
+    public String getPassword();
+
+    /**
+     * Returns True if the authentication for the user
+     * has expired.
+     */
+    public boolean hasExpired();
+
+    /**
+     * Returns a list of roles corresponsing the the user
+     */
+    public List<String> getRoles();
+
+
+    /**
+     * Returns true if the user is allowed access the feature
+     */
+    public boolean canUseFeature(String feature);
+
+    /**
+     * Returns the users account name
+     */
+    public String getAccount();
+}
+// vim:set ts=4 sw=4 si et fenc=utf8 tw=80:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/UserClient.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,158 @@
+package de.intevation.flys.client.server.auth;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifacts.common.ArtifactNamespaceContext;
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+import de.intevation.artifacts.httpclient.exceptions.ConnectionException;
+import de.intevation.artifacts.httpclient.http.HttpClient;
+import de.intevation.artifacts.httpclient.http.HttpClientImpl;
+
+/**
+ * UserClient is a class to allow easier communication
+ * with the REST based artifact user protocol
+ */
+public class UserClient {
+
+    private static final Logger logger = Logger.getLogger(UserClient.class);
+
+    private String url;
+
+    public UserClient(String url) {
+        this.url = url;
+    }
+
+    public boolean userExists(User user) throws ConnectionException {
+        if (user == null) {
+            return false;
+        }
+
+        Element data = this.findUser(user);
+
+        String XPATH_USERACCOUNT = "/art:user/art:account/@art:name";
+
+        String account = XMLUtils.xpathString(
+            data, XPATH_USERACCOUNT, ArtifactNamespaceContext.INSTANCE);
+
+        if (account == null) {
+            return false;
+        }
+
+        return account.equals(user.getAccount());
+    }
+
+    public boolean createUser(User user) throws ConnectionException {
+        if(user == null) {
+            logger.warn("createUser: given user is null");
+            return false;
+        }
+
+        logger.debug("Creating new user " + user.getName());
+        HttpClient client = new HttpClientImpl(this.url);
+
+        Document document = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
+            document,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX
+        );
+
+        Element action = creator.create("action");
+
+        Element type = creator.create("type");
+        type.setAttribute("name", "create");
+        Element artuser = creator.create("user");
+        artuser.setAttribute("name", user.getName());
+        Element account = creator.create("account");
+        account.setAttribute("name", user.getAccount());
+
+        //TODO create roles
+        artuser.appendChild(account);
+        action.appendChild(type);
+        action.appendChild(artuser);
+        document.appendChild(action);
+
+        logger.debug("Create user request xml: " + XMLUtils.toString(document));
+
+        Document resp = client.createUser(document);
+
+        logger.debug("Create user response xml: " + XMLUtils.toString(resp));
+
+        String XPATH_RESPONSE = "/art:result";
+        Node nresult = (Node) XMLUtils.xpath(
+            resp,
+            XPATH_RESPONSE,
+            XPathConstants.NODE,
+            ArtifactNamespaceContext.INSTANCE);
+        String result = nresult.getTextContent();
+        return (result != null && result.equalsIgnoreCase("success"));
+    }
+
+    public NodeList listUsers() throws ConnectionException {
+        HttpClient client = new HttpClientImpl(this.url);
+
+        Document users = (Document) client.listUsers();
+
+        String XPATH_USERS = "/art:users/art:user";
+
+        return (NodeList) XMLUtils.xpath(
+            users,
+            XPATH_USERS,
+            XPathConstants.NODESET,
+            ArtifactNamespaceContext.INSTANCE);
+    }
+
+    public Element findUser(User user) throws ConnectionException {
+        if(user == null) {
+            throw new IllegalArgumentException("user is null");
+        }
+
+        HttpClient client = new HttpClientImpl(this.url);
+
+        Document document = XMLUtils.newDocument();
+
+        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
+            document,
+            ArtifactNamespaceContext.NAMESPACE_URI,
+            ArtifactNamespaceContext.NAMESPACE_PREFIX
+        );
+
+        Element action = creator.create("action");
+
+        Element type = creator.create("type");
+        type.setAttribute("name", "find");
+        Element account = creator.create("account");
+        account.setAttribute("name", user.getAccount());
+
+        action.appendChild(type);
+        action.appendChild(account);
+        document.appendChild(action);
+
+        boolean debug = logger.isDebugEnabled();
+
+        if (debug) {
+            logger.debug("Find user request xml: " +
+                XMLUtils.toString(document));
+        }
+
+        Document resp = client.findUser(document);
+
+        if (debug) {
+            logger.debug("Find user request response xml: " +
+                XMLUtils.toString(resp));
+        }
+
+        return resp.getDocumentElement();
+    }
+}
+// vim: set si et fileencoding=utf-8 ts=4 sw=4 tw=80:
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/plain/Authenticator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,134 @@
+package de.intevation.flys.client.server.auth.plain;
+
+import de.intevation.flys.client.server.auth.AuthenticationException;
+import de.intevation.flys.client.server.auth.DefaultUser;
+import de.intevation.flys.client.server.auth.User;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import de.intevation.flys.client.server.features.Features;
+
+/**
+ * Authenticator that uses a local file as user backend.
+ */
+public class Authenticator
+implements   de.intevation.flys.client.server.auth.Authenticator
+{
+    private static final Logger log =
+        Logger.getLogger(Authenticator.class);
+
+    public static class Authentication
+    implements          de.intevation.flys.client.server.auth.Authentication
+    {
+        protected String       user;
+        protected String       password;
+        protected List<String> roles;
+        protected Features     features;
+
+        public Authentication(
+            String       user,
+            String       password,
+            List<String> roles,
+            Features features
+        ) {
+            this.user     = user;
+            this.password = password;
+            this.roles    = roles;
+            this.features = features;
+        }
+
+        @Override
+        public boolean isSuccess() {
+            return user != null;
+        }
+
+        @Override
+        public User getUser() {
+            return isSuccess()
+                ? new DefaultUser(user, password, false, roles, this.features.getFeatures(roles))
+                : null;
+        }
+    } // class Authentication
+
+    public Authenticator() {
+    }
+
+    private static File credentialsFile() {
+        String env = System.getenv("FLYS_USER_FILE");
+        if (env == null) {
+            env = System.getProperty(
+                "flys.user.file",
+                System.getProperty("user.home", ".")
+                + System.getProperty("file.separator")
+                + "flys_user_file");
+        }
+        log.debug("Using credentials file " + env);
+        return new File(env);
+
+    }
+
+    @Override
+    public de.intevation.flys.client.server.auth.Authentication auth(
+        String username,
+        String password,
+        String encoding,
+        Features features
+    )
+    throws AuthenticationException, IOException
+    {
+        File file = credentialsFile();
+        if (!file.canRead() || !file.isFile()) {
+            log.error("cannot find user file '" + file + "'");
+            return new Authentication(null, null, new ArrayList<String>(0), features);
+        }
+
+        BufferedReader reader =
+            new BufferedReader(
+            new FileReader(file));
+        try {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                if ((line = line.trim()).length() == 0
+                || line.startsWith("#")) {
+                    continue;
+                }
+
+                String[] parts = line.split("\\s+");
+                if (parts.length < 2) {
+                    continue;
+                }
+
+                if (parts[0].equals(username)) {
+                    log.debug("user '" + username + "' found.");
+                    if (parts[1].equals(password)) {
+                        List<String> roles =
+                            new ArrayList<String>(parts.length - 2);
+
+                        for (int i = 2; i < parts.length; i++) {
+                            roles.add(parts[i]);
+                        }
+
+                        log.debug("success");
+                        return new Authentication(username, password, roles, features);
+                    }
+                    // Stop: user found, wrong password
+                    break;
+                }
+            }
+        }
+        finally {
+            reader.close();
+        }
+        log.debug("failed");
+        return null;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/server/auth/was/Assertion.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,178 @@
+package de.intevation.flys.client.server.auth.was;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Iterator;
+import java.util.Date;
+import java.util.List;
+import java.util.LinkedList;
+
+import org.apache.log4j.Logger;
+
+import org.jdom.Element;
+
+public class Assertion {
+
+    private static Logger logger = Logger.getLogger(Assertion.class);
+
+    private Element assertion;
+    private LinkedList<String> roles;
+    private String assertion_id;
+    private String user_id;
+    private String name_id;
+    private String group_id;
+    private String group_name;
+    private Date notbefore;
+    private Date notonorafter;
+    private Signature signature;
+
+    private static final String ATTR_CONT_USER_ID =
+        "urn:conterra:names:sdi-suite:policy:attribute:user-id";
+    private static final String ATTR_CONT_GROUP_ID =
+        "urn:conterra:names:sdi-suite:policy:attribute:group-id";
+    private static final String ATTR_CONT_GROUP_NAME =
+        "urn:conterra:names:sdi-suite:policy:attribute:group-name";
+    private static final String ATTR_CONT_ROLE =
+        "urn:conterra:names:sdi-suite:policy:attribute:role";
+
+
+    public Assertion(Element assertion) {
+        this.assertion = assertion;
+        this.roles = new LinkedList<String>();
+
+        this.assertion_id = assertion.getAttributeValue("AssertionID");
+
+        this.parseContition();
+        this.parseAttributeStatement();
+    }
+
+    private void parseContition() {
+        Element condition = this.assertion.getChild("Conditions",
+                Namespaces.SAML_NS_ASSERT);
+        if (condition != null) {
+            SimpleDateFormat dateformat = new SimpleDateFormat();
+            // format should be "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" but that's only
+            // available in java 7+
+            dateformat.applyPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+            String from = condition.getAttributeValue("NotBefore");
+            if (from != null) {
+                try {
+                    this.notbefore = dateformat.parse(from);
+                }
+                catch(ParseException e) {
+                    logger.error("Unknown datetime format for Condition " +
+                            "NotBefore " + from);
+                }
+            }
+
+            String until = condition.getAttributeValue("NotOnOrAfter");
+            if (until != null) {
+                try {
+                    this.notonorafter = dateformat.parse(until);
+                }
+                catch(ParseException e) {
+                    logger.error("Unknown datetime format for Condition " +
+                            "NotOnOrAfter " + until);
+                }
+            }
+        }
+    }
+
+    private void parseAttributeStatement() {
+        Element attrstatement = this.assertion.getChild("AttributeStatement",
+                Namespaces.SAML_NS_ASSERT);
+        if (attrstatement != null) {
+
+            Element subject = attrstatement.getChild("Subject",
+                    Namespaces.SAML_NS_ASSERT);
+            if (subject != null) {
+                this.name_id = subject.getChildText("NameIdentifier",
+                        Namespaces.SAML_NS_ASSERT);
+            }
+
+            List attributes = attrstatement.getChildren("Attribute",
+                    Namespaces.SAML_NS_ASSERT);
+            for(Iterator i = attributes.iterator(); i.hasNext();) {
+                Element attr = (Element)i.next();
+                String attrname = attr.getAttributeValue("AttributeName");
+                if (attrname.equals(ATTR_CONT_USER_ID)) {
+                    this.user_id = this.getAttributeValue(attr);
+                }
+                else if (attrname.equals(ATTR_CONT_GROUP_ID)) {
+                    this.group_id = this.getAttributeValue(attr);
+                }
+                else if (attrname.equals(ATTR_CONT_GROUP_NAME)) {
+                    this.group_name = this.getAttributeValue(attr);
+                }
+                else if (attrname.equals(ATTR_CONT_ROLE)) {
+                    List roles = attr.getChildren("AttributeValue",
+                            Namespaces.SAML_NS_ASSERT);
+                    for(Iterator j = roles.iterator(); j.hasNext();) {
+                        Element role = (Element)j.next();
+                        this.roles.add(role.getText());
+                    }
+                }
+                else {
+                    logger.debug("Unknown AttributeName " + attrname +
+                            " found while parsing AttributeStatement.");
+                }
+            }
+        }
+    }
+
+    private String getAttributeValue(Element attr) {
+        return attr.getChildText("AttributeValue", Namespaces.SAML_NS_ASSERT);
+    }
+
+    public List<String> getRoles() {
+        return this.roles;
+    }
+
+    public Boolean isValid() {
+        // TODO:
+        // check signature digest
+        // check signature value
+        // check signature cert
+        return false;
+    }
+
+    public Signature getSiganture() {
+        if (this.signature == null) {
+            Element signature = this.assertion.getChild("Signature",
+                    Namespaces.XML_SIG_NS);
+            if (signature != null) {
+                this.signature = new Signature(signature);
+            }
+        }
+        return this.signature;
+    }
+
+    public String getUserID() {
+        return this.user_id;
+    }
+
+    public String getNameID() {
+        return this.name_id;
+    }
+
+    public String getGroupID() {
+        return this.group_id;
+    }
+
+    public String getGroupName() {
+        return this.group_name;
+    }
+
+    public String getID() {
+        return this.assertion_id;
+    }
+
+    public Date getFrom() {
+        return this.notbefore;
+    }
+
+    public Date getUntil() {
+        return this.notonorafter;
+    }
+}
+// vim: set fileencoding=utf-8 ts=4 sw=4 et si tw=80:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/was/Authenticator.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,55 @@
+package de.intevation.flys.client.server.auth.was;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import de.intevation.flys.client.server.GGInATrustStrategy;
+import de.intevation.flys.client.server.auth.Authentication;
+import de.intevation.flys.client.server.auth.AuthenticationException;
+import de.intevation.flys.client.server.features.Features;
+
+public class Authenticator
+implements de.intevation.flys.client.server.auth.Authenticator {
+
+    @Override
+    public Authentication auth(
+        String username,
+        String password,
+        String encoding,
+        Features features
+    ) throws
+        AuthenticationException,
+        IOException
+    {
+            try {
+                SSLSocketFactory sf = new SSLSocketFactory(
+                        new GGInATrustStrategy());
+                Scheme https = new Scheme("https", 443, sf);
+                HttpClient httpclient = new DefaultHttpClient();
+                httpclient.getConnectionManager().getSchemeRegistry().register(
+                        https);
+
+                Request httpget = new Request("https://geoportal.bafg.de/" +
+                        "administration/WAS", username, password, encoding);
+                HttpResponse response = httpclient.execute(httpget);
+                HttpEntity entity = response.getEntity();
+                if (entity == null) {
+                    //FIXME throw AuthenticationException
+                    return null;
+                }
+                else {
+                    return new Response(entity, username, password, features);
+                }
+            }
+            catch(GeneralSecurityException e) {
+                throw new AuthenticationException(e);
+            }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/was/Namespaces.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,14 @@
+package de.intevation.flys.client.server.auth.was;
+
+import org.jdom.Namespace;
+
+public class Namespaces {
+
+    public static final Namespace SAML_NS_ASSERT =
+        Namespace.getNamespace("urn:oasis:names:tc:SAML:1.0:assertion");
+    public static final Namespace SAML_NS_PROTO =
+        Namespace.getNamespace("urn:oasis:names:tc:SAML:1.0:protocol");
+    public static final Namespace XML_SIG_NS =
+        Namespace.getNamespace("http://www.w3.org/2000/09/xmldsig#");
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/was/Request.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,59 @@
+package de.intevation.flys.client.server.auth.was;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.log4j.Logger;
+
+public class Request extends HttpGet {
+
+    private final static String VERSION = "1.1";
+    private final static String REQUEST_SAML_RESPONSE = "GetSAMLResponse";
+    private final static String METHOD_AUTH_PASSWORD =
+        "urn:opengeospatial:authNMethod:OWS:1.0:password";
+
+    private static Logger logger = Logger.getLogger(Request.class);
+
+    public Request(String uri) {
+        String request = uri + "?VERSION=" + VERSION + "&REQUEST=" +
+            REQUEST_SAML_RESPONSE + "&METHOD=" + METHOD_AUTH_PASSWORD +
+            "&ANONYMOUS=TRUE&CREDENTIALS=";
+        this.setURI(URI.create(request));
+    }
+
+    public Request(String uri, String user, String pass, String encoding) {
+        try {
+            String base64user = this.toBase64(user, encoding);
+            String base64pass = this.toBase64(pass, encoding);
+
+            String request = uri + "?VERSION=" + VERSION + "&REQUEST=" +
+                REQUEST_SAML_RESPONSE + "&METHOD=" + METHOD_AUTH_PASSWORD +
+                "&CREDENTIALS=" + base64user + "," + base64pass;
+
+            this.setURI(URI.create(request));
+        }
+        catch(UnsupportedEncodingException e) {
+            logger.error(e);
+        }
+    }
+
+    private String toBase64(String value, String encoding) throws
+        UnsupportedEncodingException {
+        if (encoding == null) {
+            encoding = "utf-8";
+        }
+        try {
+            return new String(Base64.encodeBase64(value.getBytes(encoding)));
+        }
+        catch(UnsupportedEncodingException e) {
+            logger.warn("Can't encode string with encoding " + encoding +
+                    ". Falling back to utf-8. " + e);
+            return this.toBase64(value, "utf-8");
+        }
+    }
+
+}
+// vim: set et si fileencoding=utf-8 ts=4 sw=4 tw=80:
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/was/Response.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,118 @@
+package de.intevation.flys.client.server.auth.was;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.commons.codec.binary.Base64InputStream;
+
+import org.apache.http.HttpEntity;
+
+import org.apache.log4j.Logger;
+
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+
+import de.intevation.flys.client.server.auth.Authentication;
+import de.intevation.flys.client.server.auth.AuthenticationException;
+
+import de.intevation.flys.client.server.features.Features;
+
+public class Response implements Authentication {
+
+    private static Logger logger = Logger.getLogger(Response.class);
+
+    private Element root;
+    private Assertion assertion;
+    private String username;
+    private String password;
+    private Features features;
+
+
+    public Response(HttpEntity entity, String username, String password, Features features) throws AuthenticationException, IOException {
+
+        if (entity == null) {
+            throw new ServiceException("Invalid response");
+        }
+
+        String contenttype = entity.getContentType().getValue();
+
+        try {
+            InputStream in = entity.getContent();
+
+            if (!contenttype.equals("application/vnd.ogc.se_xml")) {
+                // XXX: Assume base64 encoded content.
+                in = new Base64InputStream(in);
+            }
+
+            SAXBuilder builder = new SAXBuilder();
+            Document doc = builder.build(in);
+            Element root = doc.getRootElement();
+            String rname = root.getName();
+
+            if (rname != null && rname.equals("ServiceExceptionReport")) {
+                throw new ServiceException(root.getChildText("ServiceException"));
+            }
+
+            this.root = root;
+            this.username = username;
+            this.password = password;
+            this.features = features;
+
+        }
+        catch(JDOMException e) {
+            throw new AuthenticationException(e);
+        }
+    }
+
+    public Element getRoot() {
+        return this.root;
+    }
+
+    @Override
+    public boolean isSuccess() {
+        String status = getStatus();
+        return status != null && status.equals("samlp:Success");
+    }
+
+    public String getStatus() {
+        Element status = this.root.getChild("Status", Namespaces.SAML_NS_PROTO);
+        if (status == null) {
+            return null;
+        }
+        Element statuscode = status.getChild("StatusCode",
+                Namespaces.SAML_NS_PROTO);
+        if (statuscode == null) {
+            return null;
+        }
+        return statuscode.getAttributeValue("Value");
+    }
+
+    public Assertion getAssertion() {
+        if (this.assertion == null && this.root != null) {
+            Element assertion = this.root.getChild("Assertion",
+                    Namespaces.SAML_NS_ASSERT);
+            if (assertion != null) {
+                this.assertion = new Assertion(assertion);
+            }
+        }
+        return this.assertion;
+    }
+
+    @Override
+    public User getUser() throws AuthenticationException {
+        Assertion assertion = this.getAssertion();
+        if (assertion == null) {
+            throw new AuthenticationException("Response doesn't contain an assertion");
+        }
+        List<String> features = this.features.getFeatures(
+                this.assertion.getRoles());
+        logger.debug("User " + this.username + " with features " + features +
+                     " successfully authenticated.");
+        return new User(this.username, this.password, assertion.getNameID(),
+                this.assertion.getRoles(), assertion, features);
+    }
+}
+// vim: set si et fileencoding=utf-8 ts=4 sw=4 tw=80:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/was/ServiceException.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,15 @@
+package de.intevation.flys.client.server.auth.was;
+
+import de.intevation.flys.client.server.auth.AuthenticationException;
+
+public class ServiceException extends AuthenticationException {
+
+    public ServiceException(String message) {
+        super(message);
+    }
+
+    public ServiceException(Exception e) {
+        super(e);
+    }
+}
+// vim: set si et fileencoding=utf-8 ts=4 sw=4 tw=80:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/was/Signature.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,120 @@
+package de.intevation.flys.client.server.auth.was;
+
+import java.io.ByteArrayInputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+import org.jdom.Element;
+
+public class Signature {
+
+    private static Logger logger = Logger.getLogger(Signature.class);
+
+    private static final String XML_SIG_DIGEST_SHA1 =
+        "http://www.w3.org/2000/09/xmldsig#sha1";
+    private static final String XML_SIG_SIGNATURE_RSA_SHA1 =
+        "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
+
+    private final Element signature;
+    private Certificate cert;
+    private byte[] value;
+    private byte[] digestvalue;
+    private String reference;
+
+    public Signature(Element signature) {
+        this.signature = signature;
+        this.parseSignatureInfo();
+        this.parseSignatureValue();
+        this.parseCertificate();
+    }
+
+    private void parseSignatureInfo() {
+        Element signatureinfo = this.signature.getChild("SignedInfo",
+                Namespaces.XML_SIG_NS);
+        if (signatureinfo != null) {
+            Element signaturemethod = signatureinfo.getChild("SignatureMethod",
+                    Namespaces.XML_SIG_NS);
+            String algorithm = signaturemethod.getAttributeValue("Algorithm");
+            if (!algorithm.equals(XML_SIG_SIGNATURE_RSA_SHA1)) {
+                logger.warn("Unkown signature alorithm " + algorithm);
+            }
+
+            // There could be several references in XML-Sig spec but for me it
+            // doesn't make sense to have more then one in a SAML Assertion
+            Element reference = signatureinfo.getChild("Reference",
+                    Namespaces.XML_SIG_NS);
+            // reference must be present but its better to check
+            if (reference != null) {
+                String digestvalue = reference.getChildText("DigestValue",
+                        Namespaces.XML_SIG_NS);
+                String digestmethod = reference.getChildText("DigestMethod",
+                        Namespaces.XML_SIG_NS);
+                if (!digestmethod.equals(XML_SIG_DIGEST_SHA1)) {
+                    logger.warn("Unknown digest method " + digestmethod);
+                }
+                this.digestvalue = Base64.decodeBase64(digestvalue);
+
+                String referenceuri = reference.getAttributeValue("URI");
+                if (referenceuri.startsWith("#")) {
+                    this.reference = referenceuri.substring(1);
+                }
+                else {
+                    logger.warn("Unkown reference type " + referenceuri);
+                    this.reference = referenceuri;
+                }
+            }
+        }
+    }
+
+    private void parseSignatureValue() {
+        String signaturevalue = this.signature.getChildText("SignatureValue",
+                Namespaces.XML_SIG_NS);
+        this.value = Base64.decodeBase64(signaturevalue);
+    }
+
+    private void parseCertificate() {
+        Element keyinfo = this.signature.getChild("KeyInfo",
+                Namespaces.XML_SIG_NS);
+        if (keyinfo != null) {
+            Element data = keyinfo.getChild("X509Data", Namespaces.XML_SIG_NS);
+            if (data != null) {
+                String base64cert = data.getChildText("X509Certificate",
+                        Namespaces.XML_SIG_NS);
+                if (base64cert != null) {
+                    byte[] bytes = Base64.decodeBase64(base64cert);
+                    try {
+                        CertificateFactory cf = CertificateFactory.getInstance(
+                                "X.509");
+                        this.cert = cf.generateCertificate(
+                                new ByteArrayInputStream(bytes));
+                    }
+                    catch(CertificateException e) {
+                        // should never occur
+                        logger.error(e);
+                    }
+                }
+            }
+        }
+    }
+
+    public Certificate getCertificate() {
+        return this.cert;
+    }
+
+    public byte[] getValue() {
+        return this.value;
+    }
+
+    public String getReference() {
+        // In theory there could be several references with digestvalues, ...
+        return this.reference;
+    }
+
+    public byte[] getDigestValue() {
+        return this.digestvalue;
+    }
+}
+// vim: set si et fileencoding=utf-8 ts=4 sw=4 tw=80:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/auth/was/User.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,40 @@
+package de.intevation.flys.client.server.auth.was;
+
+import java.util.Date;
+import java.util.List;
+
+import de.intevation.flys.client.server.auth.DefaultUser;
+
+public class User
+extends DefaultUser
+implements de.intevation.flys.client.server.auth.User {
+
+    private Assertion assertion;
+
+    public User(String name,
+        String       password,
+        String       account,
+        List<String> roles,
+        Assertion    assertion,
+        List<String> features
+    ) {
+        this.setName(name);
+        this.setPassword(password);
+        this.setRoles(roles);
+        this.assertion = assertion;
+        this.setAllowedFeatures(features);
+        this.setAccount(account);
+    }
+
+    @Override
+    public boolean hasExpired() {
+        Date until = this.assertion.getUntil();
+        if (until != null) {
+            Date current = new Date();
+            return !current.after(until);
+        }
+        return false;
+    }
+}
+
+// vim:set ts=4 sw=4 si et fenc=utf8 tw=80:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/features/Features.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,13 @@
+package de.intevation.flys.client.server.features;
+
+import java.util.List;
+
+public interface Features {
+
+    public static final String CONTEXT_ATTRIBUTE = "de.intevation.flys.client.server.features";
+
+    /**
+     * Returns all allowed features to a list of roles
+     */
+    public List<String> getFeatures(List<String> roles);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/features/FeaturesNamespaceContext.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,80 @@
+package de.intevation.flys.client.server.features;
+
+import java.util.Iterator;
+
+import javax.xml.XMLConstants;
+
+import javax.xml.namespace.NamespaceContext;
+
+public class FeaturesNamespaceContext
+implements   NamespaceContext {
+
+    /**
+     * The URI of the namespace of the features.
+     */
+    public final static String NAMESPACE_URI =
+        "http://www.intevation.de/2012/flys/features";
+
+    /**
+     * The XML prefix for the features namespace.
+     */
+    public final static String NAMESPACE_PREFIX = "ftr";
+
+    /**
+     * Final instance to be easily used to avoid creation
+     * of instances.
+     */
+    public static final FeaturesNamespaceContext INSTANCE =
+        new FeaturesNamespaceContext();
+
+    /**
+     * The default constructor.
+     */
+    public FeaturesNamespaceContext() {
+    }
+
+    /**
+     * @see javax.xml.namespace.NamespaceContext#getNamespaceURI(String)
+     * @param prefix The prefix
+     * @return The corresponing URI
+     */
+    @Override
+    public String getNamespaceURI(String prefix) {
+
+        if (prefix == null) {
+            throw new NullPointerException("Null prefix");
+        }
+
+        if (NAMESPACE_PREFIX.equals(prefix)) {
+            return NAMESPACE_URI;
+        }
+
+        if ("xml".equals(prefix)) {
+            return XMLConstants.XML_NS_URI;
+        }
+
+        return XMLConstants.NULL_NS_URI;
+    }
+
+    /**
+     * @see javax.xml.namespace.NamespaceContext#getPrefix(String)
+     * @param uri The URI
+     * @return nothing.
+     * @throws java.lang.UnsupportedOperationException
+     */
+    @Override
+    public String getPrefix(String uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @see javax.xml.namespace.NamespaceContext#getPrefixes(java.lang.String)
+     * @param uri The URI
+     * @return nothing
+     * @throws java.lang.UnsupportedOperationException
+     */
+    @Override
+    public Iterator getPrefixes(String uri) {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/features/XMLFileFeatures.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,96 @@
+package de.intevation.flys.client.server.features;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.xpath.XPathConstants;
+
+import org.apache.log4j.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import de.intevation.artifacts.common.utils.XMLUtils;
+
+public class XMLFileFeatures implements Features {
+
+    private static final Logger logger =
+        Logger.getLogger(XMLFileFeatures.class);
+
+    private Map<String, List<String>> featuremap =
+        new HashMap<String, List<String>>();
+
+    private final static String XPATH_FEATURES = "ftr:feature/child::text()";
+    private final static String XPATH_ROLES    = "/ftr:features/ftr:role";
+
+    public XMLFileFeatures(String filename) throws IOException {
+        FileInputStream finput = new FileInputStream(filename);
+
+        try {
+            Document doc = XMLUtils.parseDocument(finput);
+
+            NodeList roles = (NodeList) XMLUtils.xpath(
+                doc,
+                XPATH_ROLES,
+                XPathConstants.NODESET,
+                FeaturesNamespaceContext.INSTANCE);
+
+            for(int i = 0, m = roles.getLength(); i < m; i++) {
+                Element rolenode = (Element)roles.item(i);
+
+                String name = rolenode.getAttribute("name");
+
+                logger.debug("Found role: " + name);
+
+                NodeList features = (NodeList) XMLUtils.xpath(
+                    rolenode,
+                    XPATH_FEATURES,
+                    XPathConstants.NODESET,
+                    FeaturesNamespaceContext.INSTANCE);
+
+                if (features == null) {
+                    continue;
+                }
+
+                int N = features.getLength();
+
+                if (N > 0) {
+                    List<String> allowed = new ArrayList<String>(N);
+                    for (int j = 0; j < N; j++) {
+                        Node featurenode = features.item(j);
+                        String featurename = featurenode.getNodeValue();
+
+                        logger.debug("Found feature: " + featurename);
+
+                        allowed.add(featurename);
+                    }
+                    featuremap.put(name, allowed);
+                }
+            }
+            logger.debug("Loaded all features");
+        }
+        finally {
+            finput.close();
+        }
+    }
+
+    @Override
+    public List<String> getFeatures(List<String> roles) {
+        List<String> features = new ArrayList<String>();
+
+        for (String role: roles) {
+            List<String> allowed = this.featuremap.get(role);
+            if (allowed != null) {
+                features.addAll(allowed);
+            }
+        }
+        return features;
+    }
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/server/meta/Converter.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/server/meta/Converter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -19,6 +19,10 @@
 
 import de.intevation.artifacts.common.utils.XMLUtils;
 
+/**
+ * Converts document parts (meta-data xml) to datacagenodes/trees,
+ * which are shown in datacage widgets.
+ */
 public class Converter
 {
     private static final Logger logger = Logger.getLogger(Converter.class);
@@ -58,42 +62,24 @@
         }
     } // I18NConverter
 
-    protected Map<String, NodeConverter> converters;
+    private static Map<String, NodeConverter> converters = new HashMap<String, NodeConverter>();
 
-    protected void convertChildren(DataCageNode parent, Element sub) {
-        //System.err.println("convertChildren called");
-        NodeList children = sub.getChildNodes();
-        for (int i = 0, N = children.getLength(); i < N; ++i) {
-            Node child = children.item(i);
-            if (child.getNodeType() == Node.ELEMENT_NODE) {
-                String name = child.getLocalName();
-                NodeConverter converter = converters.get(name);
-                if (converter == null) {
-                    converter = I18N_CONVERTER;
-                }
-                DataCageNode son = converter.convert(
-                    (Element)child, this);
-                parent.addChild(son);
-            }
-        } // for all children
-    }
+    public static final NodeConverter NAME_CONVERTER = new NameConverter();
+    public static final NodeConverter I18N_CONVERTER = new I18NConverter();
 
-    public Converter() {
-        converters = new HashMap<String, NodeConverter>();
-        registerConverters();
-    }
-
-    public static final NodeConverter NAME_CONVERTER = new NameConverter(); 
-    public static final NodeConverter I18N_CONVERTER = new I18NConverter(); 
-
-    protected void registerConverters() {
-        logger.debug("register converters called");
+    static {
         converters.put("river",      NAME_CONVERTER);
         converters.put("gauge",      NAME_CONVERTER);
         converters.put("historical", NAME_CONVERTER);
         converters.put("column",     NAME_CONVERTER);
     }
 
+
+    /** Trivial constructor. */
+    public Converter() {
+    }
+
+
     public DataCageTree convert(Document document) {
         logger.debug("convert called");
         //System.err.println(XMLUtils.toString(document));
@@ -116,6 +102,31 @@
             : new DataCageTree(roots.get(0));
     }
 
+    protected void convertChildren(DataCageNode parent, Element sub) {
+        //System.err.println("convertChildren called");
+        NodeList children = sub.getChildNodes();
+        for (int i = 0, N = children.getLength(); i < N; ++i) {
+            Node child = children.item(i);
+            if (child.getNodeType() == Node.ELEMENT_NODE) {
+                String name = child.getLocalName();
+                NodeConverter converter = converters.get(name);
+                if (converter == null) {
+                    converter = I18N_CONVERTER;
+                }
+                DataCageNode son = converter.convert(
+                    (Element)child, this);
+                parent.addChild(son);
+
+            if (((Element)child).hasAttribute("description"))
+                logger.debug("nwd: " + ((Element)child).getAttribute("description"));
+            }
+        } // for all children
+    }
+
+
+    /**
+     * Creates key/value pairs from Nodes Attributes.
+     */
     public static AttrList toAttrList(NamedNodeMap nodeMap) {
         if (nodeMap == null) {
             return null;
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/DoubleUtils.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/DoubleUtils.java	Fri Sep 28 12:15:52 2012 +0200
@@ -50,5 +50,32 @@
             ? mm
             : null;
     }
+
+    /** toIndex is not inclusive, fromIndex is. */
+    static void fill(double[] array, int fromIndex, int toIndex, double val) {
+        for (int i = fromIndex; i < toIndex; i++) {
+            array[i] = val;
+        }
+    }
+
+    /** @see java.util.Arrays.copyOf */
+    public static double[] copyOf(double[] toCopy, int newLen) {
+        double[] nArray = new double[newLen];
+
+        if (toCopy == null) {
+            fill(nArray, 0, nArray.length, 0d);
+            return nArray;
+        }
+
+        int goTo = (newLen < toCopy.length)
+            ? newLen
+            : toCopy.length;
+
+        for (int i = 0; i < goTo; i++) {
+            nArray[i] = toCopy[i];
+        }
+        fill (nArray, goTo, nArray.length, 0d);
+        return nArray;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/MapUtils.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/MapUtils.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,5 +1,7 @@
 package de.intevation.flys.client.shared;
 
+import java.util.Date;
+
 
 public class MapUtils {
 
@@ -22,6 +24,7 @@
         String url = GET_LEGEND_GRAPHIC_TEMPLATE;
         url = url.replace("${SERVER}", server);
         url = url.replace("${LAYER}", layer);
+        url = url + "&timestamp=" + new Date().getTime();
 
         return url;
     }
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/Transform2D.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/Transform2D.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,8 +1,12 @@
 package de.intevation.flys.client.shared;
 
 import java.io.Serializable;
+import java.util.Date;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+import com.google.gwt.i18n.client.NumberFormat;
 
 
 /**
@@ -13,6 +17,9 @@
  */
 public class Transform2D implements Serializable {
 
+    protected String xType;
+    protected String yType;
+
     protected double sx;
     protected double sy;
 
@@ -33,6 +40,19 @@
      * @param ty The translation factor for the y axis.
      */
     public Transform2D(double sx, double sy, double tx, double ty) {
+        this(sx, sy, tx, ty, "number", "number");
+    }
+
+
+    public Transform2D(
+        double sx, double sy,
+        double tx, double ty,
+        String xType,
+        String yType
+    ) {
+        this.xType = xType;
+        this.yType = yType;
+
         this.sx  = sx;
         this.sy  = sy;
         this.tx  = tx;
@@ -52,6 +72,53 @@
     }
 
 
+    public String[] format(Number[] xy) {
+        String x = null;
+        String y = null;
+
+        if (xType.equals("date")) {
+            x = formatDate(xy[0].longValue());
+        }
+        else {
+            x = formatNumber(xy[0].doubleValue());
+        }
+
+        if (yType.equals("date")) {
+            y = formatDate(xy[1].longValue());
+        }
+        else {
+            y = formatNumber(xy[1].doubleValue());
+        }
+
+        return new String[] { x, y };
+    }
+
+
+    protected String formatDate(long time) {
+        Date date = new Date(time);
+        DateTimeFormat df = getDateTimeFormat();
+
+        return df.format(date);
+    }
+
+
+    protected String formatNumber(double number) {
+        NumberFormat nf = getNumberFormat();
+
+        return nf.format(number);
+    }
+
+
+    public DateTimeFormat getDateTimeFormat() {
+        return DateTimeFormat.getFormat(PredefinedFormat.DATE_SHORT);
+    }
+
+
+    public NumberFormat getNumberFormat() {
+        return NumberFormat.getDecimalFormat();
+    }
+
+
     public void dumpGWT() {
         GWT.log("SX = " + sx);
         GWT.log("SY = " + sy);
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/Artifact.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/Artifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -30,8 +30,9 @@
 
     /**
      * Returns the name of the artifact.
+     * This happens to be the factory name, too.
      *
-     * @return the name-
+     * @return the name.
      */
     public String getName();
 
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/ArtifactDescription.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/ArtifactDescription.java	Fri Sep 28 12:15:52 2012 +0200
@@ -63,6 +63,24 @@
 
 
     /**
+     * Returns the selected reference gauge (which needs to be a data named
+     * 'reference_gauge'.
+     *
+     * @return the selected reference gauge (which needs to be a data named
+     * 'reference_gauge'.
+     */
+    public String getReferenceGauge();
+
+
+    /**
+     * Returns the string value of a data object with name <i>dataName</i>.
+     *
+     * @return the string value of a data object with name <i>dataName</i>.
+     */
+    public String getDataValueAsString(String dataName);
+
+
+    /**
      * Returns the available output modes.
      *
      * @return the available output modes.
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/Axis.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/Axis.java	Fri Sep 28 12:15:52 2012 +0200
@@ -6,52 +6,16 @@
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
-public class Axis implements Serializable {
-
-    protected int pos;
-
-    protected double from;
-    protected double to;
-
-    protected double min;
-    protected double max;
-
-
-    public Axis() {
-    }
-
-
-    public Axis(int pos, double from, double to, double min, double max) {
-        this.pos  = pos;
-        this.from = from;
-        this.to   = to;
-        this.min  = min;
-        this.max  = max;
-    }
+public interface Axis extends Serializable {
 
-
-    public int getPos() {
-        return pos;
-    }
-
-
-    public double getFrom() {
-        return from;
-    }
-
+    int getPos();
 
-    public double getTo() {
-        return to;
-    }
-
+    Number getFrom();
 
-    public double getMin() {
-        return min;
-    }
+    Number getTo();
 
+    Number getMin();
 
-    public double getMax() {
-        return max;
-    }
+    Number getMax();
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/BooleanProperty.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/BooleanProperty.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,8 +1,53 @@
 package de.intevation.flys.client.shared.model;
 
+import java.util.HashMap;
+
 /**
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
 public class BooleanProperty extends PropertySetting {
 
+    /**
+     * Create a new BooleanProperty for settings.
+     */
+    public BooleanProperty() {
+        this.attributes = new HashMap<String, String>();
+    }
+
+
+    /**
+     * Create a new BooleanProperty.
+     * @param name The attribute name.
+     * @param value The current value.
+     */
+    public BooleanProperty(
+        String name,
+        Boolean value)
+    {
+        this.name = name;
+        this.value = value.toString();
+        this.attributes = new HashMap<String, String>();
+    }
+
+
+    @Override
+    public Boolean getValue() {
+        return Boolean.valueOf(this.value);
+    }
+
+
+    public void setValue(Boolean value) {
+        this.value = value.toString();
+    }
+
+
+    public Object clone() {
+        BooleanProperty clone = new BooleanProperty(this.getName(),
+                                                    this.getValue());
+        for(String s: this.getAttributeList()) {
+            clone.setAttribute(s, this.getAttribute(s));
+        }
+        return clone;
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/ChartArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,40 @@
+package de.intevation.flys.client.shared.model;
+
+import java.util.List;
+
+
+/**
+ * The Chart implementation of an Artifact.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class ChartArtifact extends DefaultArtifact {
+
+    /** The name of this artifact: 'new_chart'.*/
+    public static final String NAME = "new_chart";
+
+
+    public ChartArtifact() {
+    }
+
+
+    public  ChartArtifact(String uuid, String hash) {
+        super(uuid, hash);
+    }
+
+
+    public ChartArtifact(
+        String                   uuid,
+        String                   hash,
+        boolean                  inBackground,
+        List<CalculationMessage> messages
+    ) {
+        super(uuid, hash, inBackground, messages);
+    }
+
+
+    public String getName() {
+        return NAME;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/ChartInfo.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/ChartInfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -8,6 +8,8 @@
 
 
 /**
+ * Give information about chart dimension and transform of chart<->pixel
+ * space.
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class ChartInfo implements Serializable {
@@ -38,6 +40,11 @@
     }
 
 
+    public int getTransformerCount() {
+        return transformer.length;
+    }
+
+
     public int getXAxisCount() {
         return xAxes.length;
     }
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/ChartMode.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/ChartMode.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,6 +5,7 @@
 import de.intevation.flys.client.client.ui.CollectionView;
 import de.intevation.flys.client.client.ui.OutputTab;
 import de.intevation.flys.client.client.ui.chart.ChartOutputTab;
+import de.intevation.flys.client.client.ui.chart.NaviChartOutputTab;
 
 
 /**
@@ -25,14 +26,22 @@
         String name,
         String descrition,
         String mimeType,
-        List<Facet> facets)
+        List<Facet> facets,
+        String type)
     {
         super(name, descrition, mimeType, facets);
+        this.type = type;
     }
 
 
     @Override
     public OutputTab createOutputTab(String t, Collection c, CollectionView p) {
+        if (this.getName().equals("fix_wq_curve") ||
+            this.getName().equals("fix_deltawt_curve") ||
+            this.getName().equals("fix_derivate_curve") ||
+            this.getName().equals("fix_vollmer_wq_curve")){
+            return new NaviChartOutputTab(t, c, this, p);
+        }
         return new ChartOutputTab(t, c, this, p);
     }
 }
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/Collection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/Collection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -34,6 +34,8 @@
 
     public CollectionItem getItem(int idx);
 
+    public CollectionItem getItem(String uuid);
+
     public Map<String, OutputMode> getOutputModes();
 
     public ThemeList getThemeList(String outName);
@@ -42,6 +44,8 @@
 
     public void setSettings(Map<String, Settings> settings);
 
+    public void addSettings(String name, Settings settings);
+
     /** Sets mapping outputname to ThemeList. */
     public void setThemeLists(Map<String, ThemeList> map);
 
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/Data.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/Data.java	Fri Sep 28 12:15:52 2012 +0200
@@ -50,5 +50,13 @@
      * @return the default value.
      */
     public DataItem getDefault();
+
+
+    /**
+     * Returns the values as colon separated string.
+     *
+     * @return colon separated string.
+     */
+    public String getStringValue();
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/DataList.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DataList.java	Fri Sep 28 12:15:52 2012 +0200
@@ -21,6 +21,9 @@
     /** The label that should be used to label data objects. */
     protected String label;
 
+    /** The help text (URL) that should be displayed for this data object. */
+    protected String helpText;
+
 
     /**
      * The default constructor that creates a new DataList without Data objects
@@ -73,6 +76,28 @@
 
 
     /**
+     * A constructor that creates a new DataList without Data objects and no
+     * UIProvider. Size defines the initial size of the list.
+     *
+     * @param state The name of the state that this list belongs to.
+     * @param size The initial size of the list.
+     * @param uiprovider The UIProvider that should be used to render this list.
+     * @param label The label.
+     * @param helpText The help text (should be an URL).
+     */
+    public DataList(
+        String state,
+        int    size,
+        String uiprovider,
+        String label,
+        String helpText
+    ) {
+        this(state, size, uiprovider, label);
+        this.helpText = helpText;
+    }
+
+
+    /**
      * Adds a new Data object to the list.
      *
      * @param obj The Data object.
@@ -163,12 +188,23 @@
     }
 
 
+    /**
+     * Returns the help text which should be an URL.
+     *
+     * @return the help text.
+     */
+    public String getHelpText() {
+        return helpText;
+    }
+
+
     public Object clone() {
         DataList clone = new DataList(
             this.state,
             this.data.size(),
             this.uiprovider,
-            this.label);
+            this.label,
+            this.helpText);
         clone.data = (List<Data>) ((ArrayList<Data>)data).clone();
 
         return clone;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DateAxis.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,64 @@
+package de.intevation.flys.client.shared.model;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DateAxis implements Axis {
+
+    public static final String TYPE = "date";
+
+
+    protected int pos;
+
+    protected long from;
+    protected long to;
+
+    protected long min;
+    protected long max;
+
+
+    public DateAxis() {
+    }
+
+
+    public DateAxis(int pos, long from, long to, long min, long max) {
+        this.pos  = pos;
+        this.from = from;
+        this.to   = to;
+        this.min  = min;
+        this.max  = max;
+    }
+
+
+    @Override
+    public int getPos() {
+        return pos;
+    }
+
+
+    @Override
+    public Number getFrom() {
+        return from;
+    }
+
+
+    @Override
+    public Number getTo() {
+        return to;
+    }
+
+
+    @Override
+    public Number getMin() {
+        return min;
+    }
+
+
+    @Override
+    public Number getMax() {
+        return max;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultArtifactDescription.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultArtifactDescription.java	Fri Sep 28 12:15:52 2012 +0200
@@ -112,23 +112,11 @@
 
 
     public String getRiver() {
-        for (DataList list: oldData) {
-            List<Data> dataList = list.getAll();
-
-            for (Data d: dataList) {
-                String dataName = d.getLabel();
-                DataItem item   = d.getItems()[0];
-
-                if (dataName.equals("river")) {
-                    return item.getStringValue();
-                }
-            }
-        }
-
-        return null;
+        return getDataValueAsString("river");
     }
 
 
+    /** Get [min,max] of data items. */
     public double[] getKMRange() {
         Double[] mm = new Double[2];
 
@@ -139,14 +127,14 @@
                 String dataName = data.getLabel();
                 DataItem item   = data.getItems()[0];
 
-                if (dataName.equals("ld_from")) {
+                if (dataName.equals("ld_from") || dataName.equals("from")) {
                     Double d = DoubleUtils.getDouble(item.getStringValue());
 
                     if (d != null) {
                         mm[0] = d;
                     }
                 }
-                else if (dataName.equals("ld_to")) {
+                else if (dataName.equals("ld_to") || dataName.equals("to")) {
                     Double d = DoubleUtils.getDouble(item.getStringValue());
 
                     if (d != null) {
@@ -165,5 +153,31 @@
 
         return null;
     }
+
+
+    public String getReferenceGauge() {
+        return getDataValueAsString("reference_gauge");
+    }
+
+
+    public String getDataValueAsString(String name) {
+        if (oldData == null) {
+            return null;
+        }
+        for (DataList list: oldData) {
+            List<Data> dataList = list.getAll();
+
+            for (Data d: dataList) {
+                String dataName = d.getLabel();
+                DataItem item   = d.getItems()[0];
+
+                if (dataName.equals(name)) {
+                    return item.getStringValue();
+                }
+            }
+        }
+
+        return null;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultCollection.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultCollection.java	Fri Sep 28 12:15:52 2012 +0200
@@ -104,6 +104,7 @@
         this.settings = settings;
     }
 
+
     /**
      * Creates a new DefaultCollection with uuid and name.
      *
@@ -169,6 +170,7 @@
     }
 
 
+    /** Returns item at index (0-based), or null if out of range. */
     public CollectionItem getItem(int idx) {
         if (idx >= getItemLength()) {
             return null;
@@ -178,6 +180,23 @@
     }
 
 
+    /**
+     * Get item whose identifier is the given string.
+     * @param uuid identifier of collection item (artifacts uuid).
+     * @return CollectionItem whose identifier is given String, null if not found.
+     */
+    public CollectionItem getItem(String uuid) {
+        int size = getItemLength();
+        for (int i = 0; i < size; i++) {
+            CollectionItem item = getItem(i);
+            if (item.identifier().equals(uuid)) {
+                return item;
+            }
+        }
+        return null;
+    }
+
+
     public Map<String, OutputMode> getOutputModes() {
         Map<String, OutputMode> modes = new HashMap<String, OutputMode>();
 
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultData.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,7 +1,5 @@
 package de.intevation.flys.client.shared.model;
 
-import de.intevation.flys.client.shared.model.DefaultDataItem;
-
 /**
  * The default implementation of a {@link Data} item. This class just implements
  * constructors to create instances and the necessary methods of the interface.
@@ -115,5 +113,23 @@
         return new Data[]
             { new DefaultData(name, null, null, new DataItem[] {d})};
     }
+
+    /**
+     * Returns the values as colon separated string.
+     *
+     * @return colon separated string.
+     */
+    public String getStringValue() {
+        String data = "";
+        boolean first = true;
+        for (int i = 0; i < items.length; i++) {
+            if (!first) {
+                data += ";";
+            }
+            data += items[i].getStringValue();
+            first = false;
+        }
+        return data;
+    }
 }
 // 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-client/src/main/java/de/intevation/flys/client/shared/model/DefaultGaugeInfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,151 @@
+package de.intevation.flys.client.shared.model;
+
+/**
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public class DefaultGaugeInfo implements GaugeInfo {
+
+    private String name;
+    private Double start;
+    private Double end;
+    private Double aeo;
+    private Double datum;
+    private Double minq;
+    private Double maxq;
+    private Double minw;
+    private Double maxw;
+    private boolean kmup;
+    private Double station;
+    private String wstunit;
+    private Long officialnumber;
+    private String rivername;
+
+    public DefaultGaugeInfo() {
+    }
+
+    public DefaultGaugeInfo(
+            String rivername,
+            String name,
+            boolean kmup,
+            Double station,
+            Double start,
+            Double end,
+            Double datum,
+            Double aeo,
+            Double minq,
+            Double maxq,
+            Double minw,
+            Double maxw,
+            String wstunit,
+            Long official)
+    {
+        this.rivername      = rivername;
+        this.name           = name;
+        this.kmup           = kmup;
+        this.station        = station;
+        this.start          = start;
+        this.end            = end;
+        this.datum          = datum;
+        this.aeo            = aeo;
+        this.minq           = minq;
+        this.maxq           = maxq;
+        this.minw           = minw;
+        this.maxw           = maxw;
+        this.wstunit        = wstunit;
+        this.officialnumber = official;
+    }
+    /**
+     * Returns the name of the gauge
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Returns the start KM of the gauge or null if not available
+     */
+    public Double getKmStart() {
+        return this.start;
+    }
+
+    /**
+     * Returns the end KM of the gauge or null if not available
+     */
+    public Double getKmEnd() {
+        return this.end;
+    }
+
+    /**
+     * Returns the mimimum Q value at this gauge or null if not available
+     */
+    public Double getMinQ() {
+        return this.minq;
+    }
+
+    /**
+     * Returns the maximum Q value at this gauge or null if not available
+     */
+    public Double getMaxQ() {
+        return this.maxq;
+    }
+
+    /**
+     * Returns the mimimum W value at this gauge or null if not available
+     */
+    public Double getMinW() {
+        return this.minw;
+    }
+
+    /**
+     * Returns the maximim W value at this gauge or null if not available
+     */
+    public Double getMaxW() {
+        return this.maxw;
+    }
+
+    /**
+     * Returns the datum value or null if not available
+     */
+    public Double getDatum() {
+        return this.datum;
+    }
+
+    /**
+     * Returns the aeo value or null if not available
+     */
+    public Double getAeo() {
+        return this.aeo;
+    }
+
+    public boolean isKmUp() {
+        return this.kmup;
+    }
+
+    /**
+     * Returns the station km of the gauge or null if not available
+     */
+    public Double getStation() {
+        return this.station;
+    }
+
+    /**
+     * Returns the wst unit as a String
+     */
+    public String getWstUnit() {
+        return this.wstunit;
+    }
+
+    /**
+     * Returns the official number of this gauge
+     */
+    public Long getOfficialNumber() {
+        return this.officialnumber;
+    }
+
+    /**
+     * Returns the river to which this gauge belongs
+     */
+    public String getRiverName() {
+        return this.rivername;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultModule.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,39 @@
+package de.intevation.flys.client.shared.model;
+
+public class DefaultModule implements Module {
+
+    private String name;
+    private String localname;
+    private boolean selected = false;
+
+    public DefaultModule() {
+    }
+
+    public DefaultModule(String name, String localname, boolean selected) {
+        this.name = name;
+        this.localname = localname;
+        this.selected = selected;
+    }
+
+    /**
+     * Returns the name of the module
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Returns the localized name of the module
+     */
+    public String getLocalizedName() {
+        return this.localname;
+    }
+
+    /**
+     * Returns true if the module should be selected
+     */
+    public boolean isSelected() {
+        return this.selected;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultRiverInfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,107 @@
+package de.intevation.flys.client.shared.model;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+
+public class DefaultRiverInfo implements RiverInfo {
+
+    private String name;
+    private boolean kmup;
+    private Double start;
+    private Double end;
+    private String wstunit;
+    private Double minq;
+    private Double maxq;
+    private Long officialnumber;
+
+    private List<GaugeInfo> gaugeinfo;
+
+    public DefaultRiverInfo() {
+    }
+
+    public DefaultRiverInfo(
+            String name,
+            boolean kmup,
+            Double start,
+            Double end,
+            String wstunit,
+            Double minq,
+            Double maxq,
+            Long official,
+            List<GaugeInfo> gaugeinfo)
+    {
+        this.name           = name;
+        this.kmup           = kmup;
+        this.start          = start;
+        this.end            = end;
+        this.wstunit        = wstunit;
+        this.minq           = minq;
+        this.maxq           = maxq;
+        this.officialnumber = official;
+        this.gaugeinfo      = gaugeinfo;
+    }
+
+
+    public boolean isKmUp() {
+        return this.kmup;
+    }
+
+    /**
+     * Start KM of the river
+     */
+    public Double getKmStart() {
+        return this.start;
+    }
+
+    /**
+     * End KM of the river
+     */
+    public Double getKmEnd() {
+        return this.end;
+    }
+
+    /**
+     * Returns the name of the river
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Returns the name of the WST unit
+     */
+    public String getWstUnit() {
+        return this.wstunit;
+    }
+
+    /**
+     * Return all gauge info of the river
+     */
+    public List<GaugeInfo> getGauges() {
+        return this.gaugeinfo;
+    }
+
+    /**
+     * Returns the min q value of the river
+     */
+    public Double getMinQ() {
+        return this.minq;
+    }
+
+    /**
+     * Returns the max q value of the river
+     */
+    public Double getMaxQ() {
+        return maxq;
+    }
+
+    /**
+     * Returns the official number of the river
+     */
+    public Long getOfficialNumber() {
+        return this.officialnumber;
+    }
+}
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultTheme.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DefaultTheme.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,8 +1,5 @@
 package de.intevation.flys.client.shared.model;
 
-import de.intevation.flys.client.shared.model.CollectionItem;
-
-
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DischargeInfoObject.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.client.shared.model;
+
+import java.io.Serializable;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public interface DischargeInfoObject extends Serializable {
+
+    String getDescription();
+
+    Integer getStartYear();
+
+    Integer getEndYear();
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/DischargeInfoObjectImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,44 @@
+package de.intevation.flys.client.shared.model;
+
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class DischargeInfoObjectImpl implements DischargeInfoObject {
+
+    protected String description;
+
+    protected Integer startYear;
+
+    protected Integer endYear;
+
+
+    public DischargeInfoObjectImpl() {
+    }
+
+
+    public DischargeInfoObjectImpl(
+        String description,
+        Integer startYear,
+        Integer endYear
+    ) {
+        this.description = description;
+        this.startYear   = startYear;
+        this.endYear     = endYear;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+
+    public Integer getStartYear() {
+        return startYear;
+    }
+
+
+    public Integer getEndYear() {
+        return endYear;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/DoubleArrayData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,126 @@
+package de.intevation.flys.client.shared.model;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class DoubleArrayData implements Data {
+
+    public static final String TYPE = "doublearray";
+
+
+    protected String label;
+    protected String description;
+
+    protected double[] values;
+
+
+    public DoubleArrayData() {
+    }
+
+
+    public DoubleArrayData(String label, String description, double[] values) {
+        this.label       = label;
+        this.description = description;
+        this.values      = values;
+    }
+
+
+    /**
+     * Returns the label of the item.
+     *
+     * @return the label.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+
+    /**
+     * Returns the description of the item.
+     *
+     * @return the description.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the type of the item.
+     *
+     * @return the type.
+     */
+    public String getType() {
+        return TYPE;
+    }
+
+
+    /**
+     * Returns a DataItem which value is a string that consists of the double
+     * values separated by a ';'.
+     *
+     * @return the DataItem.
+     */
+    public DataItem[] getItems() {
+        if (values == null || values.length == 0) {
+            return new DataItem[0];
+        }
+
+        StringBuilder sb    = new StringBuilder();
+        boolean       first = true;
+
+        for (double value: values) {
+            if (first) {
+                sb.append(String.valueOf(value));
+            }
+            else {
+                sb.append(";" + String.valueOf(value));
+            }
+        }
+
+        String  value = sb.toString();
+        DataItem item = new DefaultDataItem(value, value, value);
+
+        return new DataItem[] { item };
+    }
+
+
+    /**
+     * Returns the values as array.
+     *
+     * @return the values as array.
+     */
+    public double[] getValues() {
+        return values;
+    }
+
+
+    /**
+     * @return always null.
+     */
+    public DataItem getDefault() {
+        return null;
+    }
+
+
+    /**
+     * Returns the values as colon separated string.
+     *
+     * @return colon separated string.
+     */
+    public String getStringValue() {
+        String data = "";
+        boolean first = true;
+        for (int i = 0; i < values.length; i++) {
+            if (!first) {
+                data += ";";
+            }
+            data += String.valueOf(values[i]);
+            first = false;
+        }
+        return data;
+    }
+
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/DoubleProperty.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DoubleProperty.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,8 +1,86 @@
 package de.intevation.flys.client.shared.model;
 
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+
+import java.util.HashMap;
+
 /**
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
 public class DoubleProperty extends PropertySetting {
 
+    /**
+     * Create a new DoubleProperty for settings.
+     */
+    public DoubleProperty() {
+        this.attributes = new HashMap<String, String>();
+    }
+
+
+    /**
+     * Create a new DoubleProperty.
+     * @param name The attribute name.
+     * @param value The current value.
+     */
+    public DoubleProperty(
+        String name,
+        Double value)
+    {
+        this.name = name;
+        this.value = value.toString();
+        this.attributes = new HashMap<String, String>();
+    }
+
+    @Override
+    public Double getValue() {
+        try {
+            Double value = Double.valueOf(this.value);
+            GWT.log("returning: " + value);
+            return value;
+        }
+        catch(NumberFormatException nfe) {
+            //Should never happen, if property is used correctly.
+            return null;
+        }
+    }
+
+
+    public void setValueFromUI(String value) {
+        NumberFormat nf = NumberFormat.getDecimalFormat();
+        double d;
+        try {
+            d = nf.parse(value);
+            GWT.log("setting " + value + " as " + d);
+            this.value = Double.toString(d);
+        }
+        catch(NumberFormatException nfe) {}
+    }
+
+    public void setValue(Double value) {
+        this.value = value.toString();
+    }
+
+
+    public String toUIString() {
+        double dv;
+        NumberFormat nf = NumberFormat.getDecimalFormat();
+        try {
+            dv = Double.parseDouble(this.value);
+        }
+        catch (NumberFormatException nfe) {
+            return null;
+        }
+        return nf.format(dv);
+    }
+
+    @Override
+    public Object clone() {
+        DoubleProperty clone = new DoubleProperty(this.getName(),
+                                                  this.getValue());
+        for(String s: this.getAttributeList()) {
+            clone.setAttribute(s, this.getAttribute(s));
+        }
+        return clone;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/DoubleRangeData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,133 @@
+package de.intevation.flys.client.shared.model;
+
+
+public class DoubleRangeData implements RangeData {
+
+    public static final String TYPE = "doublerange";
+
+
+    protected String label;
+    protected String description;
+
+    protected double lower;
+    protected double upper;
+
+    protected Double defLower;
+    protected Double defUpper;
+
+
+    public DoubleRangeData() {
+    }
+
+
+    public DoubleRangeData(String label, String desc, double lower, double upper) {
+        this(label, desc, lower, upper, null, null);
+    }
+
+
+    public DoubleRangeData(
+        String  label,
+        String  desc,
+        double     lower,
+        double     upper,
+        Double defLower,
+        Double defUpper
+    ) {
+        this.label       = label;
+        this.description = desc;
+        this.lower       = lower;
+        this.upper       = upper;
+        this.defLower    = defLower;
+        this.defUpper    = defUpper;
+    }
+
+
+    /**
+     * Returns the label of the item.
+     *
+     * @return the label.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+
+    /**
+     * Returns the description of the item.
+     *
+     * @return the description.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the type of the item.
+     *
+     * @return the type.
+     */
+    public String getType() {
+        return "doublerange";
+    }
+
+
+    /**
+     * Returns a DataItem which value is a string that consists of the min and
+     * max value separated by a ';'.
+     *
+     * @return the DataItem.
+     */
+    public DataItem[] getItems() {
+        String theMin = String.valueOf(lower);
+        String theMax = String.valueOf(upper);
+
+        String label = theMin + " - " + theMax;
+        String value = theMin + ";" + theMax;
+
+        DataItem item  = new DefaultDataItem(label, label, value);
+
+        return new DataItem[] { item };
+    }
+
+
+    /**
+     * @return always null.
+     */
+    public DataItem getDefault() {
+        return null;
+    }
+
+
+    public Object getLower() {
+        return lower;
+    }
+
+
+    public Object getUpper() {
+        return upper;
+    }
+
+
+    public Object getDefaultLower() {
+        return defLower;
+    }
+
+
+    public Object getDefaultUpper() {
+        return defUpper;
+    }
+
+
+    /**
+     * Returns the values as colon separated string.
+     *
+     * @return colon separated string.
+     */
+    public String getStringValue() {
+        String data = lower + ";" + upper;
+        return data;
+    }
+
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/FacetRecord.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/FacetRecord.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,10 +2,8 @@
 
 import com.smartgwt.client.widgets.grid.ListGridRecord;
 
-import de.intevation.flys.client.shared.model.Facet;
-
-
 /**
+ * ListGridRecord for Facets.
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class FacetRecord extends ListGridRecord {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/FixAnalysisArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,150 @@
+package de.intevation.flys.client.shared.model;
+
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+
+
+/**
+ * The Fixanalysis implementation of an Artifact.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class FixAnalysisArtifact extends DefaultArtifact {
+
+    /** The name of this artifact: 'fixanalysis'.*/
+    public static final String NAME = "fixanalysis";
+
+    protected FixFilter filter;
+
+    public FixAnalysisArtifact() {
+        this.filter = null;
+    }
+
+
+    public  FixAnalysisArtifact(String uuid, String hash) {
+        super(uuid, hash);
+        this.filter = null;
+    }
+
+
+    public FixAnalysisArtifact(
+        String                   uuid,
+        String                   hash,
+        boolean                  inBackground,
+        List<CalculationMessage> messages
+    ) {
+        super(uuid, hash, inBackground, messages);
+    }
+
+
+    public String getName() {
+        return NAME;
+    }
+
+
+    public FixFilter getFilter () {
+        return createFilter();
+    }
+
+
+    protected FixFilter createFilter() {
+        if (this.filter == null) {
+            this.filter = new FixFilter();
+        }
+        DataList[] old = artifactDescription.getOldData();
+
+        String river = artifactDescription.getDataValueAsString("river");
+        if (river != null) {
+            this.filter.setRiver(river);
+        }
+
+        String from = artifactDescription.getDataValueAsString("from");
+        if (from != null) {
+            try {
+                double fkm = Double.parseDouble(from);
+                this.filter.setFromKm(fkm);
+            }
+            catch(NumberFormatException nfe) {
+                GWT.log("Could not parse from km.");
+            }
+        }
+
+        String to = artifactDescription.getDataValueAsString("to");
+        if (to != null) {
+            try {
+                double tkm = Double.parseDouble(to);
+                this.filter.setToKm(tkm);
+            }
+            catch(NumberFormatException nfe) {
+                GWT.log("Could not parse to km");
+            }
+        }
+
+        String start = artifactDescription.getDataValueAsString("start");
+        if (start != null) {
+            try {
+                long s = Long.parseLong(start);
+                this.filter.setFromDate(s);
+            }
+            catch(NumberFormatException nfe) {
+                GWT.log("Could not parse start date");
+            }
+        }
+
+        String end = artifactDescription.getDataValueAsString("end");
+        if (end != null) {
+            try {
+                long e = Long.parseLong(end);
+                this.filter.setToDate(e);
+            }
+            catch(NumberFormatException nfe) {
+                GWT.log("Could not parse end date");
+            }
+        }
+
+        String q1 = artifactDescription.getDataValueAsString("q1");
+        if (q1 != null) {
+            try {
+                int q1i = Integer.parseInt(q1);
+                this.filter.setFromClass(q1i);
+            }
+            catch(NumberFormatException nfe) {
+                GWT.log("Could not parse start class");
+            }
+        }
+
+        String q2 = artifactDescription.getDataValueAsString("q2");
+        if (q2 != null) {
+            try {
+                int q2i = Integer.parseInt(q2);
+                this.filter.setToClass(q2i);
+            }
+            catch(NumberFormatException nfe) {
+                GWT.log("could not parse end class");
+            }
+        }
+
+        for (DataList list: old) {
+            List<Data> items = list.getAll();
+            String state = list.getState();
+            if(state.equals("state.fix.eventselect")) {
+                Data de = getData(items, "events");
+                IntegerArrayData iad = (IntegerArrayData) de;
+                this.filter.setEvents(iad.getValues());
+            }
+        }
+
+        return this.filter;
+    }
+
+    protected Data getData(List<Data> data, String name) {
+        for (Data d: data) {
+            if (name.equals(d.getLabel())) {
+                return d;
+            }
+        }
+        return null;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/FixFilter.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,106 @@
+package de.intevation.flys.client.shared.model;
+
+import java.io.Serializable;
+
+
+public class FixFilter implements Serializable{
+
+    protected String river;
+    protected double fromKm;
+    protected double toKm;
+    protected double currentKm;
+    protected int fromClass;
+    protected int toClass;
+    protected long fromDate;
+    protected long toDate;
+    protected boolean hasDate;
+    protected int[] events;
+
+    public FixFilter() {
+        this.river = "";
+        this.fromKm = -Double.MAX_VALUE;
+        this.toKm = -1;
+        this.currentKm = -1;
+        this.fromClass = -1;
+        this.toClass = -1;
+        this.fromDate = -1;
+        this.toDate = -1;
+        this.hasDate = false;
+        this.events = new int[0];
+    }
+
+    public void setRiver(String river) {
+        this.river = river;
+    }
+
+    public void setFromKm(double from) {
+        this.fromKm = from;
+    }
+
+    public void setToKm(double to) {
+        this.toKm = to;
+    }
+
+    public void setCurrentKm(double km) {
+        this.currentKm = km;
+    }
+
+    public void setFromClass(int from) {
+        this.fromClass = from;
+    }
+
+    public void setToClass(int to) {
+        this.toClass = to;
+    }
+
+    public void setFromDate(long from) {
+        this.hasDate = true;
+        this.fromDate = from;
+    }
+
+    public void setToDate(long to) {
+        this.hasDate = true;
+        this.toDate = to;
+    }
+
+    public void setEvents(int[] ev) {
+        this.events = ev;
+    }
+
+    public String getRiver() {
+        return this.river;
+    }
+
+    public double getFromKm() {
+        return this.fromKm;
+    }
+
+    public double getToKm() {
+        return this.toKm;
+    }
+
+    public double getCurrentKm() {
+        return this.currentKm;
+    }
+
+    public int getFromClass() {
+        return this.fromClass;
+    }
+
+    public int getToClass() {
+        return this.toClass;
+    }
+
+    public long getFromDate() {
+        return this.fromDate;
+    }
+
+    public long getToDate() {
+        return this.toDate;
+    }
+
+    public int[] getEvents() {
+        return this.events;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/FixingsOverviewInfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,136 @@
+package de.intevation.flys.client.shared.model;
+
+import java.io.Serializable;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class FixingsOverviewInfo implements Serializable {
+
+    protected List<FixEvent> events;
+    protected String river;
+    protected double from;
+    protected double to;
+    protected int rid;
+    protected String html;
+
+    protected FixingsOverviewInfo() {}
+
+    public FixingsOverviewInfo(
+        int rid,
+        String river,
+        double from,
+        double to,
+        List<FixEvent> events,
+        String html
+    ) {
+        this.rid = rid;
+        this.river = river;
+        this.from = from;
+        this.to = to;
+        this.events = new ArrayList<FixEvent>(events);
+        this.html = html;
+    }
+
+    public int getRId() {
+        return this.rid;
+    }
+
+    public String getRiver() {
+        return this.river;
+    }
+
+    public double getFrom() {
+        return this.from;
+    }
+
+    public double getTo() {
+        return this.to;
+    }
+
+    public List<FixEvent> getEvents() {
+        return this.events;
+    }
+
+    public FixEvent getEventByCId(String cid) {
+        for (int i = 0; i < events.size(); i++) {
+            if (events.get(i).getCId().equals(cid)) {
+                return events.get(i);
+            }
+        }
+        return null;
+    }
+
+    public String getHTML() {
+        return this.html;
+    }
+
+
+    public static class FixEvent implements Serializable {
+        protected String cid;
+        protected String date;
+        protected String description;
+        protected List<Sector> sectors;
+
+        protected FixEvent () {}
+
+        public FixEvent(
+            String cid,
+            String date,
+            String description,
+            List<Sector> sectors
+        ) {
+            this.cid = cid;
+            this.date = date;
+            this.description = description;
+            this.sectors = new ArrayList<Sector>(sectors);
+        }
+
+        public String getCId() {
+            return this.cid;
+        }
+
+        public String getDate() {
+            return this.date;
+        }
+
+        public String getDescription() {
+            return this.description;
+        }
+
+        public List<Sector> getSectors() {
+            return this.sectors;
+        }
+    }
+
+    public static class Sector implements Serializable {
+        protected int cls;
+        protected double from;
+        protected double to;
+
+        protected Sector () {}
+
+        public Sector(
+            int cls,
+            double from,
+            double to
+        ) {
+            this.cls = cls;
+            this.from = from;
+            this.to = to;
+        }
+
+        public int getCls() {
+            return this.cls;
+        }
+
+        public double getFrom() {
+            return this.from;
+        }
+
+        public double getTo() {
+            return this.to;
+        }
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/Gauge.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,13 @@
+package de.intevation.flys.client.shared.model;
+
+import java.io.Serializable;
+
+
+public interface Gauge extends Serializable {
+
+    String getName();
+
+    double getLower();
+
+    double getUpper();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/GaugeDischargeCurveArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,39 @@
+package de.intevation.flys.client.shared.model;
+
+import java.util.List;
+
+/**
+ * The GaugeDischargeCurveArtifact implementation of an Artifact.
+ *
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public class GaugeDischargeCurveArtifact extends DefaultArtifact {
+
+    /** The name of this artifact */
+    public static final String NAME = "gauge_discharge_curve";
+
+
+    public GaugeDischargeCurveArtifact() {
+    }
+
+
+    public GaugeDischargeCurveArtifact(String uuid, String hash) {
+        super(uuid, hash);
+    }
+
+
+    public GaugeDischargeCurveArtifact(
+        String                   uuid,
+        String                   hash,
+        boolean                  inBackground,
+        List<CalculationMessage> messages
+    ) {
+        super(uuid, hash, inBackground, messages);
+    }
+
+
+    public String getName() {
+        return NAME;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/GaugeImpl.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,51 @@
+package de.intevation.flys.client.shared.model;
+
+
+public class GaugeImpl implements Gauge {
+
+    private String name;
+
+    private double lower;
+    private double upper;
+
+
+    public GaugeImpl() {
+    }
+
+
+    public GaugeImpl(String name, double lower, double upper) {
+        this.name  = name;
+        this.lower = lower;
+        this.upper = upper;
+    }
+
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    public String getName() {
+        return name;
+    }
+
+
+    public void setLower(double lower) {
+        this.lower = lower;
+    }
+
+
+    public double getLower() {
+        return lower;
+    }
+
+
+    public void setUpper(double upper) {
+        this.upper = upper;
+    }
+
+
+    public double getUpper() {
+        return upper;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/GaugeInfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,76 @@
+package de.intevation.flys.client.shared.model;
+
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+public interface GaugeInfo extends Serializable {
+
+    /**
+     * Returns the name of the gauge
+     */
+    String getName();
+
+    /**
+     * Returns the start KM of the gauge or null if not available
+     */
+    Double getKmStart();
+
+    /**
+     * Returns the end KM of the gauge or null if not available
+     */
+    Double getKmEnd();
+
+    /**
+     * Returns the mimimum Q value at this gauge or null if not available
+     */
+    Double getMinQ();
+
+    /**
+     * Returns the maximum Q value at this gauge or null if not available
+     */
+    Double getMaxQ();
+
+    /**
+     * Returns the mimimum W value at this gauge or null if not available
+     */
+    Double getMinW();
+
+    /**
+     * Returns the maximim W value at this gauge or null if not available
+     */
+    Double getMaxW();
+
+    /**
+     * Returns the datum value or null if not available
+     */
+    Double getDatum();
+
+    /**
+     * Returns the aeo value or null if not available
+     */
+    Double getAeo();
+
+    boolean isKmUp();
+
+    /**
+     * Returns the station km of the gauge or null if not available
+     */
+    Double getStation();
+
+    /**
+     * Returns the wst unit as a String
+     */
+    String getWstUnit();
+
+    /**
+     * Returns the official number of this gauge
+     */
+    Long getOfficialNumber();
+
+    /**
+     * Returns the river to which this gauge belongs
+     */
+    String getRiverName();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/IntDataItem.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,57 @@
+package de.intevation.flys.client.shared.model;
+
+
+/**
+ * The integer implementation of a {@link DataItem}.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class IntDataItem implements DataItem {
+
+    /** The label. */
+    protected String label;
+
+    /** The description. */
+    protected String description;
+
+    /** The value. */
+    protected int value;
+
+
+    public IntDataItem() {
+    }
+
+
+    /**
+     * The default constructor to create new instances.
+     *
+     * @param label The label.
+     * @param description The description.
+     * @param value The value.
+     */
+    public IntDataItem(String label, String description, int value) {
+        this.label       = label;
+        this.description = description;
+        this.value       = value;
+    }
+
+
+    public String getLabel() {
+        return label;
+    }
+
+
+    public String getDescription() {
+        return description;
+    }
+
+
+    public String getStringValue() {
+        return String.valueOf(value);
+    }
+
+    public int getValue() {
+        return value;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/IntegerArrayData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,110 @@
+package de.intevation.flys.client.shared.model;
+
+
+public class IntegerArrayData implements Data {
+
+    public static final String TYPE = "intarray";
+
+
+    protected String label;
+    protected String description;
+
+    protected IntDataItem[] values;
+
+
+    public IntegerArrayData() {
+    }
+
+
+    public IntegerArrayData(
+        String label,
+        String description,
+        IntDataItem[] values
+    ) {
+        this.label       = label;
+        this.description = description;
+        this.values      = values;
+    }
+
+
+    /**
+     * Returns the label of the item.
+     *
+     * @return the label.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+
+    /**
+     * Returns the description of the item.
+     *
+     * @return the description.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the type of the item.
+     *
+     * @return the type.
+     */
+    public String getType() {
+        return "intarray";
+    }
+
+
+    /**
+     * Returns a DataItem which value is a string that consists of the integer
+     * values separated by a ';'.
+     *
+     * @return the DataItem.
+     */
+    public DataItem[] getItems() {
+        return values;
+    }
+
+
+    /**
+     * Returns the values as array.
+     *
+     * @return the values as array.
+     */
+    public int[] getValues() {
+        int[] data = new int[values.length];
+        for (int i = 0; i < values.length; i++) {
+            data[i] = values[i].getValue();
+        }
+        return data;
+    }
+
+
+    /**
+     * Returns the values as colon separated string.
+     *
+     * @return colon separated string.
+     */
+    public String getStringValue() {
+        String data = "";
+        boolean first = true;
+        for (int i = 0; i < values.length; i++) {
+            if (!first) {
+                data += ";";
+            }
+            data += values[i].getStringValue();
+            first = false;
+        }
+        return data;
+    }
+
+    /**
+     * @return always null.
+     */
+    public DataItem getDefault() {
+        return null;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/IntegerData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,21 @@
+package de.intevation.flys.client.shared.model;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class IntegerData extends DefaultData {
+
+    public static final String TYPE = "integer";
+
+
+    public IntegerData() {
+        super();
+    }
+
+
+    public IntegerData(String name, String description, DataItem[] items) {
+        super(name, description, TYPE, items);
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/IntegerOptionsData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,93 @@
+package de.intevation.flys.client.shared.model;
+
+
+/** Data matching to labelled integer(s). */
+public class IntegerOptionsData implements Data {
+
+    public static final String TYPE = "intoptions";
+
+    protected String label;
+    protected String description;
+
+    public DataItem[] opts;
+
+
+    public IntegerOptionsData() {
+    }
+
+
+    public IntegerOptionsData(String label, String desc, DataItem[] opts) {
+        this.label       = label;
+        this.description = desc;
+        this.opts        = opts;
+    }
+
+
+    /**
+     * Returns the label of the item.
+     *
+     * @return the label.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+
+    /**
+     * Returns the description of the item.
+     *
+     * @return the description.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the type of the item.
+     *
+     * @return the type.
+     */
+    public String getType() {
+        return TYPE;
+    }
+
+
+    /**
+     * Returns the data items which represent the allowed options for this Data.
+     *
+     * @return the allowed options as DataItem array.
+     */
+    public DataItem[] getItems() {
+        return opts;
+    }
+
+
+    /**
+     * @return always null.
+     */
+    public DataItem getDefault() {
+        return null;
+    }
+
+
+    /**
+     * Returns the values as colon separated string.
+     *
+     * @return colon separated string.
+     */
+    public String getStringValue() {
+        String data = "";
+        boolean first = true;
+        for (int i = 0; i < opts.length; i++) {
+            if (!first) {
+                data += ";";
+            }
+            data += opts[i].getStringValue();
+            first = false;
+        }
+        return data;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/IntegerProperty.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/IntegerProperty.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,8 +1,57 @@
 package de.intevation.flys.client.shared.model;
 
+import java.util.HashMap;
+
 /**
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
 public class IntegerProperty extends PropertySetting {
 
+    /**
+     * Create a new IntegerProperty for settings.
+     */
+    public IntegerProperty() {
+        this.attributes = new HashMap<String, String>();
+    }
+
+
+    /**
+     * Create a new IntegerProperty.
+     * @param name The attribute name.
+     * @param value The current value.
+     */
+    public IntegerProperty(
+        String name,
+        Integer value)
+    {
+        this.name = name;
+        this.value = value.toString();
+        this.attributes = new HashMap<String, String>();
+    }
+
+
+    @Override
+    public Integer getValue() {
+        try {
+            return Integer.valueOf(this.value);
+        }
+        catch(NumberFormatException nfe) {
+            return null;
+        }
+    }
+
+
+    public void setValue(Integer value) {
+        this.value = value.toString();
+    }
+
+    public Object clone() {
+        IntegerProperty clone = new IntegerProperty(this.getName(),
+                                                    this.getValue());
+        for(String s: this.getAttributeList()) {
+            clone.setAttribute(s, this.getAttribute(s));
+        }
+        return clone;
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/IntegerRangeData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,144 @@
+package de.intevation.flys.client.shared.model;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class IntegerRangeData implements RangeData {
+
+    public static final String TYPE = "intrange";
+
+
+    protected String label;
+    protected String description;
+
+    protected int lower;
+    protected int upper;
+
+    protected Integer defLower;
+    protected Integer defUpper;
+
+
+    public IntegerRangeData() {
+    }
+
+
+    public IntegerRangeData(String label, String desc, int lower, int upper) {
+        this(label, desc, lower, upper, null, null);
+    }
+
+
+    /**
+     * @param label
+     * @param desc
+     * @param lower
+     * @param upper
+     * @param defLower
+     * @param defUpper
+     */
+    public IntegerRangeData(
+        String  label,
+        String  desc,
+        int     lower,
+        int     upper,
+        Integer defLower,
+        Integer defUpper
+    ) {
+        this.label       = label;
+        this.description = desc;
+        this.lower       = lower;
+        this.upper       = upper;
+        this.defLower    = defLower;
+        this.defUpper    = defUpper;
+    }
+
+
+    /**
+     * Returns the label of the item.
+     *
+     * @return the label.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+
+    /**
+     * Returns the description of the item.
+     *
+     * @return the description.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the type of the item.
+     *
+     * @return the type.
+     */
+    public String getType() {
+        return "intrange";
+    }
+
+
+    /**
+     * Returns a DataItem which value is a string that consists of the min and
+     * max value separated by a ';'.
+     *
+     * @return the DataItem.
+     */
+    public DataItem[] getItems() {
+        String theMin = String.valueOf(lower);
+        String theMax = String.valueOf(upper);
+
+        String label = theMin + " - " + theMax;
+        String value = theMin + ";" + theMax;
+
+        DataItem item  = new DefaultDataItem(label, label, value);
+
+        return new DataItem[] { item };
+    }
+
+
+    /**
+     * @return always null.
+     */
+    public DataItem getDefault() {
+        return null;
+    }
+
+
+    public Object getLower() {
+        return lower;
+    }
+
+
+    public Object getUpper() {
+        return upper;
+    }
+
+
+    public Object getDefaultLower() {
+        return defLower;
+    }
+
+
+    public Object getDefaultUpper() {
+        return defUpper;
+    }
+
+
+    /**
+     * Returns the values as colon separated string.
+     *
+     * @return colon separated string.
+     */
+    public String getStringValue() {
+        String data = lower + ";" + upper;
+        return data;
+    }
+
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/LongRangeData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,143 @@
+package de.intevation.flys.client.shared.model;
+
+/**
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class LongRangeData implements RangeData {
+
+    public static final String TYPE = "longrange";
+
+
+    protected String label;
+    protected String description;
+
+    protected long lower;
+    protected long upper;
+
+    protected Long defLower;
+    protected Long defUpper;
+
+
+    public LongRangeData() {
+    }
+
+
+    public LongRangeData(String label, String desc, long lower, long upper) {
+        this(label, desc, lower, upper, null, null);
+    }
+
+
+    /**
+     * @param label
+     * @param desc
+     * @param lower
+     * @param upper
+     * @param defLower
+     * @param defUpper
+     */
+    public LongRangeData(
+        String  label,
+        String  desc,
+        long    lower,
+        long    upper,
+        Long    defLower,
+        Long    defUpper
+    ) {
+        this.label       = label;
+        this.description = desc;
+        this.lower       = lower;
+        this.upper       = upper;
+        this.defLower    = defLower;
+        this.defUpper    = defUpper;
+    }
+
+
+    /**
+     * Returns the label of the item.
+     *
+     * @return the label.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+
+    /**
+     * Returns the description of the item.
+     *
+     * @return the description.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the type of the item.
+     *
+     * @return the type.
+     */
+    public String getType() {
+        return "longrange";
+    }
+
+
+    /**
+     * Returns a DataItem which value is a string that consists of the min and
+     * max value separated by a ';'.
+     *
+     * @return the DataItem.
+     */
+    public DataItem[] getItems() {
+        String theMin = String.valueOf(lower);
+        String theMax = String.valueOf(upper);
+
+        String label = theMin + " - " + theMax;
+        String value = theMin + ";" + theMax;
+
+        DataItem item  = new DefaultDataItem(label, label, value);
+
+        return new DataItem[] { item };
+    }
+
+
+    /**
+     * @return always null.
+     */
+    public DataItem getDefault() {
+        return null;
+    }
+
+
+    public Object getLower() {
+        return lower;
+    }
+
+
+    public Object getUpper() {
+        return upper;
+    }
+
+
+    public Object getDefaultLower() {
+        return defLower;
+    }
+
+
+    public Object getDefaultUpper() {
+        return defUpper;
+    }
+
+
+    /**
+     * Returns the values as colon separated string.
+     *
+     * @return colon separated string.
+     */
+    public String getStringValue() {
+        String data = lower + ";" + upper;
+        return data;
+    }
+
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/MINFOArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,40 @@
+package de.intevation.flys.client.shared.model;
+
+import java.util.List;
+
+
+/**
+ * The WINFO implementation of an Artifact.
+ *
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class MINFOArtifact extends DefaultArtifact {
+
+    /** The name of this artifact: 'minfo'.*/
+    public static final String NAME = "minfo";
+
+
+    public MINFOArtifact() {
+    }
+
+
+    public  MINFOArtifact(String uuid, String hash) {
+        super(uuid, hash);
+    }
+
+
+    public MINFOArtifact(
+        String                   uuid,
+        String                   hash,
+        boolean                  inBackground,
+        List<CalculationMessage> messages
+    ) {
+        super(uuid, hash, inBackground, messages);
+    }
+
+
+    public String getName() {
+        return NAME;
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/MapArtifact.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,40 @@
+package de.intevation.flys.client.shared.model;
+
+import java.util.List;
+
+
+/**
+ * The MAP implementation of an Artifact.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class MapArtifact extends DefaultArtifact {
+
+    /** The name of this artifact: 'map'.*/
+    public static final String NAME = "new_map";
+
+
+    public MapArtifact() {
+    }
+
+
+    public  MapArtifact(String uuid, String hash) {
+        super(uuid, hash);
+    }
+
+
+    public MapArtifact(
+        String                   uuid,
+        String                   hash,
+        boolean                  inBackground,
+        List<CalculationMessage> messages
+    ) {
+        super(uuid, hash, inBackground, messages);
+    }
+
+
+    public String getName() {
+        return NAME;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/MapMode.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/MapMode.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,21 +1,23 @@
 package de.intevation.flys.client.shared.model;
 
-import java.util.List;
-
 import de.intevation.flys.client.client.ui.CollectionView;
 import de.intevation.flys.client.client.ui.OutputTab;
 import de.intevation.flys.client.client.ui.map.MapOutputTab;
 
+import java.util.List;
+
 
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public class MapMode extends DefaultOutputMode {
 
+    /**
+     * Default constructor required for serialization.
+     */
     public MapMode() {
     }
 
-
     public MapMode(String name, String desc, String mimeType) {
         super(name, desc, mimeType);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/Module.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,13 @@
+package de.intevation.flys.client.shared.model;
+
+import java.io.Serializable;
+
+public interface Module extends Serializable {
+
+    String getName();
+
+    String getLocalizedName();
+
+    boolean isSelected();
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 tw=80 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/NumberAxis.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,60 @@
+package de.intevation.flys.client.shared.model;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class NumberAxis implements Axis {
+
+    protected int pos;
+
+    protected double from;
+    protected double to;
+
+    protected double min;
+    protected double max;
+
+
+    public NumberAxis() {
+    }
+
+
+    public NumberAxis(int pos, double from, double to, double min, double max) {
+        this.pos  = pos;
+        this.from = from;
+        this.to   = to;
+        this.min  = min;
+        this.max  = max;
+    }
+
+
+    @Override
+    public int getPos() {
+        return pos;
+    }
+
+
+    @Override
+    public Number getFrom() {
+        return from;
+    }
+
+
+    @Override
+    public Number getTo() {
+        return to;
+    }
+
+
+    @Override
+    public Number getMin() {
+        return min;
+    }
+
+
+    @Override
+    public Number getMax() {
+        return max;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/OutputSettings.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/OutputSettings.java	Fri Sep 28 12:15:52 2012 +0200
@@ -7,7 +7,7 @@
 /**
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
-public class OutputSettings implements Settings {
+public class OutputSettings implements Settings, Cloneable {
 
     /** The output name. */
     protected String name;
@@ -27,11 +27,13 @@
     }
 
 
+    /** Set output name. */
     public void setName(String name) {
         this.name = name;
     }
 
 
+    /** Get output name. */
     public String getName() {
         return this.name;
     }
@@ -50,8 +52,23 @@
     }
 
 
-    public List getCategories() {
+    public List<String> getCategories() {
         ArrayList<String> list = new ArrayList<String>(categories.keySet());
         return list;
     }
+
+
+    public Object clone() {
+        OutputSettings clone = new OutputSettings(this.getName());
+        for (String s: this.getCategories()) {
+            ArrayList cloneList = new ArrayList<Property>();
+            for(Property p: this.getSettings(s)) {
+                cloneList.add((Property)p.clone());
+            }
+            clone.setSettings(s, cloneList);
+        }
+        return clone;
+    }
 }
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/OverviewMode.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,45 @@
+package de.intevation.flys.client.shared.model;
+
+import java.util.List;
+
+import de.intevation.flys.client.client.ui.CollectionView;
+import de.intevation.flys.client.client.ui.OutputTab;
+import de.intevation.flys.client.client.ui.chart.OverviewOutputTab;
+
+
+/**
+ * Output mode for chart overviews.
+ *
+ * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
+ */
+public class OverviewMode
+extends
+DefaultOutputMode {
+
+    public OverviewMode() {
+    }
+
+
+    public OverviewMode(String name, String desc, String mimeType) {
+        super(name, desc, mimeType);
+    }
+
+
+    public OverviewMode(
+        String name,
+        String descrition,
+        String mimeType,
+        List<Facet> facets,
+        String type)
+    {
+        super(name, descrition, mimeType, facets);
+        this.type = type;
+    }
+
+
+    @Override
+    public OutputTab createOutputTab(String t, Collection c, CollectionView p) {
+        return new OverviewOutputTab(t, c, this, p);
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/Property.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/Property.java	Fri Sep 28 12:15:52 2012 +0200
@@ -12,4 +12,6 @@
     String getName();
 
     void setName(String name);
+
+    Object clone();
 }
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/PropertyGroup.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/PropertyGroup.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,11 +1,13 @@
 package de.intevation.flys.client.shared.model;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
+ * A group of properties.
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
-public class PropertyGroup implements Property {
+public class PropertyGroup implements Property, Cloneable {
 
     /** The group name */
     protected String name;
@@ -13,7 +15,6 @@
     protected List<Property> properties;
 
     public PropertyGroup() {
-
     }
 
     public PropertyGroup(String name) {
@@ -49,4 +50,31 @@
         }
         return null;
     }
+
+    @Override
+    public Object clone() {
+        PropertyGroup clone = new PropertyGroup(this.getName());
+        List<Property> cloneList = new ArrayList<Property>();
+        for(Property p: properties) {
+            cloneList.add((Property)p.clone());
+        }
+        clone.setProperties(cloneList);
+        return clone;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+
+        for(Property p : properties) {
+            buf.append(p.getName());
+            buf.append("=");
+            if(p instanceof PropertySetting) {
+                buf.append(((PropertySetting)p).getValue().toString());
+            }
+            buf.append(" ");
+        }
+
+        return buf.toString();
+    }
 }
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/PropertySetting.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/PropertySetting.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,12 +1,13 @@
 package de.intevation.flys.client.shared.model;
 
+import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.ArrayList;
+import java.util.List;
 
 /**
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
-public class PropertySetting implements Property {
+public class PropertySetting implements Property, Cloneable {
 
     /**The settings name.*/
     protected String name;
@@ -55,7 +56,7 @@
         return this.name;
     }
 
-    public String getValue() {
+    public Object getValue() {
         return this.value;
     }
 
@@ -63,8 +64,18 @@
         return attributes.get(key);
     }
 
-    public ArrayList<String> getAttributeList() {
+    public List<String> getAttributeList() {
         return new ArrayList<String>(attributes.keySet());
     }
+
+    @Override
+    public Object clone() {
+        PropertySetting clone = new PropertySetting(this.getName(),
+                                                    this.getValue().toString());
+        for(String s: this.getAttributeList()) {
+            clone.setAttribute(s, this.getAttribute(s));
+        }
+        return clone;
+    }
 }
 // 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-client/src/main/java/de/intevation/flys/client/shared/model/RangeData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,17 @@
+package de.intevation.flys.client.shared.model;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public interface RangeData extends Data {
+
+    Object getLower();
+
+    Object getUpper();
+
+    Object getDefaultLower();
+
+    Object getDefaultUpper();
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/Recommendation.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/Recommendation.java	Fri Sep 28 12:15:52 2012 +0200
@@ -18,7 +18,8 @@
 
         /** Facet name. */
         protected String name;
-        /** Facet name. */
+
+        /** Facet index. */
         protected String index;
 
         public Facet() {
@@ -104,6 +105,7 @@
     protected String factory;
     /** Sometimes database ids, sometimes other freeform text. */
     protected String ids;
+    /** Artifacts uuid that should serve as master artifact. */
     protected String masterArtifact;
     /** Optional facet filter. */
     protected Filter filter;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/RiverInfo.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,55 @@
+package de.intevation.flys.client.shared.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a>
+ */
+
+public interface RiverInfo extends Serializable {
+
+    boolean isKmUp();
+
+    /**
+     * Start KM of the river
+     */
+    Double getKmStart();
+
+    /**
+     * End KM of the river
+     */
+    Double getKmEnd();
+
+    /**
+     * Returns the name of the river
+     */
+    String getName();
+
+    /**
+     * Returns the name of the WST unit
+     */
+    String getWstUnit();
+
+    /**
+     * Return all gauge info of the river
+     */
+    List<GaugeInfo> getGauges();
+
+    /**
+     * Returns the min q value of the river
+     */
+    Double getMinQ();
+
+    /**
+     * Returns the max q value of the river
+     */
+    Double getMaxQ();
+
+    /**
+     * Returns the official number of the river
+     */
+    Long getOfficialNumber();
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/StringData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,21 @@
+package de.intevation.flys.client.shared.model;
+
+
+/**
+ * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ */
+public class StringData extends DefaultData {
+
+    public static final String TYPE = "string";
+
+
+    public StringData() {
+        super();
+    }
+
+
+    public StringData(String name, String description, DataItem[] items) {
+        super(name, description, TYPE, items);
+    }
+}
+// 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-client/src/main/java/de/intevation/flys/client/shared/model/StringOptionsData.java	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,91 @@
+package de.intevation.flys.client.shared.model;
+
+
+public class StringOptionsData implements Data {
+
+    public static final String TYPE = "options";
+
+    protected String label;
+    protected String description;
+
+    public DataItem[] opts;
+
+
+    public StringOptionsData() {
+    }
+
+
+    public StringOptionsData(String label, String desc, DataItem[] opts) {
+        this.label       = label;
+        this.description = desc;
+        this.opts        = opts;
+    }
+
+
+    /**
+     * Returns the label of the item.
+     *
+     * @return the label.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+
+    /**
+     * Returns the description of the item.
+     *
+     * @return the description.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Returns the type of the item.
+     *
+     * @return the type.
+     */
+    public String getType() {
+        return TYPE;
+    }
+
+
+    /**
+     * Returns the data items which represent the allowed options for this Data.
+     *
+     * @return the allowed options as DataItem array.
+     */
+    public DataItem[] getItems() {
+        return opts;
+    }
+
+
+    /**
+     * @return always null.
+     */
+    public DataItem getDefault() {
+        return null;
+    }
+
+
+    /**
+     * Returns the values as colon separated string.
+     *
+     * @return colon separated string.
+     */
+    public String getStringValue() {
+        String data = "";
+        boolean first = true;
+        for (int i = 0; i < opts.length; i++) {
+            if (!first) {
+                data += ";";
+            }
+            data += opts[i].getStringValue();
+            first = false;
+        }
+        return data;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/StringProperty.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/StringProperty.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,8 +1,49 @@
 package de.intevation.flys.client.shared.model;
 
+import java.util.HashMap;
+
 /**
  * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
  */
 public class StringProperty extends PropertySetting {
 
+    /**
+     * Create a new StringProperty for settings.
+     */
+    public StringProperty() {
+        this.attributes = new HashMap<String, String>();
+    }
+
+
+    /**
+     * Create a new StringProperty.
+     * @param name The attribute name.
+     * @param value The current value.
+     */
+    public StringProperty(
+        String name,
+        String value)
+    {
+        this.name = name;
+        this.value = value;
+        this.attributes = new HashMap<String, String>();
+    }
+
+
+    @Override
+    public String getValue() {
+        return this.value;
+    }
+
+
+    public Object clone() {
+        StringProperty clone = new StringProperty(this.getName(),
+                                                    this.getValue());
+        for(String s: this.getAttributeList()) {
+            clone.setAttribute(s, this.getAttribute(s));
+        }
+        return clone;
+    }
 }
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/StyleSetting.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/StyleSetting.java	Fri Sep 28 12:15:52 2012 +0200
@@ -23,6 +23,9 @@
     /**The type*/
     protected String type;
 
+    /** Determines, if the property should be visible in UI or not.*/
+    protected boolean hidden;
+
 
     /**
      * Create a new StyleSetting for theme attribution.
@@ -40,17 +43,19 @@
      * @param type The attribute type.
      */
     public StyleSetting(
-        String name,
-        String defaultValue,
-        String displayName,
-        String hints,
-        String type)
+        String  name,
+        String  defaultValue,
+        String  displayName,
+        String  hints,
+        String  type,
+        boolean hidden)
     {
-        this.name = name;
+        this.name         = name;
         this.defaultValue = defaultValue;
-        this.displayName = displayName;
-        this.hints = hints;
-        this.type = type;
+        this.displayName  = displayName;
+        this.hints        = hints;
+        this.type         = type;
+        this.hidden       = hidden;
     }
 
     public void setName(String name) {
@@ -92,6 +97,10 @@
     public String getType() {
         return this.type;
     }
+
+    public boolean isHidden() {
+        return hidden;
+    }
 }
 
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/Theme.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/Theme.java	Fri Sep 28 12:15:52 2012 +0200
@@ -1,11 +1,16 @@
 package de.intevation.flys.client.shared.model;
 
-import de.intevation.flys.client.shared.model.CollectionItem;
-
 import java.io.Serializable;
 
 
 /**
+ * A 'Theme' is something displayed in a Chart. It can be activated or
+ * deactivated to show/hide in the resultant visual representation in the
+ * chart.
+ *
+ * A Theme maps more or less directly to a Facet of an Artifact in a
+ * Collection (certain attributes are added at Collection-Level).
+ *
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
  */
 public interface Theme extends Serializable {
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/ThemeList.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/ThemeList.java	Fri Sep 28 12:15:52 2012 +0200
@@ -2,6 +2,7 @@
 
 import java.io.Serializable;
 
+import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 
@@ -29,6 +30,24 @@
     }
 
 
+    public List<Theme> getActiveThemes() {
+        List<Theme> active = new ArrayList<Theme>();
+        List<Theme> all    = getThemes();
+
+        if (all == null || all.isEmpty()) {
+            return active;
+        }
+
+        for (Theme theme: all) {
+            if (theme.getActive() == 1) {
+                active.add(theme);
+            }
+        }
+
+        return active;
+    }
+
+
     public int getThemeCount() {
         return themes.size();
     }
--- a/flys-client/src/main/java/de/intevation/flys/client/shared/model/ZoomObj.java	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/java/de/intevation/flys/client/shared/model/ZoomObj.java	Fri Sep 28 12:15:52 2012 +0200
@@ -5,17 +5,17 @@
 
 public class ZoomObj implements Serializable {
 
-    protected double a;
-    protected double b;
-    protected double c;
-    protected double d;
+    protected Number a;
+    protected Number b;
+    protected Number c;
+    protected Number d;
 
 
     public ZoomObj() {
     }
 
 
-    public ZoomObj(double a, double b, double c, double d) {
+    public ZoomObj(Number a, Number b, Number c, Number d) {
         this.a = a;
         this.b = b;
         this.c = c;
@@ -23,8 +23,8 @@
     }
 
 
-    public double[] getZoom() {
-        return new double[] { a, b, c, d };
+    public Number[] getZoom() {
+        return new Number[] { a, b, c, d };
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/flys-client/src/main/webapp/FLYS.css	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/webapp/FLYS.css	Fri Sep 28 12:15:52 2012 +0200
@@ -147,3 +147,40 @@
     border-style: solid;
     border-color: black;
 }
+
+/* Login jsp */
+#authentication {
+    margin-left: 25%;
+    margin-right: 25%;
+    padding: 2em;
+    border: 2px solid #cfe1f1;
+    border-radius: 15px;
+}
+
+#authentication div {
+    margin: 1em 0;
+    font-size: 1.2em;
+}
+
+#authentication div.error {
+    text-align: center;
+    border: 1px solid red;
+    border-radius: 5px;
+}
+
+#authentication table {
+    margin-bottom: 1em;
+}
+
+.riverinfopanel {
+    border: 3px solid #CFE1F1;
+    padding: 8px;
+    margin-top: 10px;
+    margin-left: 10px;
+    margin-bottom: 10px;
+    font-size: 1.3em;
+}
+
+.riverinfopanel .gwt-Label {
+    margin-right: 10px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/webapp/WEB-INF/config.yaml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,145 @@
+#===========================================================================
+# allowed DPIs
+#===========================================================================
+dpis: [254, 190, 127, 56]
+
+#===========================================================================
+# allowed Formats
+#===========================================================================
+formats: ['*']
+
+#===========================================================================
+# the allowed scales
+#===========================================================================
+scales:
+  - 2500
+  - 5000
+  - 10000
+  - 15000
+  - 25000
+  - 50000
+  - 100000
+  - 200000
+  - 500000
+  - 1000000
+  - 2000000
+  - 4000000
+
+outputFilename: 'flys-${date}.pdf'
+
+#===========================================================================
+# the list of allowed hosts
+#===========================================================================
+hosts:
+  - !localMatch
+    dummy: true
+  - !dnsMatch
+    host: wsvmapserv.wsv.bund.de
+    port: 80
+  - !dnsMatch
+    host: tile.openstreetmap.org
+    port: 80
+  - !dnsMatch
+    host: www.pegelonline.wsv.de
+    port: 80
+
+layouts:
+  #===========================================================================
+  A4 portrait:
+  #===========================================================================
+    metaData:
+      title: '${title}'
+      author: 'MapFish print module'
+      subject: 'Simple layout'
+      keywords: 'map,print'
+      creator: 'MapFish'
+
+#    titlePage:
+#      pageSize: A4
+#      items:
+#        - !text
+#          spacingAfter: 150
+#        - !text
+#          font: Helvetica
+#          fontSize: 40
+#          spacingAfter: 100
+#          align: center
+#          text: '${title}'
+#        - !image
+#          maxWidth: 160
+#          maxHeight: 160
+#          spacingAfter: 100
+#          align: center
+#          url: http://trac.mapfish.org/trac/mapfish/attachment/ticket/3/logo_v8_sphere.svg?format=raw
+#        - !image
+#          maxWidth: 160
+#          maxHeight: 160
+#          spacingAfter: 100
+#          align: center
+#          url: 'file://${configDir}/../images/flys_logo.gif'
+#        - !text
+#          font: Helvetica
+#          fontSize: 14
+#          align: left
+#          text: |
+#            Two layers are asked by the client:
+#            - a base layer from Metacarta
+#            - a transparent layer from Camptocamp.org (routes)
+#            .
+#            Some text is added over the map, just to demonstrate the absolute positionning.
+#      footer: &commonFooter
+#        height: 30
+#        items:
+#          - !columns
+#            config:
+#              cells:
+#                - paddingBottom: 5   
+#            items:
+#              - !image
+#                maxWidth: 40
+#                backgroundColor: #FF0000
+#                align: left
+#                url: '${configDir}/../images/properties.gif'
+#              - !text
+#                backgroundColor: #FF0000
+#                text: ©Camptocamp SA
+#              - !text
+#                align: right
+#                text: 'Page ${pageNum}'
+
+    #-------------------------------------------------------------------------
+    mainPage:
+      pageSize: A4
+      rotation: true
+      header:
+        height: 50
+        items:
+          - !text
+            font: Helvetica
+            fontSize: 30
+            align: right
+            text: '${mapTitle}'
+      items:
+        - !map
+          spacingAfter: 30
+          width: 440
+          height: 483
+        - !scalebar
+          type: bar
+          maxSize: 100
+          barBgColor: white
+          fontSize: 8
+          align: right
+        - !text
+          text: '${comment}'
+          spacingAfter: 30
+        - !text
+          font: Helvetica
+          fontSize: 9
+          align: right
+          text: '1:${scale} ${now MM.dd.yyyy}'
+        - !legends
+          align: left
+          maxIconWidth: 32
+          maxIconHeight: 32
+      footer: *commonFooter
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/webapp/WEB-INF/features.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ftr:features xmlns:ftr="http://www.intevation.de/2012/flys/features">
+    <ftr:role name="flys_bfg">
+        <ftr:feature>module:winfo</ftr:feature>
+        <ftr:feature>module:minfo</ftr:feature>
+        <ftr:feature>module:new_map</ftr:feature>
+        <ftr:feature>module:new_chart</ftr:feature>
+        <ftr:feature>module:fixanalysis</ftr:feature>
+        <ftr:feature>river:Saar</ftr:feature>
+        <ftr:feature>river:Rhein</ftr:feature>
+        <ftr:feature>river:Mosel</ftr:feature>
+        <ftr:feature>river:Elbe</ftr:feature>
+    </ftr:role>
+    <ftr:role name="flys_wsa_koblenz">
+        <ftr:feature>module:winfo</ftr:feature>
+        <ftr:feature>module:minfo</ftr:feature>
+        <ftr:feature>module:new_map</ftr:feature>
+        <ftr:feature>module:new_chart</ftr:feature>
+        <ftr:feature>module:fixanalysis</ftr:feature>
+        <ftr:feature>river:Rhein</ftr:feature>
+        <ftr:feature>river:Mosel</ftr:feature>
+    </ftr:role>
+    <ftr:role name="flys_wsa_trier">
+        <ftr:feature>module:winfo</ftr:feature>
+        <ftr:feature>module:minfo</ftr:feature>
+        <ftr:feature>module:new_map</ftr:feature>
+        <ftr:feature>module:new_chart</ftr:feature>
+        <ftr:feature>module:fixanalysis</ftr:feature>
+        <ftr:feature>river:Saar</ftr:feature>
+        <ftr:feature>river:Mosel</ftr:feature>
+    </ftr:role>
+    <ftr:role name="flys_wsa_schweinfurt">
+        <ftr:feature>module:winfo</ftr:feature>
+        <ftr:feature>module:minfo</ftr:feature>
+        <ftr:feature>module:new_map</ftr:feature>
+        <ftr:feature>module:new_chart</ftr:feature>
+        <ftr:feature>module:fixanalysis</ftr:feature>
+        <ftr:feature>river:Saar</ftr:feature>
+        <ftr:feature>river:Mosel</ftr:feature>
+        <ftr:feature>river:Elbe</ftr:feature>
+    </ftr:role>
+    <ftr:role name="flys_user_extern">
+        <ftr:feature>module:winfo</ftr:feature>
+        <ftr:feature>module:minfo</ftr:feature>
+        <ftr:feature>river:Elbe</ftr:feature>
+    </ftr:role>
+</ftr:features>
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/webapp/WEB-INF/stylesheets/fixoverview2html.xsl	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,398 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet
+  version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="html" encoding="UTF-8"/>
+
+  <xsl:param name="project-uuid">de3f3307-3429-4ff9-8f43-3fb2fcf21b27</xsl:param>
+  <xsl:param name="render-checkboxes" select="true()"/>
+  <xsl:param name="callback"/>
+
+  <xsl:param name="locale">de</xsl:param>
+
+  <xsl:decimal-format name="de" decimal-separator=',' grouping-separator='.'/>
+  <xsl:decimal-format name="en" decimal-separator='.' grouping-separator=','/>
+
+  <!-- XXX: This kind of i18n is cheesy.
+            It should be better done in an external resource. -->
+
+  <xsl:variable name="km-pattern">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">0,##</xsl:when>
+      <xsl:otherwise>0.##</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-event">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">Ereignis</xsl:when>
+      <xsl:otherwise>Event</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-legend">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">Legende</xsl:when>
+      <xsl:otherwise>Caption</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-color">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">Farbe</xsl:when>
+      <xsl:otherwise>Color</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-meaning">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">Bedeutung</xsl:when>
+      <xsl:otherwise>Meaning</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-around-mnq">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">um MNQ</xsl:when>
+      <xsl:otherwise>around MNQ</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-around-mq">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">um MQ</xsl:when>
+      <xsl:otherwise>around MQ</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-around-mhq">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">um MHQ</xsl:when>
+      <xsl:otherwise>around MHQ</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="i18n-above-hq5">
+    <xsl:choose>
+      <xsl:when test="$locale = 'de'">über HQ5</xsl:when>
+      <xsl:otherwise>above HQ5</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <!-- TODO: Format dates according locale. -->
+
+  <xsl:template match="@*" mode="min">
+    <xsl:if test="position() = 1">
+      <xsl:value-of select="number(.)"/>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="@*" mode="max">
+    <xsl:if test="position() = last()">
+      <xsl:value-of select="number(.)"/>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:variable name="global-min">
+    <xsl:choose>
+      <xsl:when test="count(/fixings/events/event/sector) &gt; 0">
+        <xsl:apply-templates mode="min" select="/fixings/events/event/sector/@from">
+          <xsl:sort data-type="number" select="."/>
+        </xsl:apply-templates>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="number(/fixings/river/@from)"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:variable name="global-max">
+    <xsl:choose>
+      <xsl:when test="count(/fixings/events/event/sector) &gt; 0">
+        <xsl:apply-templates mode="max" select="/fixings/events/event/sector/@to">
+          <xsl:sort data-type="number" select="."/>
+        </xsl:apply-templates>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="number(/fixings/river/@to)"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
+  <xsl:template name="percent">
+    <xsl:param name="sector"/>
+
+    <xsl:variable name="start">
+      <xsl:choose>
+        <xsl:when test="number($sector/@from) &lt; $global-min">
+          <xsl:value-of select="$global-min"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="number($sector/@from)"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:variable name="end">
+      <xsl:choose>
+        <xsl:when test="number($sector/@to) &gt; $global-max">
+          <xsl:value-of select="$global-max"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="number($sector/@to)"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:choose>
+      <xsl:when test="$end &lt; $start">
+        <xsl:value-of select="number(0)"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="100.0 * (($end - $start) div ($global-max - $global-min))"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="emit-gap-gauge">
+    <xsl:param name="gauge"/>
+    <xsl:call-template name="internal-emit-gap">
+      <xsl:with-param name="sector" select="$gauge"/>
+      <xsl:with-param name="preds" select="$gauge/preceding-sibling::gauge"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="emit-gap">
+    <xsl:param name="sector"/>
+    <xsl:call-template name="internal-emit-gap">
+      <xsl:with-param name="sector" select="$sector"/>
+      <xsl:with-param name="preds" select="$sector/preceding-sibling::sector"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="internal-emit-gap">
+    <xsl:param name="sector"/>
+    <xsl:param name="preds"/>
+
+    <xsl:variable name="start">
+      <xsl:choose>
+        <xsl:when test="number($sector/@from) &lt; $global-min">
+          <xsl:value-of select="$global-min"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="$sector/@from"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:if test="$start &lt; $global-max">
+      <xsl:variable name="num-preds" select="count($preds)"/>
+      <xsl:variable name="prev-end">
+        <xsl:choose>
+          <xsl:when test="count($preds) &lt; 1">
+            <xsl:value-of select="$global-min"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:variable name="prev-to" select="number($preds[last()]/@to)"/>
+            <xsl:choose>
+              <xsl:when test="$prev-to &lt; $global-min">
+                <xsl:value-of select="$global-min"/>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:value-of select="$prev-to"/>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+
+      <xsl:if test="$prev-end &lt; $global-max">
+        <xsl:variable name="gap-len" select="$start - $prev-end"/>
+        <xsl:if test="$gap-len &gt; 0.005">
+          <div>
+            <xsl:attribute name="style">
+              <xsl:text>width:</xsl:text>
+                <xsl:value-of select="100.0 * ($gap-len div ($global-max - $global-min))"/>
+              <xsl:text>%;float:left</xsl:text>
+            </xsl:attribute>
+            <xsl:text disable-output-escaping="yes"><![CDATA[&nbsp;]]></xsl:text>
+          </div>
+        </xsl:if>
+      </xsl:if>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="sector" mode="sectors">
+    <xsl:call-template name="emit-gap">
+      <xsl:with-param name="sector" select="."/>
+    </xsl:call-template>
+    <div>
+      <xsl:attribute name="style">
+        <xsl:text>background:</xsl:text>
+        <xsl:choose>
+          <xsl:when test="@class = '0'">green</xsl:when>
+          <xsl:when test="@class = '1'">blue</xsl:when>
+          <xsl:when test="@class = '2'">magenta</xsl:when>
+          <xsl:when test="@class = '3'">red</xsl:when>
+          <xsl:otherwise>black</xsl:otherwise>
+        </xsl:choose>
+        <xsl:text>;width:</xsl:text>
+        <xsl:call-template name="percent">
+          <xsl:with-param name="sector" select="."/>
+        </xsl:call-template>
+        <xsl:text>%</xsl:text>
+        <xsl:text>;float:left</xsl:text>
+      </xsl:attribute>
+      <xsl:attribute name="title">
+        <xsl:text>km </xsl:text>
+        <xsl:value-of select="format-number(@from, $km-pattern, $locale)"/>
+        <xsl:text> - </xsl:text>
+        <xsl:value-of select="format-number(@to, $km-pattern, $locale)"/>
+        <xsl:choose>
+          <xsl:when test="@class = '0'"> / Q <xsl:value-of select="$i18n-around-mnq"/></xsl:when>
+          <xsl:when test="@class = '1'"> / Q <xsl:value-of select="$i18n-around-mq"/></xsl:when>
+          <xsl:when test="@class = '2'"> / Q <xsl:value-of select="$i18n-around-mhq"/></xsl:when>
+          <xsl:when test="@class = '3'"> / Q <xsl:value-of select="$i18n-above-hq5"/></xsl:when>
+        </xsl:choose>
+      </xsl:attribute>
+      <xsl:text disable-output-escaping="yes"><![CDATA[&nbsp;]]></xsl:text>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="event">
+    <tr id="{@cid}">
+      <xsl:if test="$render-checkboxes">
+        <td>
+          <input type="checkbox" name="{$project-uuid}:{@cid}" checked="true" onclick="{$callback}"/>
+        </td>
+      </xsl:if>
+      <td>
+        <xsl:apply-templates mode="sectors"/>
+      </td>
+      <td align="center">
+        <xsl:attribute name="title"><xsl:value-of select="@description"/></xsl:attribute>
+        <xsl:value-of select="@date"/>
+      </td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="gauge" mode="gauges">
+    <xsl:call-template name="emit-gap-gauge">
+      <xsl:with-param name="gauge" select="."/>
+    </xsl:call-template>
+
+    <div>
+      <xsl:attribute name="style">
+        <xsl:text>overflow:hidden;background:</xsl:text>
+        <xsl:choose>
+          <xsl:when test="(count(preceding::*) mod 2) = 0">#ada96e</xsl:when>
+          <xsl:otherwise>silver</xsl:otherwise>
+        </xsl:choose>
+        <xsl:text>;width:</xsl:text>
+        <xsl:call-template name="percent">
+          <xsl:with-param name="sector" select="."/>
+        </xsl:call-template>
+        <xsl:text>%</xsl:text>
+        <xsl:text>;float:left</xsl:text>
+      </xsl:attribute>
+
+      <xsl:attribute name="title">
+        <xsl:variable name="start">
+          <xsl:choose>
+            <xsl:when test="number(@from) &lt; $global-min">
+              <xsl:value-of select="$global-min"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="number(@from)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+
+        <xsl:variable name="end">
+          <xsl:choose>
+            <xsl:when test="number(@to) &gt; $global-max">
+              <xsl:value-of select="$global-max"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="number(@to)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+
+        <xsl:value-of select="@name"/>
+        <xsl:text>: km </xsl:text>
+        <xsl:value-of select="format-number($start, $km-pattern, $locale)"/>
+        <xsl:text> - </xsl:text>
+        <xsl:value-of select="format-number($end, $km-pattern, $locale)"/>
+      </xsl:attribute>
+      <nobr><xsl:value-of select="@name"/></nobr>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="events">
+    <table width="97%" border="1" cellspacing="0" cellpadding="0"
+           style="font-size: 10pt;font-family:Arial;Verdana,sans-serif">
+      <colgroup>
+        <xsl:if test="$render-checkboxes">
+            <col width="20px"/>
+        </xsl:if>
+        <col width="*"/>
+        <col width="75px"/>
+      </colgroup>
+      <tr>
+        <xsl:if test="$render-checkboxes">
+          <th>&#160;</th>
+        </xsl:if>
+        <th><xsl:apply-templates mode="gauges" select="/fixings/gauges"/></th>
+        <th><xsl:value-of select="$i18n-event"/></th>
+      </tr>
+      <xsl:apply-templates/>
+    </table>
+  </xsl:template>
+
+  <xsl:template match="/">
+    <xsl:apply-templates/>
+    <hr/>
+    <table border="1" cellspacing="0" cellpadding="0">
+      <caption><xsl:value-of select="$i18n-legend"/></caption>
+      <tr>
+        <th><xsl:value-of select="$i18n-color"/></th>
+        <th colspan="2"><xsl:value-of select="$i18n-meaning"/></th>
+      </tr>
+      <xsl:if test="count(/fixings/events/event/sector[@class = '0']) &gt; 0">
+      <tr>
+        <td style="background: green">&#160;</td>
+        <td><xsl:value-of select="$i18n-around-mnq"/></td>
+        <td>Q &#8712; [0, (MNQ+MQ)/2)</td>
+      </tr>
+      </xsl:if>
+      <xsl:if test="count(/fixings/events/event/sector[@class = '1']) &gt; 0">
+      <tr>
+        <td style="background: blue">&#160;</td>
+        <td><xsl:value-of select="$i18n-around-mq"/></td>
+        <td>Q &#8712; [(MNQ+MQ)/2, (MQ+MHQ)/2)</td>
+      </tr>
+      </xsl:if>
+      <xsl:if test="count(/fixings/events/event/sector[@class = '2']) &gt; 0">
+      <tr>
+        <td style="background: magenta">&#160;</td>
+        <td><xsl:value-of select="$i18n-around-mhq"/></td>
+        <td>Q &#8712; [(MQ+MHQ)/2, HQ5)</td>
+      </tr>
+      </xsl:if>
+      <xsl:if test="count(/fixings/events/event/sector[@class = '3']) &gt; 0">
+      <tr>
+        <td style="background: red">&#160;</td>
+        <td><xsl:value-of select="$i18n-above-hq5"/></td>
+        <td>Q &#8712; [HQ5, &#8734;)</td>
+      </tr>
+      </xsl:if>
+    </table>
+  </xsl:template>
+
+  <xsl:template match="text()"/>
+  <xsl:template match="text()" mode="sectors"/>
+  <xsl:template match="text()" mode="gauges"/>
+
+</xsl:stylesheet>
--- a/flys-client/src/main/webapp/WEB-INF/web.xml	Fri Sep 28 12:14:57 2012 +0200
+++ b/flys-client/src/main/webapp/WEB-INF/web.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -9,25 +9,33 @@
         <param-name>server-url</param-name>
         <param-value>http://localhost:8181</param-value>
     </context-param>
-  
-  <!-- Servlets -->
-  <servlet>
-    <servlet-name>BaseServlet</servlet-name>
-    <servlet-class>de.intevation.flys.client.server.BaseServlet</servlet-class>
 
-    <init-param>
+    <context-param>
+        <param-name>authentication</param-name>
+        <param-value>GGInA</param-value>
+    </context-param>
+
+    <context-param>
+        <param-name>features-file</param-name>
+        <param-value>/WEB-INF/features.xml</param-value>
+    </context-param>
+
+    <context-param>
         <param-name>log4j-properties</param-name>
         <param-value>/WEB-INF/log4j.properties</param-value>
-    </init-param>
+    </context-param>
 
-    <load-on-startup>1</load-on-startup>
-  </servlet>
+    <listener>
+        <listener-class>de.intevation.flys.client.server.BaseServletContextListener</listener-class>
+    </listener>
 
+
+  <!-- Servlets -->
   <servlet>
     <servlet-name>user</servlet-name>
     <servlet-class>de.intevation.flys.client.server.UserServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>user</servlet-name>
     <url-pattern>/flys/user</url-pattern>
@@ -37,7 +45,7 @@
     <servlet-name>artifact</servlet-name>
     <servlet-class>de.intevation.flys.client.server.ArtifactServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>artifact</servlet-name>
     <url-pattern>/flys/artifact</url-pattern>
@@ -47,7 +55,7 @@
     <servlet-name>getartifact</servlet-name>
     <servlet-class>de.intevation.flys.client.server.GetArtifactServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>getartifact</servlet-name>
     <url-pattern>/flys/getartifact</url-pattern>
@@ -57,7 +65,7 @@
     <servlet-name>cross-section-km</servlet-name>
     <servlet-class>de.intevation.flys.client.server.CrossSectionKMServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>cross-section-km</servlet-name>
     <url-pattern>/flys/cross-section-km</url-pattern>
@@ -67,7 +75,7 @@
     <servlet-name>create-collection</servlet-name>
     <servlet-class>de.intevation.flys.client.server.CreateCollectionServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>create-collection</servlet-name>
     <url-pattern>/flys/create-collection</url-pattern>
@@ -77,17 +85,27 @@
     <servlet-name>rivers</servlet-name>
     <servlet-class>de.intevation.flys.client.server.RiverServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>rivers</servlet-name>
     <url-pattern>/flys/rivers</url-pattern>
   </servlet-mapping>
 
   <servlet>
+    <servlet-name>gaugeoverviewinfo</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.GaugeOverviewInfoServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>gaugeoverviewinfo</servlet-name>
+    <url-pattern>/flys/gaugeoverviewinfo</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
     <servlet-name>forward</servlet-name>
     <servlet-class>de.intevation.flys.client.server.StepForwardServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>forward</servlet-name>
     <url-pattern>/flys/forward</url-pattern>
@@ -97,17 +115,27 @@
     <servlet-name>feed</servlet-name>
     <servlet-class>de.intevation.flys.client.server.FeedServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>feed</servlet-name>
     <url-pattern>/flys/feed</url-pattern>
   </servlet-mapping>
 
   <servlet>
+    <servlet-name>fixings-overview</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.FixingsOverviewServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>fixings-overview</servlet-name>
+    <url-pattern>/flys/fixings-overview</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
     <servlet-name>advance</servlet-name>
     <servlet-class>de.intevation.flys.client.server.AdvanceServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>advance</servlet-name>
     <url-pattern>/flys/advance</url-pattern>
@@ -117,7 +145,7 @@
     <servlet-name>add-artifact</servlet-name>
     <servlet-class>de.intevation.flys.client.server.AddArtifactServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>add-artifact</servlet-name>
     <url-pattern>/flys/add-artifact</url-pattern>
@@ -127,7 +155,7 @@
     <servlet-name>load-artifact</servlet-name>
     <servlet-class>de.intevation.flys.client.server.LoadArtifactServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>load-artifact</servlet-name>
     <url-pattern>/flys/load-artifact</url-pattern>
@@ -137,7 +165,7 @@
     <servlet-name>describe-collection</servlet-name>
     <servlet-class>de.intevation.flys.client.server.DescribeCollectionServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>describe-collection</servlet-name>
     <url-pattern>/flys/describe-collection</url-pattern>
@@ -147,7 +175,7 @@
     <servlet-name>user-collections</servlet-name>
     <servlet-class>de.intevation.flys.client.server.UserCollectionsServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>user-collections</servlet-name>
     <url-pattern>/flys/user-collections</url-pattern>
@@ -157,17 +185,37 @@
     <servlet-name>distanceinfo</servlet-name>
     <servlet-class>de.intevation.flys.client.server.DistanceInfoServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>distanceinfo</servlet-name>
     <url-pattern>/flys/distanceinfo</url-pattern>
   </servlet-mapping>
 
   <servlet>
+    <servlet-name>dischargeinfo</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.DischargeInfoServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>dischargeinfo</servlet-name>
+    <url-pattern>/flys/dischargeinfo</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
+    <servlet-name>DischargeInfoXML</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.DischargeInfoXML</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>DischargeInfoXML</servlet-name>
+    <url-pattern>/flys/dischargeinfoxml</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
     <servlet-name>meta-data</servlet-name>
     <servlet-class>de.intevation.flys.client.server.MetaDataServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>meta-data</servlet-name>
     <url-pattern>/flys/meta-data</url-pattern>
@@ -177,27 +225,43 @@
     <servlet-name>mainvalues</servlet-name>
     <servlet-class>de.intevation.flys.client.server.WQInfoServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>mainvalues</servlet-name>
     <url-pattern>/flys/mainvalues</url-pattern>
   </servlet-mapping>
 
   <servlet>
+    <servlet-name>gaugeinfo</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.GaugeInfoServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>gaugeinfo</servlet-name>
+    <url-pattern>/flys/gaugeinfo</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
     <servlet-name>csv</servlet-name>
     <servlet-class>de.intevation.flys.client.server.CSVExportServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>csv</servlet-name>
     <url-pattern>/flys/csv</url-pattern>
   </servlet-mapping>
-  
+
   <servlet>
     <servlet-name>ChartOutputService</servlet-name>
     <servlet-class>de.intevation.flys.client.server.ChartOutputServiceImpl</servlet-class>
   </servlet>
 
+  <servlet-mapping>
+    <servlet-name>ChartOutputService</servlet-name>
+    <url-pattern>/flys/chart</url-pattern>
+  </servlet-mapping>
+
+  <!-- MapFish Print -->
   <servlet>
     <servlet-name>MapOutputService</servlet-name>
     <servlet-class>de.intevation.flys.client.server.MapOutputServiceImpl</servlet-class>
@@ -208,9 +272,48 @@
     <url-pattern>/flys/map</url-pattern>
   </servlet-mapping>
 
+  <servlet>
+    <servlet-name>mapfish.print</servlet-name>
+    <servlet-class>org.mapfish.print.servlet.MapPrinterServlet</servlet-class>
+    <init-param>
+      <param-name>config</param-name>
+      <param-value>WEB-INF/config.yaml</param-value>
+    </init-param>
+  </servlet>
+
   <servlet-mapping>
-    <servlet-name>ChartOutputService</servlet-name>
-    <url-pattern>/flys/chart</url-pattern>
+    <servlet-name>mapfish.print</servlet-name>
+    <url-pattern>/flys/mapfish-print/*</url-pattern>
+  </servlet-mapping>
+
+  <!-- Servlet to bridge between MapFish Print and FLYS3 -->
+  <servlet>
+    <servlet-name>MapPrintService</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.MapPrintServiceImpl</servlet-class>
+    <init-param>
+      <param-name>config</param-name>
+      <param-value>WEB-INF/config.yaml</param-value>
+    </init-param>
+    <init-param>
+      <param-name>print-url</param-name>
+      <param-value>http://localhost:8888/flys/mapfish-print</param-value>
+    </init-param>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>MapPrintService</servlet-name>
+    <url-pattern>/flys/map-print</url-pattern>
+  </servlet-mapping>
+
+
+  <servlet>
+    <servlet-name>FixingsKMChartService</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.FixingsKMChartServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>FixingsKMChartService</servlet-name>
+    <url-pattern>/flys/fixings-km-chart</url-pattern>
   </servlet-mapping>
 
   <servlet>
@@ -317,7 +420,7 @@
     <servlet-name>getfeatureinfo</servlet-name>
     <servlet-class>de.intevation.flys.client.server.GFIServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>getfeatureinfo</servlet-name>
     <url-pattern>/flys/getfeatureinfo</url-pattern>
@@ -327,7 +430,7 @@
     <servlet-name>getcapabilities</servlet-name>
     <servlet-class>de.intevation.flys.client.server.GCServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>getcapabilities</servlet-name>
     <url-pattern>/flys/getcapabilities</url-pattern>
@@ -347,12 +450,106 @@
     <servlet-name>remove-artifact</servlet-name>
     <servlet-class>de.intevation.flys.client.server.RemoveArtifactServiceImpl</servlet-class>
   </servlet>
-  
+
   <servlet-mapping>
     <servlet-name>remove-artifact</servlet-name>
     <url-pattern>/flys/remove-artifact</url-pattern>
   </servlet-mapping>
 
+  <servlet>
+    <servlet-name>GetWMSUrls</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.MapUrlServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>GetWMSUrls</servlet-name>
+    <url-pattern>/flys/map-urls</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
+    <servlet-name>FileUpload</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.FileUploadServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>FileUpload</servlet-name>
+    <url-pattern>/flys/fileupload</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
+    <servlet-name>themelisting</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.ThemeListingServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>themelisting</servlet-name>
+    <url-pattern>/flys/themelisting</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
+    <servlet-name>SQKMChart</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.SQKMChartServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>SQKMChart</servlet-name>
+    <url-pattern>/flys/sq-km-chart</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
+    <servlet-name>BedKMChart</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.BedKMChartServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>BedKMChart</servlet-name>
+    <url-pattern>/flys/bed-km-chart</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
+    <servlet-name>BedloadKMChart</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.BedloadKMChartServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>BedloadKMChart</servlet-name>
+    <url-pattern>/flys/bedload-km-chart</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
+    <servlet-name>login</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.LoginServlet</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>login</servlet-name>
+    <url-pattern>/flys/login</url-pattern>
+  </servlet-mapping>
+
+  <servlet>
+    <servlet-name>modules</servlet-name>
+    <servlet-class>de.intevation.flys.client.server.ModuleServiceImpl</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>modules</servlet-name>
+    <url-pattern>/flys/modules</url-pattern>
+  </servlet-mapping>
+
+  <filter>
+    <filter-name>GGInAFilter</filter-name>
+    <filter-class>de.intevation.flys.client.server.GGInAFilter</filter-class>
+    <init-param>
+        <param-name>deactivate</param-name>
+        <param-value>false</param-value>
+    </init-param>
+  </filter>
+
+  <filter-mapping>
+    <filter-name>GGInAFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+  </filter-mapping>
+
   <!-- Default page to serve -->
   <welcome-file-list>
     <welcome-file>FLYS.html</welcome-file>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/webapp/WEB-INF/wms-services.xml	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wms-services>
+  <wms name="Luftbilder RLP" url="http://geo4.service24.rlp.de/wms/dop40_geo4.fcgi"/>
+  <wms name="TOP-Karten der WSV" url="http://wsvmapserv.ilmenau.baw.de/cgi-bin/wmstkappl?"/>
+  <wms name="Bundeswasserstraßenkarte 1:1 Mio" url="http://wsvmapserv.ilmenau.baw.de/cgi-bin/wmsdbwk1000?"/>
+  <wms name="DBWK2" url="http://wsvmapserv.wsv.bvbs.bund.de/cgi-bin/wms_dbwk2?"/>
+  <wms name="Infos zu Bundeswasserstraßen" url="http://wsvmapserv.wsv.bund.de/wms_bwastr?Version=1.1.0"/>
+  <wms name="Einzugsgebiete Deutschland" url="http://wsvmapserv.wsv.bund.de/wmsezg?"/>
+  <wms name="Orthophotos BKG" url="http://gdz.bkg.bund.de"/>
+  <wms name="Orthophotos der WSV" url="http://wsvmapserv.ilmenau.baw.de/cgi-bin/wmsluft?"/>
+  <wms name="Pegelonline" url="http://www.pegelonline.wsv.de/webservices/gis/wms/aktuell?"/>
+</wms-services>
Binary file flys-client/src/main/webapp/images/addWMS.png has changed
Binary file flys-client/src/main/webapp/images/add_map.png has changed
Binary file flys-client/src/main/webapp/images/add_map_Selected.png has changed
Binary file flys-client/src/main/webapp/images/arrow_down.png has changed
Binary file flys-client/src/main/webapp/images/arrow_first.png has changed
Binary file flys-client/src/main/webapp/images/arrow_last.png has changed
Binary file flys-client/src/main/webapp/images/arrow_up.png has changed
Binary file flys-client/src/main/webapp/images/getFeatureInfo.png has changed
Binary file flys-client/src/main/webapp/images/getFeatureInfo_Selected.png has changed
Binary file flys-client/src/main/webapp/images/hand.png has changed
Binary file flys-client/src/main/webapp/images/info.png has changed
Binary file flys-client/src/main/webapp/images/info_Selected.png has changed
Binary file flys-client/src/main/webapp/images/logo-bfg.gif has changed
Binary file flys-client/src/main/webapp/images/logo-intevation.png has changed
Binary file flys-client/src/main/webapp/images/mag_100.png has changed
Binary file flys-client/src/main/webapp/images/mag_100_Selected.png has changed
Binary file flys-client/src/main/webapp/images/mag_glass.png has changed
Binary file flys-client/src/main/webapp/images/mag_zoom_back.png has changed
Binary file flys-client/src/main/webapp/images/mag_zoom_back_Selected.png has changed
Binary file flys-client/src/main/webapp/images/mag_zoom_box.png has changed
Binary file flys-client/src/main/webapp/images/mag_zoom_box_Selected.png has changed
Binary file flys-client/src/main/webapp/images/mag_zoom_minus.png has changed
Binary file flys-client/src/main/webapp/images/mag_zoom_minus_Selected.png has changed
Binary file flys-client/src/main/webapp/images/mag_zoom_plus.png has changed
Binary file flys-client/src/main/webapp/images/mag_zoom_plus_Selected.png has changed
Binary file flys-client/src/main/webapp/images/measureLine.png has changed
Binary file flys-client/src/main/webapp/images/measureLine_Selected.png has changed
Binary file flys-client/src/main/webapp/images/measurePolygon.png has changed
Binary file flys-client/src/main/webapp/images/measurePolygon_Selected.png has changed
Binary file flys-client/src/main/webapp/images/measure_line.png has changed
Binary file flys-client/src/main/webapp/images/measure_line_Selected.png has changed
Binary file flys-client/src/main/webapp/images/measure_plane.png has changed
Binary file flys-client/src/main/webapp/images/measure_plane_Selected.png has changed
Binary file flys-client/src/main/webapp/images/pdf_export.png has changed
Binary file flys-client/src/main/webapp/images/pdf_export_Selected.png has changed
Binary file flys-client/src/main/webapp/images/png_export.png has changed
Binary file flys-client/src/main/webapp/images/png_export_Selected.png has changed
Binary file flys-client/src/main/webapp/images/properties.png has changed
Binary file flys-client/src/main/webapp/images/properties_Selected.png has changed
Binary file flys-client/src/main/webapp/images/save.png has changed
Binary file flys-client/src/main/webapp/images/save_Selected.png has changed
Binary file flys-client/src/main/webapp/images/svg_export.png has changed
Binary file flys-client/src/main/webapp/images/svg_export_Selected.png has changed
Binary file flys-client/src/main/webapp/images/theme_bottom.png has changed
Binary file flys-client/src/main/webapp/images/theme_down.png has changed
Binary file flys-client/src/main/webapp/images/theme_top.png has changed
Binary file flys-client/src/main/webapp/images/theme_up.png has changed
Binary file flys-client/src/main/webapp/images/zoom-1.png has changed
Binary file flys-client/src/main/webapp/images/zoom-back.png has changed
Binary file flys-client/src/main/webapp/images/zoom-in.png has changed
Binary file flys-client/src/main/webapp/images/zoom-in_Selected.png has changed
Binary file flys-client/src/main/webapp/images/zoom-out.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-client/src/main/webapp/login.jsp	Fri Sep 28 12:15:52 2012 +0200
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>FLYS - Login</title>
+        <link href="FLYS.css" type="text/css" rel="stylesheet">
+    </head>
+
+    <body>
+        <form method="POST" action="<%= request.getContextPath() + "/flys/login" %>" id="authentication">
+            <h1>FLYS Anmeldung</h1>
+            <% String error = request.getParameter("error"); %>
+            <% if (error != null) { %>
+                <div class="error">
+                    <h2>Authentifizierung fehlgeschlagen</h2>
+                    <div class="details">
+                        <%= error %>
+                    </div>
+                </div>
+            <% } %>
+            <div>Bitte geben Sie eine Benutzerkennung und ein Passwort ein.</div>
+            <table>
+                <tr>
+                    <td><label for="username">Benutzername: </label></td>
+                    <td><input type="text" name="username" /></td>
+                </tr>
+                <tr>
+                    <td><label for="password">Passwort: </label></td>
+                    <td><input type="password" name="password" /></td>
+                </tr>
+            </table>
+            <input type="submit" class="sendButton" value="Anmelden"/>
+        </form>
+    </body>
+</html>

http://dive4elements.wald.intevation.org