/// <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>
        /// Handles the Click event of the titlesSearchButton 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 TitlesSearchButtonClick(object sender, RoutedEventArgs e)
        {
            if (titlesListView.SelectedIndex == -1) return;

            var sels = titlesListView.SelectedItems.OfType<TitlesListViewItem>().ToList();

            if (MessageBox.Show("Are you sure you want to search for the foreign title of " + (sels.Count == 1 ? sels[0].Title : sels.Count + " shows") + " on an external service?", "Search foreign titles", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                var td = new TaskDialog
                    {
                        Title           = "Searching foreign titles...",
                        Instruction     = "Searching foreign titles...",
                        CommonButtons   = TaskDialogButton.Cancel,
                        ShowProgressBar = true
                    };

                var thd = new Thread(() =>
                    {
                        var i = 1;
                        foreach (var sel in sels)
                        {
                            Database.ShowData(sel.Show.ShowID, "title." + sel.LangCode, string.Empty);
                            sel.Show.GetForeignTitle(sel.LangCode, true, s => td.Content = s);

                            td.ProgressBarPosition = (int) Math.Round(((double) i/(double) sels.Count)*100d);
                            i++;
                        }

                        td.SimulateButtonClick(-1);
                    });

                td.ButtonClick += (o, a) =>
                    {
                        try
                        {
                            thd.Abort();
                        }
                        catch { }

                        Dispatcher.Invoke((Action)ReloadTitles);
                    };

                new Thread(() => td.Show()).Start();

                thd.Start();
            }
        }
        /// <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>
        /// Begins the file extraction.
        /// </summary>
        /// <param name="file">The file within the archive.</param>
        /// <param name="archive">The archive.</param>
        private void ExtractFile(IArchiveEntry file, IArchive archive)
        {
            _td = new TaskDialog
                {
                    Title           = "Extracting...",
                    Instruction     = Path.GetFileName(file.FilePath),
                    Content         = "Extracting file...",
                    CommonButtons   = TaskDialogButton.Cancel,
                    ShowProgressBar = true
                };

            _td.Destroyed   += TaskDialogDestroyed;
            _td.ButtonClick += TaskDialogDestroyed;

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

            _ext = Path.Combine(Path.GetDirectoryName(_file), Path.GetFileName(file.FilePath));

            var total = file.Size;
            var last = DateTime.MinValue;

            archive.CompressedBytesRead += (sender, args) =>
                {
                    if (args.CurrentFilePartCompressedBytesRead == total)
                    {
                        return;
                    }

                    if ((DateTime.Now - last).TotalMilliseconds < 150)
                    {
                        return;
                    }

                    last = DateTime.Now;

                    var perc = ((double)args.CurrentFilePartCompressedBytesRead / (double)total) * 100;
                    _td.ProgressBarPosition = (int)perc;
                    _td.Content = "Extracting file: " + Utils.GetFileSize(args.CurrentFilePartCompressedBytesRead) + " / " + perc.ToString("0.00") + "% done...";
                };
            archive.EntryExtractionEnd += (sender, args) =>
                {
                    _td.SimulateButtonClick(-1);

                    if (!File.Exists(_ext))
                    {
                        return;
                    }

                    new Thread(() =>
                        {
                            Thread.Sleep(250);
                            Utils.Run(_ext);

                            Thread.Sleep(10000);
                            AskAfterUse();
                        }).Start();
                };

            _thd = new Thread(() => file.WriteToFile(_ext));
            _thd.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();
        }