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 void AppendBlockedTasks( IEnumerable<Tuple<WorkItem, WorkItem>> blockedTasks, List<Tuple<Tuple<WorkItem, WorkItem>, int>> schedule, DataContainer dataContainer, Dictionary<int, string> planningAssignments, FocusFactorCalculator focusFactorCalculator, Dictionary<int, Tuple<int?, int>> scheduledTasksDict, Dictionary<string, HashSet<int>> usersBlockers) { var comparer = new TaskPriorityComparer(); foreach (var tuple in blockedTasks) { WorkItem blockedTask = tuple.Item1; var finishData = GetFinishDateForBlockedTask( blockedTask, dataContainer, planningAssignments, focusFactorCalculator, scheduledTasksDict); if (finishData.Item1 == null) { schedule.Add(new Tuple<Tuple<WorkItem, WorkItem>, int>(tuple, 0)); } else { double? remaining = tuple.Item1.IsActive() ? blockedTask.Remaining() : blockedTask.Estimate(); int taskDaysCount = remaining == null ? 0 : focusFactorCalculator.CalculateDaysByTime( remaining.Value, planningAssignments.GetAssignee(tuple.Item1)); int startDay = 0; bool added = false; for (int i = 0; i < schedule.Count; i++) { var taskData = schedule[i]; if (taskData.Item1.Item1.IsActive()) continue; if (startDay > finishData.Item1.Value && comparer.Compare(tuple, taskData.Item1) < 0) { schedule.Insert(i, new Tuple<Tuple<WorkItem, WorkItem>, int>(tuple, taskDaysCount)); added = true; break; } startDay += taskData.Item1.Item1.IsActive() ? Math.Max(taskData.Item2 - startDay, 0) : taskData.Item2; } if (!added) schedule.Add(new Tuple<Tuple<WorkItem, WorkItem>, int>(tuple, taskDaysCount)); } foreach (var userBlockersPair in finishData.Item2) { HashSet<int> blockers; if (usersBlockers.ContainsKey(userBlockersPair.Key)) { blockers = usersBlockers[userBlockersPair.Key]; } else { blockers = new HashSet<int>(); usersBlockers.Add(userBlockersPair.Key, blockers); } foreach (int blockerId in userBlockersPair.Value) { blockers.Add(blockerId); } } } }
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? GetFinishDay( WorkItem task, Dictionary<int, string> planningAssignments, FocusFactorCalculator focusFactorCalculator, Dictionary<int, Tuple<int?, int>> scheduledTasksDict) { int? result = null; if (scheduledTasksDict.ContainsKey(task.Id)) { var blockerSchedule = scheduledTasksDict[task.Id]; if (blockerSchedule.Item1 != null) result = blockerSchedule.Item1.Value + blockerSchedule.Item2; } else { double? remaining = task.IsProposed() ? task.Estimate() : task.Remaining(); if (remaining != null) result = focusFactorCalculator.CalculateDaysByTime( remaining.Value, planningAssignments.GetAssignee(task)); } return result; }
private static Tuple<int?, Dictionary<string, HashSet<int>>> GetFinishDateForBlockedTask( WorkItem blockedTask, DataContainer dataContainer, Dictionary<int, string> planningAssignments, FocusFactorCalculator focusFactorCalculator, Dictionary<int, Tuple<int?, int>> scheduledTasksDict) { int? finish = GetFinishDay( blockedTask, planningAssignments, focusFactorCalculator, scheduledTasksDict); Dictionary<string, HashSet<int>> userBlockersDict; if (dataContainer.BlockersDict.ContainsKey(blockedTask.Id)) { userBlockersDict = new Dictionary<string, HashSet<int>>(); foreach (int blockerId in dataContainer.BlockersDict[blockedTask.Id]) { WorkItem blocker = dataContainer.WiDict[blockerId]; var blockerData = GetFinishDateForBlockedTask( blocker, dataContainer, planningAssignments, focusFactorCalculator, scheduledTasksDict); int? currentFinish = GetFinishDay( blocker, planningAssignments, focusFactorCalculator, scheduledTasksDict); currentFinish = MaxDay(currentFinish, blockerData.Item1); finish = MaxDay(finish, currentFinish); foreach (var blockerAssignData in blockerData.Item2) { if (!userBlockersDict.ContainsKey(blockerAssignData.Key)) userBlockersDict.Add(blockerAssignData.Key, new HashSet<int>()); var ids = userBlockersDict[blockerAssignData.Key]; foreach (int parentBlockerId in blockerAssignData.Value) { ids.Add(parentBlockerId); } } string blockerAssignee = planningAssignments.GetAssignee(blocker); if (userBlockersDict.ContainsKey(blockerAssignee)) userBlockersDict[blockerAssignee].Add(blockerId); else userBlockersDict.Add(blockerAssignee, new HashSet<int> {blockerId}); } } else { userBlockersDict = new Dictionary<string, HashSet<int>>(0); } var result = new Tuple<int?, Dictionary<string, HashSet<int>>>(finish, userBlockersDict); 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; }