package flare.vis.operator.layout
{
    import flare.util.Shapes;
    import flare.util.Sort;
    import flare.vis.data.Data;
    import flare.vis.data.NodeSprite;
    import flare.vis.data.render.ShapeRenderer;
    
    import flash.geom.Rectangle;

    /**
     * Layout that places nodes as circles compacted into a larger circle.
     * 
     * <p>Circle sizes are determined by a node's <code>size</code> property.
     * It is assumed that the sizes are set <i>before</i> this operator is run,
     * for example, by placing a <code>SizeEncoder</code> prior to this layout
     * in an operator list.</p>
     * 
     * <p>If the <code>treeLayout</code> property is <code>false</code>, all
     * nodes will be treated the same and the result will be a "bubble" chart.
     * If the <code>treeLayout<code> property is <code>true<code>, circles will
     * be nested inside each other according to the tree structure of the data.
     * </p>
     * 
     * <p>The results of this layout can vary dramatically based on the sort
     * order of the nodes. For example, sorting the nodes by the
     * <code>size</code> property (in either ascending or descending order)
     * can result in much cleaner layouts. Use the <code>sort</code> property
     * of this class to set a preferred sorting routine. By default, this
     * operator will not perform any sorting.</p>
     * 
     * <p>NOTE: This operator will set a node's <code>renderer</code> and
     * <code>shape</code> properties, overriding any previous values.</p>
     * 
     * <p>The algorithm used to perform the circle packing is adapted from
     * W. Wang, H. Wang, G. Dai, and H. Wang's <a
     * href="http://portal.acm.org/citation.cfm?id=1124772.1124851">
     * Visualization of large hierarchical data by circle packing</a>,
     * ACM CHI 2006.</p>
     */
    public class CirclePackingLayout extends Layout
    {
        private var _sort:Sort = null;
        private var _order:int;
        private var _b:Rectangle = new Rectangle();
        
        /** The data group to process. This setting will be ignored if tree mode
         *  is set to true. */
        public var group:String = Data.NODES;
        
        /** The amount of spacing between neighboring circles.
         *  The default value is 4 pixels. */
        public var spacing:Number = 4;
        
        /** Indicates if the view should be scaled to fit within the
         *  display bounds. The default is true. */
        public var fitInBounds:Boolean = true;
        
        /** Indicates if a tree layout (circles nested within circles) should
         *  be computed. The default is false. Any data group settings will
         *  be ignored if this operator uses a tree layout. */
        public var treeLayout:Boolean = false;
        
        /** A sort criteria for ordering nodes in this layout.
         *  Ordered nodes are placed in a spiral starting at the center.
         *  The default is null, meaning no sorting is performed. */
        public function get sort():Sort { return _sort; }
        public function set sort(s:*):void {
            _sort = s==null ? s : (s is Sort ? Sort(s) : new Sort(s));
        }
        
        // --------------------------------------------------------------------
        
        /**
         * Creates a new CirclePackingLayout.
         * @param spacing the minimum spacing between neighboring circles
         * @param treeLayout if true, a hierarchical circles-within-circles
         *  layout will be peformed; if false (the default) all nodes will be
         *  considered equally
         * @param sort a sort criteria for ordering nodes in the layout.
         *  Ordered nodes are placed in a spiral starting at the center.
         */
        public function CirclePackingLayout(spacing:Number=4,
            treeLayout:Boolean=false, sort:*=n