ingo@1095: package de.intevation.flys.utils;
ingo@1095: 
felix@1150: import org.apache.log4j.Logger;
ingo@1740: 
ingo@1740: import java.text.NumberFormat;
ingo@1105: import java.util.HashMap;
ingo@1740: import java.util.List;
ingo@1105: import java.util.Map;
ingo@2068: import java.util.regex.Matcher;
ingo@2068: import java.util.regex.Pattern;
ingo@1105: 
ingo@1105: import javax.xml.xpath.XPathConstants;
ingo@1105: 
ingo@1105: import org.w3c.dom.Document;
ingo@1105: 
ingo@1845: import org.hibernate.SessionFactory;
ingo@1845: import org.hibernate.impl.SessionFactoryImpl;
ingo@1845: 
ingo@1095: import gnu.trove.TDoubleArrayList;
ingo@2216: import gnu.trove.TIntArrayList;
raimund@2600: import gnu.trove.TLongArrayList;
ingo@1095: 
ingo@1174: import de.intevation.artifacts.Artifact;
ingo@1118: import de.intevation.artifacts.CallContext;
ingo@1118: 
ingo@1105: import de.intevation.artifacts.common.utils.Config;
ingo@1105: import de.intevation.artifacts.common.utils.XMLUtils;
ingo@1105: 
ingo@1845: import de.intevation.flys.backend.SessionFactoryProvider;
ingo@1845: 
felix@1777: import de.intevation.flys.artifacts.context.FLYSContext;
ingo@1095: import de.intevation.flys.artifacts.FLYSArtifact;
ingo@1740: import de.intevation.flys.artifacts.WINFOArtifact;
raimund@2179: import de.intevation.flys.artifacts.StaticWKmsArtifact;
felix@1099: import de.intevation.flys.artifacts.model.RiverFactory;
ingo@2063: import de.intevation.flys.artifacts.model.LocationProvider;
ingo@2068: import de.intevation.flys.artifacts.model.WQ;
raimund@2179: import de.intevation.flys.artifacts.model.WKms;
raimund@2179: import de.intevation.flys.artifacts.model.WQKms;
raimund@2179: 
raimund@2179: import de.intevation.artifactdatabase.state.State;
raimund@2179: import de.intevation.flys.artifacts.states.WaterlevelSelectState;
raimund@2179: import de.intevation.flys.artifacts.states.WDifferencesState;
ingo@1740: import de.intevation.flys.model.Gauge;
ingo@1740: import de.intevation.flys.model.MainValue;
felix@1099: import de.intevation.flys.model.River;
ingo@1095: 
felix@3047: 
felix@3047: /** static helper methods to e.g. access FLYSArtifacts data. */
ingo@1095: public class FLYSUtils {
ingo@1095: 
felix@1150:     /** The logger that is used in this utility. */
felix@1150:     private static Logger logger = Logger.getLogger(FLYSUtils.class);
felix@1150: 
ingo@1095:     public static enum KM_MODE { RANGE, LOCATIONS, NONE };
ingo@1095: 
ingo@2038:     /**
ingo@2038:      * An enum that represents the 5 possible WQ modes in FLYS. The 5 values are
ingo@2038:      * <i>QFREE</i> <i>QGAUGE</i> <i>WGAUGE</i> <i>WFREE</i> and <i>NONE</i>.
ingo@2038:      */
ingo@2038:     public static enum WQ_MODE { QFREE, QGAUGE, WFREE, WGAUGE, NONE };
ingo@2038: 
ingo@2422:     /**
ingo@2422:      * An enum that represents the 4 possible WQ input modes in FLYS. The 4
ingo@2422:      * values are
ingo@2422:      * <i>ADAPTED</i> <i>SINGLE</i> <i>RANGE</i> and <i>NONE</i>.
ingo@2422:      */
ingo@2422:     public static enum WQ_INPUT { ADAPTED, SINGLE, RANGE, NONE };
ingo@2068: 
ingo@2068:     public static final Pattern NUMBERS_PATTERN =
ingo@2068:         Pattern.compile("\\D*(\\d++.\\d*)\\D*");
ingo@2068: 
ingo@1105:     public static final String XPATH_RIVER_PROJECTION =
ingo@1105:         "/artifact-database/floodmap/river[@name=$name]/srid/@value";
ingo@1105: 
ingo@1129:     public static final String XPATH_SHAPEFILE_DIR =
ingo@1129:         "/artifact-database/floodmap/shapefile-path/@value";
ingo@1129: 
ingo@1129:     public static final String XPATH_VELOCITY_LOGFILE =
ingo@1129:         "/artifact-database/floodmap/velocity/logfile/@path";
ingo@1129: 
ingo@1129:     public static final String XPATH_MAPSERVER_URL =
ingo@1129:         "/artifact-database/floodmap/mapserver/server/@path";
ingo@1129: 
ingo@1129:     public static final String XPATH_MAPFILE_PATH =
ingo@1129:         "/artifact-database/floodmap/mapserver/mapfile/@path";
ingo@1129: 
ingo@1129:     public static final String XPATH_MAPFILE_TEMPLATE =
ingo@1129:         "/artifact-database/floodmap/mapserver/map-template/@path";
ingo@1129: 
ingo@1129:     public static final String XPATH_MAPSERVER_TEMPLATE_PATH =
ingo@1129:         "/artifact-database/floodmap/mapserver/templates/@path";
ingo@1129: 
ingo@1095: 
ingo@1095:     private FLYSUtils() {
ingo@1095:     }
ingo@1095: 
ingo@1095: 
felix@2017:     /**
felix@2017:      * Pulls Artifact with given UUID fromm database.
felix@2017:      * @return FLYSArtifact with given UUID or null (in case of errors).
felix@2017:      */
ingo@1118:     public static FLYSArtifact getArtifact(String uuid, CallContext context) {
felix@1150:         try {
ingo@1174:             Artifact artifact = context.getDatabase().getRawArtifact(uuid);
ingo@1174: 
ingo@1174:             if (artifact == null) {
ingo@1174:                 logger.error("Artifact '" + uuid + "' does not exist.");
ingo@1174:                 return null;
ingo@1174:             }
ingo@1174: 
ingo@1174:             if (!(artifact instanceof FLYSArtifact)) {
ingo@1174:                 logger.error("Artifact '" +uuid+ "' is no valid FLYSArtifact.");
ingo@1174:                 return null;
ingo@1174:             }
ingo@1174: 
ingo@1174:             return (FLYSArtifact) artifact;
felix@1150:         }
felix@1150:         // TODO: catch more selective
felix@1150:         catch (Exception e) {
felix@2017:             logger.error("Cannot get FLYSArtifact " + uuid
felix@2017:                 + " from database (" + e.getMessage() + ").");
felix@1150:             return null;
felix@1150:         }
ingo@1118:     }
ingo@1118: 
ingo@1118: 
ingo@1129:     /**
felix@1777:      * Returns the FLYSContext from context object.
felix@1777:      *
felix@1777:      * @param context The CallContext or the FLYSContext.
felix@1777:      *
felix@1777:      * @return the FLYSContext.
felix@1777:      */
felix@1777:     public static FLYSContext getFlysContext(Object context) {
felix@1777:         return context instanceof FLYSContext
felix@1777:             ? (FLYSContext) context
felix@1777:             : (FLYSContext) ((CallContext) context).globalContext();
felix@1777:     }
felix@1777: 
felix@1777: 
felix@1777:     /**
ingo@1129:      * Convinience function to retrieve an XPath as string with replaced config
ingo@1129:      * directory.
ingo@1129:      *
ingo@1129:      * @param xpath The XPath expression.
ingo@1129:      *
ingo@1129:      * @return a string with replaced config directory.
ingo@1129:      */
ingo@1129:     public static String getXPathString(String xpath) {
ingo@1129:         String tmp = Config.getStringXPath(xpath);
ingo@1129:         tmp        = Config.replaceConfigDir(tmp);
ingo@1129: 
ingo@1129:         return tmp;
ingo@1129:     }
ingo@1129: 
ingo@1129: 
ingo@1845:     public static boolean isUsingOracle() {
ingo@1845:         SessionFactory sf = SessionFactoryProvider.getSessionFactory();
ingo@1845: 
ingo@1845:         String d = SessionFactoryProvider.getDriver((SessionFactoryImpl) sf);
ingo@1845: 
ingo@1845:         return d != null ? d.indexOf("Oracle") >= 0 : false;
ingo@1845:     }
ingo@1845: 
ingo@1845: 
ingo@2038:     /**
ingo@2038:      * This method returns an WQ_MODE enum which is based on the parameters
ingo@2423:      * stored in <i>flys</i> Artifact. If there is no <i>wq_isq</i> parameter
ingo@2038:      * existing, WQ_MODE.NONE is returned.
ingo@2038:      *
ingo@2038:      * @param flys The FLYSArtifact that stores wq mode relevant parameters.
ingo@2038:      *
ingo@2038:      * @return an enum WQ_MODE.
ingo@2038:      */
ingo@2038:     public static WQ_MODE getWQMode(FLYSArtifact flys) {
ingo@2081:         if (flys == null) {
ingo@2081:             return WQ_MODE.NONE;
ingo@2081:         }
ingo@2081: 
ingo@2422:         String values = flys.getDataAsString("wq_values");
felix@3444:         Boolean isQ   = flys.getDataAsBoolean("wq_isq");
ingo@2038: 
ingo@2422:         if (values != null) {
ingo@2422:             return isQ ? WQ_MODE.QGAUGE : WQ_MODE.WGAUGE;
ingo@2038:         }
ingo@2422: 
ingo@2423:         Boolean isFree = flys.getDataAsBoolean("wq_isfree");
ingo@2422: 
ingo@2422:         if (isQ) {
ingo@2422:             return isFree ? WQ_MODE.QFREE : WQ_MODE.QGAUGE;
ingo@2422:         }
ingo@2422:         else if (!isQ) {
ingo@2422:             return isFree ? WQ_MODE.WFREE : WQ_MODE.WGAUGE;
ingo@2038:         }
ingo@2038:         else {
ingo@2038:             return WQ_MODE.NONE;
ingo@2038:         }
ingo@2038:     }
ingo@2038: 
ingo@2038: 
ingo@2422:     public static WQ_INPUT getWQInputMode(FLYSArtifact flys) {
ingo@2422:         if (flys == null) {
ingo@2422:             return WQ_INPUT.NONE;
ingo@2422:         }
ingo@2422: 
ingo@2423:         Boolean selection = flys.getDataAsBoolean("wq_isrange");
ingo@2422:         String adapted = flys.getDataAsString("wq_values");
ingo@2422: 
ingo@2422:         if(adapted != null && adapted.length() > 0) {
ingo@2422:             return WQ_INPUT.ADAPTED;
ingo@2422:         }
ingo@2422: 
ingo@2422:         if (selection != null && selection) {
ingo@2422:             return WQ_INPUT.RANGE;
ingo@2422:         }
ingo@2422:         else {
ingo@2422:             return WQ_INPUT.SINGLE;
ingo@2422:         }
ingo@2422:     }
ingo@2422: 
ingo@1095:     public static KM_MODE getKmRangeMode(FLYSArtifact flys) {
felix@1099:         String mode = flys.getDataAsString("ld_mode");
ingo@1095: 
ingo@1095:         if (mode == null || mode.length() == 0) {
ingo@1095:             return KM_MODE.NONE;
ingo@1095:         }
ingo@1095:         else if (mode.equals("distance"))  {
ingo@1095:             return KM_MODE.RANGE;
ingo@1095:         }
ingo@1095:         else if (mode.equals("locations")) {
ingo@1095:             return KM_MODE.LOCATIONS;
ingo@1095:         }
ingo@1095:         else {
ingo@1095:             return KM_MODE.NONE;
ingo@1095:         }
ingo@1095:     }
ingo@1095: 
felix@2041:     /**
felix@2041:      * Get min and max kilometer, independent of parametization
felix@2041:      * (ld_from/to vs ld_locations).
felix@2041:      */
ingo@1095:     public static double[] getKmRange(FLYSArtifact flys) {
ingo@1095:         switch (getKmRangeMode(flys)) {
ingo@1095:             case RANGE: {
ingo@1095:                 return getKmFromTo(flys);
ingo@1095:             }
ingo@1095: 
ingo@1095:             case LOCATIONS: {
ingo@1095:                 double[] locs = getLocations(flys);
ingo@1095:                 return new double[] { locs[0], locs[locs.length-1] };
ingo@1095:             }
ingo@1095: 
ingo@1095:             case NONE: {
ingo@1095:                 double[] locs = getLocations(flys);
ingo@1095:                 if (locs != null) {
ingo@1095:                     return new double[] { locs[0], locs[locs.length-1] };
ingo@1095:                 }
ingo@1095:                 else {
ingo@1095:                     return getKmFromTo(flys);
ingo@1095:                 }
ingo@1095:             }
ingo@1095:         }
ingo@1095: 
ingo@1095:         return new double[] { Double.NaN, Double.NaN };
ingo@1095:     }
ingo@1095: 
ingo@1095: 
felix@2235:     /**
felix@2235:      * Get bounds for river of artifact.
felix@2235:      * @param flysArtifact artifact which has a "river" data.
felix@2235:      * @return double array. min is at[0], max at[1]. null if given artifact is null
felix@2235:      */
felix@2235:     public static double[] getRiverMinMax(FLYSArtifact flysArtifact) {
felix@2235:         if (flysArtifact == null) {
felix@2235:             return null;
felix@2235:         }
felix@2235: 
felix@2235:         String riverName = flysArtifact.getDataAsString("river");
felix@2235: 
felix@2235:         if (riverName == null) {
felix@2235:             riverName = "";
felix@2235:         }
felix@2235: 
felix@2235:         logger.debug("Search for the min/max distances of '" + riverName + "'");
felix@2235: 
felix@2235:         River river = RiverFactory.getRiver(riverName);
felix@2235: 
felix@2235:         return river != null
felix@2235:             ? river.determineMinMaxDistance()
felix@2235:             : null;
felix@2235:     }
felix@2235: 
felix@2235: 
ingo@1095:     public static double[] getKmFromTo(FLYSArtifact flys) {
ingo@1095:         String strFrom = flys.getDataAsString("ld_from");
ingo@1095:         String strTo   = flys.getDataAsString("ld_to");
ingo@1095: 
felix@3444:         if (strFrom == null) {
felix@3444:             strFrom = flys.getDataAsString("from");
felix@3444:         }
felix@3444: 
felix@3444:         if (strTo == null) {
felix@3444:             strTo = flys.getDataAsString("to");
felix@3444:         }
felix@3444: 
ingo@1095:         if (strFrom == null || strTo == null) {
ingo@1095:             return null;
ingo@1095:         }
ingo@1095: 
ingo@1095:         try {
ingo@1095:             return new double[] {
ingo@1095:                 Double.parseDouble(strFrom),
ingo@1095:                 Double.parseDouble(strTo) };
ingo@1095:         }
ingo@1095:         catch (NumberFormatException nfe) {
ingo@1095:             return null;
ingo@1095:         }
ingo@1095:     }
ingo@1095: 
ingo@1095: 
felix@2041:     /**
felix@2041:      * Return sorted array of locations at which stuff was calculated
felix@2041:      * (from ld_locations data), null if not parameterized this way.
felix@2041:      */
ingo@1095:     public static double[] getLocations(FLYSArtifact flys) {
ingo@1095:         String locationStr = flys.getDataAsString("ld_locations");
ingo@1095: 
ingo@1095:         if (locationStr == null || locationStr.length() == 0) {
felix@2765:             if (flys instanceof WINFOArtifact) {
felix@2765:                 WINFOArtifact winfo = (WINFOArtifact) flys;
felix@2765:                 if (winfo.getReferenceStartKm() != null) {
felix@2765:                     return new double[]
felix@2765:                         {
felix@2765:                             winfo.getReferenceStartKm().doubleValue(),
felix@2765:                             winfo.getReferenceEndKms()[0]
felix@2765:                         };
felix@2765:                 }
felix@2765:             }
ingo@1095:             return null;
ingo@1095:         }
ingo@1095: 
ingo@1095:         String[] tmp               = locationStr.split(" ");
ingo@1095:         TDoubleArrayList locations = new TDoubleArrayList();
ingo@1095: 
ingo@1095:         for (String l: tmp) {
ingo@1095:             try {
ingo@1095:                 locations.add(Double.parseDouble(l));
ingo@1095:             }
ingo@1095:             catch (NumberFormatException nfe) {
ingo@1095:             }
ingo@1095:         }
ingo@1095: 
ingo@1095:         locations.sort();
ingo@1095: 
ingo@1095:         return locations.toNativeArray();
ingo@1095:     }
felix@1099: 
felix@1099: 
felix@1099:     /**
ingo@2045:      * Returns the Qs for a given FLYSArtifact. This method currently accepts
ingo@2045:      * only instances of WINFOArtifact.
ingo@2045:      *
ingo@2045:      * @param flys A FLYSArtifact.
ingo@2045:      *
ingo@2045:      * @return the Qs.
ingo@2045:      */
ingo@2045:     public static double[] getQs(FLYSArtifact flys) {
ingo@2045:         // XXX this is not nice!
ingo@2045:         if (flys instanceof WINFOArtifact) {
ingo@2423:             return ((WINFOArtifact) flys).getQs();
ingo@2045:         }
ingo@2045: 
ingo@2045:         logger.warn("This method currently supports WINFOArtifact only!");
ingo@2045: 
ingo@2045:         return null;
ingo@2045:     }
ingo@2045: 
ingo@2045: 
ingo@2045:     /**
ingo@2045:      * Returns the Ws for a given FLYSArtifact. This method currently accepts
ingo@2045:      * only instances of WINFOArtifact.
ingo@2045:      *
ingo@2045:      * @param flys A FLYSArtifact.
ingo@2045:      *
ingo@2045:      * @return the Ws.
ingo@2045:      */
ingo@2045:     public static double[] getWs(FLYSArtifact flys) {
ingo@2045:         // XXX this is not nice!
ingo@2045:         if (flys instanceof WINFOArtifact) {
ingo@2422:             return ((WINFOArtifact) flys).getWs();
ingo@2045:         }
ingo@2045: 
ingo@2045:         logger.warn("This method currently supports WINFOArtifact only!");
ingo@2045: 
ingo@2045:         return null;
ingo@2045:     }
ingo@2045: 
ingo@2045: 
ingo@2045:     /**
felix@1099:      * Returns the selected River object based on the 'river' data that might
felix@1099:      * have been inserted by the user.
felix@1099:      *
felix@1099:      * @return the selected River or null if no river has been chosen yet.
felix@1099:      */
felix@1099:     public static River getRiver(FLYSArtifact flys) {
ingo@2045:         String sRiver = getRivername(flys);
felix@1099: 
felix@1099:         return (sRiver != null)
felix@1099:             ? RiverFactory.getRiver(sRiver)
felix@1099:             : null;
felix@1099:     }
ingo@1105: 
ingo@1105: 
ingo@1105:     /**
ingo@2045:      * Returns the name of the river specified in the given <i>flys</i>
ingo@2045:      * Artifact.
ingo@2045:      *
ingo@2045:      * @param flys The FLYSArtifact that stores a river relevant information.
ingo@2045:      *
ingo@2045:      * @return the name of the specified river or null.
ingo@2045:      */
ingo@2045:     public static String getRivername(FLYSArtifact flys) {
ingo@2045:         return flys != null ? flys.getDataAsString("river") : null;
ingo@2045:     }
ingo@2045: 
ingo@2045: 
ingo@2045:     /**
ingo@1105:      * Extracts the SRID defined in the global configuration for the river
ingo@1105:      * specified in <i>artifact</i>.
ingo@1105:      *
ingo@1105:      * @param artifact The FLYSArtifact that stores the name of the river.
ingo@1105:      *
ingo@1105:      * @return the SRID as string (e.g. "31466").
ingo@1105:      */
ingo@1105:     public static String getRiverSrid(FLYSArtifact artifact) {
ingo@1105:         String river = artifact.getDataAsString("river");
ingo@1105: 
ingo@1105:         if (river == null || river.length() == 0) {
ingo@1105:             return null;
ingo@1105:         }
ingo@1105: 
ingo@1805:         return getRiverSrid(river);
ingo@1805:     }
ingo@1805: 
ingo@1805: 
ingo@1805:     public static String getRiverSrid(String rivername) {
ingo@1105:         Map<String, String> variables = new HashMap<String, String>(1);
ingo@1805:         variables.put("name", rivername);
ingo@1105: 
ingo@1105:         Document cfg = Config.getConfig();
ingo@1105: 
ingo@1105:         return (String) XMLUtils.xpath(
ingo@1105:             cfg,
ingo@1105:             XPATH_RIVER_PROJECTION,
ingo@1105:             XPathConstants.STRING,
ingo@1105:             null,
ingo@1105:             variables);
ingo@1105:     }
ingo@1740: 
ingo@1740: 
felix@3284:     /**
felix@3284:      * Return the (first) Gauge corresponding to the given location(s) of
felix@3284:      * the artifact.
felix@3284:      * @param flys the artifact in question.
felix@3284:      * @return (First) gauge of locations of river of artifact.
felix@3284:      */
ingo@2045:     public static Gauge getGauge(FLYSArtifact flys) {
ingo@2045:         River river = getRiver(flys);
ingo@2045: 
ingo@2045:         if (river == null) {
ingo@2045:             logger.debug("no river found");
ingo@2045:             return null;
ingo@2045:         }
ingo@2045: 
ingo@2045:         double[] dist  = getKmRange(flys);
ingo@2045: 
ingo@2045:         if (dist == null) {
ingo@2045:             logger.debug("no range found");
ingo@2045:             return null;
ingo@2045:         }
ingo@2045: 
ingo@2045:         if (logger.isDebugEnabled()) {
ingo@2045:             logger.debug("Determine gauge for:");
ingo@2045:             logger.debug("... river: " + river.getName());
ingo@2045:             logger.debug("... distance: " + dist[0] + " - " + dist[1]);
ingo@2045:         }
ingo@2045: 
ingo@2045:         Gauge gauge = river.determineGauge(dist[0], dist[1]);
ingo@2045: 
ingo@2045:         String name = gauge != null ? gauge.getName() : "'n/a";
ingo@2045:         logger.debug("Found gauge: " + name);
ingo@2045: 
ingo@2045:         return gauge;
ingo@2045:     }
ingo@2045: 
ingo@2045: 
ingo@2045:     public static String getGaugename(FLYSArtifact flys) {
ingo@2045:         Gauge gauge = getGauge(flys);
ingo@2045: 
ingo@2045:         return gauge != null ? gauge.getName() : null;
ingo@2045:     }
ingo@2045: 
ingo@2045: 
ingo@2128:     public static Gauge getReferenceGauge(FLYSArtifact flys) {
ingo@2128:         Long officialNumber = flys.getDataAsLong("reference_gauge");
ingo@2128: 
ingo@2128:         return officialNumber != null
ingo@2128:             ? Gauge.getGaugeByOfficialNumber(officialNumber)
ingo@2128:             : null;
ingo@2128:     }
ingo@2128: 
ingo@2128: 
ingo@2249:     public static String getReferenceGaugeName(FLYSArtifact flys) {
ingo@2249:         Gauge refGauge = getReferenceGauge(flys);
ingo@2249: 
ingo@2249:         return refGauge != null
ingo@2249:             ? refGauge.getName()
ingo@2249:             : "-- not found --";
ingo@2249:     }
ingo@2249: 
ingo@2249: 
ingo@2068:     public static Double getValueFromWQ(WQ wq) {
ingo@2068:         if (wq == null) {
ingo@2068:             return null;
ingo@2068:         }
ingo@2068: 
ingo@2068:         Matcher m = NUMBERS_PATTERN.matcher(wq.getName());
ingo@2068: 
ingo@2068:         if (m.matches()) {
ingo@2068:             logger.debug("Found a number.");
ingo@2068: 
ingo@2068:             String raw = m.group(1);
ingo@2068: 
ingo@2068:             try {
ingo@2068:                 return Double.valueOf(raw);
ingo@2068:             }
ingo@2068:             catch (NumberFormatException nfe) {
ingo@2068:             }
ingo@2068:         }
ingo@2068: 
ingo@2068:         return null;
ingo@2068:     }
ingo@2068: 
ingo@2068: 
felix@4363:     /** Creates human-readable name for a wsp (waterlevel/longitudinal section).
felix@4363:      * @param name will be split at '='s.
felix@4363:      */
ingo@1740:     public static String createWspWTitle(
ingo@1740:         WINFOArtifact winfo,
ingo@1740:         CallContext   cc,
ingo@1740:         String        name
ingo@1740:     ) {
ingo@1740:         String[] parts = name.split("=");
ingo@1740: 
ingo@1740:         NumberFormat nf = Formatter.getWaterlevelW(cc);
ingo@1740: 
ingo@1740:         String namedMainValue = null;
ingo@1740: 
ingo@1740:         boolean isQ    = winfo.isQ();
ingo@1740:         boolean isFree = winfo.isFreeQ();
ingo@1740: 
ingo@1740:         double v;
ingo@1740: 
ingo@1740:         try {
ingo@1740:             v = Double.valueOf(parts[1]);
ingo@1740: 
ingo@1740:             namedMainValue = getNamedMainValue(winfo.getGauge(), v);
ingo@1740:         }
ingo@1740:         catch (NumberFormatException nfe) {
ingo@1740:             logger.warn("Cannot parse Double of: '" + parts[1] + "'");
ingo@1740:             return name;
ingo@1740:         }
ingo@1740: 
ingo@1740:         String prefix = null;
ingo@1740: 
ingo@1740:         if (isQ && !isFree && namedMainValue != null) {
ingo@1740:             return "W (" + namedMainValue + ")";
ingo@1740:         }
ingo@1740: 
ingo@1740:         if (isQ) {
ingo@1740:             prefix = "Q=";
ingo@1740:         }
ingo@1740: 
ingo@1740:         return prefix == null
ingo@1740:             ? "W(" + nf.format(v) + ")"
ingo@1740:             : "W(" + prefix + nf.format(v) + ")";
ingo@1740:     }
ingo@1740: 
ingo@1740: 
ingo@1740:     public static String createWspQTitle(
ingo@1740:         WINFOArtifact winfo,
ingo@1740:         CallContext   cc,
ingo@1740:         String        name
ingo@1740:     ) {
ingo@1740:         String[] parts = name.split("=");
ingo@1740: 
ingo@1740:         NumberFormat nf = Formatter.getWaterlevelQ(cc);
ingo@1740: 
ingo@1740:         String namedMainValue = null;
ingo@1740: 
ingo@1740:         boolean isQ    = winfo.isQ();
ingo@1740:         boolean isFree = winfo.isFreeQ();
ingo@1740: 
ingo@1740:         double v;
ingo@1740: 
ingo@1740:         try {
ingo@1740:             v = Double.valueOf(parts[1]);
ingo@1740: 
ingo@1740:             namedMainValue = getNamedMainValue(winfo.getGauge(), v);
ingo@1740:         }
ingo@1740:         catch (NumberFormatException nfe) {
ingo@1740:             logger.warn("Cannot parse Double of: '" + parts[1] + "'");
ingo@1740:             return name;
ingo@1740:         }
ingo@1740: 
ingo@1740:         String prefix = null;
ingo@1740: 
ingo@1740:         if (isQ && !isFree && namedMainValue != null) {
ingo@1740:             return namedMainValue;
ingo@1740:         }
ingo@1740: 
ingo@1740:         if (!isQ) {
ingo@1740:             prefix = "W=";
ingo@1740:         }
ingo@1740: 
ingo@1740:         return prefix == null
ingo@1740:             ? "Q(" + nf.format(v) + ")"
ingo@1740:             : "Q(" + prefix + nf.format(v) + ")";
ingo@1740:     }
ingo@1740: 
ingo@1740: 
ingo@2038:     /**
ingo@2038:      * Returns the named main value if a Q was selected and if this Q fits to a
ingo@2038:      * named main value. Otherwise, this function returns null.
ingo@2038:      *
ingo@2038:      * @param winfo The WINFO Artifact.
ingo@2038:      * @param value The Q (or W) value.
ingo@2038:      *
ingo@2038:      * @return a named main value or null.
ingo@2038:      */
ingo@2038:     public static String getNamedMainValue(WINFOArtifact winfo, double value) {
ingo@2038:         WQ_MODE wqmode = getWQMode(winfo);
ingo@2038: 
ingo@2038:         if (wqmode != WQ_MODE.QGAUGE) {
ingo@2038:             return null;
ingo@2038:         }
ingo@2038:         else {
ingo@2038:             return getNamedMainValue(winfo.getGauge(), value);
ingo@2038:         }
ingo@2038:     }
ingo@2038: 
ingo@2038: 
ingo@1740:     public static String getNamedMainValue(Gauge gauge, double value) {
ingo@1740:         List<MainValue> mainValues = gauge.getMainValues();
ingo@1740:         logger.debug("Search named main value for: " + value);
ingo@1740: 
ingo@1740:         for (MainValue mv: mainValues) {
ingo@1740:             if (mv.getValue().doubleValue() == value) {
ingo@1740:                 logger.debug("Found named main value: " + mv.getMainValue().getName());
ingo@1740:                 return mv.getMainValue().getName();
ingo@1740:             }
ingo@1740:         }
ingo@1740: 
ingo@1740:         logger.debug("Did not find a named main value for: " + value);
ingo@1740:         return null;
ingo@1740:     }
ingo@1792: 
ingo@1792: 
ingo@1792:     /**
ingo@2035:      *
ingo@2035:      * @param nmv A string that represents a named main value.
ingo@2035:      *
ingo@2035:      * @throws NullPointerException if nmv is null.
ingo@2035:      */
ingo@2035:     public static String stripNamedMainValue(String nmv) {
ingo@2035:         int startIndex = nmv.indexOf("(");
ingo@2035:         int endIndex   = nmv.indexOf(")");
ingo@2035: 
ingo@2035:         if (startIndex > 0 && endIndex > 0 && startIndex < endIndex) {
ingo@2035:             return nmv.substring(0, startIndex);
ingo@2035:         }
ingo@2035: 
ingo@2035:         return nmv;
ingo@2035:     }
ingo@2035: 
ingo@2035: 
ingo@2035:     /**
ingo@1792:      * Returns the URL of user mapfile for the owner of Artifact
ingo@1792:      * <i>artifactId</i>.
ingo@1792:      *
ingo@1792:      * @param artifactId The UUID of an artifact.
ingo@1792:      *
ingo@1792:      * @return the URL of the user wms.
ingo@1792:      */
ingo@1792:     public static String getUserWMSUrl(String artifactId) {
ingo@1792:         String url = getXPathString(XPATH_MAPSERVER_URL);
ingo@2296:         url = url.endsWith("/") ? url + "user-wms" : url + "/" + "user-wms";
ingo@1792: 
ingo@1792:         return url;
ingo@1792:     }
ingo@2063: 
ingo@2063: 
ingo@2063:     /**
ingo@2063:      * This method returns the description for a given <i>km</i> for a specific
ingo@2063:      * river. The river is provided by the FLYSArtifact <i>flys</i>.
ingo@2063:      *
ingo@2063:      * @param flys The FLYSArtifact that provides a river.
ingo@2063:      * @param km The kilometer.
ingo@2063:      *
ingo@2063:      * @return the description for <i>km</i> or an empty string if no
ingo@2063:      * description was found.
ingo@2063:      */
ingo@2063:     public static String getLocationDescription(FLYSArtifact flys, double km) {
ingo@2063:         String river = getRivername(flys);
ingo@2063: 
ingo@2063:         if (river == null) {
ingo@2063:             return "";
ingo@2063:         }
ingo@2063: 
ingo@2063:         return LocationProvider.getLocation(river, km);
ingo@2063:     }
raimund@2179: 
raimund@2179: 
raimund@2179:     /**
raimund@2179:      * This method returns the differences for a w-differences calculation.
raimund@2179:      *
raimund@2179:      * @param winfo The WINFOArtifact.
raimund@2179:      * @param context The context.
raimund@2179:      *
raimund@2179:      * @return The differences as string separated by semicolon and linebreak.
raimund@2179:      */
raimund@2179:     public static String getWDifferences(
raimund@2179:         WINFOArtifact winfo,
raimund@2179:         CallContext context)
raimund@2179:     {
raimund@2179:         State state = winfo.getCurrentState(context);
raimund@2179:         if(state instanceof WDifferencesState) {
raimund@2179:             String diffids = winfo.getDataAsString("diffids");
raimund@2179:             String datas[] = diffids.split("#");
raimund@2179: 
raimund@2179:             // Validate the Data-Strings.
raimund@2179:             for (String s: datas) {
felix@4054:                 if (!WaterlevelSelectState.isValueValid(s)) {
raimund@2179:                     return "";
raimund@2179:                 }
raimund@2179:             }
raimund@2179: 
raimund@2179:             if (datas.length < 2) {
raimund@2179:                 return "";
raimund@2179:             }
raimund@2179: 
raimund@2179:             String diffs = "";
raimund@2179:             for(int i = 0; i < datas.length; i+=2) {
raimund@2179:                 // e.g.:
raimund@2179:                 // 42537f1e-3522-42ef-8968-635b03d8e9c6;longitudinal_section.w;1
raimund@2179:                 WKms minuendWKms = getWKms(StringUtil.unbracket(datas[i+0]),
raimund@2179:                     context);
raimund@2179:                 WKms subtrahendWKms = getWKms(StringUtil.unbracket(datas[i+1]),
raimund@2179:                     context);
raimund@2179:                 if (minuendWKms != null && subtrahendWKms != null) {
sascha@3076:                     diffs += StringUtil.wWrap(minuendWKms.getName())
raimund@2179:                         + " - " + StringUtil.wWrap(subtrahendWKms.getName());
raimund@2179:                 }
raimund@2179:                 diffs += ";\n";
raimund@2179:             }
raimund@2179:             return diffs;
raimund@2179:         }
raimund@2179:         else {
raimund@2179:             logger.warn("Not a valid state for differences.");
raimund@2179:             return "";
raimund@2179:         }
raimund@2179:     }
raimund@2179: 
raimund@2179: 
raimund@2179:     protected static WKms getWKms(String mingle, CallContext context) {
raimund@2179:         String[] def  = mingle.split(";");
raimund@2179:         String   uuid = def[0];
raimund@2179:         String   name = def[1];
raimund@2179:         int      idx  = Integer.parseInt(def[2]);
raimund@2179: 
raimund@2179:         if (name.startsWith("staticwkms")) {
raimund@2179:             StaticWKmsArtifact staticWKms =
raimund@2179:                 (StaticWKmsArtifact) FLYSUtils.getArtifact(
raimund@2179:                     uuid,
raimund@2179:                     context);
raimund@2179:             WKms wkms = staticWKms.getWKms(idx);
raimund@2179:             if (wkms == null)
raimund@2179:                 logger.error("No WKms from artifact.");
raimund@2179:             return wkms;
raimund@2179:         }
raimund@2179: 
raimund@2179:         WINFOArtifact flys = (WINFOArtifact) FLYSUtils.getArtifact(
raimund@2179:             uuid,
raimund@2179:             context);
raimund@2179: 
raimund@2179:         if (flys == null) {
raimund@2179:             logger.warn("One of the artifacts (1) for diff calculation could not be loaded");
raimund@2179:             return null;
raimund@2179:         }
raimund@2179:         else{
raimund@2179:             WQKms[] wqkms = (WQKms[]) flys.getWaterlevelData().
raimund@2179:                                               getData();
raimund@2179:             if (wqkms == null)
raimund@2179:             logger.warn("not  waterlevels in artifact");
raimund@2179:             else if (wqkms.length < idx)
raimund@2179:             logger.warn("not enough waterlevels in artifact");
raimund@2179:             return wqkms[idx];
raimund@2179:         }
raimund@2179:     }
ingo@2216: 
ingo@2216: 
ingo@2216:     /**
ingo@2216:      * This method transform a string into an int array. Therefore, the string
ingo@2216:      * <i>raw</i> must consist of int values separated by a <i>';'</i>.
ingo@2216:      *
ingo@2216:      * @param raw The raw integer array as string separated by a ';'.
ingo@2216:      *
ingo@2216:      * @return an array of int values.
ingo@2216:      */
ingo@2216:     public static int[] intArrayFromString(String raw) {
ingo@2216:         String[] splitted = raw != null ? raw.split(";") : null;
ingo@2216: 
ingo@2216:         if (splitted == null || splitted.length == 0) {
ingo@2216:             logger.warn("No integer values found in '" + raw + "'");
ingo@2216:             return new int[0];
ingo@2216:         }
ingo@2216: 
ingo@2216:         TIntArrayList integers = new TIntArrayList(splitted.length);
ingo@2216: 
ingo@2216:         for (String value: splitted) {
ingo@2216:             try {
sascha@3405:                 integers.add(Integer.parseInt(value));
ingo@2216:             }
ingo@2216:             catch (NumberFormatException nfe) {
ingo@2216:                 logger.warn("Parsing integer failed: " + nfe);
ingo@2216:             }
ingo@2216:         }
ingo@2216: 
ingo@2216:         return integers.toNativeArray();
ingo@2216:     }
ingo@2216: 
ingo@2216: 
ingo@2216:     /**
raimund@2600:      * This method transform a string into a long array. Therefore, the string
raimund@2600:      * <i>raw</i> must consist of int values separated by a <i>';'</i>.
raimund@2600:      *
raimund@2600:      * @param raw The raw long array as string separated by a ';'.
raimund@2600:      *
raimund@2600:      * @return an array of int values.
raimund@2600:      */
raimund@2600:     public static long[] longArrayFromString(String raw) {
raimund@2600:         String[] splitted = raw != null ? raw.split(";") : null;
raimund@2600: 
raimund@2600:         if (splitted == null || splitted.length == 0) {
raimund@2600:             logger.warn("No long values found in '" + raw + "'");
raimund@2600:             return new long[0];
raimund@2600:         }
raimund@2600: 
raimund@2600:         TLongArrayList longs = new TLongArrayList(splitted.length);
raimund@2600: 
raimund@2600:         for (String value: splitted) {
raimund@2600:             try {
raimund@2600:                 longs.add(Long.valueOf(value));
raimund@2600:             }
raimund@2600:             catch (NumberFormatException nfe) {
raimund@2600:                 logger.warn("Parsing long failed: " + nfe);
raimund@2600:             }
raimund@2600:         }
raimund@2600: 
raimund@2600:         return longs.toNativeArray();
raimund@2600:     }
raimund@2600: 
raimund@2600: 
raimund@2600:     /**
ingo@2216:      * This method transform a string into an double array. Therefore, the
ingo@2216:      * string <i>raw</i> must consist of double values separated by a
ingo@2216:      * <i>';'</i>.
ingo@2216:      *
ingo@2216:      * @param raw The raw double array as string separated by a ';'.
ingo@2216:      *
ingo@2216:      * @return an array of double values.
ingo@2216:      */
ingo@2216:     public static double[] doubleArrayFromString(String raw) {
ingo@2216:         String[] splitted = raw != null ? raw.split(";") : null;
ingo@2216: 
ingo@2216:         if (splitted == null || splitted.length == 0) {
ingo@2216:             logger.warn("No double values found in '" + raw + "'");
ingo@2216:             return new double[0];
ingo@2216:         }
ingo@2216: 
ingo@2216:         TDoubleArrayList doubles = new TDoubleArrayList(splitted.length);
ingo@2216: 
ingo@2216:         for (String value: splitted) {
ingo@2216:             try {
ingo@2216:                 doubles.add(Double.valueOf(value));
ingo@2216:             }
ingo@2216:             catch (NumberFormatException nfe) {
ingo@2216:                 logger.warn("Parsing double failed: " + nfe);
ingo@2216:             }
ingo@2216:         }
ingo@2216: 
ingo@2216:         return doubles.toNativeArray();
ingo@2216:     }
felix@3444: 
felix@3444: 
felix@3444:     /**
felix@3444:      * Returns the gauges that match the selected kilometer range.
felix@3444:      *
felix@3444:      * @param flys the flys artifact.
felix@3444:      *
felix@3444:      * @return the gauges based on the selected kilometer range (null if
felix@3444:      *         none/no range set).
felix@3444:      */
felix@3444:     public static List<Gauge> getGauges(FLYSArtifact flys) {
felix@3444: 
felix@3444:         River river = getRiver(flys);
felix@3444:         if (river == null) {
felix@3444:             logger.debug("getGauges: no river!");
felix@3444:             return null;
felix@3444:         }
felix@3444: 
felix@3444:         double [] dist = getKmRange(flys);
felix@3444:         if (dist == null) {
felix@3444:             logger.debug("getGauges: no dist!");
felix@3444:             return null;
felix@3444:         }
felix@3444:         logger.debug("getGauges: " + dist[0] + " - " + dist[1]);
felix@3444: 
felix@3444:         return river.determineGauges(dist[0], dist[1]);
felix@3444:     }
ingo@1095: }
ingo@1105: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :