internal static Dictionary<int, Tuple<int?, int>> MakeSchedule( DataContainer dataContainer, Dictionary<int, string> planningAssignments, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator) { var result = new Dictionary<int, Tuple<int?, int>>(); var usersBlockersDict = new Dictionary<string, Dictionary<int, BlockerData>>(); var usersTasksDict = SeparateByUser(dataContainer, planningAssignments); short i = 0; var numbersToUsersMapping = usersTasksDict.ToDictionary(u => ++i, u => u.Key); i = 0; var usersToNumbersMapping = usersTasksDict.Keys.ToDictionary(u => u, u => ++i); var usersToProcess = new List<short>(numbersToUsersMapping.Keys); var processedUsers = new List<short>(2*numbersToUsersMapping.Keys.Count); while (usersToProcess.Count > 0) { string user = numbersToUsersMapping[usersToProcess[0]]; var blockersFromOtherUsers = ScheduleUserTasks( usersTasksDict[user], user, freeDaysCalculator, focusFactorCalculator, dataContainer, planningAssignments, result); var usersToRecalculate = ProcessBlockers( blockersFromOtherUsers, usersBlockersDict, result, user); foreach (short userNumber in usersToRecalculate .Where(usersToNumbersMapping.ContainsKey) .Select(u => usersToNumbersMapping[u])) { if (usersToProcess.Count > 0 && usersToProcess[usersToProcess.Count - 1] == userNumber) continue; usersToProcess.Add(userNumber); } if (usersToProcess.Count == 2*numbersToUsersMapping.Keys.Count) processedUsers.RemoveAt(0); processedUsers.Add(usersToProcess[0]); usersToProcess.RemoveAt(0); if (CheckCycle(processedUsers)) throw new InvalidOperationException("Cycle blockers collision!"); } return result; }
private static Dictionary<string, HashSet<int>> ScheduleUserTasks( IEnumerable<Tuple<WorkItem, WorkItem>> userTasks, string user, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator, DataContainer dataContainer, Dictionary<int, string> planningAssignments, Dictionary<int, Tuple<int?, int>> scheduledTasksDict) { var nonBlockedTasks = new List<Tuple<WorkItem, WorkItem>>(); var activeBlockedTasks = new List<Tuple<WorkItem, WorkItem>>(); var proposedBlockedTasks = new List<Tuple<WorkItem, WorkItem>>(); foreach (Tuple<WorkItem, WorkItem> tuple in userTasks) { if (tuple.Item1.IsActive()) { if (!dataContainer.BlockersDict.ContainsKey(tuple.Item1.Id)) nonBlockedTasks.Add(tuple); else activeBlockedTasks.Add(tuple); } else if (tuple.Item1.IsProposed()) { if (!dataContainer.BlockersDict.ContainsKey(tuple.Item1.Id)) nonBlockedTasks.Add(tuple); else proposedBlockedTasks.Add(tuple); } } var schedule = AppendNonBlockedTasks( nonBlockedTasks, user, scheduledTasksDict, freeDaysCalculator, focusFactorCalculator); var result = new Dictionary<string, HashSet<int>>(); AppendBlockedTasks( proposedBlockedTasks, schedule, dataContainer, planningAssignments, focusFactorCalculator, scheduledTasksDict, result); AppendBlockedTasks( activeBlockedTasks, schedule, dataContainer, planningAssignments, focusFactorCalculator, scheduledTasksDict, result); int currentDay = 0; foreach (var pair in schedule) { bool isTaskActive = pair.Item1.Item1.IsActive(); int startDayIndex = isTaskActive ? 0 : currentDay; int vacationDaysCount = freeDaysCalculator.GetVacationsDaysCount( user, startDayIndex, pair.Item2); scheduledTasksDict[pair.Item1.Item1.Id] = new Tuple<int?, int>(startDayIndex, pair.Item2 + vacationDaysCount); currentDay += vacationDaysCount; currentDay += isTaskActive ? Math.Max(pair.Item2 - currentDay, 0) : pair.Item2; } return result; }
private static int GetDaysCount( WorkItem task, string user, Dictionary<int, Tuple<int?, int>> scheduledTasksDict, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator) { if (task.IsActive()) { DateTime? finishDate = task.FinishDate(); int finish = scheduledTasksDict.ContainsKey(task.Id) ? scheduledTasksDict[task.Id].Item2 : (finishDate == null ? 0 : freeDaysCalculator.GetDaysCount(finishDate.Value, user)); double? remaining = task.Remaining(); if (remaining != null && remaining > 0) { int finishByRemaining = focusFactorCalculator.CalculateDaysByTime(remaining.Value, user); if (finish < finishByRemaining) finish = finishByRemaining; } return finish; } double? estimate = task.Estimate(); return estimate == null ? 0 : focusFactorCalculator.CalculateDaysByTime(estimate.Value, user); }
private static List<Tuple<Tuple<WorkItem, WorkItem>, int>> AppendNonBlockedTasks( ICollection<Tuple<WorkItem, WorkItem>> nonBlockedTasks, string user, Dictionary<int, Tuple<int?, int>> scheduledTasksDict, FreeDaysCalculator freeDaysCalculator, FocusFactorCalculator focusFactorCalculator) { var result = new List<Tuple<Tuple<WorkItem, WorkItem>, int>>(nonBlockedTasks.Count); result.AddRange( nonBlockedTasks .OrderBy(i => i, new TaskPriorityComparer()) .Select(pair => new Tuple<Tuple<WorkItem, WorkItem>, int>( pair, GetDaysCount( pair.Item1, user, scheduledTasksDict, freeDaysCalculator, focusFactorCalculator)))); return result; }