view flys-artifacts/src/main/java/de/intevation/flys/utils/FLYSUtils.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 aa9cc91c8193
children bf67eb014443
line wrap: on
line source
package de.intevation.flys.utils;

import org.apache.log4j.Logger;

import java.text.NumberFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.xpath.XPathConstants;

import org.w3c.dom.Document;

import org.hibernate.SessionFactory;
import org.hibernate.impl.SessionFactoryImpl;

import gnu.trove.TDoubleArrayList;

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

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

import de.intevation.flys.backend.SessionFactoryProvider;

import de.intevation.flys.artifacts.context.FLYSContext;
import de.intevation.flys.artifacts.FLYSArtifact;
import de.intevation.flys.artifacts.WINFOArtifact;
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.model.Gauge;
import de.intevation.flys.model.MainValue;
import de.intevation.flys.model.River;

public class FLYSUtils {

    /** The logger that is used in this utility. */
    private static Logger logger = Logger.getLogger(FLYSUtils.class);

    public static enum KM_MODE { RANGE, LOCATIONS, NONE };

    /**
     * An enum that represents the 5 possible WQ modes in FLYS. The 5 values are
     * <i>QFREE</i> <i>QGAUGE</i> <i>WGAUGE</i> <i>WFREE</i> and <i>NONE</i>.
     */
    public static enum WQ_MODE { QFREE, QGAUGE, WFREE, WGAUGE, NONE };


    public static final Pattern NUMBERS_PATTERN =
        Pattern.compile("\\D*(\\d++.\\d*)\\D*");

    public static final String XPATH_RIVER_PROJECTION =
        "/artifact-database/floodmap/river[@name=$name]/srid/@value";

    public static final String XPATH_SHAPEFILE_DIR =
        "/artifact-database/floodmap/shapefile-path/@value";

    public static final String XPATH_VELOCITY_LOGFILE =
        "/artifact-database/floodmap/velocity/logfile/@path";

    public static final String XPATH_MAPSERVER_URL =
        "/artifact-database/floodmap/mapserver/server/@path";

    public static final String XPATH_MAPFILE_PATH =
        "/artifact-database/floodmap/mapserver/mapfile/@path";

    public static final String XPATH_MAPFILE_TEMPLATE =
        "/artifact-database/floodmap/mapserver/map-template/@path";

    public static final String XPATH_MAPSERVER_TEMPLATE_PATH =
        "/artifact-database/floodmap/mapserver/templates/@path";


    private FLYSUtils() {
    }


    /**
     * Pulls Artifact with given UUID fromm database.
     * @return FLYSArtifact with given UUID or null (in case of errors).
     */
    public static FLYSArtifact getArtifact(String uuid, CallContext context) {
        try {
            Artifact artifact = context.getDatabase().getRawArtifact(uuid);

            if (artifact == null) {
                logger.error("Artifact '" + uuid + "' does not exist.");
                return null;
            }

            if (!(artifact instanceof FLYSArtifact)) {
                logger.error("Artifact '" +uuid+ "' is no valid FLYSArtifact.");
                return null;
            }

            return (FLYSArtifact) artifact;
        }
        // TODO: catch more selective
        catch (Exception e) {
            logger.error("Cannot get FLYSArtifact " + uuid
                + " from database (" + e.getMessage() + ").");
            return null;
        }
    }


    /**
     * Returns the FLYSContext from context object.
     *
     * @param context The CallContext or the FLYSContext.
     *
     * @return the FLYSContext.
     */
    public static FLYSContext getFlysContext(Object context) {
        return context instanceof FLYSContext
            ? (FLYSContext) context
            : (FLYSContext) ((CallContext) context).globalContext();
    }


    /**
     * Convinience function to retrieve an XPath as string with replaced config
     * directory.
     *
     * @param xpath The XPath expression.
     *
     * @return a string with replaced config directory.
     */
    public static String getXPathString(String xpath) {
        String tmp = Config.getStringXPath(xpath);
        tmp        = Config.replaceConfigDir(tmp);

        return tmp;
    }


    public static boolean isUsingOracle() {
        SessionFactory sf = SessionFactoryProvider.getSessionFactory();

        String d = SessionFactoryProvider.getDriver((SessionFactoryImpl) sf);

        return d != null ? d.indexOf("Oracle") >= 0 : false;
    }


    /**
     * 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
     * existing, WQ_MODE.NONE is returned.
     *
     * @param flys The FLYSArtifact that stores wq mode relevant parameters.
     *
     * @return an enum WQ_MODE.
     */
    public static WQ_MODE getWQMode(FLYSArtifact flys) {
        if (flys == null) {
            return WQ_MODE.NONE;
        }

        String  mode = flys.getDataAsString("wq_mode");
        Boolean free = flys.getDataAsBoolean("wq_free");

        free = free != null ? free : false;

        if (mode != null && mode.equals("Q")) {
            return free ? WQ_MODE.QFREE : WQ_MODE.QGAUGE;
        }
        else if (mode != null && mode.equals("W")) {
            return free ? WQ_MODE.WFREE : WQ_MODE.WGAUGE;
        }
        else {
            return WQ_MODE.NONE;
        }
    }


