using System;
using System.ComponentModel;
using System.Windows.Forms;
using ComponentPro.Net;
using ComponentPro;

namespace MultipleThreads
{
    public partial class MTForm : Form
    {
        private readonly bool _exception;
        private SettingInfo _settings;

        public MTForm()
        {
            try
            {
                InitializeComponent();

#if !Framework4_5
                this.emailValidator.ValidateEmailsCompleted += this.sfbEmailValidator_ValidateTextFileCompleted;
#endif
            }
            catch (ComponentPro.Licensing.EmailValidator.UltimateLicenseException exc)
            {
                MessageBox.Show(exc.Message);
                _exception = true;
                return;
            }
        }

        /// <summary>
        /// Handles the form's Load event.
        /// </summary>
        /// <param name="e">The event arguments.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (_exception)
                this.Close();

            _settings = SettingInfo.LoadConfig();

            emailValidator.ProxyHttpConnectAuthMethodMethod = _settings.ProxyMethod;
            emailValidator.ProxyHost = _settings.ProxyServer;
            emailValidator.ProxyPassword = _settings.ProxyPassword;
            emailValidator.ProxyPort = _settings.ProxyPort;
            emailValidator.ProxyType = _settings.ProxyType;
            emailValidator.ProxyUserName = _settings.ProxyUser;
            emailValidator.ProxyDomain = _settings.ProxyDomain;

            #region Settings

            // Initialize the text box.
            txtEmailListThread.Text = _settings.EmailListFile;

            #endregion
        }

        /// <summary>
        /// Handles the form's Closing event.
        /// </summary>
        /// <param name="e">The event arguments.</param>
        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            _settings.EmailListFile = txtEmailListThread.Text;
            _settings.SaveConfig();

            base.OnClosing(e);
        }

        /// <summary>
        /// Handles the Browse file button's Click event.
        /// </summary>
        /// <param name="sender">The button object.</param>
        /// <param name="e">The event arguments.</param>
        private void btnBrowseFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            try
            {
                dlg.FileName = txtEmailListThread.Text;
                dlg.Filter = "List File (*.txt)|*.txt|All files (*.*)|*.*";
                dlg.FilterIndex = 1;
                dlg.Title = "Select Email List File";
                // Show Open file dialog.
                if (dlg.ShowDialog() != DialogResult.OK)
                    return;

                txtEmailListThread.Text = dlg.FileName;
            }
            catch
            {
                MessageBox.Show(dlg.FileName + " is not a valid address list", "Error");
            }
        }

        void EnableDialog(bool enable)
        {
            txtEmailListThread.Enabled = enable;
            btnBrowseFile.Enabled = enable;
            btnProxy.Enabled = enable;

            btnSingleThread.Enabled = enable;
            btnTwoThreads.Enabled = enable;
            btnAbort.Enabled = !enable;

            Util.EnableCloseButton(this, enable);
        }

        /// <summary>
        /// Handles the TwoThreads button's Click.
        /// </summary>
        /// <param name="sender">The button object.</param>
        /// <param name="e">The event arguments.</param>
        private void btnTwoThreads_Click(object sender, EventArgs e)
        {
            // Clear logs.
            lst1AdvancedLog.Items.Clear();
            lst2AdvancedLog.Items.Clear();
            lst1Log.Items.Clear();
            lst2Log.Items.Clear();

            try
            {
                // Disable controls.
                EnableDialog(false);
                // Start validating emails in the specified file with multi-threads (2).
                emailValidator.MultiThreadsValidateTextFile(txtEmailListThread.Text, 2, true);
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                EnableDialog(true);
            }
        }

        private void sfbEmailValidator_MessageLogging(object sender, ComponentPro.Net.EmailValidatorLogEventArgs e)
        {
            if (!IsDisposed)
                Invoke(new EventHandler<EmailValidatorLogEventArgs>(MessageLogging), sender, e);
        }

        /// <summary>
        /// Handles the emailvalidator's MessageLogging event.
        /// </summary>
        /// <param name="sender">The email validator object.</param>
        /// <param name="e">The event arguments.</param>
        void MessageLogging(object sender, ComponentPro.Net.EmailValidatorLogEventArgs e)
        {
            AdvancedLog(e.SmtpTranscript, e.ThreadId);
        }

        /// <summary>
        /// Logs message.
        /// </summary>
        /// <param name="message">The message to log.</param>
        /// <param name="threadId">The Thread Id.</param>
        void AdvancedLog(string message, int threadId)
        {
            message = message.Replace("\r\n", string.Empty);

            // Validate Email Addresses loaded from a file with two threads                    
            ListBox lb = threadId == 0 ? lst1AdvancedLog : lst2AdvancedLog;
            lb.Items.Add(message);
        }

        /// <summary>
        /// Logs message.
        /// </summary>
        /// <param name="message">The message to log.</param>
        /// <param name="threadId">The Thread Id.</param>
        void Log(string message, int threadId)
        {
            // Validate Email Addresses loaded from a file with two threads
            ListBox lb = threadId == 0 ? lst1Log : lst2Log;
            lb.Items.Add(message);
        }

        /// <summary>
        /// Handles the Single Thread button's Click event.
        /// </summary>
        /// <param name="sender">The button object.</param>
        /// <param name="e">The event arguments.</param>
        private void btnAbort_Click(object sender, EventArgs e)
        {
            // Abort the operation.
            btnAbort.Enabled = false;
            emailValidator.Cancel();
        }

        /// <summary>
        /// Handles the Single Thread button's Click event.
        /// </summary>
        /// <param name="sender">The button object.</param>
        /// <param name="e">The event arguments.</param>
