Downloads a file.
This downloader uses multiple connections to download the file. It also supports resuming interrupted downloads.
			/// <summary>
			/// A simple constructor that initializes the object with the given values.
			/// </summary>
			/// <param name="p_fdrFileDownloader">The <see cref="FileDownloader"/> from which to retrieve the block this
			/// downloader will download.</param>
			/// <param name="p_fmdInfo">The metadata of the to be downloaded.</param>
			/// <param name="p_fwrWriter">The writer to use to write the file to the disk.</param>
			/// <param name="p_intBufferSize">The size of the buffer to send to the file writer.</param>
			/// <param name="p_strUserAgent">The current User Agent.</param>
			public BlockDownloader(FileDownloader p_fdrFileDownloader, FileMetadata p_fmdInfo, FileWriter p_fwrWriter, Int32 p_intBufferSize, string p_strUserAgent)
			{
				m_fdrFileDownloader = p_fdrFileDownloader;
				m_fmdInfo = p_fmdInfo;
				m_fwrWriter = p_fwrWriter;
				m_intBufferSize = p_intBufferSize;
				m_strUserAgent = p_strUserAgent;
				m_fwrWriter.UnableToWrite += new EventHandler(FileWriter_UnableToWrite);
			}
		/// <summary>
		/// Downloads the speificed file to the specified location.
		/// </summary>
		/// <remarks>
		/// This method starts the download and returns.
		/// 
		/// If the given <paramref name="p_strSavePath"/> already exists, an attempt will be made to
		/// resume the download. If the pre-existing file is not a partial download, or the download
		/// cannot be resumed, the file will be overwritten.
		/// </remarks>
		/// <param name="p_uriURL">The URL list of the file to download.</param>
		/// <param name="p_dicCookies">A list of cookies that should be sent in the request to download the file.</param>
		/// <param name="p_strSavePath">The path to which to save the file.
		/// If <paramref name="p_booUseDefaultFileName"/> is <c>false</c>, this value should be a complete
		/// path, including filename. If <paramref name="p_booUseDefaultFileName"/> is <c>true</c>,
		/// this value should be the directory in which to save the file.</param>
		/// <param name="p_booUseDefaultFileName">Whether to use the file name suggested by the server.</param>
		public void DownloadAsync(List<Uri> p_uriURL, Dictionary<string, string> p_dicCookies, string p_strSavePath, bool p_booUseDefaultFileName)
		{
			System.Diagnostics.Stopwatch swRetry = new System.Diagnostics.Stopwatch();
			int retries = 1;
			int i = 0;
			Uri uriURL = p_uriURL[i];
			ItemProgress = i;
			Status = TaskStatus.Running;

			while ((retries <= m_intRetries) || (Status != TaskStatus.Paused) || (Status != TaskStatus.Queued))
			{
				if ((Status == TaskStatus.Paused) || (Status == TaskStatus.Queued))
					break;
				else if (Status == TaskStatus.Retrying)
					Status = TaskStatus.Running;

				m_fdrDownloader = new FileDownloader(uriURL, p_dicCookies, p_strSavePath, p_booUseDefaultFileName, m_intMaxConnections, m_intMinBlockSize, m_strUserAgent);
				m_steState = new State(true, uriURL, p_dicCookies, p_strSavePath, p_booUseDefaultFileName);
				m_fdrDownloader.DownloadComplete += new EventHandler<CompletedDownloadEventArgs>(Downloader_DownloadComplete);
				ShowItemProgress = false;
				OverallProgressMaximum = (Int64)(m_fdrDownloader.FileSize / 1024);
				OverallProgressMinimum = 0;
				OverallProgressStepSize = 1;
				OverallProgress = (Int64)m_fdrDownloader.DownloadedByteCount;

				if (Status == TaskStatus.Cancelling)
					retries = m_intRetries;
				else if (Status == TaskStatus.Paused)
					break;

				if (!m_fdrDownloader.FileExists)
				{
					if (m_fdrDownloader.FileNotFound)
					{
						swRetry.Start();
						retries = 1;
						OverallMessage = String.Format("File not found on this server, retrying.. ({0}/{1})", retries, m_intRetries);
						Status = TaskStatus.Retrying;

						if (i++ == p_uriURL.Count)
						{
							Status = TaskStatus.Error;
							OnTaskEnded(String.Format("File does not exist: {0}", uriURL.ToString()), null);
							return;
						}

						ItemProgress = i;
						uriURL = p_uriURL[i];

						while ((swRetry.ElapsedMilliseconds < m_intRetryInterval) && swRetry.IsRunning)
						{
							if ((Status == TaskStatus.Cancelling) || (Status == TaskStatus.Paused) || (Status == TaskStatus.Queued))
								break;
						}
						swRetry.Stop();
						swRetry.Reset();
					}
					else if (m_fdrDownloader.ErrorCode == "666")
					{
						ErrorCode = m_fdrDownloader.ErrorCode;
						ErrorInfo = m_fdrDownloader.ErrorInfo;
						Status = TaskStatus.Error;
						OnTaskEnded(m_fdrDownloader.ErrorInfo, null);
						return;
					}
					else if (++retries <= m_intRetries)
					{
						swRetry.Start();
						OverallMessage = String.Format("Server busy or unavailable, retrying.. ({0}/{1})", retries, m_intRetries);
						Status = TaskStatus.Retrying;

						if ((retries == m_intRetries) && (++i < p_uriURL.Count))
						{
							ItemProgress = i;
							retries = 1;
							uriURL = p_uriURL[i];
						}

						while ((swRetry.ElapsedMilliseconds < m_intRetryInterval) && swRetry.IsRunning)
						{
							if ((Status == TaskStatus.Cancelling) || (Status == TaskStatus.Paused) || (Status == TaskStatus.Queued))
								break;
						}
						swRetry.Stop();
						swRetry.Reset();
					}
					else
					{
						Status = TaskStatus.Error;
						OnTaskEnded(String.Format("Error trying to get the file: {0}", uriURL.ToString()), null);
						return;
					}
				}
				else
				{
					break;
				}
			}

			if (ModRepository.IsOffline)
				this.Pause();
			else if (Status == TaskStatus.Running)
			{
				m_fdrDownloader.StartDownload();
				m_tmrUpdater.Start();
			}
		}
		/// <summary>
		/// Halts the file download.
		/// </summary>
		/// <remarks>
		/// After being disposed, that is no guarantee that the task's status will be correct. Further
		/// interaction with the object is undefined.
		/// </remarks>
		public void Dispose()
		{
			if (m_fdrDownloader != null)
			{
				m_fdrDownloader.DownloadComplete -= new EventHandler<CompletedDownloadEventArgs>(Downloader_DownloadComplete);
				m_fdrDownloader.Stop();
				m_fdrDownloader = null;
			}
		}
		/// <summary>
		/// Downloads the specified file, and returns the local path where the file was saved.
		/// </summary>
		/// <param name="p_uriUrl">The URL of the file to download.</param>
		/// <returns>The local path where the specified file was saved.</returns>
		protected string DownloadFile(Uri p_uriUrl)
		{
			//TODO get the block size from settings
			FileDownloader fdrDownloader = new FileDownloader(p_uriUrl, null, EnvironmentInfo.TemporaryPath, true, 1, 500 * 1024, "");
			fdrDownloader.DownloadComplete += new EventHandler<CompletedDownloadEventArgs>(Downloader_DownloadComplete);
			fdrDownloader.StartDownload();
			m_dicWaitForDownloads[fdrDownloader] = new AutoResetEvent(false);
			m_dicWaitForDownloads[fdrDownloader].WaitOne();
			
			string strFileName = m_dicSaveDownloadPaths[fdrDownloader];
			m_dicSaveDownloadPaths.Remove(fdrDownloader);
			m_dicWaitForDownloads.Remove(fdrDownloader);
			return strFileName;
		}