    package flare.vis.operator.layout
    {
        import flare.vis.data.NodeSprite;
        import flare.animate.Transitioner;
        import flash.geom.Point;
        import flare.util.Arrays;
        import flare.vis.data.EdgeSprite;

        /**
         * Layout that places tree nodes in an indented outline layout.
         */
        public class IndentedTreeLayout extends Layout
        {
            private var _bspace:Number = 5;  // the spacing between sibling nodes
            private var _dspace:Number = 50; // the spacing between depth levels
            private var _depths:Array = new Array(20); // TODO make sure array regrows as needed
            private var _maxDepth:int = 0;
            private var _ax:Number, _ay:Number; // for holding anchor co-ordinates

            /** The spacing to use between depth levels (the amount of indent). */
            public function get depthSpacing():Number { return _dspace; }
            public function set depthSpacing(s:Number):void { _dspace = s; }

            /** The spacing to use between rows in the layout. */
            public function get breadthSpacing():Number { return _bspace; }
            public function set breadthSpacing(s:Number):void { _bspace = s; }

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

            /**
             * Creates a new IndentedTreeLayout.
             * @param depthSpace the amount of indent between depth levels
             * @param breadthSpace the amount of spacing between rows
             */
            public function IndentedTreeLayout(depthSpace:Number=50,
                                               breadthSpace:Number=5)
            {
                _bspace = breadthSpace;
                _dspace = depthSpace;
            }

            /** @inheritDoc */
            protected override function layout():void
            {
                Arrays.fill(_depths, 0);
                _maxDepth = 0;

                var a:Point = layoutAnchor;
                _ax = a.x + layoutBounds.x;
                _ay = a.y + layoutBounds.y;

                var root:NodeSprite = layoutRoot as NodeSprite;
                if (root == null) return; // TODO: throw exception?

                layoutNode(root,0,0,true);
            }

            private function layoutNode(node:NodeSprite, height:Number, indent:uint, visible:Boolean):Number
            {
                var x:Number = _ax + indent * _dspace;
                var y:Number = _ay + height;
                var o:Object = _t.$(node);
                node.h = _t.endSize(node, _rect).height;

                // update node
                o.x = x;
                o.y = y;
                o.alpha = visible ? 1.0 : 0.0;

                // update edge
                if (node.parentEdge != null)
                {
                    var e:EdgeSprite = node.parentEdge;
                    var p:NodeSprite = node.parentNode;
                    o = _t.$(e);
                    o.alpha = visible ? 1.0 : 0.0;
                    if (e.points == null) {
                        e.points = [(p.x+node.x)/2, (p.y+node.y)/2];
                    }
                    o.points = [_t.getValue(p,"x"), y];
                }

                if (visible) { height += node.h + _bspace; }
                if (!node.expanded) { visible = false; }

                if (node.childDegree > 0) // is not a leaf node
                {
                    var c:NodeSprite = node.firstChildNode;
                    for (; c != null; c = c.nextNode) {
                        height = layoutNode(c, height, indent+1, visible);
                    }
                }
                return height;
            }

        } // end of class IndentedTreeLayout
    }