public static GroupTree <T> ParseGroups <T>(IList <T> paged, List <DynamicGroupBy <T> > groupBy, Func <T, object> uniqueKeyExpression)
        {
            var firstLevelGroups = paged.GroupBy(groupBy[0].Expression.Compile());

            var groupsRoot = new GroupTree <T>(RootGroupString, GroupState.EXPANDED);

            foreach (var group in firstLevelGroups)
            {
                var groupItems = group.ToList();
                var subGroup   = new GroupTree <T>(group.Key == null? NullString : group.Key,
                                                   groupBy[0].Column,
                                                   groupBy[0].Expanded ? GroupState.EXPANDED : GroupState.COLLAPSED);

                if (groupBy.Count() > 1)
                {
                    var nestedGroups = ParseNestedGroups(subGroup, groupItems, groupBy, 1, uniqueKeyExpression);
                    groupsRoot.SubGroups.Add(nestedGroups);
                }
                else
                {
                    subGroup.Parent = groupsRoot;
                    subGroup.Items.AddRange(groupItems);
                    subGroup.UniqueItemKeys = subGroup.Items.Select(uniqueKeyExpression).ToList();
                    groupsRoot.SubGroups.Add(subGroup);
                }
            }

            return(groupsRoot);
        }
        public static GroupTree <T> ParseNestedGroups <T>(GroupTree <T> root, List <T> items, List <DynamicGroupBy <T> > groupBy, int counter, Func <T, object> uniqueKeyExpression)
        {
            if (counter == groupBy.Count())
            {
                root.Items.AddRange(items);
                root.UniqueItemKeys = root.Items.Select(uniqueKeyExpression).ToList();
                return(root);
            }

            var groups = items.GroupBy(groupBy[counter].Expression.Compile());

            foreach (var group in groups)
            {
                var groupItems  = group.ToList();
                var nextCounter = counter + 1;
                var subGroup    = new GroupTree <T>(group.Key,
                                                    groupBy[counter].Column,
                                                    groupBy[counter].Expanded ? GroupState.EXPANDED : GroupState.COLLAPSED);
                subGroup.Parent = root;

                root.SubGroups.Add(ParseNestedGroups(subGroup, groupItems, groupBy, nextCounter, uniqueKeyExpression));
            }

            return(root);
        }
        public static int GetTotalGroups <T>(GroupTree <T> group)
        {
            var totalGroups = group.SubGroups.Count;

            foreach (var subGroup in @group.SubGroups)
            {
                totalGroups += GetTotalGroups(subGroup);
            }

            return(totalGroups);
        }
 public static void FormatGroupedAggregators <T>(GroupTree <T> group, Dictionary <string, string> formattings)
 {
     foreach (var aggregatorInfo in group.Aggregates)
     {
         var formatting = formattings.ContainsKey(aggregatorInfo.Column) ? formattings[aggregatorInfo.Column] : null;
         aggregatorInfo.FormatValue(formatting);
         foreach (var subGroup in group.SubGroups)
         {
             FormatGroupedAggregators(subGroup, formattings);
         }
     }
 }
        private static GroupTree <T> RecreateHierarchicalGroupStructure <T>(List <LeafGroup> data, Dictionary <string, string> ColumnsToFormattings)
        {
            // Our root
            var groupsRoot = new GroupTree <T>(RootGroupString, GroupState.EXPANDED);

            // Maximum Nesting Level
            var maxLevel = data.Count > 0 ? data[0].Level : 0;

            // Start from level one and create tree level by level
            for (var level = 1; level <= maxLevel; level++)
            {
                // Find the distinct groups for this level
                var thisGroups = data.GroupBy(d => d.PathAtLevel(level));

                // Iterate through these Level Groups
                foreach (var group in thisGroups.ToList())
                {
                    // Get the first Leaf Group in each Level Group
                    // This leaf group always exists and is enough for this task
                    var first = group.ToList()[0];

                    // Groupped by Column
                    var column = first.ColumnsToKeys.ElementAt(level - 1).Key;

                    // Column Value
                    var value = first.ColumnsToKeys.ElementAt(level - 1).Value;

                    // Column Formatting
                    var formatting = ColumnsToFormattings.ContainsKey(column)
                                        ? ColumnsToFormattings[column]
                                        : null;

                    // Group's Initial State
                    // Last Level Groups must be Collapsed as there are no records
                    var state = level < maxLevel && maxLevel > 1
                            ? GroupState.EXPANDED
                            : GroupState.COLLAPSED;

                    // Create the actual Group
                    var groupTree = new GroupTree <T>(value, column, state);

                    // For the last level Groups, include the aggregators we have retrieved
                    if (level == maxLevel)
                    {
                        var aggList = new List <AggregatorInfo <T> >();

                        foreach (var agg in first.Aggregators)
                        {
                            aggList.Add(new AggregatorInfo <T>(agg.Column, agg.Type, agg.Value, formatting));
                        }

                        groupTree.Aggregates = aggList;
                    }

                    // We now need to find were this Group belongs in the tree
                    // If we are at first level, the Group belongs to the tree's root
                    // For higher levels, we search for the parent Group
                    var owner = level > 1
                        ? groupsRoot.FindSubGroup(first.PathAtLevel(level - 1))
                        : groupsRoot;

                    // Add Group to Owner
                    groupTree.Parent = owner;
                    owner.SubGroups.Add(groupTree);
                }
            }

            // Calculate Aggregates and Count for all Groups based on the last level Groups
            groupsRoot.AggregateSubGroupAggregators();

            // Special handle for the Average Aggregates which require Group Count to be available
            groupsRoot.AggregateSubGroupAggregators(true);

            return(groupsRoot);
        }