package flare.query
{
    /**
     * Expression operator for arithmetic operations. Performs addition,
     * subtraction, multiplication, or division of sub-expression values.
     */
    public class Arithmetic extends BinaryExpression
    {
        /** Indicates an addition operation. */
        public static const ADD:int = 0;
        /** Indicates a subtraction operation. */
        public static const SUB:int = 1;
        /** Indicates a multiplication operation. */
        public static const MUL:int = 2;
        /** Indicates a division operation. */
        public static const DIV:int = 3;
        /** Indicates a modulo operation. */
        public static const MOD:int = 4;
        
        /** Returns a string representation of the arithmetic operator. */
        public override function get operatorString():String
        {
            switch (_op) {
                case ADD: return '+';
                case SUB: return '-';
                case MUL: return '*';
                case DIV: return '/';
                case MOD: return '%';
                default: return '?';
            }
        }
        
        /**
         * Create a new Arithmetic expression.
         * @param operation the operation to perform
         * @param left the left sub-expression
         * @param right the right sub-expression
         */
        public function Arithmetic(op:int, left:*, right:*)
        {
            super(op, ADD, MOD, left, right);
        }
        
        /**
         * @inheritDoc
         */
        public override function clone():Expression
        {
            return new Arithmetic(_op, _left.clone(), _right.clone());
        }
        
        /**
         * @inheritDoc
         */
        public override function eval(o:Object=null):*
        {
            var x:Number = Number(_left.eval(o));
            var y:Number = Number(_right.eval(o));
            
            // compute return value
            switch (_op) {
                case ADD: return x+y;
                case SUB: return x-y;
                case MUL: return x*y;
                case DIV: return x/y;
                case MOD: return x%y;
            }
            throw new Error("Unknown operation type: "+_op);
        }
        
        // -- Static constructors ---------------------------------------------
        
        /**
         * Creates a new Arithmetic operator for adding two numbers.
         * @param left the left-hand input expression
         * @param right the right-hand input expression
         * @return the new Arithmetic operator
         */
        public static function Add(left:*, right:*):Arithmetic
        {
            return new Arithmetic(ADD, left, right);
        }
        
        /**
         * Creates a new Arithmetic operator for subtracting one number
         *  from another.
         * @param left the left-hand input expression
         * @param right the right-hand input expression
         * @return the new Arithmetic operator
         */
        public static function Subtract(left:*, right:*):Arithmetic
        {
            return new Arithmetic(SUB, left, right);
        }
        
        /**
         * Creates a new Arithmetic operator for multiplying two numbers.
         * @param left the left-hand input expression
         * @param right the right-hand input expression
         * @return the new Arithmetic operator
         */
        public static function Multiply(left:*, right:*):Arithmetic
        {
            return new Arithmetic(MUL, left, right);
        }
        
        /**
         * Creates a new Arithmetic operator for dividing one number
         *  by another.
         * @param left the left-hand input expression
         * @param right the right-hand input expression
         * @return the new Arithmetic operator
         */
        public static function Divide(left:*, right:*):Arithmetic
        {
            return new Arithmetic(DIV, left, right);
        }
        
        /**
         * Creates a new Arithmetic operator for computing the modulo
         *  (remainder) of a number.
         * @param left the left-hand input expression
         * @param right the right-hand input expression
         * @return the new Arithmetic operator
         */
        public static function Mod(left:*, right:*):Arithmetic
        {
            return new Arithmetic(MOD, left, right);
        }
        
    } // end of class Arithmetic
}