ingo@136: package de.intevation.flys.artifacts.states; ingo@136: ingo@687: import java.util.List; ingo@687: ingo@136: import org.apache.log4j.Logger; ingo@136: ingo@136: import org.w3c.dom.Element; ingo@136: ingo@628: import gnu.trove.TDoubleArrayList; ingo@628: ingo@313: import de.intevation.artifacts.Artifact; ingo@136: import de.intevation.artifacts.CallContext; ingo@136: ingo@136: import de.intevation.artifacts.common.utils.XMLUtils; ingo@136: ingo@136: import de.intevation.artifactdatabase.ProtocolUtils; ingo@136: import de.intevation.artifactdatabase.data.StateData; ingo@687: import de.intevation.artifactdatabase.state.Facet; ingo@136: ingo@313: import de.intevation.flys.model.River; ingo@313: ingo@313: import de.intevation.flys.artifacts.FLYSArtifact; ingo@687: import de.intevation.flys.artifacts.WINFOArtifact; ingo@687: import de.intevation.flys.artifacts.model.ComputeCallback; ingo@689: import de.intevation.flys.artifacts.model.ComputeCallbackAdapter; ingo@313: import de.intevation.flys.artifacts.model.RiverFactory; ingo@136: import de.intevation.flys.artifacts.resources.Resources; ingo@136: ingo@136: /** ingo@136: * @author Ingo Weinzierl ingo@136: */ ingo@322: public class LocationDistanceSelect extends RangeState { ingo@136: ingo@136: /** The logger used in this class.*/ ingo@136: private static Logger logger = Logger.getLogger(LocationDistanceSelect.class); ingo@136: ingo@136: ingo@136: /** The default step width.*/ ingo@136: public static final String DEFAULT_STEP = "100"; ingo@136: ingo@627: /** The name of the 'mode' field. */ ingo@627: public static final String MODE = "ld_mode"; ingo@627: ingo@627: /** The name of the 'locations' field.*/ ingo@627: public static final String LOCATIONS = "ld_locations"; ingo@627: ingo@322: /** The name of the 'from' field. */ ingo@322: public static final String FROM = "ld_from"; ingo@322: ingo@322: /** The name of the 'to' field. */ ingo@322: public static final String TO = "ld_to"; ingo@322: ingo@322: /** The name of the 'step' field. */ ingo@322: public static final String STEP = "ld_step"; ingo@322: ingo@136: /** ingo@136: * The default constructor that initializes an empty State object. ingo@136: */ ingo@136: public LocationDistanceSelect() { ingo@136: } ingo@136: ingo@136: protected Element createData( ingo@136: XMLUtils.ElementCreator cr, ingo@313: Artifact artifact, ingo@136: StateData data, ingo@136: CallContext context) ingo@136: { ingo@136: Element select = ProtocolUtils.createArtNode( ingo@136: cr, "select", null, null); ingo@136: ingo@136: cr.addAttr(select, "name", data.getName(), true); ingo@136: ingo@136: Element label = ProtocolUtils.createArtNode( ingo@136: cr, "label", null, null); ingo@136: ingo@136: Element choices = ProtocolUtils.createArtNode( ingo@136: cr, "choices", null, null); ingo@136: ingo@136: label.setTextContent(Resources.getMsg( ingo@136: context.getMeta(), ingo@136: data.getName(), ingo@136: data.getName())); ingo@136: ingo@136: select.appendChild(label); ingo@136: ingo@136: return select; ingo@136: } ingo@136: ingo@136: sascha@660: @Override ingo@136: protected Element[] createItems( ingo@136: XMLUtils.ElementCreator cr, ingo@313: Artifact artifact, ingo@136: String name, ingo@136: CallContext context) ingo@136: { ingo@313: double[] minmax = getMinMaxDistance(artifact); ingo@313: ingo@313: double minVal = Double.MIN_VALUE; ingo@313: double maxVal = Double.MAX_VALUE; ingo@313: ingo@313: if (minmax != null) { ingo@313: minVal = minmax[0]; ingo@313: maxVal = minmax[1]; ingo@313: } ingo@313: else { ingo@313: logger.warn("Could not read min/max distance values!"); ingo@313: } ingo@136: ingo@136: if (name.equals("ld_from")) { ingo@313: Element min = createItem( ingo@313: cr, ingo@313: new String[] {"min", new Double(minVal).toString()}); ingo@313: ingo@136: return new Element[] { min }; ingo@136: } ingo@136: else if (name.equals("ld_to")) { ingo@313: Element max = createItem( ingo@313: cr, ingo@313: new String[] {"max", new Double(maxVal).toString()}); ingo@313: ingo@136: return new Element[] { max }; ingo@136: } ingo@136: else { ingo@136: Element step = createItem(cr, new String[] {"step", DEFAULT_STEP}); ingo@136: return new Element[] { step }; ingo@136: } ingo@136: ingo@136: } ingo@136: ingo@136: ingo@136: protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { ingo@136: Element item = ProtocolUtils.createArtNode(cr, "item", null, null); ingo@136: Element label = ProtocolUtils.createArtNode(cr, "label", null, null); ingo@136: Element value = ProtocolUtils.createArtNode(cr, "value", null, null); ingo@136: ingo@136: String[] arr = (String[]) obj; ingo@136: ingo@136: label.setTextContent(arr[0]); ingo@136: value.setTextContent(arr[1]); ingo@136: ingo@136: item.appendChild(label); ingo@136: item.appendChild(value); ingo@136: ingo@136: return item; ingo@136: } ingo@136: ingo@136: sascha@660: @Override ingo@136: protected String getUIProvider() { ingo@136: return "location_distance_panel"; ingo@136: } ingo@313: ingo@313: ingo@313: protected double[] getMinMaxDistance(Artifact artifact) { ingo@313: FLYSArtifact flysArtifact = (FLYSArtifact) artifact; ingo@624: StateData data = getData(flysArtifact, "river"); ingo@313: ingo@624: String name = data != null ? (String) data.getValue() : ""; ingo@313: ingo@313: logger.debug("Search for the min/max distances of '" + name + "'"); ingo@313: ingo@313: River river = RiverFactory.getRiver(name); ingo@313: ingo@313: return river != null ? river.determineMinMaxDistance() : null; ingo@313: } ingo@322: ingo@322: ingo@322: @Override ingo@322: public boolean validate(Artifact artifact, CallContext context) ingo@322: throws IllegalArgumentException ingo@322: { ingo@322: logger.debug("LocationDistanceSelect.validate"); ingo@322: ingo@624: FLYSArtifact flys = (FLYSArtifact) artifact; ingo@322: ingo@627: if (flys.isRange()) { ingo@627: return validateRange(flys, context); ingo@627: } ingo@627: else { ingo@627: return validateLocations(flys, context); ingo@627: } ingo@627: } ingo@627: ingo@627: ingo@627: protected boolean validateLocations(FLYSArtifact flys, CallContext context) ingo@627: throws IllegalArgumentException ingo@627: { ingo@627: StateData dValues = getData(flys, LOCATIONS); ingo@627: String values = dValues != null ? (String)dValues.getValue() : null; ingo@627: ingo@627: if (values == null || values.length() == 0) { ingo@627: throw new IllegalArgumentException("error_empty_state"); ingo@627: } ingo@627: ingo@627: double[] absMinMax = getMinMaxDistance(flys); ingo@627: double[] relMinMax = getMinMaxFromString(values); ingo@627: ingo@627: if (relMinMax[0] < absMinMax[0] || relMinMax[0] > absMinMax[1]) { ingo@627: throw new IllegalArgumentException("error_feed_from_out_of_range"); ingo@627: } ingo@627: ingo@627: if (relMinMax[1] > absMinMax[1] || relMinMax[1] < absMinMax[0]) { ingo@627: throw new IllegalArgumentException("error_feed_to_out_of_range"); ingo@627: } ingo@627: ingo@627: return true; ingo@627: } ingo@627: ingo@627: ingo@627: protected boolean validateRange(FLYSArtifact flys, CallContext context) ingo@627: throws IllegalArgumentException ingo@627: { ingo@624: StateData dFrom = getData(flys, FROM); ingo@624: StateData dTo = getData(flys, TO); ingo@624: StateData dStep = getData(flys, STEP); ingo@624: ingo@624: String fromStr = dFrom != null ? (String) dFrom.getValue() : null; ingo@624: String toStr = dTo != null ? (String) dTo.getValue() : null; ingo@624: String stepStr = dStep != null ? (String) dStep.getValue() : null; ingo@322: ingo@352: if (fromStr == null || toStr == null || stepStr == null) { ingo@352: throw new IllegalArgumentException("error_empty_state"); ingo@352: } ingo@352: ingo@322: try { ingo@322: double from = Double.parseDouble(fromStr); ingo@322: double to = Double.parseDouble(toStr); ingo@322: double step = Double.parseDouble(stepStr); ingo@322: ingo@627: double[] minmaxDist = getMinMaxDistance(flys); ingo@322: ingo@379: return validateBounds(minmaxDist[0], minmaxDist[1], from, to, step); ingo@322: } ingo@322: catch (NumberFormatException nfe) { ingo@627: throw new IllegalArgumentException("error_invalid_double_value"); ingo@322: } ingo@322: } ingo@627: ingo@627: ingo@627: /** ingo@627: * Extracts the min/max values from String s. An ingo@627: * IllegalArgumentException is thrown if there is a value that throws a ingo@627: * NumberFormatException. ingo@627: * ingo@627: * @param s String that contains whitespace separated double values. ingo@627: * ingo@627: * @return a 2dmin array [min,max]. ingo@627: */ ingo@627: public static double[] getMinMaxFromString(String s) ingo@627: throws IllegalArgumentException ingo@627: { ingo@627: String[] values = s.split(" "); ingo@627: ingo@627: double[] minmax = new double[] { ingo@627: Double.MAX_VALUE, ingo@627: -Double.MAX_VALUE }; ingo@627: ingo@627: for (String v: values) { ingo@627: try { ingo@627: double value = Double.valueOf(v); ingo@627: ingo@627: minmax[0] = minmax[0] < value ? minmax[0] : value; ingo@627: minmax[1] = minmax[1] > value ? minmax[1] : value; ingo@627: } ingo@627: catch (NumberFormatException nfe) { ingo@627: throw new IllegalArgumentException( ingo@627: "error_invalid_double_value"); ingo@627: } ingo@627: } ingo@627: ingo@627: return minmax; ingo@627: } ingo@628: ingo@628: ingo@628: public static double[] getLocations(FLYSArtifact flys) { ingo@628: StateData data = flys.getData("ld_locations"); ingo@628: String value = data != null ? (String) data.getValue() : null; ingo@628: ingo@628: if (value == null || value.length() == 0) { ingo@628: logger.warn("No location data given."); ingo@628: return null; ingo@628: } ingo@628: ingo@628: String[] splitted = value.split(" "); ingo@628: TDoubleArrayList values = new TDoubleArrayList(); ingo@628: ingo@628: for (String split: splitted) { ingo@628: try { ingo@628: values.add(Double.valueOf(split)); ingo@628: } ingo@628: catch (NumberFormatException nfe) { ingo@628: logger.warn(nfe, nfe); ingo@628: } ingo@628: } ingo@628: ingo@628: return values.toNativeArray(); ingo@628: } ingo@687: ingo@687: ingo@687: @Override ingo@687: public ComputeCallback createComputeCallback( ingo@687: String hash, FLYSArtifact flys) ingo@687: { ingo@687: final WINFOArtifact winfo = (WINFOArtifact) flys; ingo@687: ingo@689: return new ComputeCallbackAdapter() { ingo@689: ingo@689: @Override ingo@692: public Object computeFeed(CallContext context, List facets) { ingo@687: return winfo.getDischargeCurveData(); ingo@687: } ingo@687: }; ingo@687: } ingo@136: } ingo@136: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :