namespace VideoBrowser.Core { using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; /// /// Defines the . /// public static class DownloadQueueHandler { #region Fields private static bool _stop; #endregion Fields #region Properties /// /// Gets the DownloadingCount. /// private static int DownloadingCount => Queue.Count(o => IsDownloaderType(o) && o.CanPause()); /// /// Gets or sets a value indicating whether LimitDownloads. /// public static bool LimitDownloads { get; set; } /// /// Gets or sets the MaxDownloads. /// public static int MaxDownloads { get; set; } /// /// Gets or sets the Queue. /// public static List Queue { get; } = new List(); #endregion Properties #region Methods /// /// The Add. /// /// The operation. public static void Add(Operation operation) { operation.Completed += Operation_Completed; operation.Resumed += Operation_Resumed; operation.StatusChanged += Operation_StatusChanged; Queue.Add(operation); } /// /// The GetQueued. /// /// The . public static Operation[] GetQueued() { return Queue.Where(o => IsDownloaderType(o) && o.Status == OperationStatus.Queued).ToArray(); } /// /// The GetWorking. /// /// The . public static Operation[] GetWorking() { return Queue.Where(o => IsDownloaderType(o) && o.Status == OperationStatus.Working).ToArray(); } /// /// The Remove. /// /// The operation. public static void Remove(Operation operation) { operation.Completed -= Operation_Completed; operation.Resumed -= Operation_Resumed; operation.StatusChanged -= Operation_StatusChanged; Queue.Remove(operation); } /// /// The StartWatching. /// /// The maxDownloads. public static void StartWatching(int maxDownloads) { MaxDownloads = maxDownloads; MainLoop(); } /// /// The Stop. /// public static void Stop() { _stop = true; } /// /// The IsDownloaderType. /// /// The operation. /// The . private static bool IsDownloaderType(Operation operation) { return operation is DownloadOperation; } /// /// The MainLoop. /// private static async void MainLoop() { while (!_stop) { await Task.Delay(1000); var queued = GetQueued(); // If downloads isn't limited, start all queued operations if (!LimitDownloads) { if (queued.Length == 0) { continue; } foreach (var operation in queued) { if (operation.HasStarted) { operation.ResumeQuiet(); } else { operation.Start(); } } } else if (DownloadingCount < MaxDownloads) { // Number of operations to start var count = Math.Min(MaxDownloads - DownloadingCount, queued.Length); for (var i = 0; i < count; i++) { if (queued[i].HasStarted) { queued[i].ResumeQuiet(); } else { queued[i].Start(); } } } else if (DownloadingCount > MaxDownloads) { // Number of operations to pause var count = DownloadingCount - MaxDownloads; var working = GetWorking(); for (var i = DownloadingCount - 1; i > (MaxDownloads - 1); i--) { working[i].Queue(); } } } } /// /// The Operation_Completed. /// /// The sender. /// The e. private static void Operation_Completed(object sender, OperationEventArgs e) { Remove((sender as Operation)); } /// /// The Operation_Resumed. /// /// The sender. /// The e. private static void Operation_Resumed(object sender, EventArgs e) { // User resumed operation, prioritize this operation over other queued var operation = sender as Operation; // Move operation to top of queue, since pausing happens from the bottom. // I.E. this operation will only paused if absolutely necessary. Queue.Remove(operation); Queue.Insert(0, operation); } /// /// The Operation_StatusChanged. /// /// The sender. /// The e. private static void Operation_StatusChanged(object sender, StatusChangedEventArgs e) { } #endregion Methods } }