#if Framework4_5
        async
#endif
            void btnSingleThread_Click(object sender, EventArgs e)
        {
            // Make sure the email list file textbox is not empty.
            if (txtEmailListThread.Text.Length == 0)
            {
                MessageBox.Show("Please enter file name.");
                return;
            }

            // Disable controls.
            EnableDialog(false);

            // Clear logs.
            lst1AdvancedLog.Items.Clear();
            lst2AdvancedLog.Items.Clear();
            lst1Log.Items.Clear();
            lst2Log.Items.Clear();

            // Reset counters.
            _processed = 0;
            _passed = 0;

#if Framework4_5 || SYNC
            try
            {
#if SYNC
                emailValidator.ValidateTextFile(txtEmailListThread.Text);
#else
                // Asynchronously Validate a Text File.
                await emailValidator.ValidateTextFileAsync(txtEmailListThread.Text);
#endif
                MessageBox.Show(string.Format("Single thread validation completed. {0} email(s) processed, {1} passed", _processed, _passed));
            }
            catch (Exception ex)
            {
                Util.ShowError(exc);
            }

            // Enable controls.
            EnableDialog(true);
            }
#else
            // Asynchronously Validate a Text File.
            emailValidator.ValidateTextFileAsync(txtEmailListThread.Text);
#endif
        }

        private void sfbEmailValidator_ThreadsCompleted(object sender, EmailValidatorThreadsCompletedEventArgs e)
        {
            if (!IsDisposed)
                Invoke(new EventHandler<EmailValidatorThreadsCompletedEventArgs>(ThreadsCompleted), sender, e);
        }

        /// <summary>
        /// Handles the emailvalidator's ThreadsCompleted event.
        /// </summary>
        /// <param name="sender">The emailverifer object.</param>
        /// <param name="e">The event arguments.</param>
        void ThreadsCompleted(object sender, EmailValidatorThreadsCompletedEventArgs e)
        {
            MessageBox.Show(string.Format("Multi-threads validation completed. {0} email(s) processed, {1} passed", e.EmailsProcessed, e.EmailsPassed));
            EnableDialog(true);
        }

        private void sfbEmailValidator_ThreadCompleted(object sender, EmailValidatorThreadCompletedEventArgs e)
        {
            if (!IsDisposed)
                Invoke(new EventHandler<EmailValidatorThreadCompletedEventArgs>(ThreadCompleted), sender, e);
        }

        /// <summary>
        /// Handles the emailvalidator's ThreadCompleted event.
        /// </summary>
        /// <param name="sender">The emailverifer object.</param>
        /// <param name="e">The event arguments.</param>
        void ThreadCompleted(object sender, EmailValidatorThreadCompletedEventArgs e)
        {
            Log(string.Format("Validation completed. {0} email(s) processed, {1} passed", e.EmailsProcessed, e.EmailsPassed), e.ThreadId);
            if (e.LastException != null)
                Log("Last error: " + e.LastException.Message, e.ThreadId);
        }

