using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using LCU.Shared.Collections.RepoApiLib.Formatting; using LCU.Shared.Collections.RepoApiLib.Models.Reporting.Responses; namespace LCU.API.Collections.RepoApi.Factories { public enum ReportSumType { WholeNumber, Currency, WholeNumberAvg, CurrencyAvg, PercentageAvg } public static class ReportTableFactory { public static ReportTable CreateHistoricalSummationTable( ReportSumType reportType, IEnumerable dataRows, string pluralEntityName, DateTime lowDateTime, DateTime highDateTime, Func cellValue, Func uniqueRowDisplay, Func dateTimeField, Func rowKey, bool showAbsenceRow = true ) { var totalMonths = CalculateTotalMonths(lowDateTime, highDateTime); var rows = CreateUniqueRowNames(dataRows, uniqueRowDisplay, pluralEntityName, showAbsenceRow); var reportTable = new ReportTable() { Headers = CreateMonthHeaders(lowDateTime, highDateTime, new string[] { "" }, new string[] { "Total" }), Cells = new ReportCell[rows.Count(), totalMonths + 2] }; // Build the Report Table Values var uniqueRowIdentifiers = new List(); var rawValueTableLengths = new int[rows.Count(), totalMonths + 1]; var rawValueTable = new decimal[rows.Count(), totalMonths + 1]; foreach (var currentDataRow in dataRows) { var rowDisplay = uniqueRowDisplay(currentDataRow); var currentKey = rowKey(currentDataRow); var currentValue = cellValue(currentDataRow); var currentDateOfRow = dateTimeField(currentDataRow); if (currentDateOfRow != null && currentValue != null && !uniqueRowIdentifiers.Contains(currentKey)) { uniqueRowIdentifiers.Add(currentKey); var monthIndex = CalculateMonthOffset(lowDateTime, currentDateOfRow.Value); var currentItemIndex = FindUniqueRowIndex(rows, rowDisplay); // "All Entities" Value rawValueTable[0, monthIndex] += currentValue.Value; // Totals for Month rawValueTable[0, totalMonths] += currentValue.Value; // Totals for All // "All Entities" Length rawValueTableLengths[0, monthIndex] += 1; // Totals for Month rawValueTableLengths[0, totalMonths] += 1; // Totals for All // Current Auction Row if (currentItemIndex != 0) { rawValueTable[currentItemIndex, monthIndex] += currentValue.Value; // Total for Month rawValueTable[currentItemIndex, totalMonths] += currentValue.Value; // Total for Auction House. rawValueTableLengths[currentItemIndex, monthIndex] += 1; // Total for Month rawValueTableLengths[currentItemIndex, totalMonths] += 1; // Total for Auction House. } } } // Convert Report Table into ReportCells for (var i = 0; i < rawValueTable.GetLength(0); i++) { for (var j = 0; j < rawValueTable.GetLength(1); j++) { var rawValue = rawValueTable[i, j]; var columnIndex = j + 1; // Add 1 to compensate for Row Display Column if (reportType == ReportSumType.WholeNumberAvg || reportType == ReportSumType.PercentageAvg || reportType == ReportSumType.CurrencyAvg) { var rawValueLength = rawValueTableLengths[i, j]; if (rawValueLength != 0) { rawValue = rawValue / rawValueLength; } } switch(reportType) { case ReportSumType.WholeNumberAvg: case ReportSumType.WholeNumber: reportTable.Cells[i, columnIndex] = ReportCellFormatting.CreateIntCell(Convert.ToInt32(rawValue)); break; case ReportSumType.Currency: case ReportSumType.CurrencyAvg: reportTable.Cells[i, columnIndex] = ReportCellFormatting.CreateCurrencyCell(rawValue); break; case ReportSumType.PercentageAvg: reportTable.Cells[i, columnIndex] = ReportCellFormatting.CreatePercentageCell(rawValue); break; } } } // Add Auction Names to Left Column for (var i = 0; i < rows.Count(); i++) { reportTable.Cells[i, 0] = ReportCellFormatting.CreateStringCell(rows.ElementAt(i)); } return reportTable; } public static int FindUniqueRowIndex(IEnumerable uniqueRows, string columnName) { if (columnName != null) { foreach (var item in uniqueRows.Select((value, index) => new { index, value })) { if (item.value == columnName) { return item.index; } } } return uniqueRows.Count() - 1; } private static IEnumerable CreateUniqueRowNames(IEnumerable reportData, Func uniqueRowDisplay, string pluralEntityName, bool showAbsenceRow = true) { var list = new List(); list.Add("All " + pluralEntityName); if (uniqueRowDisplay != null) { foreach (var row in reportData) { var rowName = uniqueRowDisplay(row); if (rowName != null) { if (!list.Contains(rowName)) { list.Add(rowName); } } } } if (showAbsenceRow) { list.Add("No " + pluralEntityName); } return list; } private static string[] CreateMonthHeaders(DateTime lowDateTime, DateTime highDateTime, string[] preHeaders = null, string[] postHeaders = null) { var totalMonths = CalculateTotalMonths(lowDateTime, highDateTime); var preHeadersLength = preHeaders?.Length ?? 0; var postHeadersLength = postHeaders?.Length ?? 0; string[] monthHeaders = new string[totalMonths + preHeadersLength + postHeadersLength]; for (var i = 0; i < preHeadersLength; i++) { monthHeaders[i] = preHeaders[i]; } for (var i = 0; i < totalMonths; i++) { var currentDate = lowDateTime.AddMonths(i); monthHeaders[preHeadersLength + i] = $"{currentDate.ToString("MMM", CultureInfo.InvariantCulture)} {currentDate.Year}"; } for (var i = 0; i < postHeadersLength; i++) { monthHeaders[preHeadersLength + totalMonths + i] = postHeaders[i]; } return monthHeaders; } private static int CalculateTotalMonths(DateTime lowDateTime, DateTime highDateTime) { return CalculateMonthOffset(lowDateTime, highDateTime) + 1; } private static int CalculateMonthOffset(DateTime lowDateTime, DateTime highDateTime) { return (((highDateTime.Year - lowDateTime.Year) * 12) + highDateTime.Month - lowDateTime.Month); } } }