package flare.query
{
    /**
     * Aggregate operator for computing variance or standard deviation.
     */
    public class Variance extends AggregateExpression
    {
        /** Flag indicating the population variance or deviation. */
        public static const POPULATION:int = 0;
        /** Flag indicating the sample variance or deviation. */
        public static const SAMPLE:int     = 2;
        /** Flag indicating the variance should be computed. */
        public static const VARIANCE:int   = 0;
        /** Flag indicating the standard deviation should be computed. */
        public static const DEVIATION:int  = 1;
        
        private var _type:int;
        private var _sum:Number;
        private var _accum:Number;
        private var _count:Number;
        
        /**
         * Creates a new Variance operator. By default, the population variance
         * is computed. Use the type flags to change this. For example, the type
         * argument <code>Variance.SAMPLE | Variance.DEVIATION</code> results in
         * the sample standard deviation being computed.
         * @param input the sub-expression of which to compute variance
         * @param type the type of variance or deviation to compute
         */
        public function Variance(input:*, type:int=0) {
            super(input);
            _type = type;
        }
        
        /**
         * @inheritDoc
         */
        public override function reset():void
        {
            _sum = 0;
            _accum = 0;
            _count = 0;
        }
        
        /**
         * @inheritDoc
         */
        public override function eval(o:Object=null):*
        {
            var n:Number = _count - (_type & SAMPLE ? 1 : 0);
            var v:Number = _sum / n;
            v = v*v + _accum / n;
            return (_type & DEVIATION ? Math.sqrt(v) : v);
        }
        
        /**
         * @inheritDoc
         */
        public override function aggregate(value:Object):void
        {
            var x:Number = Number(_expr.eval(value));
            if (!isNaN(x)) {
                _sum += x;
                _accum += x*x;
                _count += 1;
            }
        }
        
    } // end of class Variance
}