    package flare.vis.operator.encoder
    {
        import flare.animate.Transitioner;
        import flare.scale.ScaleType;
        import flare.util.palette.ColorPalette;
        import flare.util.palette.Palette;
        import flare.vis.data.Data;

        /**
         * Encodes a data field into color values, using a scale transform and
         * color palette.
         */
        public class ColorEncoder extends Encoder
        {
            private var _palette:ColorPalette;
            private var _setPalette:Boolean = true;
            private var _ordinal:Boolean = false;

            /** @inheritDoc */
            public override function get palette():Palette { return _palette; }
            public override function set palette(p:Palette):void {
                _palette = p as ColorPalette;
                _setPalette = (_palette == null);
            }
            /** The palette as a ColorPalette instance. */
            public function get colors():ColorPalette { return _palette; }

            // --------------------------------------------------------------------

            /**
             * Creates a new ColorEncoder.
             * @param source the source property
             * @param group the data group to encode ("nodes" by default)
             * @param target the target property ("lineColor" by default)
             * @param scaleType the type of scale to use. If null, the scale type
             *  will be determined by the underlying <code>ScaleBinding</code>
             *  instance, based on the type of data.
             * @param palette the color palette to use. If null, a default color
             *  palette will be determined based on the scale type.
             */
            public function ColorEncoder(source:String=null,
                group:String=Data.NODES, target:String="lineColor",
                scaleType:String=null, palette:ColorPalette=null)
            {
                super(source, target, group);
                _binding.scaleType = scaleType;
                this.palette = palette;
            }

            /** @inheritDoc */
            public override function setup():void
            {
                if (visualization==null) return;
                super.setup();
            }

            /** @inheritDoc */
            public override function operate(t:Transitioner=null):void
            {
                _binding.updateBinding();
                _ordinal = ScaleType.isOrdinal(_binding.scaleType);

                // create a default color palette if none explicitly set
                if (_setPalette) _palette = getDefaultPalette();
                super.operate(t); // run encoder
            }

            /** @inheritDoc */
            protected override function encode(val:Object):*
            {
                if (_ordinal) {
                    return _palette.getColorByIndex(_binding.index(val));
                } else {
                    return _palette.getColor(_binding.interpolate(val));
                }
            }

            /**
             * Returns a default color palette based on the input scale.
             * @param scale the scale of values to map to colors
             * @return a default color palette for the input scale
             */
            protected function getDefaultPalette():ColorPalette
            {
                /// TODO: more intelligent color palette selection?
                if (ScaleType.isOrdinal(_binding.scaleType))
                {
                    return ColorPalette.category(_binding.length);
                }
                else if (ScaleType.isQuantitative(_binding.scaleType))
                {
                    var min:Number = Number(_binding.min);
                    var max:Number = Number(_binding.max);
                    if (min < 0 && max > 0)
                        return ColorPalette.diverging();
                }
                return ColorPalette.ramp();
            }

        } // end of class ColorEncoder
    }