/// <inheritdoc />
        public IEnumerable <ITaskProcessorRuntimeInfo> ChooseProcessorForTask(ITaskRuntimeInfo pendingTaskInfo)
        {
            if (pendingTaskInfo == null)
            {
                throw new ArgumentNullException("pendingTaskInfo");
            }

            ITaskRuntimeInfo[] activeTasksInfo = this.repository.TaskRuntimeInfo.GetActive().ToArray();

            return(this.repository.TaskProcessorRuntimeInfo.GetAll()
                   .Where(processorInfo => DefaultTaskDistributor.CanExecuteTask(pendingTaskInfo, processorInfo, activeTasksInfo))
                   .OrderBy(t => activeTasksInfo.Count(tt => tt.TaskProcessorId == t.TaskProcessorId)));
        }
        /// <inheritdoc />
        public IEnumerable <ITaskRuntimeInfo> ChooseNextTasksForProcessor(Guid taskProcessorId)
        {
            Trace.WriteLine("ENTER: Choosing next tasks to assign to processor '{0}' ...".FormatInvariant(taskProcessorId));

            ITaskProcessorRuntimeInfo taskProcessor = this.repository.TaskProcessorRuntimeInfo.GetById(taskProcessorId);

            if (taskProcessor == null)
            {
                Trace.WriteLine("EXIT: Processor '{0}' not found in configuration.".FormatInvariant(taskProcessorId));

                yield break;
            }

            var pendingAndActiveTasks = this.repository.TaskRuntimeInfo.GetPendingAndActive();

            IEnumerable <ITaskRuntimeInfo> pendingTasksInfo = pendingAndActiveTasks[TaskStatus.Pending];
            IEnumerable <ITaskRuntimeInfo> activeTasksInfo  = pendingAndActiveTasks[TaskStatus.InProgress];

            int?remainingTasksCount = null;

            if (taskProcessor.Configuration.Tasks.MaxWorkers.HasValue)
            {
                remainingTasksCount = taskProcessor.Configuration.Tasks.MaxWorkers.Value - activeTasksInfo.Count(t => t.TaskProcessorId == taskProcessor.TaskProcessorId);

                if (remainingTasksCount <= 0)
                {
                    Trace.WriteLine("EXIT: No tasks to assign because processor max workers threshold {0} is reached.".FormatInvariant(taskProcessor.Configuration.Tasks.MaxWorkers.Value));

                    yield break;
                }
            }

            Dictionary <Type, int> remainingTasksCountByTaskType = new Dictionary <Type, int>();

            Func <ITaskRuntimeInfo, bool> filterPredicate = pendingTaskInfo =>
            {
                Lazy <int> activeTasksCountByTaskType = new Lazy <int>(() => activeTasksInfo.Count(t => t.TaskType == pendingTaskInfo.TaskType));

                Lazy <int?> remainingTasksByTaskTypeValue = new Lazy <int?>(() => null);

                ITaskJobConfiguration processorTaskJobConfig = taskProcessor.Configuration.Tasks[pendingTaskInfo.TaskType];

                Lazy <int> activeProcessorTasksCountByTaskType = new Lazy <int>(() => activeTasksInfo.Count(t => (t.TaskType == pendingTaskInfo.TaskType) && (t.TaskProcessorId == taskProcessor.TaskProcessorId)));

                Lazy <int?> remainingProcessorTasksCountByTaskType = new Lazy <int?>(() => null);

                if ((processorTaskJobConfig != null) && processorTaskJobConfig.MaxWorkers.HasValue)
                {
                    if (activeProcessorTasksCountByTaskType.Value >= processorTaskJobConfig.MaxWorkers.Value)
                    {
                        return(false);
                    }

                    remainingProcessorTasksCountByTaskType = new Lazy <int?>(() => processorTaskJobConfig.MaxWorkers.Value - activeProcessorTasksCountByTaskType.Value);
                }

                if (!remainingTasksCountByTaskType.ContainsKey(pendingTaskInfo.TaskType))
                {
                    int?value = DefaultTaskDistributor.GetMinMaxWorkers(
                        remainingTasksByTaskTypeValue.Value,
                        remainingProcessorTasksCountByTaskType.Value);

                    if (value.HasValue)
                    {
                        remainingTasksCountByTaskType.Add(pendingTaskInfo.TaskType, value.Value);
                    }
                }

                return(true);
            };

            foreach (ITaskRuntimeInfo result in pendingTasksInfo
                     .OrderByDescending(t => (int)t.Priority)
                     .Where(filterPredicate))
            {
                int count;

                if (remainingTasksCountByTaskType.TryGetValue(result.TaskType, out count))
                {
                    if (count == 0)
                    {
                        continue;
                    }

                    remainingTasksCountByTaskType[result.TaskType] = count - 1;
                }

                yield return(result);

                if (remainingTasksCount == 1)
                {
                    yield break;
                }

                remainingTasksCount++;
            }
        }