////////////////////////////////////////////////////////////////////////////////
//
//
////////////////////////////////////////////////////////////////////////////////

package mx.collections {

import flash.events.TimerEvent;
import flash.utils.Dictionary;
import flash.utils.Timer;

import mx.collections.errors.ItemPendingError;
import mx.core.mx_internal;
import mx.events.CollectionEvent;
import mx.events.CollectionEventKind;
import mx.events.CubeEvent;

use namespace mx_internal;

//--------------------------------------
//  Other metadata
//--------------------------------------

[DefaultProperty("grouping")]

/**
 *  The GroupingCollection class lets you create grouped data from flat data 
 *  for display in the AdvancedDataGrid control.
 *  When you create the instance of the GroupingCollection from your flat data, 
 *  you specify the field or fields of the data used to create the hierarchy.
 *
 *  <p>To populate the AdvancedDataGrid control with grouped data, 
 *  you create an instance of the GroupingCollection class from your flat data, 
 *  and then pass that GroupingCollection instance to the data provider 
 *  of the AdvancedDataGrid control. 
 *  To specify the grouping fields of your flat data, 
 *  you pass a Grouping instance to 
 *  the <code>GroupingCollection.grouping</code> property. 
 *  The Grouping instance contains an Array of GroupingField instances, 
 *  one per grouping field. </p>
 *
 *  <p>The following example uses the GroupingCollection class to define
 *  two grouping fields: Region and Territory.</p>
 *
 *  <pre>
 *  &lt;mx:AdvancedDataGrid id=&quot;myADG&quot;    
 *    &lt;mx:dataProvider&gt; 
 *      &lt;mx:GroupingCollection id=&quot;gc&quot; source=&quot;{dpFlat}&quot;&gt; 
 *        &lt;mx:grouping&gt; 
 *          &lt;mx:Grouping&gt; 
 *            &lt;mx:GroupingField name=&quot;Region&quot;/&gt; 
 *            &lt;mx:GroupingField name=&quot;Territory&quot;/&gt; 
 *          &lt;/mx:Grouping&gt; 
 *        &lt;/mx:grouping&gt; 
 *      &lt;/mx:GroupingCollection&gt; 
 *    &lt;/mx:dataProvider&gt;  
 *     
 *    &lt;mx:columns&gt; 
 *      &lt;mx:AdvancedDataGridColumn dataField=&quot;Region&quot;/&gt; 
 *      &lt;mx:AdvancedDataGridColumn dataField=&quot;Territory&quot;/&gt; 
 *      &lt;mx:AdvancedDataGridColumn dataField=&quot;Territory_Rep&quot;/&gt; 
 *      &lt;mx:AdvancedDataGridColumn dataField=&quot;Actual&quot;/&gt; 
 *      &lt;mx:AdvancedDataGridColumn dataField=&quot;Estimate&quot;/&gt; 
 *    &lt;/mx:columns&gt; 
 *  &lt;/mx:AdvancedDataGrid&gt;
 *  </pre>
 *
 *  @mxml
 *
 *  The <code>&lt;mx.GroupingCollection&gt;</code> inherits all the tag attributes of its superclass, 
 *  and defines the following tag attributes:</p>
 *
 *  <pre>
 *  &lt;mx:GroupingCollection
 *  <b>Properties </b>
 *    grouping="<i>No default</i>"
 *    source="<i>No default</i>"
 *    summaries="<i>No default</i>"
 *  /&gt;
 *  </pre>
 *
 *  @see mx.controls.AdvancedDataGrid
 *  @see mx.collections.Grouping
 *  @see mx.collections.GroupingField
 */
 [Event(name="progress", type="mx.events.CubeEvent")] 
 [Event(name="complete", type="mx.events.CubeEvent")]
public class GroupingCollection1 extends HierarchicalData implements IGroupingCollection
{
    //include "../core/Version.as";

    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------

    /**
     *  Constructor.
     */
    public function GroupingCollection1()
    {
        super();
        
        newCollection = new ArrayCollection();
        super.source = newCollection;
        
        objectSummaryMap = new Dictionary(false);
        
        parentMap = {};
    }
    
    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------
    
    /**
     *  @private
     *  
     *  denotes if the refresh is asynchronous.
     */
    private var async:Boolean = false;
    
    /**
     *  @private
     */
    private var newCollection:ArrayCollection;
    
    /**
     *  @private
     */
    private var _sourceCol:ICollectionView;
    
    /**
     *  @private
     *  
     *  the object summary map.
     *  keeps summaries corresponding to different objects
     */
    private var objectSummaryMap:Dictionary;
    
    /**
     *  @private
     *  
     *  the original sort applied to the source collection 
     */
    private var oldSort:Sort;
    
    /**
     *  The timer which is associated with an asynchronous refresh operation.
     *  You can use it to change the timing interval, pause the refresh, 
     *  or perform other actions.
     *  
     *  The default value for the <code>delay</code> property of the 
     *  Timer instance is 1, corresponding to 1 millisecond.
     *
     */
    protected var timer:Timer;
    
    /**
     *  @private
     */
    private var prepared:Boolean = false;
    
    /**
     *  @private
     */
    private var flatView:ICollectionView;
    
    /**
     *  @private
     */
    private var flatCursor:IViewCursor;
    
    /**
     *  @private
     */
//    private var hView:ICollectionView;
    
    /**
     *  @private
     */
    private var treeCursor:IViewCursor;
    
    /**
     *  @private
     */
    private var currentPosition:CursorBookmark = CursorBookmark.FIRST;
    
    /**
     *  @private
     */
    private var gf:Array;
    
    /**
     *  @private
     */
    private var fieldCount:int;
    
    /**
     *  @private
     *  
     *  contains current data being compared
     */
    private var currentData:Object;
    
    /**
     *  @private
     *  
     *  contains current group objects for different group fields
     */
    private var currentGroups:Array;
    
    /**
     *  @private
     *  
     *  contains current group labels for different group fields
     */
    private var currentGroupLabels:Array;
    
    /**
     *  @private
     *  
     *  contains next index for different group fields
     */
    private var currentIndices:Array;
    
    /**
     *  @private
     *  
     *  item index
     */
    private var itemIndex:int;
    
    /**
     *  @private
     *  
     *  the children array for the group
     */
    private var childrenArray:Array;
    
    /**
     *  @private
     *  Mapping of UID to parents.  Must be maintained as things get removed/added
     *  This map is created as objects are visited
     */
    protected var parentMap:Object;
    
    /**
     *  @private
     */
    mx_internal var optimizeSummaries:Boolean = false;
    
    /**
     *  @private
     */
    private var summaryPresent:Boolean;
    
    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------
    
    /**
     *  Array of SummaryRow instances that define any root-level data summaries.
     *  Specify one or more SummaryRow instances to define the data summaries, 
     *  as the following example shows:
     *
     *  <pre>
     *  &lt;mx:AdvancedDataGrid id="myADG" 
     *     width="100%" height="100%" 
     *     initialize="gc.refresh();"&gt;        
     *     &lt;mx:dataProvider&gt;
     *         &lt;mx:GroupingCollection id="gc" source="{dpFlat}"&gt;
     *             &lt;mx:summaries&gt;
     *                 &lt;mx:SummaryRow summaryPlacement="last"&gt;
     *                     &lt;mx:fields&gt;
     *                         &lt;mx:SummaryField dataField="Actual" 
     *                             label="Min Actual" operation="MIN"/&gt;
     *                         &lt;mx:SummaryField dataField="Actual" 
     *                             label="Max Actual" operation="MAX"/&gt;
     *                     &lt;/mx:fields&gt;
     *                   &lt;/mx:SummaryRow&gt;
     *                 &lt;/mx:summaries&gt;
     *             &lt;mx:Grouping&gt;
     *                 &lt;mx:GroupingField name="Region"/&gt;
     *                 &lt;mx:GroupingField name="Territory"/&gt;
     *             &lt;/mx:Grouping&gt;
     *         &lt;/mx:GroupingCollection&gt;
     *     &lt;/mx:dataProvider&gt;        
     *     
     *     &lt;mx:columns&gt;
     *         &lt;mx:AdvancedDataGridColumn dataField="Region"/&gt;
     *         &lt;mx:AdvancedDataGridColumn dataField="Territory_Rep"
     *             headerText="Territory Rep"/&gt;
     *         &lt;mx:AdvancedDataGridColumn dataField="Actual"/&gt;
     *         &lt;mx:AdvancedDataGridColumn dataField="Estimate"/&gt;
     *         &lt;mx:AdvancedDataGridColumn dataField="Min Actual"/&gt;
     *         &lt;mx:AdvancedDataGridColumn dataField="Max Actual"/&gt;
     *     &lt;/mx:columns&gt;
     *  &lt;/mx:AdvancedDataGrid&gt;</pre>
     *
     *  @see mx.collections.SummaryRow
     *  @see mx.collections.SummaryField
     */
    public var summaries:Array;    
    
    private var _grouping:Grouping;
    
    /**
     *  Specifies the Grouping instance applied to the source data. 
     *  Setting the <code>grouping</code> property  
     *  does not automatically refresh the view,
     *  so you must call the <code>refresh()</code> method
     *  after setting this property.
     *
     *  @see mx.collections.GroupingCollection#refresh()
     */
    public function get grouping():Grouping
    {
        return _grouping;
    }
       
    /**
     *  @private
     */
    public function set grouping(value:Grouping):void
    {
        _grouping = value;
    }

    //--------------------------------------------------------------------------
    //
    //  Overriden Methods
    //
    //--------------------------------------------------------------------------
    
    /**
     *  The source collection containing the flat data to be grouped.
     *  
     *  If the source is not a collection, it will be auto-wrapped into a collection.
     *  
     */
    override public function get source():Object
    {
        return _sourceCol;
    }
    
    override public function set source(value:Object):void
    {
//        if (_sourceCol)
//            _sourceCol.removeEventListener(CollectionEvent.COLLECTION_CHANGE, collectionChangeHandler);
        
        if (!value)
        {
            _sourceCol = null;
            return;
        }
            
        _sourceCol = ICollectionView(value);
        
//        if(_sourceCol is ICollectionView)
//            _sourceCol.addEventListener(CollectionEvent.COLLECTION_CHANGE, collectionChangeHandler);
    }
    
    /**
     * @private
     */ 
//    override public function getChildren(node:Object):Object
//    {
//        var children:Object = super.getChildren(node);
//        
//        // populate the parentMap
//        // parentMap will be populated only if the children is ICollectionView
//        var uid:String;
//        if (children != null)
//        {
//            if (children is ICollectionView)
//            {
//                var cursor:IViewCursor = ICollectionView(children).createCursor();
//                while (!cursor.afterLast)
//                {                
//                    uid = UIDUtil.getUID(cursor.current);
//                    parentMap[uid] = node;
//                    cursor.moveNext();
//                }
//            }
//            else
//            {
//                //if the children is not ICollectionView then
//                //it was not introduced by GC. (this happens in the case of XML.) 
//                return null;
//            }
//        }
//        
//        return children;
//    }
    
    /**
     *  Return <code>super.source</code>, if the <code>grouping</code> property is set, 
     *  and an ICollectionView instance that refers to <code>super.source</code> if not.
     *  
     *  @return The object to return.
     */
    override public function getRoot():Object
    {
        return super.source;
    }
    
    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------
    
    /**
     *  @inheritDoc
     */
    public function refresh(async:Boolean = false):Boolean
    {
        this.async = async;
        var resetEvent:CollectionEvent;
        
        // return if no grouping or groupingFields are supplied
        if (!grouping || grouping.fields.length < 1 )
        {
            super.source = source;
            // dispatch collection change event of kind reset.
            resetEvent =
                    new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
            resetEvent.kind = CollectionEventKind.RESET;
            dispatchEvent(resetEvent);
            buildGroups();//Just to generateRootSummaries a.k.a grandTotals
            return true;
        }
        
        super.source = newCollection;
        
        // dispatch collection change event of kind reset.
        resetEvent =
                new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
        resetEvent.kind = CollectionEventKind.RESET;
        dispatchEvent(resetEvent);
        
        // reset the parent map
        parentMap = {}; 
        
        // reset the object summary map
        objectSummaryMap = new Dictionary(false);
        
        summaryPresent = false;
        for (var i:int = 0; i < grouping.fields.length; i++)
        {
            if (GroupingField(grouping.fields[i]).summaries)
            {
                summaryPresent = true;
                break;
            }
        }
        
        var grouped:Boolean;
        if(source && grouping)
        {
            grouped = makeGroupedCollection();
        }
        
        return grouped;
    }
    
    /**
     *  @inheritDoc
     */
    public function cancelRefresh():void
    {
        if (timer)
        {
            timer.stop();
            timer = null;
            cleanUp();
        }
    }
    
    /**
     *  @private
     *  
     *  check for the existing groups if they can accomodate the item
     *  otherwise create new group and place the item.
     */  
//    private function addItem(node:Object, depth:int = 0):void
//    {   
//        var coll:ICollectionView = super.source as ICollectionView;
//        var parent:Object = null;
//        var i:int = 0;
//        while (i < grouping.fields.length)
//        {
//            // check for the parent item
//            var obj:Object = checkForParentExistence(coll, node, i);
//            // if no parent, then use the previous parent
//            if (!obj)
//                break;
//            // change the parent to point to its parent and start looking for parent again
//            parent = obj;
//            
//            if (parent)
//            {
//                coll = getChildren(parent) as ICollectionView;
//                i++;
//            }       
//        }
//        
//        // parent found
//        if (parent)
//        {
//            coll = getChildren(parent) as ICollectionView;
//            
//            // create groups for the item as no existing group matched with the item
//            if (i <= grouping.fields.length-1)
//            {
//                // create groups and place item
//                createGroupsAndInsertItem(coll, node, i);
//                // update the summary for the parents
//                updateSummary(node);
//                return;
//            }
//            // if there already exist a group for the item and insert the item in that group
//            if (coll is IList)
//            {
//                // insert the item
//                IList(coll).addItem(node);
//                // update the parent map
//                updateParentMap(parent, node);
//                // update the summary for the parents
//                updateSummary(node);
//            }
//        }
//        else
//        {
//            // no groups for the item, create groups and add item to them
//            createGroupsAndInsertItem(super.source as ICollectionView, node);
//            // update the summary for the parents
//            updateSummary(node);
//        }
//        
//    }
    
    /**
     *  @private
     *  
     *  check for existence of the groups for an item in the collection
     *  and return all the parent of that item.
     */  
//    private function checkForParentExistence(coll:ICollectionView, node:Object, depth:int):Object
//    {
//        var cursor:IViewCursor = coll.createCursor();
//        
//        var label:String = getDataLabel(node, grouping.fields[depth]);
//        
//        while (!cursor.afterLast)
//        {
//            var current:Object = cursor.current;
//            // check for matching fields
//            if (current.hasOwnProperty(grouping.label) && 
//                current[grouping.label] == label)
//            {
//                return current;
//            }
//            cursor.moveNext();
//        }
//        
//        return null;
//    }
    
    /**
     *  @private
     * 
     *  collection change handler.
     * 
     */  
//    private function collectionChangeHandler(event:CollectionEvent):void
//    {
//        if (!grouping)
//            return;
//        
//        var i:int = 0;
//        var j:int = 0;
//        var obj:Object;
//        
//        if (event.kind == CollectionEventKind.UPDATE)
//        {
//            for (i = 0; i < event.items.length; i++)
//            {
//                var summaryCalculated:Boolean;
//                // take the source property to get the updated object
//                obj = event.items[i].source;
//                
//                if (!obj)
//                    continue;
//                
//                for (j = 0; j < grouping.fields.length; j++)
//                {
//                    // check if the property corresponding to the group fields changed
//                    if (event.items[i].property == grouping.fields[j].name)
//                    {
//                        summaryCalculated = true;
//                        // update summaries - first remove the item from its group
//                        updateSummary(obj,true);
//                        // add the item to the group
//                        addItem(obj);
//                        break;
//                    }
//                }
//                // for other properties just update the summaries
//                if (!summaryCalculated)
//                    updateSummary(obj);
//            }
//        }
//        
//        if (event.kind == CollectionEventKind.ADD)
//        {
//            for (i = 0; i < event.items.length; i++)
//            {
//                obj = event.items[i];
//                // add the item to the group
//                addItem(obj);
//            }
//        }
//        
//        if (event.kind == CollectionEventKind.REMOVE)
//        {
//            for (i = 0; i < event.items.length; i++)
//            {
//                obj = event.items[i];
//                // update summaries - first remove the item from its group
//                updateSummary(obj,true);
//            }
//        }
//        
//        if (event.kind == CollectionEventKind.REPLACE)
//        {
//            for (i = 0; i < event.items.length; i++)
//            {
//                var oldValue:Object = event.items[i].oldValue;
//                var newValue:Object = event.items[i].newValue;
//                // update summaries - first remove the item from its group
//                updateSummary(oldValue,true);
//                // add the item to the group
//                addItem(newValue);
//            }
//        }
//        
//        // generate the root summaries
//        regenerateRootSummaries();
//    }
    
    /**
     *  @private
     *  
     *  creating the group for the item in the collection
     *  and placing it there.
     */  
//    private function createGroupsAndInsertItem(coll:ICollectionView, node:Object, depth:int = 0):void
//    {
//        var parent:Object;
//        for (var i:int = depth; i < grouping.fields.length ; i++)
//        {
//            // get the dataField and value
//            var dataField:String = grouping.fields[i].name;
//            var value:String = getDataLabel(node, grouping.fields[i]);
//            
//            if (!value)
//                return;
//                
//            // create a new group
//            var obj:Object;
//            if (grouping.fields[i].groupingObjectFunction != null)
//                obj = grouping.fields[i].groupingObjectFunction(value);
//            else if (grouping.groupingObjectFunction != null)
//                obj = grouping.groupingObjectFunction(value);
//            else
//                obj = {};
//            
//            obj[childrenField] = new ArrayCollection();
//            
//            obj[grouping.label] = value;
//            
//            if (coll is IList)
//            {
//                IList(coll).addItem(obj);
//                
//                // get the parent and update parent map
//                parent = parent != null ? parent : getParent(coll.createCursor().current);
//                updateParentMap(parent, obj);
//                
//                coll = getChildren(obj) as ICollectionView;
//                parent = obj;
//                // if we reach the end of the fields, just insert the item in the collection
//                if (i == grouping.fields.length-1)
//                {
//                    IList(coll).addItem(node);
//                    // update the parent map
//                    updateParentMap(obj, node);
//                    break;
//                }
//            }
//        }
//    }
    
    /**
     * @private
     * 
     * returns the collection view of the given object
     */ 
//    private function getCollection(value:Object):ICollectionView
//    {
//        // handle strings and xml
//        if (typeof(value)=="string")
//            value = new XML(value);
//        else if (value is XMLNode)
//            value = new XML(XMLNode(value).toString());
//        else if (value is XMLList)
//            value = new XMLListCollection(value as XMLList);
//        
//        if (value is XML)
//        {
//            var xl:XMLList = new XMLList();
//            xl += value;
//            return new XMLListCollection(xl);
//        }
//        //if already a collection dont make new one
//        else if (value is ICollectionView)
//        {
//            return ICollectionView(value);
//        }
//        else if (value is Array)
//        {
//            return new ArrayCollection(value as Array);
//        }
//        //all other types get wrapped in an ArrayCollection
//        else if (value is Object)
//        {         
//            // convert to an array containing this one item
//            var tmp:Array = [];
//            tmp.push(value);
//            return new ArrayCollection(tmp);
//        }
//        else
//        {
//            return new ArrayCollection();
//        }
//    }
    
    /**
     *  @private
     *  get the data label from user specified function.
     *  otherwise get the label from the data.
     */ 
    private function getDataLabel(data:Object,field:GroupingField):String
    {
        if (field.groupingFunction != null)
            return field.groupingFunction(data, field);
        
        // should we create a defaultGroupLabelValue property
        return data.hasOwnProperty(field.name) ? data[field.name] : "Not Available";
    }
    
    /**
     *  Returns the parent of a node.  
     *  The parent of a top-level node is <code>null</code>.
     *
     *  @param node The Object that defines the node.
     *
     *  @return The parent node containing the node as child, 
     *  <code>null</code> for a top-level node,  
     *  and <code>undefined</code> if the parent cannot be determined.
     */
//    protected function getParent(node:Object):*
//    {
//        var uid:String = UIDUtil.getUID(node);
//        if (parentMap.hasOwnProperty(uid))
//            return parentMap[uid];
//            
//        return undefined;
//    }
    
    /**
     *  @private
     * 
     *  generate the root summaries.
     *  different for flat data and grouped data.
     * 
     */  
//    private function generateRootSummaries(flatData:Boolean = false):void
//    {
//        var coll:ICollectionView = super.source as ICollectionView;
//        
//        if (flatData)
//            coll = coll.createCursor().current as ICollectionView;
//        
//        var summaryObj:Array = [];
//        // computing all the summaries
//        for (var i:int = 0; i < summaries.length; i++)
//        {
//            var summaryRow:SummaryRow = summaries[i];
//            if (coll.length > 0)
//            {
//                summaryObj[i] = 
//                    summaryRow.summaryObjectFunction != null ? summaryRow.summaryObjectFunction() : new SummaryObject();
//                
//                // for all summary fields
//                for (var j:int = 0; j < summaryRow.fields.length; j++)
//                {
//                    var summaryField:SummaryField = summaryRow.fields[j];
//                    var summary:Number = 0.0;
//                    var label:String = summaryField.label ? summaryField.label : summaryField.dataField;
//                    
//                    var cursor:IViewCursor = coll.createCursor();
//                    // if data is flat then go through each object and calculate summary.
//                    if (flatData)
//                    {
//                        while (!cursor.afterLast)
//                        {
//                            var current:Object = cursor.current;
//                            var temp:Number = current.hasOwnProperty(label) ? current[label] : 0.0;;
//                            
//                            if (summaryField.operation == "SUM" || summaryField.operation == "COUNT")
//                                summary += temp;
//                            else if (summaryField.operation == "MAX")
//                                summary = temp;
//                            else if (summaryField.operation == "MIN")
//                                summary = temp;
//                                
//                            cursor.moveNext();
//                        }
//                    }
//                    else
//                    {
//                        if (!optimizeSummaries)
//                        {
//                            var hd:HierarchicalData = new HierarchicalData(coll);
//                            hd.childrenField = this.childrenField;
//                            var hColl:ICollectionView = new HierarchicalCollectionView(hd, {});
//                            var hCursor:IViewCursor = new LeafNodeCursor(HierarchicalCollectionView(hColl), hColl, hd);
//                            
//                            if (summaryField.summaryFunction != null)
//                            {
//                                summary = summaryField.summaryFunction(
//                                    hCursor, summaryField.dataField, summaryField.operation);
//                            }
//                            else
//                            {
//                                summary = summaryUtil(
//                                    hCursor, summaryField.dataField, summaryField.operation);
//                            }
//                        }
//                        else
//                            summary = getSummaryFromCursor(cursor, summaryField.dataField, summaryField.operation);
//                    }
//                    
//                    summaryObj[i][label] = summary;
//                }
//                
//                if (objectSummaryMap[coll] == undefined)
//                    objectSummaryMap[coll] = [];
//                
//                objectSummaryMap[coll].push(summaryObj[i]);
//            }
//        }
//        insertRootSummary(summaryObj);
//    }
    
    /**
     *  @private
     * 
     *  calculate the summaries for a given parent,
     *  populate the objectSummaryMap and
     *  insert the summary in the collection
     * 
     */  
//    private function getSummaries(parent:Object, depth:int):void
//    {
//        if (depth > grouping.fields.length-1)
//            return;
//        
//        var children:ICollectionView = this.getChildren(parent) as ArrayCollection;
//        
//        if (!children || children.length == 0)
//            return;
//        
//        var summaries:Array = grouping.fields[depth].summaries;
//        if (!summaries)
//            return;
//        var summaryObj:Array = [];
//        // computing all the summaries
//        for (var i:int = 0; i < summaries.length; i++)
//        {
//            var summaryRow:SummaryRow = summaries[i];
//            summaryObj[i] = 
//                summaryRow.summaryObjectFunction != null ? summaryRow.summaryObjectFunction() : new SummaryObject();
//            
//            // for all summary fields
//            for (var j:int = 0; j < summaryRow.fields.length; j++)
//            {
//                var summaryField:SummaryField = summaryRow.fields[j];
//                var summary:Number = 0.0;
//                var label:String = summaryField.label ? summaryField.label : summaryField.dataField;
//                
//                // calculate the summary at the last level
//                var calculateSummaries:Boolean = true;
//                if (optimizeSummaries)
//                {
//                    if (depth == grouping.fields.length-1)
//                    {
//                        calculateSummaries = true;
//                    }
//                    // assume that summary is already present and fetch it from the map
//                    else
//                    {
//                        calculateSummaries = false;
//                        summary = getSummaryFromMap(parent, label, summaryField.operation);
//                    }
//                }
//                if (calculateSummaries)
//                {
//                    var hd:HierarchicalData = new HierarchicalData(children);
//                    hd.childrenField = this.childrenField;
//                    var hColl:ICollectionView = new HierarchicalCollectionView(hd, {});
//                    var hCursor:IViewCursor = new LeafNodeCursor(HierarchicalCollectionView(hColl), hColl, hd);
//                    
//                    if (summaryField.summaryFunction != null)
//                    {
//                        summary = summaryField.summaryFunction(
//                            hCursor, summaryField.dataField, summaryField.operation);
//                    }
//                    else
//                    {
//                        summary = summaryUtil(
//                            hCursor, summaryField.dataField, summaryField.operation);
//                    }
//                }
//                
//                // populate the summary object
//                summaryObj[i][label] = summary;
//            }
//            
//            // populate the object summary map
//            if (objectSummaryMap[parent] == undefined)
//                objectSummaryMap[parent] = [];
//                
//            objectSummaryMap[parent].push(summaryObj[i]);
//        }
//        // insert the summary
//        insertSummary(parent, summaryObj, summaries);
//    }
    
    /**
     *  @private
     *  
     *  computes the summary for the parent node.
     *  will fetch the summaries from the object summary map
     * 
     */  
//    private function getSummaryFromMap(parent:Object, label:String, operation:String):Number
//    {
//        var cursor:IViewCursor = (getChildren(parent) as ArrayCollection).createCursor();
//        
//        return getSummaryFromCursor(cursor, label, operation);
//    }
    
    /**
     *  @private
     * 
     *  calculates the summary by traversing over the iterator.
     * 
     */  
//    private function getSummaryFromCursor(cursor:IViewCursor, label:String, operation:String):Number
//    {
//        var result:Number = 0;
//        while (!cursor.afterLast)
//        {
//            var temp:Array = objectSummaryMap[cursor.current];
//            for (var i:int = 0; i < temp.length; i++)
//            {
//                if (temp[i] && temp[i].hasOwnProperty(label))
//                {
//                    if (operation == "SUM" || operation == "COUNT")
//                        result += temp[i][label];
//                    else if (operation == "MAX")
//                        result = result < temp[i][label] ? temp[i][label] : result;
//                    else if (operation == "MIN")
//                        result = result > temp[i][label] ? temp[i][label] : result;
//                }
//            }
//                
//            cursor.moveNext();  
//        }
//        return result;
//    }
    
    /**
     *  @private
     * 
     *  initialize the variables
     * 
     */
    private function initialize():void
    {
        currentData = null;
        currentGroups = [];
    
        currentGroupLabels = [];
        currentIndices = [] ;
        
        childrenArray = null;
        
        _generatedRootSummaries = [];
        if(source==null){
            source = new ArrayCollection;
        }
        if (source && summaries){//Init generateRootSummaries         
            _generatedRootSummaries = [];               
            for (var i:int = 0; i < summaries.length; i++) {                   
                  _generatedRootSummaries[i] = new SummaryObject();//init
               for each(var summaryField:SummaryField in  SummaryRow(summaries[i]).fields) {                   
                       if(summaryField.operation == 'STRINGAGG'){
                        /** Alphanumeric */                        
                    } else {
                        /** Numeric*/                        
                        if(summaryField.operation == 'MIN'){
                            _generatedRootSummaries[i][summaryField.dataField] = Number.MAX_VALUE;//init
                        } else if(summaryField.operation == 'MAX'){
                            _generatedRootSummaries[i][summaryField.dataField] = Number.MIN_VALUE;//init
                        } else {                            
                            _generatedRootSummaries[i][summaryField.dataField] = 0.0;//init
                        }
                            
                    }
               }
            }
        }
    }
    
    /**
     *  @private
     * 
     *  insert the root summaries
     * 
     */  
//    private function insertRootSummary(summaryObj:Array):void
//    {
//        var coll:ICollectionView = super.source as ICollectionView;
//        
//        if (!grouping)
//            coll = coll.createCursor().current as ICollectionView;
//        
//        if (!(coll is IList))
//            return;
//        
//        for (var i:int = 0; i < summaryObj.length ; i++)
//        {
//            var summaryRow:SummaryRow = summaries[i];
//            
//            if (summaryRow.summaryPlacement.indexOf("first") != -1)
//            {
//                IList(coll).addItemAt(summaryObj[i], 0);
//            }
//            
//            if (summaryRow.summaryPlacement.indexOf("last") != -1)
//            {
//                IList(coll).addItem(summaryObj[i]);
//            }
//        }
//    }
    
    /**
     *  @private
     *  
     *  inserts the summaries in the children collection of the parent node
     */  
    private function insertSummary(parent:Object, summaryObj:Array, summaries:Array):void
    {
        for (var i:int = 0; i < summaries.length ; i++)
        {
            var summaryRow:SummaryRow = summaries[i];
            if (summaryRow.summaryPlacement.indexOf("group") != -1)
            {
                for (var str:String in summaryObj[i])
                    parent[str] = summaryObj[i][str];
            }
            
            var children:IList;
            if (summaryRow.summaryPlacement.indexOf("first") != -1)
            {
                children = (getChildren(parent) as ArrayCollection);
                if (children)
                    children.addItemAt(summaryObj[i], 0);
            }
            
            if (summaryRow.summaryPlacement.indexOf("last") != -1)
            {
                children = (getChildren(parent) as ArrayCollection);
                if (children)
                    children.addItem(summaryObj[i]);
            }
        }
    }
    
    /**
     *  @private
     */
    private function makeGroupedCollection():Boolean
    {
        // save the sorting information of the source collection
        // sort the source collection and create a grouped collection
        // restore the sort of the original source collection
        
        var fields:Array = [];
        for (var i:int = 0; i < grouping.fields.length; i++)
        {
            var groupingField:GroupingField = grouping.fields[i];
            var sortField:SortField = new SortField(groupingField.name, 
                        groupingField.caseInsensitive, 
                        groupingField.descending, groupingField.numeric);
            sortField.compareFunction = groupingField.compareFunction;
            fields.push(sortField);
        }
        
        oldSort = source.sort;
        source.sort = new Sort();
        
        // Set the compare function
        if (grouping.compareFunction != null)
            source.sort.compareFunction = grouping.compareFunction;
        
        source.sort.fields = fields;
        
        var refreshed:Boolean = source.refresh();
        if (!refreshed)
            return refreshed;
        
        if (async)
        {
            timer = new Timer(1);
            timer.addEventListener(TimerEvent.TIMER, timerHandler);
            timer.start();
        }
        else
        {
            return buildGroups();
        }
        
        return true;
    }
    
    /**
     *  @private
     */
    private function timerHandler(event:TimerEvent):void
    {
        if (buildGroups())
        {
            timer.stop();
            timer = null;
        }
        
    }
    
    /**
     *  @private
     *  
     *  Start building the groups
     */
    [Bindable]public var progress:int = 0;
    private function buildGroups():Boolean {
                
        if (!prepared){
            var _openItems:Object = {};
            
            // initialize the variables
            initialize();
        
            // remove the items from the source collection if there are any.
            newCollection.removeAll();
            
            if ((source as ICollectionView).length == 0)
                return false;
            
//            var hierarchicalData:IHierarchicalData = new HierarchicalData(newCollection);
//            HierarchicalData(hierarchicalData).childrenField = childrenField;
            
//            hView = new HierarchicalCollectionView( 
//                                        hierarchicalData, _openItems);
//            treeCursor = hView.createCursor();
    
            flatView = source as ICollectionView;
            flatCursor = flatView.createCursor();
    
            gf = grouping?grouping.fields:[];
            fieldCount = gf.length;
            
            if (gf){
                prepared = true;
            
                if (async){                    
                    return false;
                }//if
            }//if
            
            if (async){                
                return true;
            }//if
        }
        
        flatCursor.seek(currentPosition);
                    
        while(!flatCursor.afterLast && currentPosition != CursorBookmark.LAST) {               
            progress = Math.max(1,1+currentPosition.getViewIndex());
            dispatchProgress(progress, source.length,"Processing data Row: " + progress + " of " + source.length );
            currentData = flatCursor.current;
            if (source && summaries){//generateRootSummaries a.k.a GrandTotals
                calculateRootSummariesLOOP(currentData);  
            }
            
            for (var i:int = 0; i < fieldCount ; ++i) {
                
                var groupingField:String = gf[i].name;
                
                var label:String = getDataLabel(currentData, gf[i]);

                if(label != currentGroupLabels[i])
                {
                    if (childrenArray && childrenArray.length)
                    {
                        ArrayCollection(currentGroups[fieldCount - 1][childrenField]).source = childrenArray;
//                        ArrayCollection(currentGroups[fieldCount - 1][childrenField]).refresh();
                        calculateSummariesEND(grouping.fields[i].summaries,i,currentData,childrenArray);
                        childrenArray = [];
                        if (async)
                            return false;
                    }
                    
                    currentGroupLabels.splice(i+1);
                    currentGroups.splice(i+1);
                    currentIndices.splice(i+1);
                    
                    currentGroupLabels[i] = label;
                    
                    // check for grouping Object Function
                    if (gf[i].groupingObjectFunction != null)
                        currentGroups[i] = gf[i].groupingObjectFunction(label);
                    else if (grouping.groupingObjectFunction != null)
                        currentGroups[i] = grouping.groupingObjectFunction(label);
                    else
                        currentGroups[i] = {};
                    
                    if(grouping.fields[i].summaries){     
                        currentGroups[i]['summaryObjArry'] = [];               
                        for (var k:int = 0; k < grouping.fields[i].summaries.length; k++) {                   
                            currentGroups[i]['summaryObjArry'][k] = new SummaryObject();//init
                        }
                    }
                    
                    currentGroups[i][childrenField] = new ArrayCollection();
                    
                    currentGroups[i][grouping.label] = currentGroupLabels[i];
                    
                    itemIndex = currentIndices[i-1];
                    // create the group
//                  HierarchicalCollectionView(hView).addChild(currentGroups[i-1], currentGroups[i]);
                    if (i > 0){
                        currentGroups[(i - 1)][childrenField].source.push(currentGroups[i]);
                    } else {
                        newCollection.source.push(currentGroups[i]);                            
                    }    
                    
                    currentIndices[i-1] = ++itemIndex;
                }
                
                // insert the node as a child of the group
                if ( i == fieldCount - 1)
                {
                    itemIndex = currentIndices[i];
                    if (!childrenArray)
                        childrenArray = [];
                    childrenArray.push(currentData);
                    currentIndices[i] = ++itemIndex;
                }
               calculateSummariesLOOP(grouping.fields[i].summaries,i,currentData,childrenArray);
            }

            try
            {
                flatCursor.moveNext();
                currentPosition = flatCursor.bookmark;
                // return in case of async refresh
//                if (async)
//                    return false;
            }
            catch (pending:ItemPendingError)
            {
                cleanUp();
                pending.addResponder(new ItemResponder(
                    function(data:Object, token:Object=null):void
                    {
                        makeGroupedCollection();
                    },
                    function(info:Object, token:Object=null):void
                    {
                        //no-op
                    }));
            }
        }
        
        if(super.source){            
            super.source.refresh();
        }
                
        if (source && summaries){//POST generateRootSummaries a.k.a GrandTotals
            calculateRootSummariesEND();  
        }
        
        dispatchEvent(new CubeEvent(CubeEvent.CUBE_COMPLETE));
        
        if (currentPosition == CursorBookmark.LAST)
        {
            if (childrenArray && childrenArray.length)
            {
                ArrayCollection(currentGroups[fieldCount - 1][childrenField]).source = childrenArray;
                calculateSummariesEND(grouping.fields[fieldCount - 1].summaries,fieldCount - 1,currentData,childrenArray);
            }
            
//            applyFunctionForParentNodes(super.source as ICollectionView, getSummaries);
            
//            if (source && summaries)
//            {
//                if (!super.source)
//                    super.source = new ArrayCollection([source]) as Object;
//                
//                generateRootSummaries(grouping == null);
//            }            
            // dispatch collection change event of kind refresh.
            var refreshEvent:CollectionEvent =
                    new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
            refreshEvent.kind = CollectionEventKind.REFRESH;
            dispatchEvent(refreshEvent);
            
            cleanUp();
            
            return true;
        }
        return true;
    }
    
    /**
     *  @private
     *  
     *  Restores the original sort in the source collection
     *  and clean up all the variables.
     */
    private function cleanUp():void
    {
        source.sort = oldSort;
        source.refresh();
        
        prepared = false;
        currentPosition = CursorBookmark.FIRST;
        progress = currentPosition.getViewIndex();
        oldSort = null;
        flatCursor = null;
        treeCursor = null;
    }
    
    /**
     *  @private
     *  
     *  It will call the function func on each node of the collection.
     */  
//    private function applyFunctionForParentNodes(coll:ICollectionView, func:Function, depth:int = 0):void
//    {   
//        if (coll.length > 0)
//        {
//            var masterCursor:IViewCursor = coll.createCursor();
//            
//            while(!masterCursor.afterLast)
//            {
//                var child:Object = getChildren(masterCursor.current);
//                if (child is ArrayCollection)
//                {
//                    var childCursor:IViewCursor = ArrayCollection(child).createCursor();
//                    
//                    while (!childCursor.afterLast)
//                    {
//                        var current:Object = childCursor.current;
//                        // recurse over each child
//                        if (this.hasChildren(current))
//                        {
//                            applyFunctionForParentNodes(child as ArrayCollection, func, depth + 1);
//                            break;
//                        }
//                        
//                        childCursor.moveNext();
//                    }   
//                }
//                
//                // calculate for the parent node
//                func(masterCursor.current, depth);
//                masterCursor.moveNext();
//            }
//        }
//    }
    
    /**
     *  @private
     *  
     *  removes the root summaries and
     *  generates them again.
     * 
     */  
//    private function regenerateRootSummaries():void
//    {
//        if(!summaries)
//            return;
//        
//        var coll:ICollectionView = super.source as ICollectionView;
//        if (!grouping)
//            coll = coll.createCursor().current as ICollectionView;
//        
//        var summaryObj:Array = objectSummaryMap[coll];
//        
//        // for the first time there will be no summaries
//        // so, this check will fail and root summaries wont
//        // be removed and regenerated again.
//        // for all the other times, the root summaries will be 
//        // regenerated.
//        if (!summaryObj || !(coll is IList))
//            return;
//        
//        // delete all the root level summaries
//        for (var n:int = 0; n < summaryObj.length ; n++)
//        {
//            var index:int = IList(coll).getItemIndex(summaryObj[n]);
//            if (index != -1)
//                IList(coll).removeItemAt(index);
//        }
//        
//        delete objectSummaryMap[coll];
//        
//        // generate the root level summaries
//        generateRootSummaries(grouping == null);
//    }
    
    /**
     *  @private
     *  
     *  removes all the summaries from the collection
     */  
//    private function removeAllSummaries():void
//    {
//        // call generate summary with remove summary function as parameter
//        applyFunctionForParentNodes(super.source as ICollectionView, removeSummary);
//    }
    
    /**
     *  @private
     *  
     *  remove the summaries for an item and its parents.
     *  return the parents of the node going one level up each time.
     * 
     */  
//    private function removeItemAndSummaries(coll:ICollectionView, node:Object, removeItem:Boolean = false):Array
//    {
//        var parentNodes:Array = [];
//        var parent:Object = getParent(node);
//        while (parent)
//        {
//            var index:int;
//            var addParent:Boolean = true;
//            var children:ICollectionView = getChildren(parent) as ArrayCollection;
//            if (children)
//            {
//                if (children.contains(node))
//                {
//                    if (children is IList)
//                    {
//                        if (removeItem)
//                        {
//                            // remove the item from the group
//                            index = IList(children).getItemIndex(node);
//                            if (index != -1)
//                            {
//                                IList(children).removeItemAt(index);
//                                // delete item from parent map
//                                var uid:String = UIDUtil.getUID(node);
//                                if (parentMap[uid])
//                                    delete parentMap[uid];
//                            }
//                        }
//                        
//                        if (objectSummaryMap[parent])
//                        {
//                            var temp:Array = objectSummaryMap[parent];
//                            for (var i:int = 0; i < temp.length; i++)
//                            {
//                                index = IList(children).getItemIndex(temp[i]);
//                                if (index != -1)
//                                {
//                                    // remove the summary information for the group
//                                    IList(children).removeItemAt(index);
//                                }
//                            }
//                            // delete summary from parent summary map
//                            delete objectSummaryMap[parent];
//                        }
//                        
//                        if (removeItem)
//                        {
//                            // remove the group if no children is present
//                            if (children.length == 0 && getParent(parent) != null)
//                            {
//                                addParent = false;
//                            }
//                            else
//                                removeItem = false;
//                        }
//                    }
//                }
//                if (addParent)
//                    parentNodes.push(parent);
//                
//                node = parent;
//                
//                parent  = getParent(parent);
//                if (!parent)
//                {
//                    // remove the parent node from the collection if its the only one remaining.
//                    // first check for the child collection length
//                    if (parentNodes.length == 1)
//                    {
//                        if ((getChildren(parentNodes[0]) as ICollectionView).length == 0 && coll is IList)
//                        {
//                            index = IList(coll).getItemIndex(node);
//                            if (index != -1)
//                            {
//                                IList(coll).removeItemAt(index);
//                                return null;
//                            }
//                        }
//                    }
//                    return parentNodes.reverse();
//                }
//            }
//        }
//        return null;
//    }
    
    /**
     *  @private
     *  
     *  removes the summaries from the parent node and all its children.
     * 
     */  
//    private function removeSummary(parent:Object, depth:int):void
//    {   
//        var children:ICollectionView = this.getChildren(parent) as ArrayCollection;
//        
//        if (!children)
//            return;
//        
//        // remove summaries from the parents of the current object
//        removeItemAndSummaries(super.source as ICollectionView, children.createCursor().current);
//    }
    
    /**
     *  @private
     *  
     *  Default implementation for operations - "SUM", "MIN", "MAX", "COUNT"
     */ 
//    private function summaryUtil(iterator:IViewCursor, dataField:String, operation:String):Number
//    {
//        if (!iterator)
//            return 0.0;
//        
//        var result:Number = 0;
//        var temp:Number = 0;
//        var once:Boolean;
//        
//        if (operation == "SUM" || operation == "COUNT" || operation == "AVG")
//        {
//            var count:int = 0;
//            while (!iterator.afterLast)
//            {
//                if (iterator.current.hasOwnProperty(dataField))
//                {
//                    count++;
//                    result += Number(iterator.current[dataField]);
//                }
//                
//                iterator.moveNext();
//            }
//            
//            if (operation == "SUM")
//                return result;
//            
//            if (operation == "COUNT")
//                return count;
//            
//            if (operation == "AVG")
//                return result / count;
//        }
//        else if (operation == "MIN")
//        {
//            while (!iterator.afterLast)
//            {
//                temp = iterator.current.hasOwnProperty(dataField) ? iterator.current[dataField] : 0.0;
//                
//                if (!once)
//                {
//                    result = temp;
//                    once = true;
//                }
//                
//                if (temp < result)
//                    result = temp;
//                
//                iterator.moveNext();    
//            }
//            
//            return result;
//        }
//        else if (operation == "MAX")
//        {
//            while (!iterator.afterLast)
//            {
//                temp = iterator.current.hasOwnProperty(dataField) ? iterator.current[dataField] : 0.0;
//                
//                if (!once)
//                {
//                    result = temp;
//                    once = true;
//                }
//                
//                if (temp > result)
//                    result = temp;
//                
//                iterator.moveNext();
//            }
//            
//            return result;
//        }
//        
//        return 0.0;
//    }
    
    /**
     *  @private
     *  
     *  updates the parent map
     */ 
//    private function updateParentMap(parent:Object, node:Object):void
//    {
//        var uid:String = UIDUtil.getUID(node);
//        parentMap[uid] = parent;
//    }
    
    /**
     *  @private
     *  
     *  removes the summary information and regenrates it for a particular node
     *  and its parents.
     *  optionally removes the item from the group also.
     */  
//    private function updateSummary(node:Object, removeItem:Boolean = false):void
//    {       
//        var coll:ICollectionView = super.source as ICollectionView;
//        
//        var parentNodes:Array;
//        if (summaryPresent || removeItem)
//            parentNodes = removeItemAndSummaries(coll, node, removeItem);
//        
//        if (summaryPresent && parentNodes)
//            for (var i:int = parentNodes.length - 1; i >= 0; i--)
//                getSummaries(parentNodes[i], i);
//    }
    
    /********************************************************************************************************/
    private function dispatchProgress(p:int, t:int, m:String=null):void{
        var ev:CubeEvent = new CubeEvent(CubeEvent.CUBE_PROGRESS);
        ev.progress = p;
        ev.total = t;
        ev.message = m;        
        dispatchEvent(ev);
    }
    
    private function calculateSummariesEND(summaries:Array,depth:int,current:Object,childrenArry:Array):void {
        
        if (depth > grouping.fields.length-1)
            return;
        if (!summaries)
            return;
            
       
        // computing all the summaries
        for (var i:int = 0; i < summaries.length; i++) {
            for each(var summaryField:SummaryField in  SummaryRow(summaries[i]).fields) {
                /** Numeric*/
                if(summaryField.operation == 'AVG'){
                       currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] /= currentGroups[depth]['summaryObjArry'][i][summaryField.dataField+'KOUNT'];
                }//if
            }//for
            
            insertSummary(currentGroups[depth],currentGroups[depth]['summaryObjArry'], summaries);           
        }//for
        
    }//calculateSummariesEND
    
    private function calculateSummariesLOOP(summaries:Array,depth:int,current:Object,childrenArry:Array):void {
        
        if (depth > grouping.fields.length-1)
            return;
        if (!summaries)
            return;
            
       
        // computing all the summaries
        for (var i:int = 0; i < summaries.length; i++) {
            for each(var summaryField:SummaryField in  SummaryRow(summaries[i]).fields) {                
                if(summaryField.operation == 'STRINGAGG'){                    
                    /** Alphanumeric */
                    var newVal:String = current[summaryField.dataField];
                    var existingVal:String = currentGroups[depth]['summaryObjArry'][i][summaryField.dataField];
                    if(existingVal){ 
                        if(existingVal.indexOf(newVal) < 0){//doesnt exist                        
                            currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] =    ([existingVal,newVal]).join(',');    
                        }
                    } else {
                        currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] =    newVal;
                    }
                } else {                
                    /** Numeric*/
                    if(summaryField.operation == 'COUNT'){
                        if(currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] == null){
                            currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] = 0.0;//init
                        }
                        currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] =    childrenArry.length;                        
                    } else if(summaryField.operation == 'MAX'){
                        if(current[summaryField.dataField] != null){
                            if(currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] == null){
                                currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] = current[summaryField.dataField];    
                            }//if                            
                            currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] = 
                                Math.max(currentGroups[depth]['summaryObjArry'][i][summaryField.dataField],current[summaryField.dataField]);
                        }//if
                    } else if(summaryField.operation == 'MIN'){
                        if(current[summaryField.dataField] != null){
                            if(currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] == null){
                                currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] = current[summaryField.dataField];    
                            }//if
                            currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] = 
                                Math.min(currentGroups[depth]['summaryObjArry'][i][summaryField.dataField],current[summaryField.dataField]);          
                        }//if
                      } else if(summaryField.operation == 'SUM'){
                          if(currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] == null){
                            currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] = 0.0;//init
                        }
                          currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] += Number(current[summaryField.dataField]);
                    } else if(summaryField.operation == 'AVG'){
                        if(currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] == null){
                            currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] = 0.0;//init
                        }
                        if(current[summaryField.dataField] != null){
                                if(currentGroups[depth]['summaryObjArry'][i][summaryField.dataField+'KOUNT'] == null){
                                    currentGroups[depth]['summaryObjArry'][i][summaryField.dataField+'KOUNT'] = 0;
                                }
                                currentGroups[depth]['summaryObjArry'][i][summaryField.dataField+'KOUNT'] +=1;
                                currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] += Number(current[summaryField.dataField]);                            
                        }//if
                    } else if(summaryField.summaryFunction != null){
                        if(currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] == null){
                            currentGroups[depth]['summaryObjArry'][i][summaryField.dataField] = 0.0;//init
                        }
                        //do nothing here.
                        //Delay the summFunc(like BPS,CPS) calculations  
                        //until dependent basic operations (like SUM) are done                            
                    }
                }//else 
            }//for
            
            for each(var sf:SummaryField in  SummaryRow(summaries[i]).fields) {
                if(sf.summaryFunction != null){
                  currentGroups[depth]['summaryObjArry'][i][sf.dataField] 
                    = expandExponents(sf.summaryFunction(currentGroups[depth]['summaryObjArry'][i],
                                depth,current,sf.dataField,sf.operation));          
                }//if
            }//for
            
            insertSummary(currentGroups[depth],currentGroups[depth]['summaryObjArry'], summaries);           
        }//for
        
    }//calculateSummariesLOOP
    
    
    /**
     * Grand Totals
     */
    private function calculateRootSummariesLOOP(current:Object):void {
            for (var i:int = 0; i < summaries.length; i++) {
                for each(var summaryField:SummaryField in  SummaryRow(summaries[i]).fields) {
                    if(summaryField.operation == 'STRINGAGG'){
                        /** Alphanumeric */
                    } else {
                        /** Numeric*/
                        if(_generatedRootSummaries[i][summaryField.dataField] == null){
                            _generatedRootSummaries[i][summaryField.dataField] = 0.0;//init
                        }
                        
                        if(summaryField.operation == 'COUNT'){
                            _generatedRootSummaries[i][summaryField.dataField] = 0;                        
                        } else if(summaryField.operation == 'MAX'){
                            _generatedRootSummaries[i][summaryField.dataField] = 
                                Math.max(_generatedRootSummaries[i][summaryField.dataField],current[summaryField.dataField]);
                        } else if(summaryField.operation == 'MIN'){
                            _generatedRootSummaries[i][summaryField.dataField] = 
                                Math.min(_generatedRootSummaries[i][summaryField.dataField],current[summaryField.dataField]);
                        } else if(summaryField.operation == 'SUM'){
                            _generatedRootSummaries[i][summaryField.dataField] += Number(current[summaryField.dataField]);                                
                        } else if(summaryField.operation == 'AVG'){
                            if(current[summaryField.dataField] != null){
                                if(_generatedRootSummaries[i][summaryField.dataField+'KOUNT'] == null){
                                    _generatedRootSummaries[i][summaryField.dataField+'KOUNT'] = 0;
                                }
                                _generatedRootSummaries[i][summaryField.dataField+'KOUNT'] +=1;
                                _generatedRootSummaries[i][summaryField.dataField] += Number(current[summaryField.dataField]);                            
                            }
                        } else if(summaryField.summaryFunction != null){
                            //do nothing here.
                            //Delay the summFunc(like BPS,CPS) calculations  
                            //until dependent basic operations (like SUM) are done                        
                        }
                    }
                }//for
                for each(var sf:SummaryField in  SummaryRow(summaries[i]).fields) {
                    if(sf.summaryFunction != null){
                        _generatedRootSummaries[i][sf.dataField] 
                                = expandExponents(sf.summaryFunction(_generatedRootSummaries[i],
                                            -1,current,sf.dataField,sf.operation));
                             
                    }//if
                }//for
              }//for
    }//calculateRootSummariesLOOP
    
    private function calculateRootSummariesEND():void {                    
        for (var i:int = 0; i < summaries.length; i++) {
            for each(var summaryField:SummaryField in  SummaryRow(summaries[i]).fields) {
                if(summaryField.operation == 'COUNT'){
                    _generatedRootSummaries[i][summaryField.dataField] = (source as ICollectionView).length;
                } else if(summaryField.operation == 'AVG'){
                    _generatedRootSummaries[i][summaryField.dataField] /= _generatedRootSummaries[i][summaryField.dataField+'KOUNT'];
                   }
            }//for
          }//for
    }//calculateRootSummariesEND
    
    public function get generatedRootSummaries():Array {
        return _generatedRootSummaries==null?[new SummaryObject]:_generatedRootSummaries;
    }
    private var _generatedRootSummaries:Array;
    
    /**********https://bugs.adobe.com/jira/browse/SDK-22643***********/    
    public function expandExponents(value:String):String {
        if(value && value.toLowerCase().indexOf("e") > -1) { //deal with exponents        
            //Break string into component parts
            var regExp:RegExp = /^([+-])?(\d+).?(\d*)[eE]([-+]?\d+)$/;
            var result:Array = regExp.exec(value);
            var sign:String = result[1];
            var first:String = result[2];
            var last:String =  result[3];
            var exp:int =  int(result[4]);
            
            //if we didn't get a good exponent  to begin with, return what we can figure out
            if (!exp){
                return (sign ? sign : "") + (first ? first : "0") + (last ? "." + last : "");
            }
            
            var r:String = first + last;
            
            var decimal:Boolean = exp < 0;
            
            if (decimal){   
                var o:Number = -1 * (first.length + exp) + 1;
                return (sign ? sign : "") + "0." + new Array(o).join("0") + r;
            } else    {
                var i:Number = exp + first.length;
                if (i >= r.length)
                    return (sign ? sign : "") + r + new Array(i - r.length + 1).join("0");
                else
                    return (sign ? sign : "") + r.substr(0,i) + "." + r.substr(i); 
            }
        }//if
        return value;
    }//expandExponents
    
}

}