public DailySummaryHierarchy(ActivityGroupHierarchy activityGroupHierarchy, int numDays) { _activityGroupHierarchy = activityGroupHierarchy; _numDays = numDays; BuildSummaryHierarchy(); }
public async Task <TotalsReply> Get([FromQuery] string groupBy, [FromQuery] DateTime from, [FromQuery] DateTime to) { // Basic validation. if (to < from) { throw new BadRequestException("'from' parameter cannot be after 'to'."); } // Select the right grouping period structure. // We'll strip off the time zone information to avoid any issues. var cleanedFrom = DateTime.SpecifyKind(from, DateTimeKind.Unspecified); var cleanedTo = DateTime.SpecifyKind(to, DateTimeKind.Unspecified); PeriodStructureBase periodStructure; if (groupBy == Day) { periodStructure = new DailyPeriodStructure(cleanedFrom, cleanedTo); } else if (groupBy == Week) { periodStructure = new WeeklyPeriodStructure(cleanedFrom, cleanedTo); } else if (groupBy == Month) { periodStructure = new MonthlyPeriodStructure(cleanedFrom, cleanedTo); } else if (groupBy == Custom) { periodStructure = new CustomPeriodStructure(cleanedFrom, cleanedTo); } else if (string.IsNullOrEmpty(groupBy)) { throw new BadRequestException("Must provide a valid 'groupBy' field."); } else { throw new BadRequestException($"Unsupported 'groupBy' value: '{groupBy}'"); } // Load the responses in the specified time range. var fromTime = periodStructure.FromTime; var toTime = periodStructure.ToTime; var numDays = (int)Math.Round((toTime - fromTime).TotalDays); if (numDays > MaxAllowedDaysInRange) { throw new BadRequestException($"The requested date range cannot have more than {MaxAllowedDaysInRange} days."); } // Load the responses for that time range. var poll = await GetDefaultPollAsync(); var timeLogEntries = await _timeLogService.Get(Db, poll.Id, fromTime, toTime); // Trim the ends to make sure that we count only the time from the first and last entry that fits // into the range. if (timeLogEntries.Count > 0) { var lastEntry = timeLogEntries[timeLogEntries.Count - 1]; if (lastEntry.FromTime < fromTime) { lastEntry.TimeBlockLength = lastEntry.TimeBlockLength - (fromTime - lastEntry.FromTime); lastEntry.FromTime = fromTime; } var firstEntry = timeLogEntries[0]; if (firstEntry.GetToTime() > toTime) { firstEntry.TimeBlockLength = firstEntry.TimeBlockLength - (firstEntry.GetToTime() - toTime); } } // Load the user's ActivityGroup hierarchy. var activityGroups = await Db.ActivityGroups.Where(g => g.PollId == poll.Id).ToListAsync(); var activityHierarchy = new ActivityGroupHierarchy(activityGroups, _loggerFactory); // Prepare for calculation. var totalsReply = new TotalsReply(); totalsReply.StartingDates = periodStructure.GetPeriodStartDates(); var summariesByActivity = new Dictionary <string, TotalsForActivity>(); // Initial pass - find all activities. var totalsHierarchy = new TotalsHierarchy(activityHierarchy, periodStructure.NumPeriods); foreach (var timeLogEntry in timeLogEntries) { int dateIndex = -2; try { var summaryForActivity = totalsHierarchy.GetOrAddActivity(timeLogEntry.EntryText); dateIndex = periodStructure.CalcEntryPeriodIndex(timeLogEntry.FromTime); summaryForActivity.TimeSpentPerPeriod[dateIndex] = summaryForActivity.TimeSpentPerPeriod[dateIndex] + timeLogEntry.TimeBlockLength; } catch (ArgumentOutOfRangeException ex) { throw new Exception($"Totals IndexOutOfRangeException. Account: {Account.Id}; dateIndex: {dateIndex}", ex); } } // Additional passes - aggregate and clean up the data. totalsHierarchy.RecalculateTimeTotals(); totalsHierarchy.PruneEmptyLeafs(); // Compose the response. totalsReply.Activities = totalsHierarchy.GetActivities(); return(totalsReply); }
public async Task <DailySummaryReply> Get([FromQuery] DateTime from, [FromQuery] DateTime to) { // Basic validation. if (to < from) { throw new BadRequestException("'from' parameter cannot be after 'to'."); } // Load the responses in the specified time range. // We'll strip off the time zone information to avoid any issues. var fromDate = DateTime.SpecifyKind(from.Date, DateTimeKind.Unspecified); var toDate = DateTime.SpecifyKind(to.Date.AddDays(1), DateTimeKind.Unspecified); // +1 day because we process responses until the END of toDate. var numDays = (int)Math.Round((toDate - fromDate).TotalDays); if (numDays > MaxAllowedDaysInRange) { throw new BadRequestException($"The requested date range cannot have more than {MaxAllowedDaysInRange} days."); } // Load the responses for that time range. var poll = await GetDefaultPollAsync(); var timeLogEntries = await _timeLogService.Get(Db, poll.Id, fromDate, toDate); // Trim the ends to make sure that we count only the time from the first and last entry that fits // into the range. if (timeLogEntries.Count > 0) { var firstEntry = timeLogEntries[0]; if (firstEntry.FromTime < fromDate) { firstEntry.TimeBlockLength = firstEntry.TimeBlockLength - (fromDate - firstEntry.FromTime); firstEntry.FromTime = fromDate; } var lastEntry = timeLogEntries[timeLogEntries.Count - 1]; if (lastEntry.GetToTime() > toDate) { lastEntry.TimeBlockLength = lastEntry.TimeBlockLength - (lastEntry.GetToTime() - toDate); } } // Load the user's ActivityGroup hierarchy. var activityGroups = await Db.ActivityGroups.Where(g => g.PollId == poll.Id).ToListAsync(); var activityHierarchy = new ActivityGroupHierarchy(activityGroups, _loggerFactory); // Prepare for calculation. var dailySummary = new DailySummaryReply(); dailySummary.Dates = GenerateDates(fromDate, numDays); var summariesByActivity = new Dictionary <string, DailySummaryForActivity>(); // Initial pass - find all activities. var dailySummaryHierarchy = new DailySummaryHierarchy(activityHierarchy, numDays); foreach (var timeLogEntry in timeLogEntries) { var summaryForActivity = dailySummaryHierarchy.GetOrAddActivity(timeLogEntry.EntryText); var dateIndex = CalcDateIndex(timeLogEntry.FromTime, fromDate); summaryForActivity.TimeSpentPerDay[dateIndex] = summaryForActivity.TimeSpentPerDay[dateIndex] + timeLogEntry.TimeBlockLength; } // Additional passes - aggregate and clean up the data. dailySummaryHierarchy.RecalculateTimeTotals(); dailySummaryHierarchy.PruneEmptyLeafs(); // Compose the response. dailySummary.Activities = dailySummaryHierarchy.GetActivities(); return(dailySummary); }