package com.comphenix.xp.expressions; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Random; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import com.comphenix.xp.parser.ParsingException; import de.congrace.exp4j.Calculable; import de.congrace.exp4j.ExpressionBuilder; import de.congrace.exp4j.InvalidCustomFunctionException; import de.congrace.exp4j.UnknownFunctionException; import de.congrace.exp4j.UnparsableExpressionException; public class MathExpression extends VariableFunction { // Default value private static final double VARIABLE_NOT_FOUND = 0; // Extra custom functions protected RandomFunctions dunif; protected RandomFunctions iunif; // Variables we will calculate protected Map<String, Boolean> variablesPresent; // The function to use protected Calculable function; // The multiplication factor protected double multiplier; public MathExpression(String expression, String[] parameters) throws ParsingException { // Parse the expression try { dunif = new RandomFunctions(RandomFunctions.SubFunction.DUNIF); iunif = new RandomFunctions(RandomFunctions.SubFunction.IUNIF); // Parse expression function = new ExpressionBuilder(expression). withCustomFunction(dunif). withCustomFunction(iunif). withVariableNames(parameters). build(); // Default value multiplier = 1; variablesPresent = new HashMap<String, Boolean>(); // Add parameters that are present for (String param : parameters) { variablesPresent.put(param, function.containsVariable(param)); function.setVariable(param, VARIABLE_NOT_FOUND); } } catch (UnknownFunctionException e) { throw new ParsingException(e.getMessage(), e); } catch (UnparsableExpressionException e) { throw new ParsingException(e.getMessage(), e); } catch (InvalidCustomFunctionException e) { throw new ParsingException(e.getMessage(), e); } } // Make a shallow copy with a different multiplier private MathExpression(MathExpression copy, double multiplier) { this.dunif = copy.dunif; this.iunif = copy.iunif; this.function = copy.function; this.variablesPresent = copy.variablesPresent; this.multiplier = multiplier; } @Override public double apply(Random random, Collection<NamedParameter> params) throws Exception { // Don't forget to use the random number generator we got dunif.setRandom(random); iunif.setRandom(random); // Apply all the parameters that exists if (params != null) { for (NamedParameter param : params) { if (variablesPresent.get(param.getName())) { function.setVariable(param.getName(), param.call()); } else { function.setVariable(param.getName(), VARIABLE_NOT_FOUND); } } } // Right, do our thing return function.calculate() * multiplier; } @Override public VariableFunction withMultiplier(double newMultiplier) { return new MathExpression(this, newMultiplier); } @Override public double getMultiplier() { return multiplier; } /** * Retrieves the expression that was used to create this instance, or NULL. * @return Expression, or NULl if not found. */ public String getExpression() { return function != null ? function.getExpression() : null; } @Override public String toString() { if (multiplier != 1) return String.format("%s * %s", multiplier, function.getExpression()); else return function.getExpression(); } @Override public int hashCode() { return new HashCodeBuilder(17, 31). append(getExpression()). append(multiplier). toHashCode(); } @Override public boolean equals(Object obj) { if (obj == null) return false; if (obj == this) return true; if (obj.getClass() != getClass()) return false; MathExpression other = (MathExpression) obj; return new EqualsBuilder(). append(getExpression(), other.getExpression()). append(multiplier, other.multiplier). isEquals(); } }