/// <summary>
        /// Searches for the specified show and its episode.
        /// </summary>
        /// <param name="ep">The episode.</param>
        public void Search(Episode ep)
        {
            _td = new TaskDialog
                {
                    Title           = "Searching...",
                    Instruction     = "{0} S{1:00}E{2:00}".FormatWith(ep.Show.Name, ep.Season, ep.Number),
                    Content         = "Searching for the episode...",
                    CommonButtons   = TaskDialogButton.Cancel,
                    ShowProgressBar = true
                };

            _td.SetMarqueeProgressBar(true);
            _td.Destroyed   += TaskDialogDestroyed;
            _td.ButtonClick += TaskDialogDestroyed;

            _active = true;
            new Thread(() =>
                {
                    Thread.Sleep(500);

                    if (_active)
                    {
                        _res = _td.Show().CommonButton;
                    }
                }).Start();

            _os.SearchAsync(ep);

            Utils.Win7Taskbar(state: TaskbarProgressBarState.Indeterminate);
        }
        /// <summary>
        /// Downloads the specified link.
        /// </summary>
        /// <param name="link">The link.</param>
        /// <param name="token">The token.</param>
        public void Download(Link link, string token)
        {
            if (link.FileURL.StartsWith("magnet:"))
            {
                DownloadFileCompleted(null, new EventArgs<string, string, string>(link.FileURL, null, token));
                return;
            }

            _td = new TaskDialog
                {
                    Title           = "Downloading...",
                    Instruction     = link.Release,
                    Content         = "Sending request to " + new Uri(link.FileURL).DnsSafeHost.Replace("www.", string.Empty) + "...",
                    CommonButtons   = TaskDialogButton.Cancel,
                    ShowProgressBar = true
                };

            _td.SetMarqueeProgressBar(true);
            _td.Destroyed   += TaskDialogDestroyed;
            _td.ButtonClick += TaskDialogDestroyed;

            new Thread(() => _res = _td.Show().CommonButton).Start();

            var prm = true;

            _dl                          = link.Source.Downloader;
            _dl.DownloadFileCompleted   += DownloadFileCompleted;
            _dl.DownloadProgressChanged += (s, a) =>
                {
                    if (_td != null && _td.IsShowing)
                    {
                        if (prm)
                        {
                            _td.SetMarqueeProgressBar(false);
                            _td.Navigate(_td);
                            prm = false;
                        }

                        _td.Content = "Downloading file... ({0}%)".FormatWith(a.Data);
                        _td.ProgressBarPosition = a.Data;
                    }
                };

            _dl.Download(link, Utils.GetRandomFileName(link.Source.Type == Types.Torrent ? "torrent" : link.Source.Type == Types.Usenet ? "nzb" : null), !string.IsNullOrWhiteSpace(token) ? token : "DownloadFile");

            Utils.Win7Taskbar(state: TaskbarProgressBarState.Indeterminate);
        }
        /// <summary>
        /// Downloads the specified link.
        /// </summary>
        /// <param name="link">The link.</param>
        public void Download(Subtitle link)
        {
            _td = new TaskDialog
                {
                    Title           = "Downloading...",
                    Instruction     = link.Release,
                    Content         = "Sending request to " + new Uri(link.FileURL ?? link.InfoURL).DnsSafeHost.Replace("www.", string.Empty) + "...",
                    CommonButtons   = TaskDialogButton.Cancel,
                    ShowProgressBar = true
                };

            _td.SetMarqueeProgressBar(true);
            _td.Destroyed   += TaskDialogDestroyed;
            _td.ButtonClick += TaskDialogDestroyed;

            new Thread(() => _res = _td.Show().CommonButton).Start();

            var prm = true;

            _dl                          = link.Source.Downloader;
            _dl.DownloadFileCompleted   += DownloadFileCompleted;
            _dl.DownloadProgressChanged += (s, a) =>
                {
                    if (_td != null && _td.IsShowing)
                    {
                        if (prm)
                        {
                            _td.SetMarqueeProgressBar(false);
                            _td.Navigate(_td);
                            prm = false;
                        }

                        _td.Content = "Downloading file... ({0}%)".FormatWith(a.Data);
                        _td.ProgressBarPosition = a.Data;
                    }
                };

            _dl.Download(link, Utils.GetRandomFileName());

            Utils.Win7Taskbar(state: TaskbarProgressBarState.Indeterminate);
        }
        /// <summary>
        /// Calls the underlying method and displays a taskdialog.
        /// </summary>
        public void Run()
        {
            _td = new TaskDialog
                {
                    Title           = "Working...",
                    Instruction     = _title,
                    Content         = _message,
                    CommonButtons   = TaskDialogButton.Cancel,
                    ShowProgressBar = true
                };

            _td.SetMarqueeProgressBar(true);
            _td.Destroyed   += TaskDialogDestroyed;
            _td.ButtonClick += TaskDialogDestroyed;

            _active = true;
            new Thread(() => { _res = _td.Show().CommonButton; }).Start();

            _thd = new Thread(new ThreadStart(_run));
            _thd.Start();

            new Thread(() =>
                {
                    while (_thd.IsAlive)
                    {
                        Thread.Sleep(250);
                    }

                    _active = false;

                    Utils.Win7Taskbar(state: TaskbarProgressBarState.NoProgress);

                    if (_td != null && _td.IsShowing)
                    {
                        _td.SimulateButtonClick(-1);
                    }

                    if (_res == Result.Cancel)
                    {
                        if (_cancellation != null)
                        {
                            _cancellation();
                        }
                    }
                    else if (_callback != null)
                    {
                        _callback();
                    }
                }).Start();

            Utils.Win7Taskbar(state: TaskbarProgressBarState.Indeterminate);
        }
        /// <summary>
        /// Searches for the specified show and its episode.
        /// </summary>
        /// <param name="episode">The episode to search for.</param>
        public void Search(Episode episode)
        {
            _ep = episode;

            var paths = Settings.Get<List<string>>("Download Paths");

            if (paths.Count == 0)
            {
                new TaskDialog
                    {
                        CommonIcon  = TaskDialogIcon.Stop,
                        Title       = "Search path not configured",
                        Instruction = "Search path not configured",
                        Content     = "To use this feature you must set your download path." + Environment.NewLine + Environment.NewLine + "To do so, click on the logo on the upper left corner of the application, then select 'Configure Software'. On the new window click the 'Browse' button under 'Download Path'."
                    }.Show();
                return;
            }

            _td = new TaskDialog
                {
                    Title           = "Searching...",
                    Instruction     = string.Format("{0} S{1:00}E{2:00}", _ep.Show.Name, _ep.Season, _ep.Number),
                    Content         = "Searching for the episode...",
                    CommonButtons   = TaskDialogButton.Cancel,
                    ShowProgressBar = true
                };

            _td.SetMarqueeProgressBar(true);
            _td.Destroyed   += TaskDialogDestroyed;
            _td.ButtonClick += TaskDialogDestroyed;

            _active = true;
            new Thread(() =>
                {
                    Thread.Sleep(500);

                    if (_active)
                    {
                        _res = _td.Show().CommonButton;
                    }
                }).Start();

            _fs = new FileSearch(paths, _ep);

            _fs.FileSearchDone += FileSearchDone;
            _fs.FileSearchProgressChanged += FileSearchProgressChanged;
            _fs.BeginSearch();

            Utils.Win7Taskbar(state: TaskbarProgressBarState.Indeterminate);
        }
        /// <summary>
        /// Handles the Click event of the testLoginButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void TestLoginButtonClick(object sender, RoutedEventArgs e)
        {
            Thread action = null;
            var done = false;

            var user = usernameTextBox.Text;
            var pass = passwordTextBox.Password;

            var td  = new TaskDialog
                {
                    Title           = Parser.Name,
                    Instruction     = "Logging in",
                    Content         = "Logging in to " + Parser.Name + " as " + user + "...",
                    CommonButtons   = TaskDialogButton.Cancel,
                    ShowProgressBar = true
                };
            td.ButtonClick += (s, v) =>
                {
                    if (!done)
                    {
                        try { action.Abort(); } catch { }
                    }
                };
            td.SetMarqueeProgressBar(true);
            new Thread(() => td.Show()).Start();

            action = new Thread(() =>
                {
                    try
                    {
                        var cookies = Parser.Login(user, pass);

                        done = true;

                        if (td.IsShowing)
                        {
                            td.SimulateButtonClick(-1);
                        }

                        if (string.IsNullOrWhiteSpace(cookies))
                        {
                            new TaskDialog
                                {
                                    CommonIcon  = TaskDialogIcon.Stop,
                                    Title       = Parser.Name,
                                    Instruction = "Login error",
                                    Content     = "The site didn't return any cookies. The username and password combination is most likely wrong.",
                                }.Show();
                            return;
                        }

                        Dispatcher.Invoke((Action)(() => cookiesTextBox.Text = cookies));
                    }
                    catch (ThreadAbortException) { }
                    catch (Exception ex)
                    {
                        done = true;

                        if (td.IsShowing)
                        {
                            td.SimulateButtonClick(-1);
                        }

                        new TaskDialog
                            {
                                CommonIcon          = TaskDialogIcon.Stop,
                                Title               = Parser.Name,
                                Instruction         = "Login error",
                                Content             = "An error occured while logging in to the site.",
                                ExpandedControlText = "Show exception message",
                                ExpandedInformation = ex.Message
                            }.Show();
                    }
                });
            action.Start();
        }
        /// <summary>
        /// Handles the Click event of the proxyTestButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ProxyTestButtonClick(object sender, RoutedEventArgs e)
        {
            if (proxiesListView.SelectedIndex == -1) return;

            Thread action = null;
            var done = false;

            var sel = (ProxiesListViewItem)proxiesListView.SelectedItem;
            var uri = new Uri(sel.Address.Replace("$domain.", string.Empty));
            var td  = new TaskDialog
                {
                    Title           = sel.Name,
                    Instruction     = "Testing proxy",
                    Content         = "Testing connection through " + uri.Host + ":" + uri.Port + "...",
                    CommonButtons   = TaskDialogButton.Cancel,
                    ShowProgressBar = true
                };
            td.ButtonClick += (s, v) =>
                {
                    if (!done)
                    {
                        try { action.Abort(); } catch { }
                    }
                };
            td.SetMarqueeProgressBar(true);
            new Thread(() => td.Show()).Start();

            action = new Thread(() =>
                {
                    var s = Stopwatch.StartNew();

                    try
                    {
                        var b = Utils.GetHTML("http://rolisoft.net/b", proxy: sel.Address);
                        s.Stop();

                        done = true;

                        if (td.IsShowing)
                        {
                            td.SimulateButtonClick(-1);
                        }

                        var tor  = b.DocumentNode.SelectSingleNode("//img[@class='tor']");
                        var ip   = b.DocumentNode.GetTextValue("//span[@class='ip'][1]");
                        var host = b.DocumentNode.GetTextValue("//span[@class='host'][1]");
                        var geo  = b.DocumentNode.GetTextValue("//span[@class='geoip'][1]");

                        if (tor != null)
                        {
                            new TaskDialog
                                {
                                    CommonIcon  = TaskDialogIcon.SecurityError,
                                    Title       = sel.Name,
                                    Instruction = "TOR detected",
                                    Content     = ip + " is a TOR exit node." + Environment.NewLine + Environment.NewLine +
                                                  "If the site you're trying to access through this proxy forbids proxy usage, they're most likely use a detection mechanism too, which will trigger an alert when it sees this IP address. Your requests will be denied and your account might also get banned. Even if the site's detector won't recognize it, using TOR is not such a good idea, because you could compromise your account as TOR exit node operators are known to be evil sometimes."
                                }.Show();
                        }

                        if (ip == null)
                        {
                            new TaskDialog
                                {
                                    CommonIcon  = TaskDialogIcon.Stop,
                                    Title       = sel.Name,
                                    Instruction = "Proxy error",
                                    Content     = "The proxy did not return the requested resource, or greatly modified the structure of the page. Either way, it is not suitable for use with this software.",
                                }.Show();
                            return;
                        }

                        new TaskDialog
                            {
                                CommonIcon  = TaskDialogIcon.Information,
                                Title       = sel.Name,
                                Instruction = "Test results",
                                Content     = "Total time to get rolisoft.net/b: " + s.Elapsed + "\r\n\r\nIP address: " + ip + "\r\nHost name: " + host + "\r\nGeoIP lookup: " + geo,
                            }.Show();
                    }
                    catch (ThreadAbortException) { }
                    catch (Exception ex)
                    {
                        done = true;

                        if (td.IsShowing)
                        {
                            td.SimulateButtonClick(-1);
                        }

                        new TaskDialog
                            {
                                CommonIcon          = TaskDialogIcon.Stop,
                                Title               = sel.Name,
                                Instruction         = "Connection error",
                                Content             = "An error occured while connecting to the proxy.",
                                ExpandedControlText = "Show exception message",
                                ExpandedInformation = ex.Message
                            }.Show();
                    }
                    finally
                    {
                        if (s.IsRunning)
                        {
                            s.Stop();
                        }
                    }
                });
            action.Start();
        }
        /// <summary>
        /// Handles the Click event of the proxySearchButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ProxySearchButtonClick(object sender, RoutedEventArgs e)
        {
            if (proxiesListView.SelectedIndex == -1) return;

            Thread action = null;
            var done = false;

            var sel = (ProxiesListViewItem)proxiesListView.SelectedItem;
            var uri = new Uri(sel.Address.Replace("$domain.", string.Empty));

            if (uri.Host == "localhost" || uri.Host == "127.0.0.1" || uri.Host == "::1")
            {
                var app = "a local application";

                try
                {
                    var tcpRows = Utils.GetExtendedTCPTable();
                    foreach (var row in tcpRows)
                    {
                        if (((row.localPort1 << 8) + (row.localPort2) + (row.localPort3 << 24) + (row.localPort4 << 16)) == uri.Port)
                        {
                            app = "PID " + row.owningPid + " (" + Process.GetProcessById(row.owningPid).Modules[0].FileName + ")";
                            break;
                        }
                    }
                }
                catch { }

                new Thread(() => new TaskDialog
                    {
                        CommonIcon  = TaskDialogIcon.SecurityWarning,
                        Title       = sel.Name,
                        Instruction = "Potentially dangerous",
                        Content     = "This proxy points to a local loopback address on port " + uri.Port + ".\r\nYour requests will go to " + app + ", which will most likely forward them to an external server."
                    }.Show()).Start();
                return;
            }

            var td  = new TaskDialog
                {
                    Title           = sel.Name,
                    Instruction     = "Testing proxy",
                    Content         = "Testing whether " + uri.Host + " is a known proxy...",
                    CommonButtons   = TaskDialogButton.Cancel,
                    ShowProgressBar = true
                };
            td.ButtonClick += (s, v) =>
                {
                    if (!done)
                    {
                        try { action.Abort(); } catch { }
                    }
                };
            td.SetMarqueeProgressBar(true);
            new Thread(() => td.Show()).Start();

            action = new Thread(() =>
                {
                    try
                    {
                        var src = new DuckDuckGo();
                        var res = new List<SearchResult>();
                        res.AddRange(src.Search("\"" + uri.Host + "\" intitle:proxy"));

                        if (res.Count == 0)
                        {
                            res.AddRange(src.Search("\"" + uri.Host + "\" intitle:proxies"));
                        }

                        done = true;

                        if (td.IsShowing)
                        {
                            td.SimulateButtonClick(-1);
                        }

                        if (res.Count == 0)
                        {
                            new TaskDialog
                                {
                                    CommonIcon  = TaskDialogIcon.SecuritySuccess,
                                    Title       = sel.Name,
                                    Instruction = "Not a known public proxy",
                                    Content     = uri.Host + " does not seem to be a known public proxy." + Environment.NewLine + Environment.NewLine +
                                                  "If your goal is to trick proxy detectors, you're probably safe for now. However, you shouldn't use public proxies if you don't want to potentially compromise your account."
                                }.Show();
                            return;
                        }
                        else
                        {
                            new TaskDialog
                                {
                                    CommonIcon  = TaskDialogIcon.SecurityError,
                                    Title       = sel.Name,
                                    Instruction = "Known public proxy",
                                    Content     = uri.Host + " is a known public proxy according to " + new Uri(res[0].URL).Host.Replace("www.", string.Empty) + Environment.NewLine + Environment.NewLine +
                                                  "If the site you're trying to access through this proxy forbids proxy usage, they're most likely use a detection mechanism too, which will trigger an alert when it sees this IP address. Your requests will be denied and your account might also get banned. Even if the site's detector won't recognize it, using a public proxy is not such a good idea, because you could compromise your account as public proxy operators are known to be evil sometimes."
                                }.Show();
                            return;
                        }
                    }
                    catch (ThreadAbortException) { }
                    catch (Exception ex)
                    {
                        done = true;

                        if (td.IsShowing)
                        {
                            td.SimulateButtonClick(-1);
                        }

                        new TaskDialog
                            {
                                CommonIcon          = TaskDialogIcon.Stop,
                                Title               = sel.Name,
                                Instruction         = "Connection error",
                                Content             = "An error occured while checking the proxy.",
                                ExpandedControlText = "Show exception message",
                                ExpandedInformation = ex.Message
                            }.Show();
                    }
                });
            action.Start();
        }