package de.congrace.exp4j;

/**
 * This class is used to create custom operators for use in expressions<br/>
 * The applyOperation(double[] values) will have to be implemented by users of this class. <br/>
 * <b>Example</b><br/>
 * <code><pre>{@code} 
 *      CustomOperator greaterEq = new CustomOperator(">=", true, 4, 2) {
 *            double applyOperation(double[] values) {
 *            	if (values[0] >= values[1]){
 *            		return 1d;
 *            	}else{
 *            		return 0d;
 *            	}
 *            }
 *        };
 *       Calculable calc = new ExpressionBuilder("1>=2").withOperation(greaterEq).build();
 *       assertTrue(0d == calc.calculate());
 * </pre></code> When constructing {@link CustomOperator} special attention has to be given to the precedence of the
 * operation. see http://en.wikipedia.org/wiki/Order_of_operations. The precendence values for the builtin operators are
 * as follows: <br/>
 * Addition and Subtraction (+,-) have precedence 1<br/>
 * Division Multiplication, and Modulo (/,*,%) have precedence 3<br/>
 * Exponentiation (^) has precendence 5 <br/>
 * Unary minus and plus (+1,-1) have precedence 7
 * 
 * @author frank asseg
 * 
 */
public abstract class CustomOperator {

	final boolean leftAssociative;

	final String symbol;

	final int precedence;

	final int operandCount;

	/**
	 * create a new {@link CustomOperator} for two operands
	 * 
	 * @param symbol
	 *            the symbol to be used in expressions to identify this operation
	 * @param leftAssociative
	 *            true is the operation is left associative
	 * @param precedence
	 *            the precedence of the operation
	 */
	protected CustomOperator(final String symbol, final boolean leftAssociative, final int precedence) {
		super();
		this.leftAssociative = leftAssociative;
		this.symbol = symbol;
		this.precedence = precedence;
		this.operandCount = 2;
	}

	/**
	 * create a new {@link CustomOperator}
	 * 
	 * @param symbol
	 *            the symbol to be used in expressions to identify this operation
	 * @param leftAssociative
	 *            true is the operation is left associative
	 * @param precedence
	 *            the precedence of the operation
	 * @param operandCount
	 *            the number of operands of the operation. A value of 1 means the operation takes one operand. Any other
	 *            value means the operation takes 2 arguments.
	 */

	protected CustomOperator(final String symbol, final boolean leftAssociative, final int precedence,
			final int operandCount) {
		super();
		this.leftAssociative = leftAssociative;
		this.symbol = symbol;
		this.precedence = precedence;
		this.operandCount = operandCount == 1 ? 1 : 2;
	}

	/**
	 * create a left associative {@link CustomOperator} with precedence value of 1 that uses two operands
	 * 
	 * @param symbol
	 *            the {@link String} to use a symbol for this operation
	 */
	protected CustomOperator(final String symbol) {
		super();
		this.leftAssociative = true;
		this.symbol = symbol;
		this.precedence = 1;
		this.operandCount = 2;
	}

	/**
	 * create a left associative {@link CustomOperator} for two operands
	 * 
	 * @param symbol
	 *            the {@link String} to use a symbol for this operation
	 * @param precedence
	 *            the precedence of the operation
	 */
	protected CustomOperator(final String symbol, final int precedence) {
		super();
		this.leftAssociative = true;
		this.symbol = symbol;
		this.precedence = precedence;
		this.operandCount = 2;
	}

	/**
	 * Apply the custom operation on the two operands and return the result as an double An example implementation for a
	 * multiplication could look like this:
	 * 
	 * <pre>
	 * <code>{@code}
	 *       double applyOperation(double[] values) {
	 *           return values[0]*values[1];
	 *       }
	 * </pre>
	 * 
	 * </code>
	 * 
	 * @param values
	 *            the operands for the operation. If the {@link CustomOperator} uses only one operand such as a
	 *            factorial the operation has to be applied to the first element of the values array. If the
	 *            {@link CustomOperator} uses two operands the operation has to be applied to the first two items in the
	 *            values array, with special care given to the operator associativity. The operand to the left of the
	 *            symbol is the first element in the array while the operand to the right is the second element of the
	 *            array.
	 * @return the result of the operation
	 */
	protected abstract double applyOperation(double[] values);
}
