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