    public static KM_MODE getKmRangeMode(FLYSArtifact flys) {
        String mode = flys.getDataAsString("ld_mode");

        if (mode == null || mode.length() == 0) {
            return KM_MODE.NONE;
        }
        else if (mode.equals("distance"))  {
            return KM_MODE.RANGE;
        }
        else if (mode.equals("locations")) {
            return KM_MODE.LOCATIONS;
        }
        else {
            return KM_MODE.NONE;
        }
    }

    /**
     * Get min and max kilometer, independent of parametization
     * (ld_from/to vs ld_locations).
     */
    public static double[] getKmRange(FLYSArtifact flys) {
        switch (getKmRangeMode(flys)) {
            case RANGE: {
                return getKmFromTo(flys);
            }

            case LOCATIONS: {
                double[] locs = getLocations(flys);
                return new double[] { locs[0], locs[locs.length-1] };
            }

            case NONE: {
                double[] locs = getLocations(flys);
                if (locs != null) {
                    return new double[] { locs[0], locs[locs.length-1] };
                }
                else {
                    return getKmFromTo(flys);
                }
            }
        }

        return new double[] { Double.NaN, Double.NaN };
    }


    public static double[] getKmFromTo(FLYSArtifact flys) {
        String strFrom = flys.getDataAsString("ld_from");
        String strTo   = flys.getDataAsString("ld_to");

        if (strFrom == null || strTo == null) {
            return null;
        }

        try {
            return new double[] {
                Double.parseDouble(strFrom),
                Double.parseDouble(strTo) };
        }
        catch (NumberFormatException nfe) {
            return null;
        }
    }


    /**
     * Return sorted array of locations at which stuff was calculated
     * (from ld_locations data), null if not parameterized this way.
     */
    public static double[] getLocations(FLYSArtifact flys) {
        String locationStr = flys.getDataAsString("ld_locations");

        if (locationStr == null || locationStr.length() == 0) {
            return null;
        }

        String[] tmp               = locationStr.split(" ");
        TDoubleArrayList locations = new TDoubleArrayList();

        for (String l: tmp) {
            try {
                locations.add(Double.parseDouble(l));
            }
            catch (NumberFormatException nfe) {
            }
        }

        locations.sort();

        return locations.toNativeArray();
    }


    /**
     * Returns the Qs for a given FLYSArtifact. This method currently accepts
     * only instances of WINFOArtifact.
     *
     * @param flys A FLYSArtifact.
     *
     * @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);
        }

        logger.warn("This method currently supports WINFOArtifact only!");

        return null;
    }


    /**
     * Returns the Ws for a given FLYSArtifact. This method currently accepts
     * only instances of WINFOArtifact.
     *
     * @param flys A FLYSArtifact.
     *
     * @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);
        }

        logger.warn("This method currently supports WINFOArtifact only!");

        return null;
    }


    /**
     * Returns the selected River object based on the 'river' data that might
     * have been inserted by the user.
     *
     * @return the selected River or null if no river has been chosen yet.
     */
    public static River getRiver(FLYSArtifact flys) {
        String sRiver = getRivername(flys);

        return (sRiver != null)
            ? RiverFactory.getRiver(sRiver)
            : null;
    }


    /**
     * Returns the name of the river specified in the given <i>flys</i>
     * Artifact.
     *
     * @param flys The FLYSArtifact that stores a river relevant information.
     *
     * @return the name of the specified river or null.
     */
    public static String getRivername(FLYSArtifact flys) {
        return flys != null ? flys.getDataAsString("river") : null;
    }


    /**
     * Extracts the SRID defined in the global configuration for the river
     * specified in <i>artifact</i>.
     *
     * @param artifact The FLYSArtifact that stores the name of the river.
     *
     * @return the SRID as string (e.g. "31466").
     */
    public static String getRiverSrid(FLYSArtifact artifact) {
        String river = artifact.getDataAsString("river");

        if (river == null || river.length() == 0) {
            return null;
        }

        return getRiverSrid(river);
    }


    public static String getRiverSrid(String rivername) {
        Map<String, String> variables = new HashMap<String, String>(1);
        variables.put("name", rivername);

        Document cfg = Config.getConfig();

        return (String) XMLUtils.xpath(
            cfg,
            XPATH_RIVER_PROJECTION,
            XPathConstants.STRING,
            null,
            variables);
    }


    public static Gauge getGauge(FLYSArtifact flys) {
        River river = getRiver(flys);

        if (river == null) {
            logger.debug("no river found");
            return null;
        }

        double[] dist  = getKmRange(flys);

        if (dist == null) {
            logger.debug("no range found");
            return null;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Determine gauge for:");
            logger.debug("... river: " + river.getName());
            logger.debug("... distance: " + dist[0] + " - " + dist[1]);
        }

        Gauge gauge = river.determineGauge(dist[0], dist[1]);

        String name = gauge != null ? gauge.getName() : "'n/a";
        logger.debug("Found gauge: " + name);

        return gauge;
    }


