--- /dev/null
+package de.congrace.exp4j;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This is Builder implementation for the exp4j API used to create a Calculable
+ * instance for the user
+ *
+ * @author ruckus
+ *
+ */
+public class ExpressionBuilder {
+ private VariableSet variables = new VariableSet();
+ private final Set<CustomFunction> customFunctions = new HashSet<CustomFunction>();
+
+ private String expression;
+
+ /**
+ * Create a new ExpressionBuilder
+ *
+ * @param expression
+ * the expression to evaluate
+ */
+ public ExpressionBuilder(String expression) {
+ this.expression = expression;
+ }
+
+ /**
+ * build a new {@link Calculable} from the expression using the supplied
+ * variables
+ *
+ * @return the {@link Calculable} which can be used to evaluate the
+ * expression
+ * @throws UnknownFunctionException
+ * when an unrecognized function name is used in the expression
+ * @throws UnparsableExpressionException
+ * if the expression could not be parsed
+ */
+ public Calculable build() throws UnknownFunctionException, UnparsableExpressionException {
+ if (expression.indexOf('=') == -1 && !variables.isEmpty()) {
+
+ // User supplied an expression without leading "f(...)="
+ // so we just append the user function to a proper "f()="
+ // for PostfixExpression.fromInfix()
+ StringBuilder function = new StringBuilder("f(");
+ for (String name : variables.getVariableNames()) {
+ function.append(name).append(',');
+ }
+ expression = function.deleteCharAt(function.length() - 1).toString() + ")=" + expression;
+ }
+ // create the PostfixExpression and return it as a Calculable
+ PostfixExpression delegate = PostfixExpression.fromInfix(expression, customFunctions);
+ for (Variable var : variables ) {
+ delegate.setVariable(var);
+ for (CustomFunction fn:customFunctions){
+ if (fn.getValue().equalsIgnoreCase(var.getName())){
+ throw new UnparsableExpressionException("variable '" + var + "' cannot have the same name as a custom function " + fn.getValue());
+ }
+ }
+ }
+ return delegate;
+ }
+
+ /**
+ * add a custom function instance for the evaluator to recognize
+ *
+ * @param function
+ * the {@link CustomFunction} to add
+ * @return the {@link ExpressionBuilder} instance
+ */
+ public ExpressionBuilder withCustomFunction(CustomFunction function) {
+ customFunctions.add(function);
+ return this;
+ }
+
+ public ExpressionBuilder withCustomFunctions(Collection<CustomFunction> functions) {
+ customFunctions.addAll(functions);
+ return this;
+ }
+
+ /**
+ * set the value for a variable
+ *
+ * @param variableName
+ * the variable name e.g. "x"
+ * @param value
+ * the value e.g. 2.32d
+ * @return the {@link ExpressionBuilder} instance
+ */
+ public ExpressionBuilder withVariable(Variable value) {
+ variables.add(value);
+ return this;
+ }
+
+ /*
+ * Provided for backwards compatibility
+ */
+ @Deprecated
+ public ExpressionBuilder withVariable(String variableName, double value) {
+ variables.add(new Variable(variableName, value));
+ return this;
+ }
+
+ /**
+ * set the variables names used in the expression without setting their
+ * values. Usefull for building an expression before you know the variable values.
+ *
+ * @param variableNames
+ * vararg {@link String} of the variable names used in the
+ * expression
+ * @return the ExpressionBuilder instance
+ */
+
+ public ExpressionBuilder withVariableNames(String... variableNames) {
+ for (String name : variableNames) {
+ variables.add( new Variable(name, Double.NaN) );
+ }
+ return this;
+ }
+
+
+ /**
+ * set the values for variables
+ *
+ * @param variableMap
+ * a map of variable names to variable values
+ * @return the {@link ExpressionBuilder} instance
+ */
+ public ExpressionBuilder withVariables(VariableSet variables) {
+ this.variables = variables;
+ return this;
+ }
+}