view flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java @ 5772:c0d0b9fd1aa8

issue1276: Re-enable fixation autorecommend at discharge_curves.
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Fri, 19 Apr 2013 09:22:44 +0200
parents fa5868a52f14
children
line wrap: on
line source
package de.intevation.flys.artifacts.states;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.log4j.Logger;

import org.apache.velocity.Template;

import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureCollections;

import org.geotools.feature.simple.SimpleFeatureBuilder;

import org.hibernate.HibernateException;

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 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.flys.artifacts.FLYSArtifact;

import de.intevation.flys.artifacts.access.RangeAccess;

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.LayerInfo;
import de.intevation.flys.artifacts.model.WQKms;

import de.intevation.flys.artifacts.model.map.HWS;
import de.intevation.flys.artifacts.model.map.HWSContainer;
import de.intevation.flys.artifacts.model.map.HWSFactory;
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.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.ArtifactMapfileGenerator;
import de.intevation.flys.utils.FLYSUtils;
import de.intevation.flys.utils.GeometryUtils;
import de.intevation.flys.utils.MapfileGenerator;

import de.intevation.flys.wsplgen.FacetCreator;
import de.intevation.flys.wsplgen.JobObserver;
import de.intevation.flys.wsplgen.Scheduler;

public class FloodMapState
extends      DefaultState
implements   FacetTypes
{
    /** The logger that is used in this state. */
    private static Logger logger = Logger.getLogger(FloodMapState.class);


    public static final String KEEP_ARTIFACT_DIR =
        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";

    public static final String WSPLGEN_PARAMETER_FILE = "wsplgen.par";
    public static final String WSPLGEN_BARRIERS_LINES = "barrier_lines.shp";
    public static final String WSPLGEN_BARRIERS_POLY  = "barrier_polygons.shp";
    public static final String WSPLGEN_AXIS           = "axis.shp";
    public static final String WSPLGEN_QPS            = "qps.shp";
    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;

    private static final String HWS_LINES_SHAPE = "hws-lines.shp";

    private static final String I18N_HWS_POINTS_OFFICIAL = "floodmap.hws.points.official";
    private static final String I18N_HWS_LINES_OFFICIAL = "floodmap.hws.lines.official";
    private static final String HWS_LINES = "hws-lines";
    private static final String HWS_POINT_SHAPE = "hws-points.shp";
    private static final String HWS_POINTS = "hws-points";

    /**
     * @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);

        ArtifactMapfileGenerator amfg = new ArtifactMapfileGenerator();
        try {
            amfg.generate();
        }
        catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
    }


    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(
        FLYSArtifact artifact,
        String       hash,
        CallContext  context,
        List<Facet>  facets,
        Object       old
    ) {
        logger.debug("FloodMapState.computeAdvance");

        File artifactDir = getDirectory(artifact);

        if (artifactDir == null) {
            logger.error("Could not create directory for WSPLGEN results!");
            return null;
        }

        WSPLGENCalculation calculation = new WSPLGENCalculation();

        FacetCreator facetCreator = new FacetCreator(
            artifact, context, hash, getID(), facets);

        WSPLGENJob job = prepareWSPLGENJob(
            artifact,
            facetCreator,
            artifactDir,
            context,
            calculation);

        CalculationResult  res   = new CalculationResult(null, calculation);
        WSPLGENReportFacet report= new WSPLGENReportFacet(
            ComputeType.ADVANCE, hash, getID(), res);

        facets.add(report);

        if (job == null) {
            if (KEEP_ARTIFACT_DIR.equals("false")) {
                removeDirectory(artifact);
            }

            calculation.addError(-1, Resources.getMsg(
                context.getMeta(),
                "wsplgen.job.error",
                "wsplgen.job.error"));

            logger.error("No WSPLGEN processing has been started!");

            return null;
        }

        context.afterCall(CallContext.BACKGROUND);
        context.addBackgroundMessage(new CalculationMessage(
            JobObserver.STEPS.length,
            0,
            Resources.getMsg(
                context.getMeta(),
                "wsplgen.job.queued",
                "wsplgen.job.queued")
        ));

        GlobalContext gc    = (GlobalContext) context.globalContext();
        Scheduler scheduler = (Scheduler) gc.get(FLYSContext.SCHEDULER);
        scheduler.addJob(job);

        return null;
    }


    /**
     * Returns (and creates if not existing) the directory for storing WSPLEN
     * data for the owner artifact.
     *
     * @param artifact The owner Artifact.
     *
     * @return the directory for WSPLEN data.
     */
    protected File getDirectory(FLYSArtifact artifact) {
        String shapePath = FLYSUtils.getXPathString(
            FLYSUtils.XPATH_FLOODMAP_SHAPEFILE_DIR);

        File artifactDir = FileTools.getDirectory(
            shapePath, artifact.identifier());

        return artifactDir;
    }


    /**
     * 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_FLOODMAP_SHAPEFILE_DIR);

        File artifactDir = new File(shapePath, artifact.identifier());

        if (artifactDir.exists()) {
            logger.info("Delete directory: " + artifactDir.getAbsolutePath());
            if (!FileTools.deleteRecursive(artifactDir)) {
                logger.warn("Could not delete directory: "
                        + artifactDir.getAbsolutePath());
            }
        }
        else {
            logger.debug("There is no directory to remove.");
        }
    }


    @Override
    public void endOfLife(Artifact artifact, Object callContext) {
        logger.info("FloodMapState.endOfLife: " + artifact.identifier());

        FLYSArtifact flys = (FLYSArtifact) artifact;

        Scheduler scheduler = Scheduler.getInstance();
        scheduler.cancelJob(flys.identifier());
    }


    protected WSPLGENJob prepareWSPLGENJob(
        FLYSArtifact       artifact,
        FacetCreator       facetCreator,
        File               artifactDir,
        CallContext        context,
        WSPLGENCalculation calculation
    ) {
        logger.debug("FloodMapState.prepareWSPLGENJob");
        String scenario = artifact.getDataAsString("scenario");

        WSPLGENJob job = new WSPLGENJob(
            artifact,
            artifactDir,
            facetCreator,
            context,
            calculation);

        File paraFile = new File(artifactDir, WSPLGEN_PARAMETER_FILE);

        setOut(artifact, job);
        setRange(artifact, job);
        setDelta(artifact, job);
        setGel(artifact, job);
        setDist(artifact, job);
        setAxis(artifact, artifactDir, job);
        setPro(artifact, artifactDir, job);
        setDgm(artifact, job, context);
        setArea(artifact, artifactDir, job);
        setOutFile(artifact, job);
        setWsp(artifact, context, artifactDir, job);    // WSP
        if (scenario.equals("scenario.current")) {
            setOfficialHWS(artifact, facetCreator, artifactDir, job);
        }
        else if (scenario.equals("scenario.scenario")) {
            setAdditionalHWS(artifact, facetCreator, artifactDir, job);
            setLine(artifact, facetCreator, artifactDir, job);
            setUserShape(artifact, facetCreator, artifactDir, job);
        }
        // TODO
        // setWspTag(artifact, job);

        try {
            job.toFile(paraFile);

            return job;
        }
        catch (IOException ioe) {
            logger.warn("Cannot write PAR file: " + ioe.getMessage());
        }
        catch (IllegalArgumentException iae) {
            logger.warn("Cannot write PAR file: " + iae.getMessage());
        }

        return null;
    }


    private void setAdditionalHWS(
        FLYSArtifact artifact,
        FacetCreator facetCreator,
        File dir,
        WSPLGENJob job) {
        File line = new File(dir, HWS_LINES_SHAPE);
        boolean lines = line.exists();
        logger.debug("shp file exists: " + lines);
        if (lines) {
            job.addLin(dir + "/" + HWS_LINES_SHAPE);
            facetCreator.createShapeFacet(I18N_HWS_LINES_OFFICIAL,
                MapfileGenerator.MS_LAYER_PREFIX + HWS_LINES,
                FLOODMAP_LINES, 2);
        }
        File point = new File(dir, HWS_POINT_SHAPE);
        boolean points = point.exists();
        logger.debug("shp file exists: " + points);
        if (points) {
            facetCreator.createShapeFacet(I18N_HWS_POINTS_OFFICIAL,
                MapfileGenerator.MS_LAYER_PREFIX + HWS_POINTS,
                FLOODMAP_FIXPOINTS, 3);
        }
    }


    private void setOfficialHWS(
        FLYSArtifact artifact,
        FacetCreator facetCreator,
        File artifactDir,
        WSPLGENJob job) {
        String river = artifact.getDataAsString("river");

        HWSContainer hwsLines = HWSFactory.getHWSLines(river);
        List<HWS> selectedLines = hwsLines.getOfficialHWS();

        FeatureCollection collectionLines = FeatureCollections.newCollection();
        SimpleFeatureType lineType = null;
        for (HWS h : selectedLines) {
            lineType = h.getFeatureType();
            collectionLines.add(h.getFeature());
        }
        boolean successLines = false;
        if (lineType != null && collectionLines.size() > 0) {
            File shapeLines = new File(artifactDir, HWS_LINES_SHAPE);
            successLines = GeometryUtils.writeShapefile(
                shapeLines, lineType, collectionLines);
        }
       if (successLines) {
            createMapfile(
                artifact,
                artifactDir,
                MapfileGenerator.MS_LAYER_PREFIX + "hws-lines",
                HWS_LINES_SHAPE,
                "LINE",
                "31467",
                "hws");
            job.addLin(artifactDir + "/" + HWS_LINES_SHAPE);
            facetCreator.createShapeFacet(I18N_HWS_LINES_OFFICIAL,
                MapfileGenerator.MS_LAYER_PREFIX + HWS_LINES,
                FLOODMAP_HWS_LINES,2);
        }
    }


    private void createMapfile(
        FLYSArtifact artifact,
        File artifactDir,
        String name,
        String hwsShapefile,
        String type,
        String srid,
        String group
    ) {
        LayerInfo info = new LayerInfo();
        info.setName(name + artifact.identifier());
        info.setType(type);
        info.setDirectory(artifact.identifier());
        info.setTitle(name);
        info.setData(hwsShapefile);
        info.setSrid(srid);
        info.setGroupTitle(group);
        MapfileGenerator generator = new ArtifactMapfileGenerator();
        Template tpl = generator.getTemplateByName(MapfileGenerator.SHP_LAYER_TEMPLATE);
        try {
            File layer = new File(artifactDir.getCanonicalPath() + "/" + name);
            generator.writeLayer(info, layer, tpl);
            List<String> layers = new ArrayList<String>();
            layers.add(layer.getAbsolutePath());
            generator.generate();
        }
        catch(FileNotFoundException fnfe) {
            logger.warn("Could not find mapfile for hws layer");
        }
        catch (Exception ioe) {
            logger.warn("Could not create mapfile for hws layer");
            logger.warn(Arrays.toString(ioe.getStackTrace()));
        }
    }


    protected void setOut(FLYSArtifact artifact, WSPLGENJob job) {
        job.setOut(WSPLGEN_DEFAULT_OUTPUT);
    }


    protected void setRange(FLYSArtifact artifact, WSPLGENJob job) {
        RangeAccess rangeAccess = new RangeAccess(artifact, null);
        double[] range = rangeAccess.getKmRange();

        job.setStart(range[0]);
        job.setEnd(range[1]);
    }


    protected void setDelta(FLYSArtifact artifact, WSPLGENJob job) {
        String from = artifact.getDataAsString("diff_from");
        String to   = artifact.getDataAsString("diff_to");
        String diff = artifact.getDataAsString("diff_diff");

        try {
            job.setFrom(Double.parseDouble(from));
        }
        catch (NumberFormatException nfe) {
        }

        try {
            job.setTo(Double.parseDouble(to));
        }
        catch (NumberFormatException nfe) {
        }

        try {
            job.setDiff(Double.parseDouble(diff));
        }
        catch (NumberFormatException nfe) {
        }
    }


    protected void setGel(FLYSArtifact artifact, WSPLGENJob job) {
        String gel = artifact.getDataAsString("scenario");

        logger.debug("Selected gel = '" + gel + "'");

        if (gel == null || gel.length() == 0) {
            job.setGel(WSPLGENJob.GEL_NOSPERRE);
        }
        else if (gel.equals("scenario.current")) {
            job.setGel(WSPLGENJob.GEL_SPERRE);
        }
        else if (gel.equals("scenario.scenario")) {
            job.setGel(WSPLGENJob.GEL_SPERRE);
        }
        else {
            job.setGel(WSPLGENJob.GEL_NOSPERRE);
        }
    }


    protected void setDist(FLYSArtifact artifact, WSPLGENJob job) {
        String dist = artifact.getDataAsString("profile_distance");

        try {
            job.setDist(Double.parseDouble(dist));
        }
        catch (NumberFormatException nfe) {
            // nothing to do here
        }
    }


    protected void setLine(
        FLYSArtifact artifact,
        FacetCreator facetCreator,
        File         dir,
        WSPLGENJob   job
    ) {
        String river   = artifact.getDataAsString("river");
        String geoJSON = artifact.getDataAsString("uesk.barriers");
        String srid    = FLYSUtils.getRiverDGMSrid(river);
        String srs     = "EPSG:" + srid;

        if (geoJSON == null || geoJSON.length() == 0) {
            logger.debug("No barrier features in parameterization existing.");
            return;
        }

        SimpleFeatureType ft = getBarriersFeatureType(
            "barriers", srs, Geometry.class);

        List<SimpleFeature> features = GeometryUtils.parseGeoJSON(geoJSON, ft);
        if (features == null || features.isEmpty()) {
            logger.debug("No barrier features extracted.");
            return;
        }

        FeatureCollection[] fcs = splitLinesAndPolygons(features);

        File shapeLines = new File(dir, WSPLGEN_BARRIERS_LINES);
        File shapePolys = new File(dir, WSPLGEN_BARRIERS_POLY);

        Object[][] obj = new Object[][] {
            new Object[] { "typ", String.class }
        };

        String scenario = job.getGel();

        boolean l = GeometryUtils.writeShapefile(
            shapeLines,
            GeometryUtils.buildFeatureType("lines", srs, LineString.class, obj),
            fcs[0]);

        if (l) {
            logger.debug(
                "Successfully created barrier line shapefile. " +
                "Write shapefile path into WSPLGEN job.");
            createMapfile(
                artifact,
                dir,
                MapfileGenerator.MS_LAYER_PREFIX + "barriers-lines",
                WSPLGEN_BARRIERS_LINES,
                "LINE",
                srid,
                "barriers");

            if (scenario.equals(WSPLGENJob.GEL_NOSPERRE)) {
                logger.debug("WSPLGEN will not use barrier features.");
            }
            else {
                job.addLin(shapeLines.getAbsolutePath());
            }
        }

        boolean p = GeometryUtils.writeShapefile(
            shapePolys,
            GeometryUtils.buildFeatureType("polygons", srs, Polygon.class, obj),
            fcs[1]);


        if (p) {
            logger.debug(
                "Successfully created barrier polygon shapefile. " +
                "Write shapefile path into WSPLGEN job.");
            createMapfile(
                artifact,
                dir,
                MapfileGenerator.MS_LAYER_PREFIX + "barriers-poly",
                shapePolys.getAbsolutePath(),
                "POLYGON",
                srid,
                "barriers");

            if (scenario.equals(WSPLGENJob.GEL_NOSPERRE)) {
                logger.debug("WSPLGEN will not use barrier features.");
            }
            else {
                job.addLin(shapePolys.getAbsolutePath());
            }
        }

        if (p || l) {
            facetCreator.createBarrierFacet();
        }
    }


    protected void setUserShape(
        FLYSArtifact artifact,
        FacetCreator facetCreator,
        File         dir,
        WSPLGENJob   job
    ) {
        File archive = new File(dir, WSPLGEN_USER_SHAPE);
        boolean exists = archive.exists();
        logger.debug("shp file exists: " + exists);
        if (exists) {
            job.addLin(dir + "/" + WSPLGEN_USER_SHAPE);
            facetCreator.createShapeFacet(FacetCreator.I18N_USERSHAPE,
                MapfileGenerator.MS_LAYER_PREFIX + "user-rgd",
                FLOODMAP_USERSHAPE,
                4);
        }
    }

    protected SimpleFeatureType getBarriersFeatureType(
        String name,
        String srs,
        Class  type
    ) {
        Object[][] attrs = new Object[3][];
        attrs[0] = new Object[] { "typ", String.class };
        attrs[1] = new Object[] { "elevation", Double.class };
        attrs[2] = new Object[] { "mark.selected", Integer.class };

        return GeometryUtils.buildFeatureType(name, srs, type, attrs);
    }


    protected FeatureCollection[] splitLinesAndPolygons(List<SimpleFeature> f) {
        FeatureCollection lines    = FeatureCollections.newCollection();
        FeatureCollection polygons = FeatureCollections.newCollection();

        for (SimpleFeature feature: f) {
            Geometry geom = (Geometry) feature.getDefaultGeometry();


            if (geom instanceof LineString) {
                geom = applyElevationAttribute(feature, geom);
                lines.add(feature);
            }
            else if (geom instanceof Polygon) {
                geom = applyElevationAttribute(feature, geom);
                polygons.add(feature);
            }
            else {
                logger.warn("Feature not supported: " + geom.getClass());
            }
        }

        logger.debug("Found " + lines.size() + " barrier lines.");
        logger.debug("Found " + polygons.size() + " barrier polygons.");

        return new FeatureCollection[] { lines, polygons };
    }


    protected static Geometry applyElevationAttribute(
        SimpleFeature feature,
        Geometry      geom
    ) {
        logger.debug("Apply elevations for: " + geom.getClass());

        List<Double> elevations = extractElevations(feature);
        int           numPoints = geom.getNumPoints();
        int        numElevation = elevations.size();

        String typ = (String) feature.getAttribute("typ");

        if (numPoints > numElevation) {
            logger.warn("More vertices in Geometry than elevations given.");
        }

        Coordinate[] c = geom.getCoordinates();
        for (int i = 0; i < numPoints; i++) {
            if (i < numElevation) {
                c[i].z = elevations.get(i);
            }
            else if (typ != null && typ.equals("Graben")) {
                c[i].z = -9999d;
            }
            else {
                c[i].z = 9999d;
            }
        }

        return geom;
    }


    protected static List<Double> extractElevations(SimpleFeature feature) {
        String tmp = (String) feature.getAttribute("elevation");
        String typ = (String) feature.getAttribute("typ");

        String[] elevations = tmp == null ? null : tmp.split(" ");

        int num = elevations != null ? elevations.length : 0;

        List<Double> list = new ArrayList<Double>(num);

        for (int i = 0; i < num; i++) {
            try {
                list.add(Double.parseDouble(elevations[i]));
            }
            catch (NumberFormatException nfe) {
                logger.warn("Error while parsing elevation at pos: " + i);
                if (typ != null && typ.equals("Graben")) {
                    list.add(new Double(-9999.0));
                }
                else {
                    list.add(new Double(9999.0));
                }
            }
        }

        return list;
    }


    protected void setAxis(FLYSArtifact artifact, File dir, WSPLGENJob job) {
        String river = artifact.getDataAsString("river");
        String srid    = FLYSUtils.getRiverDGMSrid(river);
        String srs     = "EPSG:" + srid;

        List<RiverAxis> axes = null;
        try {
            axes = RiverAxis.getRiverAxis(river);
        }
        catch (HibernateException iae) {
            logger.warn("No valid river axis found for " + river);
            return;
        }
        if (axes == null || axes.isEmpty()) {
            logger.warn("Could not find river axis for: '" + river + "'");
            return;
        }

        SimpleFeatureType ft = GeometryUtils.buildFeatureType(
            "axis", srs, LineString.class);

        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
        FeatureCollection collection = FeatureCollections.newCollection();

        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);

        boolean a = GeometryUtils.writeShapefile(
            axisShape,
            GeometryUtils.buildFeatureType("axis", srs, LineString.class),
            collection);

        if (a) {
            job.setAxis(axisShape.getAbsolutePath());
        }
    }


    protected void setPro(FLYSArtifact artifact, File dir, WSPLGENJob job) {
        String river = artifact.getDataAsString("river");
        String srid    = FLYSUtils.getRiverDGMSrid(river);
        String srs     = "EPSG:" + srid;

        List<CrossSectionTrack> cst =
            CrossSectionTrack.getCrossSectionTrack(river, WSPLGEN_QPS_NAME);

        logger.debug("Found " + cst.size() + " CrossSectionTracks.");

        Object[][] attrs = new Object[2][];
        attrs[0] = new Object[] { "ELEVATION", Double.class };
        attrs[1] = new Object[] { "KILOMETER", Double.class };

        SimpleFeatureType ft = GeometryUtils.buildFeatureType(
            "qps", srs, LineString.class, attrs);

        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
        FeatureCollection collection = FeatureCollections.newCollection();

        int i = 0;
        for (CrossSectionTrack track: cst) {
            builder.reset();
            builder.add(track.getGeom());
            builder.add(track.getZ().doubleValue());
            builder.add(track.getKm().doubleValue());

            collection.add(builder.buildFeature(String.valueOf(i++)));
        }

        File qpsShape = new File(dir, WSPLGEN_QPS);

        boolean q = GeometryUtils.writeShapefile(
            qpsShape,
            GeometryUtils.buildFeatureType("qps", srs, LineString.class, attrs),
            collection);

        if (q) {
            job.setPro(qpsShape.getAbsolutePath());
        }
    }


    protected void setDgm(
        FLYSArtifact artifact,
        WSPLGENJob job,
        CallContext context
    ) {
        String dgm_id = artifact.getDataAsString("dgm");

        int id = -1;
        try {
            id = Integer.parseInt(dgm_id);
        }
        catch (NumberFormatException nfe) { /* do nothing */ }

        DGM dgm = DGM.getDGM(id);

        if (dgm == null) {
            logger.warn("Could not find specified DGM.");

            return;
        }

        File dgmPath = new File (dgm.getPath());
        if (dgmPath.isAbsolute()) {
            job.setDgm(dgm.getPath());
        }
        else {
            FLYSContext fc = (FLYSContext)context.globalContext();
            String prefix = (String) fc.get("dgm-path");
            job.setDgm(prefix.trim() + dgm.getPath().trim());
        }
    }


    protected void setArea(FLYSArtifact artifact, File dir, WSPLGENJob job) {
        String useFloodplain = artifact.getDataAsString("use_floodplain");
        if (!Boolean.valueOf(useFloodplain)) {
            logger.debug("WSPLGEN will not use floodplain.");
            return;
        }

        String river = artifact.getDataAsString("river");
        String srid  = FLYSUtils.getRiverDGMSrid(river);
        String srs   = "EPSG:" + srid;

        Floodplain plain = Floodplain.getFloodplain(river);

        SimpleFeatureType ft = GeometryUtils.buildFeatureType(
            "talaue", srs, Polygon.class);

        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
        builder.add(plain.getGeom());

        FeatureCollection collection = FeatureCollections.newCollection();
        collection.add(builder.buildFeature("0"));

        File talaueShape = new File(dir, WSPLGEN_FLOODPLAIN);

        boolean t = GeometryUtils.writeShapefile(
            talaueShape,
            GeometryUtils.buildFeatureType("talaue", srs, Polygon.class),
            collection);

        if (t) {
            job.setArea(talaueShape.getAbsolutePath());
        }
    }


    protected void setOutFile(FLYSArtifact artifact, WSPLGENJob job) {
        job.setOutFile(WSPLGEN_OUTPUT_FILE);
    }


    protected WQKms getWQKms(FLYSArtifact flys, CallContext cc) {
        String   wspString = flys.getDataAsString(WSP_ARTIFACT);
        if (wspString == null) {
            logger.debug("getWQKms(): wspString == null");
            return null;
        }
        String[] parts = wspString.split(";");
        String otherArtifact = parts[0];

        int idx = -1;
        try {
            idx = Integer.parseInt(parts[2]);
        }
        catch (NumberFormatException nfe) { /* do nothing */ }

        FLYSArtifact src = otherArtifact != null
            ? FLYSUtils.getArtifact(otherArtifact, cc)
            : flys;

        logger.debug("Use waterlevel provided by Artifact: " + src.identifier());

        CalculationResult rawData = (CalculationResult) src.compute(
            cc,
            null,
            WINFO_WSP_STATE_ID,
            ComputeType.ADVANCE,
            false);

        WQKms[] wqkms = (WQKms[]) rawData.getData();

        return wqkms == null || idx == -1 || idx >= wqkms.length
            ? null
            : wqkms[idx];
    }


    protected void setWsp(
        FLYSArtifact artifact,
        CallContext  context,
        File         dir,
        WSPLGENJob   job)
    {
        logger.debug("FloodMapState.setWsp");

        WQKms data = getWQKms(artifact, context);

        if (data == null) {
            logger.warn("No WST data found!");
            return;
        }

        WstWriter writer = new WstWriter(1);

        // TODO REMOVE job.setWspTag(...) This is only used until the user is
        // able to select the WSP column himself!
        boolean writeWspTag = true;

        double[] buf = new double[4];
        logger.debug("Add WST column: " + data.getName());
        writer.addColumn(data.getName());

        if (writeWspTag) {
            job.setWspTag(data.getName());
            writeWspTag = false;
        }

        for (int i = 0, num = data.size(); i < num; i++) {
            data.get(i, buf);
            writer.add(buf);
        }

        FileOutputStream fout = null;

        try {
            File wspFile = new File(dir, WSPLGEN_WSP_FILE);
            fout         = new FileOutputStream(wspFile);

            writer.write(fout);

            job.setWsp(wspFile.getAbsolutePath());
        }
        catch (FileNotFoundException fnfe) {
            logger.warn("Error while writing wsp file: " + fnfe.getMessage());
        }
        finally {
            if (fout != null) {
                try {
                    fout.close();
                }
                catch (IOException ioe) { /* do nothing */ }
            }
        }
    }



}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org