view flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/WQAdapted.java @ 2089:0da8874bd378

Added initial state to map artifact to be able to advance and step back. The map artifact overrides describe() to have the complete UI information in the describe response document. flys-artifacts/trunk@3613 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Raimund Renkert <raimund.renkert@intevation.de>
date Fri, 06 Jan 2012 12:02:10 +0000
parents e0243627ba62
children 44dc117aa2b7
line wrap: on
line source
package de.intevation.flys.artifacts.states;

import java.util.ArrayList;
import java.util.List;
import java.util.Comparator;
import java.util.Collections;

import org.apache.log4j.Logger;

import org.w3c.dom.Element;

import de.intevation.artifacts.Artifact;
import de.intevation.artifacts.CallContext;

import de.intevation.artifactdatabase.ProtocolUtils;
import de.intevation.artifactdatabase.data.StateData;

import de.intevation.artifacts.common.utils.XMLUtils;

import de.intevation.flys.model.Gauge;
import de.intevation.flys.model.Range;
import de.intevation.flys.model.River;
import de.intevation.flys.model.Wst;

import de.intevation.flys.artifacts.WINFOArtifact;

import de.intevation.flys.artifacts.model.RangeWithValues;
import de.intevation.flys.artifacts.model.WstFactory;
import de.intevation.flys.utils.FLYSUtils;


