// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.roadsigns;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.openstreetmap.josm.plugins.roadsigns.javacc.ParamStringScanner;
import org.openstreetmap.josm.plugins.roadsigns.javacc.ParseException;
import org.openstreetmap.josm.plugins.roadsigns.javacc.TokenMgrError;
/**
* A parametrized string is a string that contains identifiers that can
* be substituted when the values of the parameters are known.
* The syntax is in perl style, e.g.
* "Up to $val% in ${num}th row costs 12 \$.".
*
* This class represent a parsed string (parameters are identified).
* It can be constructed from a String. Given a parameter environment,
* the String value can be determined.
*
*/
public class ParametrizedString {
final List<StringOrParameter> token = new ArrayList<>();
/**
* Describes the union of String and Parameter type. Both
* types have a single String object as their backing data.
*/
public interface StringOrParameter {
}
public static class Prm implements StringOrParameter {
public final String ident;
public Prm(String ident) {
this.ident = ident;
}
@Override
public String toString() {
return "<Prm="+ident+">";
}
}
public static class Str implements StringOrParameter {
String value;
public Str(String stringValue) {
this.value = stringValue;
}
@Override
public String toString() {
return "<Str="+value+">";
}
}
protected ParametrizedString(String input) throws ParseException, TokenMgrError {
scan(input);
}
/**
* Constructor that returns a null value for null value input.
* Once it is created, the list of token is immutable.
*/
public static ParametrizedString create(String input) throws ParseException, TokenMgrError {
if (input == null)
return null;
return new ParametrizedString(input);
}
/**
* The tokenizer. Creates the list of tokens
* from the input string.
*/
protected void scan(String input) throws ParseException, TokenMgrError {
List<StringOrParameter> tmp = null;
tmp = ParamStringScanner.parseIt(input);
StringBuffer curString = new StringBuffer();
for (StringOrParameter sp : tmp) {
if (sp instanceof Prm) {
if (curString.length() > 0) {
token.add(new Str(curString.toString()));
curString = new StringBuffer();
}
token.add(sp);
} else if (sp instanceof Str) {
curString.append(((Str) sp).value);
}
}
if (curString.length() > 0) {
token.add(new Str(curString.toString()));
}
}
/**
* Evaluates the string value, given an environment of
* parameter mappings.
*/
public String evaluate(Map<String, String> env) {
StringBuilder sb = new StringBuilder();
for (StringOrParameter t : token) {
if (t instanceof Str) {
sb.append(((Str) t).value);
} else if (t instanceof Prm) {
String val = env.get(((Prm) t).ident);
if (val == null) {
System.err.println("Warning: Parameter not in environment: "+((Prm) t).ident+" ("+this.toString()+")");
Thread.dumpStack();
val = "<?>";
}
sb.append(val);
} else
throw new AssertionError();
}
return sb.toString();
}
/**
* Converts to a string that could be parsed again to an equal object.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (StringOrParameter t : token) {
if (t instanceof Str) {
sb.append(((Str) t).value);
} else if (t instanceof Prm) {
sb.append("${"+((Prm) t).ident+"}");
} else
throw new AssertionError();
}
return sb.toString();
}
/**
* Creates a debug string for this object
*/
public String toDebugString() {
StringBuilder res = new StringBuilder();
for (StringOrParameter sop : token) {
res.append(sop);
}
return res.toString();
}
}