/// <summary>
        /// Gets called as we receive data.
        /// </summary>
        /// <param name="session">Session.</param>
        /// <param name="downloadTask">Download task.</param>
        /// <param name = "bytesWritten"></param>
        /// <param name="totalBytesWritten">Total bytes written.</param>
        /// <param name = "totalBytesExpectedToWrite"></param>
        public override void DidWriteData(NSUrlSession session, NSUrlSessionDownloadTask downloadTask, long bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite)
        {
            nuint localIdentifier = downloadTask.TaskIdentifier;
            float percentage      = (float)totalBytesWritten / (float)totalBytesExpectedToWrite;

            Console.WriteLine("DidWriteData - Task: {0}, BytesWritten: {1}, Total: {2}, Expected: {3}, Percentage: {4}", localIdentifier, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite, percentage);

            var downloadInfo = AppDelegate.GetDownloadInfoByTaskId(localIdentifier);
            int index        = AppDelegate.GetDownloadInfoIndexByTaskId(localIdentifier);

            if (downloadInfo != null)
            {
                downloadInfo.Progress = percentage;
            }
            else
            {
                Console.WriteLine("Unable to find download info for task ID '{0}'.", localIdentifier);
            }

            // We are not on the UI thread here.
            var indexPath = NSIndexPath.FromRowSection(index, 0);

            this.InvokeOnMainThread(() =>
            {
                this.controller.TableView.ReloadRows(new NSIndexPath[] { indexPath }, UITableViewRowAnimation.None);
            });
        }
        /// <summary>
        /// Very misleading method name. Gets called if a download is done. Does not necessarily indicate an error
        /// unless the NSError parameter is not null.
        /// </summary>
        public override void DidCompleteWithError(NSUrlSession session, NSUrlSessionTask task, NSError error)
        {
            var downloadInfo = AppDelegate.GetDownloadInfoByTaskId(task.TaskIdentifier);

            // Remember the first completed download. We want to play that when all downloads have finished.
            // If playback is started right here in this method, DidFinishEventsForBackgroundSession() won't be called - no idea why.
            if (this.firstCompletedDownload == null)
            {
                this.firstCompletedDownload = downloadInfo;
            }

            if (error == null)
            {
                return;
            }

            Console.WriteLine("DidCompleteWithError - Task: {0}, Error: {1}", task.TaskIdentifier, error);

            if (downloadInfo != null)
            {
                downloadInfo.Reset(true);
            }

            task.Cancel();
            this.InvokeOnMainThread(() => this.controller.TableView.ReloadData());
        }
        /// <summary>
        /// Gets called if the download has been completed.
        /// </summary>
        public override void DidFinishDownloading(NSUrlSession session, NSUrlSessionDownloadTask downloadTask, NSUrl location)
        {
            // The download location will be a file location.
            var sourceFile = location.Path;


            // Construct a destination file name.
            var destFile = downloadTask.OriginalRequest.Url.AbsoluteString.Substring(downloadTask.OriginalRequest.Url.AbsoluteString.LastIndexOf("/") + 1);

            Console.WriteLine("DidFinishDownloading - Task: {0}, Source file: {1}", downloadTask.TaskIdentifier, sourceFile);

            // Copy over to documents folder. Note that we must use NSFileManager here! File.Copy() will not be able to access the source location.
            NSFileManager fileManager = NSFileManager.DefaultManager;

            // Create the filename
            var   documentsFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            NSUrl destinationURL      = NSUrl.FromFilename(Path.Combine(documentsFolderPath, destFile));

            // Update download info object.
            var downloadInfo = AppDelegate.GetDownloadInfoByTaskId(downloadTask.TaskIdentifier);

            // Remove any existing file in our destination
            NSError error;

            fileManager.Remove(destinationURL, out error);
            bool success = fileManager.Copy(sourceFile, destinationURL.Path, out error);

            if (success)
            {
                // Update download info object.
                this.UpdateDownloadInfo(downloadInfo, DownloadInfo.STATUS.Completed, destinationURL);
            }
            else
            {
                // Clean up.
                downloadInfo.Reset(true);
                this.UpdateDownloadInfo(downloadInfo, DownloadInfo.STATUS.Cancelled, null);
                Console.WriteLine("Error during the copy: {0}", error.LocalizedDescription);
            }

            this.InvokeOnMainThread(() => {
                this.controller.TableView.ReloadData();
            });

            // Serialize all info to disk.
            AppDelegate.SerializeAvailableDownloads();
        }