package flare.scale
{
    import flare.util.Maths;
    import flare.util.Strings;
    
    /**
     * Scale that organizes data into discrete bins by quantiles.
     * For example, the quantile scale can be used to create a discrete size
     * encoding by statistically dividing the data into bins. Quantiles are
     * computed using the <code>flare.util.Maths.quantile</code> method.
     * 
     * @see flare.util.Maths#quantile
     */
    public class QuantileScale extends Scale
    {
        private var _quantiles:Array;
        
        /** @inheritDoc */
        public override function get flush():Boolean { return true; }
        public override function set flush(val:Boolean):void { /* nothing */ }
        
        /** @inheritDoc */
        public override function get min():Object { return _quantiles[0]; }
        
        /** @inheritDoc */
        public override function get max():Object { return _quantiles[_quantiles.length-1]; }
        
        // --------------------------------------------------------------------
        
        /**
         * Creates a new QuantileScale.
         * @param n the number of quantiles desired
         * @param values the data values to organized into quantiles
         * @param sorted flag indicating if the input values array is
         *  already pre-sorted
         * @param labelFormat the formatting pattern for value labels
         */
        public function QuantileScale(n:int, values:Array,
            sorted:Boolean=false, labelFormat:String=Strings.DEFAULT_NUMBER)
        {
            _quantiles = (n<0 ? values : Maths.quantile(n, values, !sorted));
            this.labelFormat = labelFormat;
        }
        
        /** @inheritDoc */
        public override function get scaleType():String {
            return ScaleType.QUANTILE;
        }
        
        /** @inheritDoc */
        public override function clone():Scale
        {
            return new QuantileScale(-1, _quantiles, false, _format);
        }
        
        /** @inheritDoc */
        public override function interpolate(value:Object):Number
        {
            return Maths.invQuantileInterp(Number(value), _quantiles);
        }
        
        /** @inheritDoc */
        public override function lookup(f:Number):Object
        {
            return Maths.quantileInterp(f, _quantiles);
        }
        
        /** @inheritDoc */
        public override function values(num:int=-1):/*Number*/Array
        {
            var a:Array = new Array();
            var stride:int = num<0 ? 1 : 
                int(Math.max(1, Math.floor(_quantiles.length/num)));
            for (var i:uint=0; i<_quantiles.length; i += stride) {
                a.push(_quantiles[i]);
            }
            return a;
        }
        
    } // end of class QuantileScale
}