private async void DownloadCourse()
        {
            Action <List <VideoModel> > update = vdos =>
            {
                this.PlaylistDisplay.ItemsSource = this.GroupToDictionary(vdos);

                this.ElapsedChip.Content =
                    TimeDisplayConverter.TimeToReadbleFormat(vdos.Where(v => v.Downloaded).Sum(v => v.WaitTime));

                this.ETAChip.Content =
                    TimeDisplayConverter.TimeToReadbleFormat(vdos.Where(v => !v.Downloaded).Sum(v => v.WaitTime));
            };

            // list all playlist items
            var url   = this.PlaulistUrlTextbox.Text;
            var data  = new KeyValuePair <string, Dictionary <VideoModel, List <VideoModel> > >();
            var start = 0;
            List <VideoModel> videos = new List <VideoModel>();
            await Task.Run(() => this.ParsePlaylist(url)).ContinueWith(
                a =>
            {
                data  = a.Result;
                start =
                    Directory.GetFiles(
                        Path.Combine(Properties.Settings.Default.Downloads, data.Key),
                        "*.mp4",
                        SearchOption.AllDirectories).Length;
                videos = data.Value.SelectMany(v => v.Value).ToList();

                for (var i = 0; i < start; i++)
                {
                    videos[i].Downloaded = true;
                }

                this.CourseTitleLabel.Text = data.Key;
                update(videos);
            },
                TaskScheduler.FromCurrentSynchronizationContext());

            // update playlist items with status, after every download
            var playlist = this.PlaylistDisplay.ItemsSource as Dictionary <VideoModel, List <VideoModel> >;

            videos = playlist.SelectMany(g => g.Value).ToList();

            for (var i = start; i < videos.Count; i++)
            {
                var video = videos[i];

                await Task.Run(
                    () =>
                {
                    UpdateOutputText($"[download] Downloading is starting for the '{video.Name}' video");

                    //var startTime = DateTime.Now;
                    var result = DownloadVideo(data.Key, url, i + 1, video.Category, video.Name);
                    //var endTime = DateTime.Now;

                    UpdateOutputText($"[download] Download is {(result ? "successful" : "unsuccessful")} for the '{video.Name}' video");

                    // var timeTaken = (int)endTime.Subtract(startTime).TotalMilliseconds;
                    var waitTime = Properties.Settings.Default.WaitTime * 1000;         //video.WaitTime * 1000 >= timeTaken ? video.WaitTime * 1000 - timeTaken : 0;

                    if (!result)
                    {
                        i--;
                        waitTime = 5 * 1000;
                    }

                    UpdateOutputText($"[wait] Waiting for the next download for {waitTime / 1000} seconds");
                    Thread.Sleep(waitTime);

                    return(result);
                }).ContinueWith(
                    a =>
                {
                    if (a.Result)
                    {
                        videos[i].Downloaded = true;
                        playlist             = this.GroupToDictionary(videos);
                        update(videos);
                        UpdateOutputText($"[download] Downloading is finished for the '{videos[i].Name}' video");
                    }
                },
                    TaskScheduler.FromCurrentSynchronizationContext());
            }

            UpdateOutputText($"[download] Downloading is finished for the '{CourseTitleLabel.Text}' course");

            await Task.Run(
                () =>
            {
                var psi = new ProcessStartInfo("shutdown", "/s /t 30");

                if (!Debugger.IsAttached)
                {
                    psi.CreateNoWindow  = true;
                    psi.UseShellExecute = false;
                }

                return(psi);
            }).ContinueWith(
                a =>
            {
                if (this.ShutdownToggleSwitch.IsChecked.Value)
                {
                    Process.Start(a.Result);
                    this.Close();
                }
            },
                TaskScheduler.FromCurrentSynchronizationContext());
        }
 public void Initialize()
 {
     _subject = new TimeDisplayConverter();
 }