private static void AddRow(DataTable table, List <Column> columns, ReportNodeInfos infos)
        {
            object[] rowValues = new object[columns.Count];
            for (int i = 0; i < columns.Count; i++)
            {
                Column column = columns[i];
                rowValues[i] = column.Formatter.GetValue(column.Extactor(infos));
            }

            table.Rows.Add(rowValues);
        }
        public static DataTable GenerateReport(ReportConfig config, ICollection <Resource> resources)
        {
            List <Column> columns = new List <Column>();

            foreach (ReportConfigColumn configColumn in config.Columns)
            {
                List <ReportFieldNode> nodes = ReportFieldNodes.ExtractNodePath(configColumn.Path);
                if (nodes != null && nodes.Count > 0)
                {
                    Func <ReportArray, ReportArray>[]   functions = nodes.Select(x => x.Extractor).ToArray();
                    Func <ReportNodeInfos, ReportArray> extractor = x => functions.Aggregate(new ReportArray(new object[] { x }), (current, function) => function(current));

                    columns.Add(new Column
                    {
                        Config    = configColumn,
                        Extactor  = extractor,
                        Formatter = ExcelFormatter.GetFormat(nodes.Last().Type)
                    });
                }
                else
                {
                    throw new Exception("Path " + configColumn.Path + " not found");
                }
            }

            DataTable table = new DataTable(config.Name);

            foreach (Column column in columns)
            {
                table.AddColumn(column.Config.Name, column.Formatter.TargetType, column.Config.Width, column.Formatter.StringFormat);
            }

            switch (config.Type)
            {
            case ReportType.ListResources:
                foreach (Resource resource in resources)
                {
                    ReportNodeInfos infos = new ReportNodeInfos
                    {
                        Resource = resource
                    };

                    AddRow(table, columns, infos);
                }
                break;

            case ReportType.ListReferences:
                foreach (Resource resource in resources)
                {
                    foreach (ResourceReference reference in resource.References)
                    {
                        ReportNodeInfos infos = new ReportNodeInfos
                        {
                            Resource  = resource,
                            Reference = reference
                        };

                        AddRow(table, columns, infos);
                    }
                }
                break;

            case ReportType.ListContent:
                foreach (Resource resource in resources)
                {
                    foreach (ResourceContent content in resource.Content)
                    {
                        ReportNodeInfos infos = new ReportNodeInfos
                        {
                            Resource = resource,
                            Content  = content
                        };

                        AddRow(table, columns, infos);
                    }
                }
                break;

            case ReportType.ListErrors:
                foreach (Resource resource in resources)
                {
                    foreach (ResourceError error in resource.Errors)
                    {
                        ReportNodeInfos infos = new ReportNodeInfos
                        {
                            Resource = resource,
                            Error    = error
                        };

                        AddRow(table, columns, infos);
                    }
                }
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(table);
        }