// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.graphview.plugin.preferences; import static org.openstreetmap.josm.tools.I18n.tr; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.plugins.graphview.core.property.VehiclePropertyType; import org.openstreetmap.josm.plugins.graphview.core.property.VehiclePropertyTypes; import org.openstreetmap.josm.plugins.graphview.core.util.ValueStringParser; /** * utility class for interpreting Strings as vehicle property values */ public final class VehiclePropertyStringParser { /** prevents instantiation */ private VehiclePropertyStringParser() { } /** * Exception class for syntax errors in property value Strings, * the message contains the reason using one of this utility class' public String constants. */ public static class PropertyValueSyntaxException extends Exception { private static final long serialVersionUID = 1L; public PropertyValueSyntaxException(String message) { super(message); } } public static final String ERROR_WEIGHT = tr("Weights must be given as positive decimal numbers with unit \"t\" or without unit."); public static final String ERROR_LENGTH = tr("Lengths must be given as positive decimal numbers with unit \"m\", \"km\", \"mi\"" + " or without unit.\nAlternatively, the format FEET'' INCHES\" can be used."); public static final String ERROR_SPEED = tr("Speeds should be given as numbers without unit or " + "as numbers followed by \"mph\"."); public static final String ERROR_INCLINE = tr("Inclines must be given as positive decimal numbers with followed by \"%\"."); public static final String ERROR_TRACKTYPE = tr("Tracktype grades must be given as integers between 0 and 5."); public static final String ERROR_SURFACE = tr("Surface values must not contain any of the following characters: '','', '' '{' '', '' '}' '', ''='', ''|''"); private static final List<Character> FORBIDDEN_SURFACE_CHARS = Arrays.asList(',', '{', '}', '=', '|'); /** * returns the value represented by the propertyValueString * * @param propertyType type of the property; != null * @param propertyValueString string to parse; != null * @return property value; != null. * Guaranteed to be valid according to propertyType's * {@link VehiclePropertyType#isValidValue(Object)} method. * * @throws PropertyValueSyntaxException if the string has syntax errors that prevent parsing * @throws InvalidParameterException if an unknown property type was passed */ public static <V> V parsePropertyValue( VehiclePropertyType<V> propertyType, String propertyValueString) throws PropertyValueSyntaxException { assert propertyType != null && propertyValueString != null; if (propertyType == VehiclePropertyTypes.AXLELOAD || propertyType == VehiclePropertyTypes.WEIGHT) { Float value = ValueStringParser.parseWeight(propertyValueString); if (value != null && propertyType.isValidValue(value)) { @SuppressWarnings("unchecked") //V must be float because of propertyType condition V result = (V) value; return result; } else { throw new PropertyValueSyntaxException(ERROR_WEIGHT); } } else if (propertyType == VehiclePropertyTypes.HEIGHT || propertyType == VehiclePropertyTypes.LENGTH || propertyType == VehiclePropertyTypes.WIDTH) { Float value = ValueStringParser.parseMeasure(propertyValueString); if (value != null && propertyType.isValidValue(value)) { @SuppressWarnings("unchecked") //V must be float because of propertyType condition V result = (V) value; return result; } else { throw new PropertyValueSyntaxException(ERROR_LENGTH); } } else if (propertyType == VehiclePropertyTypes.SPEED) { Float value = ValueStringParser.parseSpeed(propertyValueString); if (value != null && propertyType.isValidValue(value)) { @SuppressWarnings("unchecked") //V must be float because of propertyType condition V result = (V) value; return result; } else { throw new PropertyValueSyntaxException(ERROR_SPEED); } } else if (propertyType == VehiclePropertyTypes.MAX_INCLINE_DOWN || propertyType == VehiclePropertyTypes.MAX_INCLINE_UP) { Float value = ValueStringParser.parseIncline(propertyValueString); if (value != null && propertyType.isValidValue(value)) { @SuppressWarnings("unchecked") //V must be float because of propertyType condition V result = (V) value; return result; } else { throw new PropertyValueSyntaxException(ERROR_INCLINE); } } else if (propertyType == VehiclePropertyTypes.MAX_TRACKTYPE) { try { int value = Integer.parseInt(propertyValueString); if (0 <= value && value <= 5) { @SuppressWarnings("unchecked") //V must be int because of propertyType condition V result = (V) (Integer) value; return result; } } catch (NumberFormatException e) { Main.trace(e); } throw new PropertyValueSyntaxException(ERROR_TRACKTYPE); } else if (propertyType == VehiclePropertyTypes.SURFACE_BLACKLIST) { String[] surfaces = propertyValueString.split(";\\s*"); Collection<String> surfaceBlacklist = new ArrayList<>(surfaces.length); for (String surface : surfaces) { for (char nameChar : surface.toCharArray()) { if (FORBIDDEN_SURFACE_CHARS.contains(nameChar)) { throw new PropertyValueSyntaxException(ERROR_SURFACE); } } surfaceBlacklist.add(surface); } @SuppressWarnings("unchecked") //V must be Collection because of propertyType condition V result = (V) surfaceBlacklist; return result; } else { throw new InvalidParameterException("Unknown property type: " + propertyType); } } }