#if !Framework4_5
        /// <summary>
        /// Handles the emailvalidator's ValidateTextFileCompleted event.
        /// </summary>
        /// <param name="sender">The email validator object.</param>
        /// <param name="e">The event arguments.</param>
        private void sfbEmailValidator_ValidateTextFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
                Util.ShowError(e.Error);
            else
                MessageBox.Show(string.Format("Single thread validation completed. {0} email(s) processed, {1} passed", _processed, _passed));

            // Enable controls.
            EnableDialog(true);
        }
#endif

        /// <summary>
        /// Handles the proxy settings button's Click event.
        /// </summary>
        /// <param name="sender">The button object.</param>
        /// <param name="e">The event arguments.</param>
        private void btnProxy_Click(object sender, EventArgs e)
        {
            ProxySettings dlg = new ProxySettings(_settings);

            // Show the proxy settings dialog.
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                // Update emailvalidator's proxy settings.
                emailValidator.ProxyHttpConnectAuthMethodMethod = _settings.ProxyMethod;
                emailValidator.ProxyHost = _settings.ProxyServer;
                emailValidator.ProxyPassword = _settings.ProxyPassword;
                emailValidator.ProxyPort = _settings.ProxyPort;
                emailValidator.ProxyType = _settings.ProxyType;
                emailValidator.ProxyUserName = _settings.ProxyUser;
                emailValidator.ProxyDomain = _settings.ProxyDomain;
            }
        }

        private void sfbEmailValidator_EmailValidated(object sender, EmailValidatedEventArgs e)
        {
            if (!IsDisposed)
                Invoke(new EventHandler<EmailValidatedEventArgs>(EmailValidated), sender, e);
        }

        int _passed;
        int _processed;

        private void EmailValidated(object sender, EmailValidatedEventArgs e)
        {
            if (e.Error != null)
            {
                AdvancedLog(string.Format("Email '{0}' validated at level {1} with error: {2}.", e.EmailAddress, e.ValidatedLevel, e.Error.Message), e.ThreadId);
                Log(string.Format("    Mailbox '{0}' is invalid - completed with error: {1}", e.EmailAddress, e.Error.Message), e.ThreadId);
            }
            else
            {
                AdvancedLog(string.Format("Email '{0}' validated at level {1}.", e.EmailAddress, e.ValidatedLevel), e.ThreadId);

                if (e.ValidatedLevel == ValidationLevel.Success)
                {
                    Log(string.Format("    Completed successfully - Mailbox {0} is valid", e.EmailAddress), e.ThreadId);
                    _passed++;
                }
                else
                {
                    Log(string.Format("    Mailbox '{0}' is invalid - completed at level: {1}", e.EmailAddress, e.ValidatedLevel), e.ThreadId);
                }
            }
            AdvancedLog("------------------------------------", e.ThreadId);
            Log("----------------", e.ThreadId);
            _processed++;

#if DEBUG
            Console.WriteLine("Evt Validated - " + DateTime.Now);
            Console.WriteLine("   Prg: " + e.ProgressPercentage);
            Console.WriteLine("   Processed: " + e.EmailsProcessed);
#endif
        }

        private void sfbEmailValidator_Progress(object sender, EmailValidatorProgressEventArgs e)
        {
            if (!IsDisposed)
                Invoke(new EventHandler<EmailValidatorProgressEventArgs>(Progress), sender, e);
        }

        private void Progress(object sender, EmailValidatorProgressEventArgs e)
        {
            if (e.EmailAddress != null)
                if (e.Passed)
                    Log("    Passed: " + e.Level.ToString(), e.ThreadId);
                else
                    Log("    Failed: " + e.Level.ToString(), e.ThreadId);

            progressBar.Value = e.ProgressPercentage;
        }

        private void sfbEmailValidator_EmailValidating(object sender, EmailValidatingEventArgs e)
        {
            if (!IsDisposed)
                Invoke(new EventHandler<EmailValidatingEventArgs>(EmailValidating), sender, e);
        }

        private void EmailValidating(object sender, EmailValidatingEventArgs e)
        {
            Log(string.Format("Start validating e-mail address: '{0}'", e.EmailAddress), e.ThreadId);
#if DEBUG
            Console.WriteLine("Evt Validating - " + DateTime.Now);
            Console.WriteLine("   Prg: " + e.ProgressPercentage);
            Console.WriteLine("   Processed: " + e.EmailsProcessed);
#endif
        }
    }
}