    package flare.vis.axis
    {
        import flare.animate.Transitioner;
        import flare.display.RectSprite;
        import flare.display.TextSprite;
        import flare.vis.Visualization;

        import flash.geom.Rectangle;

        /**
         * Axes class representing 2D Cartesian (X-Y) axes.
         */
        public class CartesianAxes extends Axes
        {
            // -- Properties ------------------------------------------------------

            private var _xaxis:Axis;
            private var _yaxis:Axis;
            private var _xline:AxisGridLine;
            private var _yline:AxisGridLine;
            private var _border:RectSprite;
            private var _xGridClip:RectSprite;
            private var _yGridClip:RectSprite;

            /** Flag indicating if the x-origin line should be shown. */
            public var showXLine:Boolean;
            /** Flag indicating if the y-origin line should be shown. */
            public var showYLine:Boolean;
            /** Determines if the x-axis should be in reverse order. */
            public var xReverse:Boolean = false;
            /** Determines if the y-axis should be in reverse order. */
            public var yReverse:Boolean = false;

            /** The x-axis. */
            public function get xAxis():Axis { return _xaxis; }
            /** The y-axis. */
            public function get yAxis():Axis { return _yaxis; }
            /** Grid line for the origin along the x-axis. */
            public function get xLine():AxisGridLine { return _xline; }
            /** Grid line for the origin along the y-axis. */
            public function get yLine():AxisGridLine { return _yline; }

            /** The x-coordinate of the axes' origin point. */
            public function get originX():Number { return _xaxis.originX; }
            /** The y-coordinate of the axes' origin point. */
            public function get originY():Number { return _yaxis.originY; }

            /** Flag indicating if a border for the axes should be shown. */
            public function get showBorder():Boolean { return _border.visible; }
            public function set showBorder(b:Boolean):void { _border.visible = b; }

            /** The axes border color. */
            public function get borderColor():uint { return _border.lineColor; }
            public function set borderColor(c:uint):void { _border.lineColor = c; }

            /** The line width of the axes border. */
            public function get borderWidth():Number { return _border.lineWidth; }
            public function set borderWidth(w:Number):void { _border.lineWidth = w; }

            // -- Methods ---------------------------------------------------------

            /**
             * Creates new CartesianAxes.
             * @param vis the visualization the axes correspond to.
             */
            public function CartesianAxes(vis:Visualization=null) {
                _vis = vis;

                addChild(_xaxis = new Axis());
                addChild(_yaxis = new Axis());
                addChild(_xline = new AxisGridLine());
                addChild(_yline = new AxisGridLine());
                addChild(_border = new RectSprite());
                addChild(_xGridClip = new RectSprite());
                addChild(_yGridClip = new RectSprite());

                // set names
                _xaxis.name = "_xaxis";
                _yaxis.name = "_yaxis";
                _xline.name = "_xline";
                _yline.name = "_yline";
                _border.name = "_border";

                // set label anchors
                _xaxis.horizontalAnchor = TextSprite.CENTER;
                _xaxis.verticalAnchor   = TextSprite.TOP;
                _yaxis.horizontalAnchor = TextSprite.RIGHT;
                _yaxis.verticalAnchor   = TextSprite.MIDDLE;

                // set default label offsets
                _xaxis.labelOffsetX =  0; _xaxis.labelOffsetY = 8;
                _yaxis.labelOffsetX = -8; _yaxis.labelOffsetY = 0;

                // set default gridline caps
                _xaxis.lineCapX1 = _xaxis.lineCapX2 = 0;
                _xaxis.lineCapY1 = _xaxis.lineCapY2 = 0;
                _yaxis.lineCapX1 = _yaxis.lineCapX2 = 0;
                _yaxis.lineCapY1 = _yaxis.lineCapY2 = 0;

                // set default gridline colors
                _xaxis.lineColor = 0xd8d8d8;
                _yaxis.lineColor = 0xd8d8d8;

                // set default line settings
                _xline.lineColor = 0xcccccc;
                _yline.lineColor = 0xcccccc;

                // set up border
                _border.lineColor = 0xffd8d8d8;
                _border.fillColor = 0x00ffffff;

                // set up clipping masks
                _xGridClip.lineColor = 0;
                _xGridClip.fillColor = 0xffffffff;
                _yGridClip.lineColor = 0;
                _yGridClip.fillColor = 0xffffffff;
            }

            /** @inheritDoc */
            public override function update(trans:Transitioner=null):Transitioner
            {
                var t:Transitioner = (trans!=null ? trans : Transitioner.DEFAULT);
                var o:Object;
                var b:Rectangle = layoutBounds;

                // set x-axis position
                if (xReverse) {
                    _xaxis.x1 = b.right; _xaxis.y1 = b.bottom;
                    _xaxis.x2 = b.left;  _xaxis.y2 = b.bottom;
                } else {
                    _xaxis.x1 = b.left;  _xaxis.y1 = b.bottom;
                    _xaxis.x2 = b.right; _xaxis.y2 = b.bottom;
                }

                // set y-axis position
                if (yReverse) {
                    _yaxis.x1 = b.left;  _yaxis.y1 = b.top;
                    _yaxis.x2 = b.left;  _yaxis.y2 = b.bottom;
                   } else {
                       _yaxis.x1 = b.left;  _yaxis.y1 = b.bottom;
                    _yaxis.x2 = b.left;  _yaxis.y2 = b.top;
                   }

                // gridline length
                _xaxis.lineLengthX = 0;
                _xaxis.lineLengthY = -b.height;
                _yaxis.lineLengthX = b.width;
                _yaxis.lineLengthY = 0;

                // update axes
                _xaxis.update(t);
                _yaxis.update(t);

                // update x-axis origin line
                var yx:Number = _yaxis.offsetX(0);
                var yy:Number = _yaxis.offsetY(0);
                var ys:Boolean = showXLine && yx >= 0 && yx <= b.width;
                o = t.$(_xline);
                o.x1 = _xaxis.x1 + yx;
                o.y1 = _xaxis.y1 + yy;
                o.x2 = _xaxis.x2 + yx;
                o.y2 = _xaxis.y2 + yy;
                o.alpha = ys ? 1 : 0;

                // update y-axis origin line
                var xx:Number = _xaxis.offsetX(0);
                var xy:Number = _xaxis.offsetY(0);
                var xs:Boolean = showYLine && xy >= 0 && xy <= b.height;
                o = t.$(_yline);
                o.x1 = _yaxis.x1 + xx;
                o.y1 = _yaxis.y1 + xy;
                o.x2 = _yaxis.x2 + xx;
                o.y2 = _yaxis.y2 + xy;
                o.alpha = xs ? 1 : 0;

                // update axis border
                o = t.$(_border);
                o.x = b.x;
                o.y = b.y;
                o.w = b.width;
                o.h = b.height;

                // set the gridline clipping regions
                o = t.$(_xGridClip);
                o.x = b.x;
                o.y = b.y - _xaxis.lineCapY2;
                o.w = b.width + 1;
                o.h = b.height + _xaxis.lineCapY1 + _xaxis.lineCapY2;
                _xaxis.gridLines.mask = _xGridClip;

                o = t.$(_yGridClip);
                o.x = b.x - _yaxis.lineCapX1;
                o.y = b.y;
                o.w = b.width + _yaxis.lineCapX1 + _yaxis.lineCapX2;
                o.h = b.height + 1;
                _yaxis.gridLines.mask = _yGridClip;

                return trans;
            }

        } // end of class CartesianAxes
    }