public static object GetTransactionGroupOrderByValue(TransactionGroup transactionGroup, TransactionGroupOrder orderBy)
        {
            switch (orderBy)
            {
                case TransactionGroupOrder.Agrupador:
                    var groupBy = transactionGroup.Parent.GroupByDefinition.GroupBy;
                    if (groupBy == TransactionGroupBy.DateDay)
                        return DateTime.ParseExact(transactionGroup.Key.ToString(), "yyyy/MM/dd", CultureInfo.InvariantCulture);
                    else if (groupBy == TransactionGroupBy.DateMonth)
                        return DateTime.ParseExact(transactionGroup.Key.ToString() + "/01", "yyyy/MM/01", CultureInfo.InvariantCulture);
                    else if (groupBy == TransactionGroupBy.DateMonth)
                        return DateTime.ParseExact(transactionGroup.Key.ToString() + "/01/01", "yyyy/01/01", CultureInfo.InvariantCulture);

                    return transactionGroup.Key;
                case TransactionGroupOrder.Total:
                    return transactionGroup.Total;
                case TransactionGroupOrder.TransactionCount:
                    return transactionGroup.Count;
            }

            return null;
        }
        public List<ChartDataCategorized> GetChartDataCategorized(TransactionGroup transactionGroupRoot, bool tryCategorize = true)
        {
            var listReturn = new List<ChartDataCategorized>();
            Action<TransactionGroup, ChartDataCategorized> methodGroup = null;
            int id = 0;
            methodGroup = (current, parentTransversal) =>
            {
                if (current.SubGroups.Count == 0)
                    return;

                //if (grandchildrenGroups != null)
                //    if (current.GroupByDefinition.OrderByClassification == TransactionOrderClassification.Asc)
                //        grandchildrenGroups.OrderBy(f => f.Key);

                //if (tryCategorize && grandchildrenGroups.Count > 0)
                // categoriza apenas o root se for solicitado
                if (tryCategorize && current.Parent == null)
                {
                    var children = current.SubGroups;
                    var grandchildrenGroups = children.SelectMany(f => f.SubGroups).GroupBy(f => f.Key).ToList();

                    foreach (var grandchildrenGroup in grandchildrenGroups)
                    {
                        var list = grandchildrenGroup.ToList();

                        var inverted = new ChartDataCategorized()
                        {
                            Id = ++id,
                            IdParent = (parentTransversal == null ? null : (int?)parentTransversal.Id),
                            ParentPath = current.GetPath(),
                            ItemGroupName = grandchildrenGroup.Key.ToString(),
                            Items = new ChartDataCategorized.Item[children.Count]
                        };

                        listReturn.Add(inverted);

                        foreach (var grandchild in list)
                        {
                            var indexOfParent = current.SubGroups.IndexOf(grandchild.Parent);
                            inverted.Add(grandchild.GetPath(), grandchild.Parent.Key.ToString(), indexOfParent, grandchild);
                            methodGroup(grandchild, inverted);
                        }
                    }
                }
                else
                {
                    var name = current.Key != null ? current.Key.ToString() : (current.GroupByDefinition != null ? current.GroupByDefinition.GroupByName : "");
                    if (current.Parent == null && name == null)
                        name = current.SubGroups.First().GroupByDefinition.GroupByName ?? "Todos";

                    var inverted = new ChartDataCategorized()
                    {
                        Id = ++id,
                        IdParent = (parentTransversal == null ? null : (int?)parentTransversal.Id),
                        ParentPath = current.GetPath(),
                        ItemGroupName = name,
                        Items = new ChartDataCategorized.Item[current.SubGroups.Count]
                    };

                    listReturn.Add(inverted);

                    var index = 0;
                    foreach (var childGroup in current.SubGroups)
                    {
                        inverted.Add(childGroup.GetPath(), childGroup.Key.ToString(), index++, childGroup);
                        methodGroup(childGroup, inverted);
                    }
                }

                //foreach(var child in children)
                //    methodGroup(child, 0);
            };

            methodGroup(transactionGroupRoot, null);

            return listReturn;
        }
        private TransactionGroup ConfigureTransactionGroup(TransactionGroup transactionGroup, object key, string name, List<Transaction> transactions, List<TransactionGroup> subGroups, TransactionGroup parent, int level)
        {
            transactionGroup.Key = key;
            //transactionGroup.GroupByDefinition = groupByDefinition;
            transactionGroup.Name = name;
            transactionGroup.Parent = parent;
            transactionGroup.Transactions = transactions;
            transactionGroup.SubGroups = subGroups;
            transactionGroup.Level = level;

            if (transactionGroup.Total == 0)
                transactionGroup.Total = transactionGroup.Transactions.Sum(f => f.Value);

            if (transactionGroup.Count == 0)
                transactionGroup.Count = transactionGroup.Transactions.Count;

            //transactionGroup.TotalAsPositive = Math.Abs(transactionGroup.Total);
            if (parent == null)
            {
                transactionGroup.TotalPercentage.Add(100m);
                transactionGroup.CountPercentage.Add(100m);
            }

            while (parent != null)
            {
                transactionGroup.TotalPercentage.Add((transactionGroup.Total * 100m) / parent.Total);
                transactionGroup.CountPercentage.Add((transactionGroup.Count * 100m) / parent.Count);

                parent = parent.Parent;
            }

            return transactionGroup;
        }
        public TransactionGroup GetTransactionGroupRoot(List<Transaction> transactions, params TransactionGroupDefinition[] groupDefinitions)
        {
            Func<List<Transaction>, TransactionGroup, int, List<TransactionGroup>> methodGroup = null;
            methodGroup = (_transactions, transactionGroupParent, groupByIndex) =>
            {
                var groupByDefinition = default(TransactionGroupDefinition);
                var transactionGroups = new List<TransactionGroup>();

                if (groupDefinitions.Length > groupByIndex)
                    groupByDefinition = groupDefinitions[groupByIndex];

                if (groupByDefinition != null)
                {
                    var _transactionsQueryable = _transactions.AsQueryable();

                    if (groupByDefinition.OrderByClassification != null)
                    {
                        if (groupByDefinition.OrderByClassification == OrderClassification.Asc)
                            _transactionsQueryable = _transactionsQueryable.OrderBy(groupByDefinition.OrderByExpression);
                        else
                            _transactionsQueryable = _transactionsQueryable.OrderByDescending(groupByDefinition.OrderByExpression);
                    }

                    var group = _transactionsQueryable
                        .GroupBy(groupByDefinition.GroupByExpression)
                        .ToList();

                    transactionGroupParent.GroupByDefinition = groupByDefinition;

                    var nextGroupByIndex = groupByIndex + 1;
                    var transactionGroupsNews = group.Select(
                        (g, gIndex) =>
                        {
                            var list = g.ToList();
                            var name = this.GetTransactionGroupNameUsingValue(groupByDefinition.GroupBy, list);
                            var key = g.Key;
                            var transactionGroup = ConfigureTransactionGroup(new TransactionGroup(), key, name, list, null, transactionGroupParent, nextGroupByIndex);
                            transactionGroup.SubGroups = methodGroup(list, transactionGroup, nextGroupByIndex);
                            return transactionGroup;
                        }
                    );

                    if (groupByDefinition.OrderByGroupClassification != null)
                    {
                        if (groupByDefinition.OrderByGroupClassification == OrderClassification.Asc)
                            transactionGroupsNews = transactionGroupsNews.AsQueryable().OrderBy(groupByDefinition.OrderByGroupExpression);
                        else
                            transactionGroupsNews = transactionGroupsNews.AsQueryable().OrderByDescending(groupByDefinition.OrderByGroupExpression);
                    }

                    var transactionGroupsNewsList = transactionGroupsNews.ToList();
                    transactionGroups.AddRange(transactionGroupsNewsList);
                }

                return transactionGroups;
            };

            var transactionGroupRoot = new TransactionGroup();
            ConfigureTransactionGroup(transactionGroupRoot, null, "Todos", transactions, null, null, 0);
            transactionGroupRoot.SubGroups = methodGroup(transactions, transactionGroupRoot, 0);
            return transactionGroupRoot;
        }
 private List<ExpressionGraph.Expression<TransactionGroup>> GetTransactionGroupToExpression(TransactionGroup transactionGroup)
 {
     var master = new TransactionGroup { Name = "master", Key = "master" };
     master.SubGroups.Add(transactionGroup);
     return ExpressionGraph.ExpressionBuilder<TransactionGroup>.Build(master.SubGroups, f => f.SubGroups, true, false, false).ToList();
 }