create changelog entry
[debian/openrocket] / core / src / de / congrace / exp4j / ExpressionBuilder.java
1 package de.congrace.exp4j;
2
3 import java.util.Collection;
4 import java.util.HashSet;
5 import java.util.Set;
6
7 /**
8  * This is Builder implementation for the exp4j API used to create a Calculable
9  * instance for the user
10  * 
11  * @author ruckus
12  * 
13  */
14 public class ExpressionBuilder {
15         private VariableSet variables = new VariableSet();
16         private final Set<CustomFunction> customFunctions = new HashSet<CustomFunction>();
17
18         private String expression;
19
20         /**
21          * Create a new ExpressionBuilder
22          * 
23          * @param expression
24          *            the expression to evaluate
25          */
26         public ExpressionBuilder(String expression) {
27                 this.expression = expression;
28         }
29         
30         /**
31          * build a new {@link Calculable} from the expression using the supplied
32          * variables
33          * 
34          * @return the {@link Calculable} which can be used to evaluate the
35          *         expression
36          * @throws UnknownFunctionException
37          *             when an unrecognized function name is used in the expression
38          * @throws UnparsableExpressionException
39          *             if the expression could not be parsed
40          */
41         public Calculable build() throws UnknownFunctionException, UnparsableExpressionException {
42                 if (expression.indexOf('=') == -1 && !variables.isEmpty()) {
43
44                         // User supplied an expression without leading "f(...)="
45                         // so we just append the user function to a proper "f()="
46                         // for PostfixExpression.fromInfix()
47                         StringBuilder function = new StringBuilder("f(");
48                         for (String name : variables.getVariableNames()) {
49                                 function.append(name).append(',');
50                         }
51                         expression = function.deleteCharAt(function.length() - 1).toString() + ")=" + expression;
52                 }
53                 // create the PostfixExpression and return it as a Calculable
54                 PostfixExpression delegate = PostfixExpression.fromInfix(expression, customFunctions);
55                 for (Variable var : variables ) {                       
56                         delegate.setVariable(var);      
57                         for (CustomFunction fn:customFunctions){
58                                 if (fn.getValue().equalsIgnoreCase(var.getName())){
59                                         throw new UnparsableExpressionException("variable '" + var + "' cannot have the same name as a custom function " + fn.getValue());
60                                 }
61                         }
62                 }
63                 return delegate;
64         }
65
66         /**
67          * add a custom function instance for the evaluator to recognize
68          * 
69          * @param function
70          *            the {@link CustomFunction} to add
71          * @return the {@link ExpressionBuilder} instance
72          */
73         public ExpressionBuilder withCustomFunction(CustomFunction function) {
74                 customFunctions.add(function);
75                 return this;
76         }
77
78         public ExpressionBuilder withCustomFunctions(Collection<CustomFunction> functions) {
79                 customFunctions.addAll(functions);
80                 return this;
81         }
82
83         /**
84          * set the value for a variable
85          * 
86          * @param variableName
87          *            the variable name e.g. "x"
88          * @param value
89          *            the value e.g. 2.32d
90          * @return the {@link ExpressionBuilder} instance
91          */
92         public ExpressionBuilder withVariable(Variable value) {
93                 variables.add(value);
94                 return this;
95         }
96
97         /*
98          * Provided for backwards compatibility
99          */
100         @Deprecated
101         public ExpressionBuilder withVariable(String variableName, double value) {
102                 variables.add(new Variable(variableName, value));
103                 return this;
104         }
105                 
106         /**
107          * set the variables names used in the expression without setting their
108          * values. Usefull for building an expression before you know the variable values.
109          * 
110          * @param variableNames
111          *            vararg {@link String} of the variable names used in the
112          *            expression
113          * @return the ExpressionBuilder instance
114          */
115         
116         public ExpressionBuilder withVariableNames(String... variableNames) {
117                 for (String name : variableNames) {
118                         variables.add( new Variable(name, Double.NaN) );
119                 }
120                 return this;
121         }
122         
123
124         /**
125          * set the values for variables
126          * 
127          * @param variableMap
128          *            a map of variable names to variable values
129          * @return the {@link ExpressionBuilder} instance
130          */
131         public ExpressionBuilder withVariables(VariableSet variables) {
132                 this.variables = variables;
133                 return this;
134         }
135 }