/**
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class WQAdapted extends DefaultState {

    /** 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_VALUES = "wq_values";

    public static final class GaugeOrder implements Comparator<Gauge> {
        private int order;

        public GaugeOrder(boolean up) {
            order = up ? 1 : -1;
        }

        public int compare(Gauge a, Gauge b) {
            return order * a.getRange().getA().compareTo(b.getRange().getA());
        }
    } // class GaugeOrder

    public static final GaugeOrder GAUGE_UP   = new GaugeOrder(true);
    public static final GaugeOrder GAUGE_DOWN = new GaugeOrder(false);

    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
     * (from;to) where <i>from</i> is the lower bounds of the gauge or the lower
     * kilometer range. <i>to</i> is the upper bounds of the gauge or the upper
     * kilometer range.
     *
     * @param cr The ElementCreator.
     * @param artifact The FLYS artifact.
     * @param name The name of the data item.
     * @param context The CallContext.
     *
     * @return a list of elements that consist of tuples of the intersected
     * gauges of the selected river.
     */
    @Override
    protected Element[] createItems(
        XMLUtils.ElementCreator cr,
        Artifact    artifact,
        String      name,
        CallContext context)
    {
        logger.debug("WQAdapted.createItems");

        if (name != null && name.equals(FIELD_WQ_MODE)) {
            return createModeItems(cr, artifact, name, context);
        }
        else if (name != null && name.equals(FIELD_WQ_VALUES)) {
            return createValueItems(cr, artifact, name, context);
        }
        else {
            logger.warn("Unknown data object: " + name);
            return null;
        }
    }


    protected Element[] createModeItems(
        XMLUtils.ElementCreator cr,
        Artifact    artifact,
        String      name,
        CallContext context)
    {
        logger.debug("WQAdapted.createModeItems");

        Element w = createItem(cr, new String[] { "w", "W" });
        Element q = createItem(cr, new String[] { "q", "Q" });

        return new Element[] { w, q };
    }


    protected Element[] createValueItems(
        XMLUtils.ElementCreator cr,
        Artifact    artifact,
        String      name,
        CallContext context)
    {
        logger.debug("WQAdapted.createValueItems");

        WINFOArtifact flysArtifact = (WINFOArtifact) artifact;

        double[]    dist   = FLYSUtils.getKmRange(flysArtifact);
        River       river  = FLYSUtils.getRiver(flysArtifact);
        Wst         wst    = WstFactory.getWst(river);
        List<Gauge> gauges = flysArtifact.getGauges();

        int num = gauges != null ? gauges.size() : 0;

        if (num == 0) {
            logger.warn("Selected distance matches no gauges.");
            return null;
        }

        Element[] elements = new Element[num];

        double rangeFrom = dist[0];
        double rangeTo   = dist[1];

        int idx = 0;

        if (rangeFrom < rangeTo) {
            Collections.sort(gauges, GAUGE_UP);
            for (Gauge gauge: gauges) {
                Range range = gauge.getRange();
                double lower = range.getA().doubleValue();
                double upper = range.getB().doubleValue();

                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);
            }
        }
        else {
            Collections.sort(gauges, GAUGE_DOWN);
            rangeFrom = dist[1];
            rangeTo   = dist[0];
            for (Gauge gauge: gauges) {
                Range range = gauge.getRange();
                double lower = range.getA().doubleValue();
                double upper = range.getB().doubleValue();

                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[] { to + ";" + from, ""}, mmQ, mmW);
            }
        }

        return elements;
    }


    protected Element createItem(XMLUtils.ElementCreator cr, Object obj) {
        return createItem(cr, obj, null, null);
    }


    protected Element createItem(
        XMLUtils.ElementCreator cr,
        Object   obj,
        double[] q,
        double[] w)
    {
        Element item  = ProtocolUtils.createArtNode(cr, "item", null, null);
        Element label = ProtocolUtils.createArtNode(cr, "label", null, null);
        Element value = ProtocolUtils.createArtNode(cr, "value", null, null);

        String[] arr = (String[]) obj;

        label.setTextContent(arr[0]);
        value.setTextContent(arr[1]);

        item.appendChild(label);
        item.appendChild(value);

        if (q != null) {
            Element qRange = createRangeElement(cr, q, "Q");
            item.appendChild(qRange);
        }

        if (w != null) {
            Element wRange = createRangeElement(cr, w, "W");
            item.appendChild(wRange);
        }

        return item;
    }


    protected Element createRangeElement(
        XMLUtils.ElementCreator cr,
        double[] mm,
        String   type)
    {
        Element range = ProtocolUtils.createArtNode(
            cr, "range",
            new String[] {"type"},
            new String[] {type});

        Element min = ProtocolUtils.createArtNode(cr, "min", null, null);
        min.setTextContent(String.valueOf(mm[0]));

        Element max = ProtocolUtils.createArtNode(cr, "max", null, null);
        max.setTextContent(String.valueOf(mm[1]));

        range.appendChild(min);
        range.appendChild(max);

        return range;
    }


    /**
     * Determines the min and max Q value for the given gauge. If no min and
     * max values could be determined, this method will return
     * [Double.MIN_VALUE, Double.MAX_VALUE].
     *
     * @param gauge
     * @param wst
     *
     * @return the min and max Q values for the given gauge.
     */
    protected double[] determineMinMaxQ(Gauge gauge, Wst wst) {
        logger.debug("WQAdapted.determineMinMaxQ");

        double[] minmaxQ = gauge != null
            ? wst.determineMinMaxQ(gauge.getRange())
            : null;

        double minQ = minmaxQ != null ? minmaxQ[0] : Double.MIN_VALUE;
        double maxQ = minmaxQ != null ? minmaxQ[1] : Double.MAX_VALUE;

        return new double[] { minQ, maxQ };
    }


    @Override
    protected String getUIProvider() {
        return "wq_panel_adapted";
    }


    @Override
    public boolean validate(Artifact artifact)
    throws IllegalArgumentException
    {
        logger.debug("WQAdapted.validate");

        WINFOArtifact flys = (WINFOArtifact) artifact;
        StateData    data = getData(flys, FIELD_WQ_MODE);

        String mode = data != null ? (String) data.getValue() : null;

        if (mode != null && mode.equals("W")) {
            return validateW(artifact);
        }
        else if (mode != null && mode.equals("Q")) {
            return validateQ(artifact);
        }
        else {
            throw new IllegalArgumentException("error_feed_no_wq_mode_selected");
        }
    }


    protected boolean validateW(Artifact artifact)
    throws IllegalArgumentException
    {
        logger.debug("WQAdapted.validateW");
        WINFOArtifact flys = (WINFOArtifact) artifact;

        RangeWithValues[] rwvs = extractInput(getData(flys, "wq_values"));

        if (rwvs == null) {
            throw new IllegalArgumentException("error_missing_wq_data");
        }

        List<Gauge>     gauges = ((WINFOArtifact) artifact).getGauges();

        for (Gauge gauge: gauges) {
            Range range  = gauge.getRange();
            double lower = range.getA().doubleValue();
            double upper = range.getB().doubleValue();

            for (RangeWithValues rwv: rwvs) {
                if (lower <= rwv.getLower() && upper >= rwv.getUpper()) {
                    compareWsWithGauge(gauge, rwv.getValues());
                }
            }
        }

        return true;
    }


    protected boolean validateQ(Artifact artifact)
    throws IllegalArgumentException
    {
        logger.debug("WQAdapted.validateQ");
        WINFOArtifact flys = (WINFOArtifact) artifact;

        RangeWithValues[] rwvs = extractInput(getData(flys, "wq_values"));

        if (rwvs == null) {
            throw new IllegalArgumentException("error_missing_wq_data");
        }

        List<Gauge> gauges = flys.getGauges();
        River        river = FLYSUtils.getRiver(flys);
        Wst            wst = WstFactory.getWst(river);

        for (Gauge gauge: gauges) {
            Range range  = gauge.getRange();
            double lower = range.getA().doubleValue();
            double upper = range.getB().doubleValue();

            for (RangeWithValues rwv: rwvs) {
                if (lower <= rwv.getLower() && upper >= rwv.getUpper()) {
                    compareQsWithGauge(wst, gauge, rwv.getValues());
                }
            }
        }

        return true;
    }


    protected boolean compareQsWithGauge(Wst wst, Gauge gauge, double[] qs)
    throws IllegalArgumentException
    {
        double[] minmax = gauge != null
            ? wst.determineMinMaxQ(gauge.getRange())
            : null;

        if (minmax == null) {
            logger.warn("Could not determine min/max Q of gauge.");
            return true;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Validate Qs with:");
            logger.debug("-- Gauge: " + gauge.getName());
            logger.debug("-- Gauge min: " + minmax[0]);
            logger.debug("-- Gauge max: " + minmax[1]);
        }

        for (double q: qs) {
            if (q < minmax[0] || q > minmax[1]) {
                throw new IllegalArgumentException(
                    "error_feed_q_values_invalid");
            }
        }

        return true;
    }


    protected boolean compareWsWithGauge(Gauge gauge, double[] ws)
    throws IllegalArgumentException
    {
        double[] minmax = gauge != null
            ? gauge.determineMinMaxW()
            : null;

        if (minmax == null) {
            logger.warn("Could not determine min/max W of gauge.");
            return true;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Validate Ws with:");
            logger.debug("-- Gauge: " + gauge.getName());
            logger.debug("-- Gauge min: " + minmax[0]);
            logger.debug("-- Gauge max: " + minmax[1]);
        }

        for (double w: ws) {
            if (w < minmax[0] || w > minmax[1]) {
                throw new IllegalArgumentException(
                    "error_feed_w_values_invalid");
            }
        }

        return true;
    }


    protected RangeWithValues[] extractInput(StateData data) {
        if (data == null) {
            return null;
        }

        String dataString = (String) data.getValue();
        String[]   ranges = dataString.split(":");

        List<RangeWithValues> rwv = new ArrayList<RangeWithValues>();

        for (String range: ranges) {
            String[] parts = range.split(";");

            double lower = Double.parseDouble(parts[0]);
            double upper = Double.parseDouble(parts[1]);

            String[] values = parts[2].split(",");

            int      num = values.length;
            double[] res = new double[num];

            for (int i = 0; i < num; i++) {
                try {
                    res[i] = Double.parseDouble(values[i]);
                }
                catch (NumberFormatException nfe) {
                    logger.warn(nfe, nfe);
                }
            }

            rwv.add(new RangeWithValues(lower, upper, res));
        }

        return (RangeWithValues[]) rwv.toArray(new RangeWithValues[rwv.size()]);
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org