public string GenerateReport(int daysOffset = 0, TimeSpan?workableHours = null, double targetProductivity = 0.75) { if (!workableHours.HasValue) { workableHours = new TimeSpan(12, 0, 0); } // Check if we can generate the report if (!(GoogleClient.SignedIn && KanbanClient.SignedIn)) { exceptionString = "Missing authorization from either Google Client of Kanban Client"; return(""); } List <GeneralizedEvent> todaysEvents = GoogleClient.GetTodaysEvents(daysOffset); List <GeneralizedTask> dueToday = KanbanClient.GetDueToday(daysOffset); List <GeneralizedTask> dueTomorrow = KanbanClient.GetDueTomorrow(daysOffset); List <GeneralizedTask> dueThisWeek = KanbanClient.GetDueLaterThisWeek(daysOffset); Forecast weatherReport = WeatherReporter.GetDailyWeatherReport("", "", daysOffset); TimeSpan obligatedTime = new TimeSpan(); foreach (GeneralizedEvent e in todaysEvents) { if (e.Duration.HasValue) { obligatedTime += e.Duration.Value; } } // workableHours guaranteed to have value because of first conditional double anticipatedMinutes = workableHours.Value.TotalMinutes - obligatedTime.TotalMinutes; anticipatedMinutes *= targetProductivity; // Note that I'm considering extra time to be "the amount of time I can reasonably do nothing" // I'll still allocate 8% of the total time as overhead that I don't consider anywhere. This could be used // as travel time, etc. var multiplier = 1 - targetProductivity - 0.08; if (multiplier < 0) { multiplier = 0; } double slackOffMinutes = workableHours.Value.TotalMinutes - obligatedTime.TotalMinutes; slackOffMinutes *= multiplier; TimeSpan slackOffTime = new TimeSpan(0, (int)slackOffMinutes, 0); // Pomodoro Technique: // Work 25 minutes then take a 5 minute break. Every 4th break, take a 30 minute break instead // 1 cycle: (25 + 5) + (25 + 5) + (25 + 5) + (25 + 30) = 145 minutes // 4 pomodoros can be completed every 145 minutes int pomCount = (int)((anticipatedMinutes / 145) * 4); string path = createDocument(todaysEvents, dueToday, dueTomorrow, dueThisWeek, obligatedTime, weatherReport, pomCount, daysOffset, slackOffTime); //Process p = new Process(); //p.StartInfo = new ProcessStartInfo("Test.pdf"); //p.Start(); return(path); }