    public static String getGaugename(FLYSArtifact flys) {
        Gauge gauge = getGauge(flys);

        return gauge != null ? gauge.getName() : null;
    }


    public static Double getValueFromWQ(WQ wq) {
        if (wq == null) {
            return null;
        }

        Matcher m = NUMBERS_PATTERN.matcher(wq.getName());

        if (m.matches()) {
            logger.debug("Found a number.");

            String raw = m.group(1);

            try {
                return Double.valueOf(raw);
            }
            catch (NumberFormatException nfe) {
            }
        }

        return null;
    }


    public static String createWspWTitle(
        WINFOArtifact winfo,
        CallContext   cc,
        String        name
    ) {
        String[] parts = name.split("=");

        NumberFormat nf = Formatter.getWaterlevelW(cc);

        String namedMainValue = null;

        boolean isQ    = winfo.isQ();
        boolean isFree = winfo.isFreeQ();

        double v;

        try {
            v = Double.valueOf(parts[1]);

            namedMainValue = getNamedMainValue(winfo.getGauge(), v);
        }
        catch (NumberFormatException nfe) {
            logger.warn("Cannot parse Double of: '" + parts[1] + "'");
            return name;
        }

        String prefix = null;

        if (isQ && !isFree && namedMainValue != null) {
            return "W (" + namedMainValue + ")";
        }

        if (isQ) {
            prefix = "Q=";
        }

        return prefix == null
            ? "W(" + nf.format(v) + ")"
            : "W(" + prefix + nf.format(v) + ")";
    }


    public static String createWspQTitle(
        WINFOArtifact winfo,
        CallContext   cc,
        String        name
    ) {
        String[] parts = name.split("=");

        NumberFormat nf = Formatter.getWaterlevelQ(cc);

        String namedMainValue = null;

        boolean isQ    = winfo.isQ();
        boolean isFree = winfo.isFreeQ();

        double v;

        try {
            v = Double.valueOf(parts[1]);

            namedMainValue = getNamedMainValue(winfo.getGauge(), v);
        }
        catch (NumberFormatException nfe) {
            logger.warn("Cannot parse Double of: '" + parts[1] + "'");
            return name;
        }

        String prefix = null;

        if (isQ && !isFree && namedMainValue != null) {
            return namedMainValue;
        }

        if (!isQ) {
            prefix = "W=";
        }

        return prefix == null
            ? "Q(" + nf.format(v) + ")"
            : "Q(" + prefix + nf.format(v) + ")";
    }


    /**
     * Returns the named main value if a Q was selected and if this Q fits to a
     * named main value. Otherwise, this function returns null.
     *
     * @param winfo The WINFO Artifact.
     * @param value The Q (or W) value.
     *
     * @return a named main value or null.
     */
    public static String getNamedMainValue(WINFOArtifact winfo, double value) {
        WQ_MODE wqmode = getWQMode(winfo);

        if (wqmode != WQ_MODE.QGAUGE) {
            return null;
        }
        else {
            return getNamedMainValue(winfo.getGauge(), value);
        }
    }


    public static String getNamedMainValue(Gauge gauge, double value) {
        List<MainValue> mainValues = gauge.getMainValues();
        logger.debug("Search named main value for: " + value);

        for (MainValue mv: mainValues) {
            if (mv.getValue().doubleValue() == value) {
                logger.debug("Found named main value: " + mv.getMainValue().getName());
                return mv.getMainValue().getName();
            }
        }

        logger.debug("Did not find a named main value for: " + value);
        return null;
    }


    /**
     *
     * @param nmv A string that represents a named main value.
     *
     * @throws NullPointerException if nmv is null.
     */
    public static String stripNamedMainValue(String nmv) {
        int startIndex = nmv.indexOf("(");
        int endIndex   = nmv.indexOf(")");

        if (startIndex > 0 && endIndex > 0 && startIndex < endIndex) {
            return nmv.substring(0, startIndex);
        }

        return nmv;
    }


    /**
     * Returns the URL of user mapfile for the owner of Artifact
     * <i>artifactId</i>.
     *
     * @param artifactId The UUID of an artifact.
     *
     * @return the URL of the user wms.
     */
    public static String getUserWMSUrl(String artifactId) {
        String url = getXPathString(XPATH_MAPSERVER_URL);
        url = url + "user-wms";

        return url;
    }


    /**
     * This method returns the description for a given <i>km</i> for a specific
     * river. The river is provided by the FLYSArtifact <i>flys</i>.
     *
     * @param flys The FLYSArtifact that provides a river.
     * @param km The kilometer.
     *
     * @return the description for <i>km</i> or an empty string if no
     * description was found.
     */
    public static String getLocationDescription(FLYSArtifact flys, double km) {
        String river = getRivername(flys);

        if (river == null) {
            return "";
        }

        return LocationProvider.getLocation(river, km);
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org