ingo@137: package de.intevation.flys.artifacts.states; ingo@137: ingo@1743: import java.text.NumberFormat; ingo@1743: ingo@379: import gnu.trove.TDoubleArrayList; ingo@379: ingo@137: import org.apache.log4j.Logger; ingo@137: ingo@137: import org.w3c.dom.Element; ingo@137: ingo@313: import de.intevation.artifacts.Artifact; ingo@137: import de.intevation.artifacts.CallContext; ingo@137: ingo@137: import de.intevation.artifacts.common.utils.XMLUtils; ingo@1743: import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; ingo@137: ingo@137: import de.intevation.artifactdatabase.ProtocolUtils; ingo@137: import de.intevation.artifactdatabase.data.StateData; ingo@137: ingo@319: import de.intevation.flys.model.Gauge; ingo@319: import de.intevation.flys.model.River; ingo@319: import de.intevation.flys.model.Wst; ingo@319: ingo@1743: import de.intevation.flys.artifacts.FLYSArtifact; sascha@1055: import de.intevation.flys.artifacts.WINFOArtifact; sascha@1055: ingo@319: import de.intevation.flys.artifacts.model.WstFactory; ingo@137: import de.intevation.flys.artifacts.resources.Resources; ingo@137: felix@1103: import de.intevation.flys.utils.FLYSUtils; felix@1103: felix@1103: ingo@137: /** ingo@137: * @author Ingo Weinzierl ingo@137: */ ingo@921: public class WQSelect extends DefaultState { ingo@137: felix@1691: /** The logger used in this class. */ ingo@137: private static Logger logger = Logger.getLogger(WQSelect.class); ingo@137: ingo@137: felix@1691: /** The default step width for Qs. */ ingo@137: public static final String DEFAULT_STEP_Q = "50"; ingo@137: felix@1691: /** The default step width for Qs. */ ingo@137: public static final String DEFAULT_STEP_W = "30"; ingo@137: ingo@322: /** The name of the 'mode' field. */ ingo@322: public static final String WQ_MODE = "wq_mode"; ingo@322: ingo@1743: /** Them name fo the 'free' field. */ ingo@1743: public static final String WQ_FREE = "wq_free"; ingo@1743: felix@1691: /** The name of the 'selection' field. */ ingo@379: public static final String WQ_SELECTION = "wq_selection"; ingo@379: ingo@322: /** The name of the 'from' field. */ ingo@322: public static final String WQ_FROM = "wq_from"; ingo@322: ingo@322: /** The name of the 'to' field. */ ingo@322: public static final String WQ_TO = "wq_to"; ingo@322: ingo@322: /** The name of the 'step' field. */ ingo@322: public static final String WQ_STEP = "wq_step"; ingo@322: ingo@379: /** The name of the 'single' field. */ ingo@379: public static final String WQ_SINGLE = "wq_single"; ingo@379: ingo@379: ingo@137: /** ingo@137: * The default constructor that initializes an empty State object. ingo@137: */ ingo@137: public WQSelect() { ingo@137: } ingo@137: ingo@1743: ingo@1743: @Override ingo@1743: protected Element createStaticData( ingo@1743: FLYSArtifact flys, ingo@1743: ElementCreator creator, ingo@1743: CallContext cc, ingo@1743: String name, ingo@1743: String value, ingo@1743: String type ingo@1743: ) { ingo@1743: if (!name.equals(WQ_SINGLE)) { ingo@1743: return super.createStaticData(flys, creator, cc, name, value, type); ingo@1743: } ingo@1743: ingo@1743: String mode = flys.getDataAsString(WQ_MODE); ingo@1743: String free = flys.getDataAsString(WQ_FREE); ingo@1743: if (mode == null || mode.equals("W") || Boolean.valueOf(free)) { ingo@1743: return super.createStaticData(flys, creator, cc, name, value, type); ingo@1743: } ingo@1743: ingo@1743: WINFOArtifact winfo = (WINFOArtifact) flys; ingo@1743: ingo@1743: Element dataElement = creator.create("data"); ingo@1743: creator.addAttr(dataElement, "name", name, true); ingo@1743: creator.addAttr(dataElement, "type", type, true); ingo@1743: ingo@1743: Element itemElement = creator.create("item"); ingo@1743: creator.addAttr(itemElement, "value", value, true); ingo@1743: creator.addAttr(itemElement, "label", getLabel(winfo, cc, value), true); ingo@1743: ingo@1743: dataElement.appendChild(itemElement); ingo@1743: ingo@1743: return dataElement; ingo@1743: } ingo@1743: ingo@1743: ingo@1743: protected static String getLabel( ingo@1743: WINFOArtifact winfo, ingo@1743: CallContext cc, ingo@1743: String raw ingo@1743: ) { ingo@1743: String[] values = raw.split(" "); ingo@1743: String label = null; ingo@1743: ingo@1743: NumberFormat nf = NumberFormat.getInstance( ingo@1743: Resources.getLocale(cc.getMeta())); ingo@1743: ingo@1743: for (String value: values) { ingo@1743: try { ingo@1743: double v = Double.valueOf(value.trim()); ingo@1743: ingo@1743: String tmp = nf.format(v); ingo@1743: String mv = FLYSUtils.getNamedMainValue(winfo.getGauge(),v); ingo@1743: ingo@1743: if (mv != null && mv.length() > 0) { ingo@1743: String add = mv + ": " + tmp; ingo@1743: label = label != null ? label + ", " + add : add; ingo@1743: } ingo@1743: else { ingo@1743: label = label != null ? label + ", " + tmp : tmp; ingo@1743: } ingo@1743: } ingo@1743: catch (NumberFormatException nfe) { ingo@1743: // do nothing here ingo@1743: } ingo@1743: } ingo@1743: ingo@1743: return label; ingo@1743: } ingo@1743: ingo@1743: felix@1691: @Override ingo@137: protected Element createData( ingo@137: XMLUtils.ElementCreator cr, ingo@313: Artifact artifact, ingo@137: StateData data, ingo@137: CallContext context) ingo@137: { ingo@137: Element select = ProtocolUtils.createArtNode( ingo@137: cr, "select", null, null); ingo@137: ingo@137: cr.addAttr(select, "name", data.getName(), true); ingo@137: ingo@137: Element label = ProtocolUtils.createArtNode( ingo@137: cr, "label", null, null); ingo@137: ingo@137: Element choices = ProtocolUtils.createArtNode( ingo@137: cr, "choices", null, null); ingo@137: ingo@137: label.setTextContent(Resources.getMsg( ingo@137: context.getMeta(), ingo@137: data.getName(), ingo@137: data.getName())); ingo@137: ingo@137: select.appendChild(label); ingo@137: ingo@137: return select; ingo@137: } ingo@137: ingo@137: sascha@660: @Override ingo@137: protected Element[] createItems( ingo@137: XMLUtils.ElementCreator cr, ingo@313: Artifact artifact, ingo@137: String name, ingo@137: CallContext context) ingo@137: { ingo@137: // TODO Insert correct min/max values! ingo@319: double[] minmaxW = determineMinMaxW(artifact); ingo@319: double[] minmaxQ = determineMinMaxQ(artifact); ingo@137: ingo@137: if (name.equals("wq_from")) { ingo@319: Element minW = createItem( ingo@319: cr, new String[] {"minW", new Double(minmaxW[0]).toString()}); ingo@319: Element minQ = createItem( ingo@319: cr, new String[] {"minQ", new Double(minmaxQ[0]).toString()}); ingo@137: return new Element[] { minW, minQ }; ingo@137: } ingo@137: else if (name.equals("wq_to")) { ingo@319: Element maxW = createItem( ingo@319: cr, new String[] {"maxW", new Double(minmaxW[1]).toString()}); ingo@319: Element maxQ = createItem( ingo@319: cr, new String[] {"maxQ", new Double(minmaxQ[1]).toString()}); ingo@137: return new Element[] { maxW, maxQ }; ingo@137: } ingo@137: else { sascha@660: Element stepW = createItem( sascha@660: cr, new String[] {"stepW", DEFAULT_STEP_W}); sascha@660: Element stepQ = createItem( sascha@660: cr, new String[] {"stepQ", DEFAULT_STEP_Q}); ingo@137: return new Element[] { stepW, stepQ }; ingo@137: } ingo@137: } ingo@137: ingo@137: ingo@137: protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { ingo@137: Element item = ProtocolUtils.createArtNode(cr, "item", null, null); ingo@137: Element label = ProtocolUtils.createArtNode(cr, "label", null, null); ingo@137: Element value = ProtocolUtils.createArtNode(cr, "value", null, null); ingo@137: ingo@137: String[] arr = (String[]) obj; ingo@137: ingo@137: label.setTextContent(arr[0]); ingo@137: value.setTextContent(arr[1]); ingo@137: ingo@137: item.appendChild(label); ingo@137: item.appendChild(value); ingo@137: ingo@137: return item; ingo@137: } ingo@137: ingo@137: sascha@660: @Override ingo@137: protected String getUIProvider() { ingo@137: return "wq_panel"; ingo@137: } ingo@319: ingo@319: ingo@319: /** ingo@319: * Determines the min and max W value for the current gauge. If no min and ingo@319: * max values could be determined, this method will return ingo@319: * [Double.MIN_VALUE, Double.MAX_VALUE]. ingo@319: * ingo@319: * @param artifact The FLYSArtifact. ingo@319: * ingo@319: * @return the min and max W values for the current gauge. ingo@319: */ ingo@319: protected double[] determineMinMaxW(Artifact artifact) { ingo@319: logger.debug("WQSelect.determineCurrentGauge"); ingo@319: sascha@1055: Gauge gauge = ((WINFOArtifact) artifact).getGauge(); ingo@320: double[] minmaxW = gauge != null ? gauge.determineMinMaxW() : null; ingo@319: ingo@319: double minW = minmaxW != null ? minmaxW[0] : Double.MIN_VALUE; ingo@319: double maxW = minmaxW != null ? minmaxW[1] : Double.MAX_VALUE; ingo@319: ingo@319: return new double[] { minW, maxW }; ingo@319: } ingo@319: ingo@319: ingo@319: /** ingo@319: * Determines the min and max Q value for the current gauge. If no min and ingo@319: * max values could be determined, this method will return ingo@319: * [Double.MIN_VALUE, Double.MAX_VALUE]. ingo@319: * ingo@319: * @param artifact The FLYSArtifact. ingo@319: * ingo@319: * @return the min and max Q values for the current gauge. ingo@319: */ ingo@319: protected double[] determineMinMaxQ(Artifact artifact) { ingo@319: logger.debug("WQSelect.determineMinMaxQ"); ingo@319: sascha@1055: WINFOArtifact flysArtifact = (WINFOArtifact) artifact; ingo@319: felix@1103: River river = FLYSUtils.getRiver(flysArtifact); felix@1103: Gauge gauge = flysArtifact.getGauge(); felix@1103: Wst wst = WstFactory.getWst(river); ingo@319: ingo@320: double[] minmaxQ = gauge != null ingo@320: ? wst.determineMinMaxQ(gauge.getRange()) ingo@320: : null; ingo@319: ingo@319: double minQ = minmaxQ != null ? minmaxQ[0] : Double.MIN_VALUE; ingo@319: double maxQ = minmaxQ != null ? minmaxQ[1] : Double.MAX_VALUE; ingo@319: ingo@319: return new double[] { minQ, maxQ }; ingo@319: } ingo@322: ingo@322: ingo@322: @Override sascha@1050: public boolean validate(Artifact artifact) ingo@322: throws IllegalArgumentException ingo@322: { ingo@322: logger.debug("WQSelect.validate"); ingo@322: sascha@1055: WINFOArtifact flys = (WINFOArtifact) artifact; ingo@322: ingo@624: StateData data = getData(flys, WQ_SELECTION); ingo@624: String selectionMode = data != null ? (String) data.getValue() : null; ingo@379: ingo@379: if (selectionMode == null || selectionMode.equals("single")) { sascha@1050: return validateSingle(artifact); ingo@379: } ingo@379: else { sascha@1050: return validateRange(artifact); ingo@379: } ingo@379: } ingo@379: ingo@379: ingo@921: protected boolean validateBounds( ingo@921: double fromValid, double toValid, ingo@921: double from, double to, double step) ingo@921: throws IllegalArgumentException ingo@921: { ingo@921: logger.debug("RangeState.validateRange"); ingo@921: ingo@921: if (from < fromValid) { ingo@921: logger.error( ingo@921: "Invalid 'from'. " + from + " is smaller than " + fromValid); ingo@921: throw new IllegalArgumentException("error_feed_from_out_of_range"); ingo@921: } ingo@921: else if (to > toValid) { ingo@921: logger.error( ingo@921: "Invalid 'to'. " + to + " is bigger than " + toValid); ingo@921: throw new IllegalArgumentException("error_feed_to_out_of_range"); ingo@921: } ingo@921: ingo@921: return true; ingo@921: } ingo@921: ingo@921: sascha@1050: protected boolean validateSingle(Artifact artifact) ingo@379: throws IllegalArgumentException ingo@379: { ingo@379: logger.debug("WQSelect.validateSingle"); ingo@379: sascha@1055: WINFOArtifact flys = (WINFOArtifact) artifact; ingo@624: StateData data = getData(flys, WQ_SINGLE); ingo@624: ingo@624: String tmp = data != null ? (String) data.getValue() : null; ingo@379: ingo@379: if (tmp == null || tmp.length() == 0) { ingo@379: throw new IllegalArgumentException("error_empty_state"); ingo@379: } ingo@379: ingo@379: String[] strValues = tmp.split(" "); ingo@379: TDoubleArrayList all = new TDoubleArrayList(); ingo@379: ingo@379: for (String strValue: strValues) { ingo@379: try { ingo@379: all.add(Double.parseDouble(strValue)); ingo@379: } ingo@379: catch (NumberFormatException nfe) { ingo@379: logger.warn(nfe, nfe); ingo@379: } ingo@379: } ingo@379: ingo@379: all.sort(); ingo@379: ingo@624: StateData dMode = getData(flys, WQ_MODE); ingo@624: String mode = dMode != null ? (String) data.getValue() : null; ingo@624: ingo@379: logger.debug("WQ Mode: " + mode); ingo@379: ingo@379: double[] minmax = null; ingo@379: ingo@379: if (mode != null && mode.trim().toLowerCase().equals("w")) { ingo@379: minmax = determineMinMaxW(artifact); ingo@379: } ingo@379: else { ingo@379: minmax = determineMinMaxQ(artifact); ingo@379: } ingo@379: ingo@379: double min = all.get(0); ingo@379: double max = all.get(all.size()-1); ingo@379: ingo@379: logger.debug("Inserted min value = " + min); ingo@379: logger.debug("Inserted max value = " + max); ingo@379: ingo@379: return validateBounds(minmax[0], minmax[1], min, max, 0d); ingo@379: } ingo@379: ingo@379: sascha@1050: protected boolean validateRange(Artifact artifact) ingo@379: throws IllegalArgumentException ingo@379: { ingo@379: logger.debug("WQSelect.validateRange"); sascha@1055: WINFOArtifact flys = (WINFOArtifact) artifact; ingo@379: ingo@631: StateData data = flys.getData(WQ_MODE); ingo@631: String mode = data != null ? (String) data.getValue() : null; ingo@322: logger.debug("WQ Mode: " + mode); ingo@322: ingo@631: if (mode == null || mode.length() == 0) { ingo@631: throw new IllegalArgumentException("error_feed_invalid_wq_mode"); ingo@631: } ingo@631: ingo@631: StateData dFrom = flys.getData(WQ_FROM); ingo@631: StateData dTo = flys.getData(WQ_TO); ingo@631: StateData dStep = flys.getData(WQ_STEP); ingo@631: ingo@631: String fromStr = dFrom != null ? (String) dFrom.getValue() : null; ingo@631: String toStr = dTo != null ? (String) dTo.getValue() : null; ingo@631: 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@631: try { ingo@631: double from = Double.parseDouble(fromStr); ingo@631: double to = Double.parseDouble(toStr); ingo@631: double step = Double.parseDouble(stepStr); ingo@322: ingo@322: if (mode != null && mode.trim().toLowerCase().equals("w")) { sascha@1050: return validateW(artifact, from, to, step); ingo@322: } ingo@322: else if (mode != null && mode.trim().toLowerCase().equals("q")) { sascha@1050: return validateQ(artifact, from, to, step); ingo@322: } ingo@322: else { sascha@660: throw new IllegalArgumentException( sascha@660: "error_feed_invalid_wq_mode"); ingo@322: } ingo@322: } ingo@322: catch (NumberFormatException nfe) { ingo@322: throw new IllegalArgumentException("error_feed_number_format"); ingo@322: } ingo@322: } ingo@322: ingo@322: ingo@322: /** ingo@322: * Validates the inserted W values. ingo@322: * ingo@322: * @param artifact The owner artifact. ingo@322: * @param from The lower value of the W range. ingo@322: * @param to The upper value of the W range. ingo@322: * @param step The step width. ingo@322: * ingo@322: * @return true, if everything was fine, otherwise an exception is thrown. ingo@322: */ ingo@322: protected boolean validateW( ingo@322: Artifact artifact, ingo@322: double from, ingo@322: double to, ingo@322: double step) ingo@322: throws IllegalArgumentException ingo@322: { ingo@322: logger.debug("WQSelect.validateW"); ingo@322: ingo@322: double[] minmaxW = determineMinMaxW(artifact); ingo@322: ingo@379: return validateBounds(minmaxW[0], minmaxW[1], from, to, step); ingo@322: } ingo@322: ingo@322: ingo@322: /** ingo@322: * Validates the inserted Q values. ingo@322: * ingo@322: * @param artifact The owner artifact. ingo@322: * @param from The lower value of the Q range. ingo@322: * @param to The upper value of the Q range. ingo@322: * @param step The step width. ingo@322: * ingo@322: * @return true, if everything was fine, otherwise an exception is thrown. ingo@322: */ ingo@322: protected boolean validateQ( ingo@322: Artifact artifact, ingo@322: double from, ingo@322: double to, ingo@322: double step) ingo@322: throws IllegalArgumentException ingo@322: { ingo@322: logger.debug("WQSelect.validateQ"); ingo@322: ingo@322: double[] minmaxQ = determineMinMaxQ(artifact); ingo@322: ingo@379: return validateBounds(minmaxQ[0], minmaxQ[1], from, to, step); ingo@322: } ingo@137: } ingo@137: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :