//  
//   Rebex Sample Code License
// 
//   Copyright 2026, REBEX CR s.r.o.
//   All rights reserved.
//   https://www.rebex.net/
// 
//   Permission to use, copy, modify, and/or distribute this software for any
//   purpose with or without fee is hereby granted.
// 
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//   OTHER DEALINGS IN THE SOFTWARE.
// 

using System;
using System.IO;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;

using Rebex.IO;
using Rebex.Net;

namespace Rebex.Samples
{
    /// <summary>
    /// Main application form.
    /// </summary>
    public class MainForm : System.Windows.Forms.Form
    {
        // Path to configuration file
        public static readonly string ConfigFilePath = Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), string.Format("Rebex{0}FTP SSL{0}BatchTransfer.xml", Path.DirectorySeparatorChar));

        // Application configuration
        private readonly Configuration _config;

        private Ftp _ftp;
        private FolderBrowserDialog _openFolder;
        private ProblemDetectedForm _problemForm;

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        private System.Windows.Forms.Label label5;
        private System.Windows.Forms.Label label6;
        private System.Windows.Forms.TextBox tbPassword;
        private System.Windows.Forms.Label label4;
        private System.Windows.Forms.TextBox tbUserName;
        private System.Windows.Forms.Label label3;
        private System.Windows.Forms.TextBox tbPort;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.TextBox tbHostname;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.TextBox tbLocalPath;
        private System.Windows.Forms.TextBox tbRemotePath;
        private System.Windows.Forms.Label label7;
        private System.Windows.Forms.Label lblFilesCount;
        private System.Windows.Forms.ProgressBar pbFile;
        private System.Windows.Forms.ProgressBar pbTotal;
        private System.Windows.Forms.Button btnUpload;
        private System.Windows.Forms.Button btnDownload;
        private System.Windows.Forms.Button btnOpen;
        private System.Windows.Forms.Label label8;
        private System.Windows.Forms.Label lblBytesTotal;
        private StatusStrip statusStrip;
        private ToolStripStatusLabel statusLabel;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.Panel panel1;
        private System.Windows.Forms.Label label9;
        private System.Windows.Forms.Label label10;
        private System.Windows.Forms.Label lblFrom;
        private System.Windows.Forms.Label lblTo;
        private System.Windows.Forms.Label lblToPath;
        private System.Windows.Forms.Label lblFromPath;
        private System.Windows.Forms.Button btnAbort;
        private System.Windows.Forms.ComboBox cbSecurity;

        public MainForm()
        {
            CheckForIllegalCrossThreadCalls = true;
            InitializeComponent();

            _config = new Configuration(ConfigFilePath);
            _openFolder = new FolderBrowserDialog();
            _problemForm = new ProblemDetectedForm();
            lblFilesCount.Text = string.Empty;

            LoadSettings();
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.tbLocalPath = new System.Windows.Forms.TextBox();
            this.label5 = new System.Windows.Forms.Label();
            this.tbRemotePath = new System.Windows.Forms.TextBox();
            this.label6 = new System.Windows.Forms.Label();
            this.tbPassword = new System.Windows.Forms.TextBox();
            this.label4 = new System.Windows.Forms.Label();
            this.tbUserName = new System.Windows.Forms.TextBox();
            this.label3 = new System.Windows.Forms.Label();
            this.tbPort = new System.Windows.Forms.TextBox();
            this.label2 = new System.Windows.Forms.Label();
            this.tbHostname = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.btnOpen = new System.Windows.Forms.Button();
            this.label7 = new System.Windows.Forms.Label();
            this.lblFilesCount = new System.Windows.Forms.Label();
            this.lblFrom = new System.Windows.Forms.Label();
            this.lblTo = new System.Windows.Forms.Label();
            this.pbFile = new System.Windows.Forms.ProgressBar();
            this.pbTotal = new System.Windows.Forms.ProgressBar();
            this.btnUpload = new System.Windows.Forms.Button();
            this.btnDownload = new System.Windows.Forms.Button();
            this.label8 = new System.Windows.Forms.Label();
            this.lblBytesTotal = new System.Windows.Forms.Label();
            this.statusStrip = new System.Windows.Forms.StatusStrip();
            this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.cbSecurity = new System.Windows.Forms.ComboBox();
            this.panel1 = new System.Windows.Forms.Panel();
            this.label10 = new System.Windows.Forms.Label();
            this.label9 = new System.Windows.Forms.Label();
            this.lblToPath = new System.Windows.Forms.Label();
            this.lblFromPath = new System.Windows.Forms.Label();
            this.btnAbort = new System.Windows.Forms.Button();
            this.groupBox1.SuspendLayout();
            this.panel1.SuspendLayout();
            this.statusStrip.SuspendLayout();
            this.SuspendLayout();
            // 
            // tbLocalPath
            // 
            this.tbLocalPath.Location = new System.Drawing.Point(104, 72);
            this.tbLocalPath.Name = "tbLocalPath";
            this.tbLocalPath.Size = new System.Drawing.Size(272, 20);
            this.tbLocalPath.TabIndex = 5;
            // 
            // label5
            // 
            this.label5.Location = new System.Drawing.Point(8, 72);
            this.label5.Name = "label5";
            this.label5.Size = new System.Drawing.Size(96, 20);
            this.label5.TabIndex = 21;
            this.label5.Text = "Local path:";
            this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // tbRemotePath
            // 
            this.tbRemotePath.Location = new System.Drawing.Point(104, 96);
            this.tbRemotePath.Name = "tbRemotePath";
            this.tbRemotePath.Size = new System.Drawing.Size(352, 20);
            this.tbRemotePath.TabIndex = 7;
            // 
            // label6
            // 
            this.label6.Location = new System.Drawing.Point(8, 96);
            this.label6.Name = "label6";
            this.label6.Size = new System.Drawing.Size(96, 20);
            this.label6.TabIndex = 23;
            this.label6.Text = "Remote path:";
            this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // tbPassword
            // 
            this.tbPassword.Location = new System.Drawing.Point(320, 48);
            this.tbPassword.Name = "tbPassword";
            this.tbPassword.PasswordChar = '*';
            this.tbPassword.Size = new System.Drawing.Size(128, 20);
            this.tbPassword.TabIndex = 4;
            // 
            // label4
            // 
            this.label4.Location = new System.Drawing.Point(256, 48);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(64, 20);
            this.label4.TabIndex = 31;
            this.label4.Text = "Password:";
            this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // tbUserName
            // 
            this.tbUserName.Location = new System.Drawing.Point(104, 48);
            this.tbUserName.Name = "tbUserName";
            this.tbUserName.Size = new System.Drawing.Size(144, 20);
            this.tbUserName.TabIndex = 3;
            // 
            // label3
            // 
            this.label3.Location = new System.Drawing.Point(8, 48);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(96, 20);
            this.label3.TabIndex = 30;
            this.label3.Text = "Login name:";
            this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // tbPort
            // 
            this.tbPort.Location = new System.Drawing.Point(320, 24);
            this.tbPort.Name = "tbPort";
            this.tbPort.Size = new System.Drawing.Size(32, 20);
            this.tbPort.TabIndex = 1;
            this.tbPort.Text = "21";
            // 
            // label2
            // 
            this.label2.Location = new System.Drawing.Point(256, 24);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(64, 20);
            this.label2.TabIndex = 29;
            this.label2.Text = "Port:";
            this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // tbHostname
            // 
            this.tbHostname.Location = new System.Drawing.Point(104, 24);
            this.tbHostname.Name = "tbHostname";
            this.tbHostname.Size = new System.Drawing.Size(144, 20);
            this.tbHostname.TabIndex = 0;
            // 
            // label1
            // 
            this.label1.Location = new System.Drawing.Point(8, 24);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(96, 20);
            this.label1.TabIndex = 28;
            this.label1.Text = "Host name:";
            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // btnOpen
            // 
            this.btnOpen.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnOpen.Location = new System.Drawing.Point(384, 72);
            this.btnOpen.Name = "btnOpen";
            this.btnOpen.Size = new System.Drawing.Size(72, 20);
            this.btnOpen.TabIndex = 6;
            this.btnOpen.Text = "&Browse...";
            this.btnOpen.Click += new System.EventHandler(this.btnOpen_Click);
            // 
            // label7
            // 
            this.label7.Location = new System.Drawing.Point(8, 280);
            this.label7.Name = "label7";
            this.label7.Size = new System.Drawing.Size(120, 24);
            this.label7.TabIndex = 33;
            this.label7.Text = "Files processed / total:";
            // 
            // lblFilesCount
            // 
            this.lblFilesCount.Location = new System.Drawing.Point(128, 280);
            this.lblFilesCount.Name = "lblFilesCount";
            this.lblFilesCount.Size = new System.Drawing.Size(128, 24);
            this.lblFilesCount.TabIndex = 34;
            this.lblFilesCount.Text = "{0} / {1}";
            // 
            // lblFrom
            // 
            this.lblFrom.Location = new System.Drawing.Point(8, 224);
            this.lblFrom.Name = "lblFrom";
            this.lblFrom.Size = new System.Drawing.Size(48, 24);
            this.lblFrom.TabIndex = 36;
            this.lblFrom.Text = "From:";
            // 
            // lblTo
            // 
            this.lblTo.Location = new System.Drawing.Point(8, 248);
            this.lblTo.Name = "lblTo";
            this.lblTo.Size = new System.Drawing.Size(48, 24);
            this.lblTo.TabIndex = 37;
            this.lblTo.Text = "To:";
            // 
            // pbFile
            // 
            this.pbFile.Location = new System.Drawing.Point(8, 304);
            this.pbFile.Name = "pbFile";
            this.pbFile.Size = new System.Drawing.Size(492, 23);
            this.pbFile.TabIndex = 38;
            // 
            // pbTotal
            // 
            this.pbTotal.Location = new System.Drawing.Point(8, 336);
            this.pbTotal.Name = "pbTotal";
            this.pbTotal.Size = new System.Drawing.Size(492, 23);
            this.pbTotal.TabIndex = 39;
            // 
            // btnUpload
            // 
            this.btnUpload.Location = new System.Drawing.Point(344, 192);
            this.btnUpload.Name = "btnUpload";
            this.btnUpload.Size = new System.Drawing.Size(75, 23);
            this.btnUpload.TabIndex = 9;
            this.btnUpload.Text = "&Upload";
            this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);
            // 
            // btnDownload
            // 
            this.btnDownload.Location = new System.Drawing.Point(264, 192);
            this.btnDownload.Name = "btnDownload";
            this.btnDownload.Size = new System.Drawing.Size(75, 23);
            this.btnDownload.TabIndex = 8;
            this.btnDownload.Text = "&Download";
            this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click);
            // 
            // label8
            // 
            this.label8.Location = new System.Drawing.Point(272, 280);
            this.label8.Name = "label8";
            this.label8.Size = new System.Drawing.Size(80, 24);
            this.label8.TabIndex = 42;
            this.label8.Text = "Bytes total:";
            this.label8.TextAlign = System.Drawing.ContentAlignment.TopRight;
            // 
            // lblBytesTotal
            // 
            this.lblBytesTotal.Location = new System.Drawing.Point(354, 280);
            this.lblBytesTotal.Name = "lblBytesTotal";
            this.lblBytesTotal.Size = new System.Drawing.Size(144, 24);
            this.lblBytesTotal.TabIndex = 43;
            this.lblBytesTotal.Text = "0";
            // 
            // statusStrip
            // 
            this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.statusLabel});
            this.statusStrip.Location = new System.Drawing.Point(0, 374);
            this.statusStrip.Name = "statusStrip";
            this.statusStrip.Size = new System.Drawing.Size(506, 22);
            this.statusStrip.SizingGrip = false;
            this.statusStrip.TabIndex = 44;
            // 
            // statusLabel
            // 
            this.statusLabel.Name = "statusLabel";
            this.statusLabel.Size = new System.Drawing.Size(90, 21);
            this.statusLabel.Text = "Welcome!";
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.cbSecurity);
            this.groupBox1.Controls.Add(this.tbPort);
            this.groupBox1.Controls.Add(this.tbPassword);
            this.groupBox1.Controls.Add(this.label6);
            this.groupBox1.Controls.Add(this.label2);
            this.groupBox1.Controls.Add(this.tbRemotePath);
            this.groupBox1.Controls.Add(this.tbHostname);
            this.groupBox1.Controls.Add(this.label5);
            this.groupBox1.Controls.Add(this.tbLocalPath);
            this.groupBox1.Controls.Add(this.btnOpen);
            this.groupBox1.Controls.Add(this.label1);
            this.groupBox1.Controls.Add(this.label4);
            this.groupBox1.Controls.Add(this.tbUserName);
            this.groupBox1.Controls.Add(this.label3);
            this.groupBox1.Location = new System.Drawing.Point(4, 60);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(498, 128);
            this.groupBox1.TabIndex = 45;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Settings";
            // 
            // cbSecurity
            // 
            this.cbSecurity.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            this.cbSecurity.Items.AddRange(new object[] {
            "No security",
            "Explicit TLS/SSL",
            "Implicit TLS/SSL"});
            this.cbSecurity.Location = new System.Drawing.Point(360, 24);
            this.cbSecurity.MaxDropDownItems = 3;
            this.cbSecurity.Name = "cbSecurity";
            this.cbSecurity.Size = new System.Drawing.Size(132, 21);
            this.cbSecurity.TabIndex = 32;
            // 
            // panel1
            // 
            this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
            | System.Windows.Forms.AnchorStyles.Right)));
            this.panel1.BackColor = System.Drawing.Color.White;
            this.panel1.Controls.Add(this.label10);
            this.panel1.Controls.Add(this.label9);
            this.panel1.Location = new System.Drawing.Point(0, 0);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(506, 56);
            this.panel1.TabIndex = 46;
            // 
            // label10
            // 
            this.label10.Location = new System.Drawing.Point(16, 26);
            this.label10.Name = "label10";
            this.label10.Size = new System.Drawing.Size(248, 18);
            this.label10.TabIndex = 48;
            this.label10.Text = "Uploads or downloads multiple files.";
            // 
            // label9
            // 
            this.label9.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
            this.label9.Location = new System.Drawing.Point(8, 8);
            this.label9.Name = "label9";
            this.label9.Size = new System.Drawing.Size(248, 18);
            this.label9.TabIndex = 47;
            this.label9.Text = "Batch Transfer Utility";
            // 
            // lblToPath
            // 
            this.lblToPath.Location = new System.Drawing.Point(56, 248);
            this.lblToPath.Name = "lblToPath";
            this.lblToPath.Size = new System.Drawing.Size(448, 24);
            this.lblToPath.TabIndex = 48;
            // 
            // lblFromPath
            // 
            this.lblFromPath.Location = new System.Drawing.Point(56, 224);
            this.lblFromPath.Name = "lblFromPath";
            this.lblFromPath.Size = new System.Drawing.Size(448, 24);
            this.lblFromPath.TabIndex = 47;
            // 
            // btnAbort
            // 
            this.btnAbort.Enabled = false;
            this.btnAbort.Location = new System.Drawing.Point(424, 192);
            this.btnAbort.Name = "btnAbort";
            this.btnAbort.Size = new System.Drawing.Size(75, 23);
            this.btnAbort.TabIndex = 10;
            this.btnAbort.Text = "&Abort";
            this.btnAbort.Click += new System.EventHandler(this.btnAbort_Click);
            // 
            // MainForm
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(506, 396);
            this.Controls.Add(this.btnAbort);
            this.Controls.Add(this.lblToPath);
            this.Controls.Add(this.lblFromPath);
            this.Controls.Add(this.panel1);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.statusStrip);
            this.Controls.Add(this.lblBytesTotal);
            this.Controls.Add(this.label8);
            this.Controls.Add(this.btnDownload);
            this.Controls.Add(this.btnUpload);
            this.Controls.Add(this.pbTotal);
            this.Controls.Add(this.pbFile);
            this.Controls.Add(this.lblTo);
            this.Controls.Add(this.lblFrom);
            this.Controls.Add(this.lblFilesCount);
            this.Controls.Add(this.label7);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
            this.Name = "MainForm";
            this.Text = "Rebex FTP Batch Transfer Sample";
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            this.panel1.ResumeLayout(false);
            this.statusStrip.ResumeLayout(false);
            this.statusStrip.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        #endregion

        /// <summary>
        /// Displays an error message.
        /// </summary>
        /// <param name="ex">Exception to be shown.</param>
        private void ShowError(Exception ex)
        {
            MessageBox.Show(this, string.Format("{0}\r\n\r\nException details: {1}", ex.Message, ex), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// Displays an error message.
        /// </summary>
        /// <param name="message">Message to be shown.</param>
        private void ShowError(string message)
        {
            MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        /// <summary>
        /// Displays a message.
        /// </summary>
        /// <param name="message">Message to be shown.</param>
        private void ShowMessage(string message)
        {
            MessageBox.Show(this, message, "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <summary>
        /// Enable/disable buttons and other controls to match the desired state.
        /// </summary>
        /// <param name="transferring">True if transferring state is to be set; false if no transfering state is to be set.</param>
        private void SetState(bool transferring)
        {
            if (transferring)
            {
                // enable/disable buttons
                btnDownload.Enabled = false;
                btnUpload.Enabled = false;
                btnAbort.Enabled = true;

                // disable connection properties
                tbHostname.Enabled = false;
                tbPort.Enabled = false;
                tbUserName.Enabled = false;
                tbPassword.Enabled = false;

                // initialize the problem-reporting form
                _problemForm.Initialize();
            }
            else
            {
                // clear paths
                lblFromPath.Text = "";
                lblToPath.Text = "";

                // enable / disable buttons
                btnDownload.Enabled = true;
                btnUpload.Enabled = true;
                btnAbort.Enabled = false;

                // enable connection properties
                tbHostname.Enabled = true;
                tbPort.Enabled = true;
                tbUserName.Enabled = true;
                tbPassword.Enabled = true;
            }
        }

        /// <summary>
        /// Save configuration settings.
        /// </summary>
        private void SaveSettings()
        {
            _config.SetValue("hostname", tbHostname.Text);
            _config.SetValue("port", tbPort.Text);
            _config.SetValue("userName", tbUserName.Text);
            _config.SetValue("password", tbPassword.Text);
            _config.SetValue("localPath", tbLocalPath.Text);
            _config.SetValue("remotePath", tbRemotePath.Text);
            _config.SetValue("security", cbSecurity.SelectedIndex);
            _config.Save();
        }

        /// <summary>
        /// Load configuration settings.
        /// </summary>
        private void LoadSettings()
        {
            tbHostname.Text = _config.GetString("hostname", "test.rebex.net");
            tbPort.Text = _config.GetInt32("port", Ftp.DefaultPort).ToString();
            tbUserName.Text = _config.GetString("userName", "demo");
            tbPassword.Text = _config.GetString("password", "password");
            tbLocalPath.Text = _config.GetString("localPath");
            tbRemotePath.Text = _config.GetString("remotePath", "/pub/example/");
            cbSecurity.SelectedIndex = _config.GetInt32("security", 0);
        }

        /// <summary>
        /// Connect to the FTP server.
        /// </summary>
        /// <returns>True if successfully connected, false otherwise.</returns>
        private bool Connect()
        {
            int port;

            // check the hostname
            if (tbHostname.Text.Length == 0)
            {
                ShowError("Hostname is required.");
                return false;
            }

            // parse the port
            if (tbPort.Text.Length == 0)
            {
                port = Ftp.DefaultPort;
            }
            else
            {
                int.TryParse(tbPort.Text, out port);

                // check the port
                if (port <= 0)
                {
                    ShowError("Port must be a positive number.");
                    return false;
                }
            }

            try
            {
                Cursor = Cursors.WaitCursor;

                statusLabel.Text = "Connecting...";

                SslMode sslMode;
                switch (cbSecurity.SelectedIndex)
                {
                    case 1:
                        sslMode = SslMode.Explicit;
                        break;
                    case 2:
                        sslMode = SslMode.Implicit;
                        break;
                    default:
                        sslMode = SslMode.None;
                        break;
                }

                // connect and login
                _ftp = new Ftp();
                _ftp.ValidatingCertificate += new EventHandler<SslCertificateValidationEventArgs>(Verifier.ValidatingCertificate);
                _ftp.Connect(tbHostname.Text, port, sslMode);
                _ftp.Login(tbUserName.Text, tbPassword.Text);

                // register transfer events
                _ftp.ProblemDetected += new EventHandler<FtpProblemDetectedEventArgs>(ftp_ProblemDetected);
                _ftp.Traversing += new EventHandler<FtpTraversingEventArgs>(ftp_Traversing);
                _ftp.TransferProgressChanged += new EventHandler<FtpTransferProgressChangedEventArgs>(ftp_TransferProgressChanged);

                return true;
            }
            catch (Exception x)
            {
                ShowError(x);
                return false;
            }
            finally
            {
                statusLabel.Text = "";
                Cursor = Cursors.Arrow;
            }
        }

        /// <summary>
        /// Disconnect from the FTP server.
        /// </summary>
        private void Disconnect()
        {
            _ftp.Disconnect();
            _ftp.Dispose();
            _ftp = null;
        }

        /// <summary>
        /// Download files.
        /// </summary>
        /// <param name="remotePath">Source file or directory remote path.</param>
        /// <param name="localPath">Target directory local path.</param>
        private void DownloadFiles(string remotePath, string localPath)
        {
            SaveSettings();

            // check the local path
            if (localPath == null || localPath.Length == 0)
            {
                ShowError("Local path cannot be empty.");
                return;
            }

            // connect to the FTP server
            if (!Connect())
                return;

            try
            {
                SetState(true);

                // download files
                _ftp.Download(remotePath, localPath, TraversalMode.Recursive);

                string message = "Download finished successfully.";
                statusLabel.Text = message;
                ShowMessage(message);
            }
            catch (FtpException ex)
            {
                if (ex.Status == FtpExceptionStatus.OperationAborted)
                    ShowMessage("Operation aborted.");
                else
                    ShowError(ex);
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
            finally
            {
                Disconnect();
                SetState(false);
            }
        }

        /// <summary>
        /// Handles the Download button click event.
        /// </summary>
        private void btnDownload_Click(object sender, System.EventArgs e)
        {
            DownloadFiles(tbRemotePath.Text, tbLocalPath.Text);
        }

        /// <summary>
        /// Upload files.
        /// </summary>
        /// <param name="localPath">Source file or directory local path.</param>
        /// <param name="remotePath">Target directory remote path.</param>
        private void UploadFiles(string localPath, string remotePath)
        {
            SaveSettings();

            // check the local path
            if (localPath == null || localPath.Length == 0)
            {
                ShowError("Local path cannot be empty.");
                return;
            }

            // connect to the FTP server
            if (!Connect())
                return;

            try
            {
                SetState(true);

                // upload files
                _ftp.Upload(localPath, remotePath, TraversalMode.Recursive);

                string message = "Upload finished successfully.";
                statusLabel.Text = message;
                ShowMessage(message);
            }
            catch (FtpException ex)
            {
                if (ex.Status == FtpExceptionStatus.OperationAborted)
                    ShowMessage("Operation aborted.");
                else
                    ShowError(ex);
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
            finally
            {
                Disconnect();
                SetState(false);
            }
        }

        /// <summary>
        /// Handles the Upload button click event.
        /// </summary>
        private void btnUpload_Click(object sender, System.EventArgs e)
        {
            UploadFiles(tbLocalPath.Text, tbRemotePath.Text);
        }

        /// <summary>
        /// Handles the Open button click event.
        /// </summary>
        private void btnOpen_Click(object sender, System.EventArgs e)
        {
            DialogResult res = _openFolder.ShowDialog(this);

            if (res != DialogResult.OK)
                return;

            tbLocalPath.Text = _openFolder.SelectedPath;
        }

        /// <summary>
        /// Handles the Abort button click event.
        /// </summary>
        private void btnAbort_Click(object sender, System.EventArgs e)
        {
            _ftp.Abort();
        }

        /// <summary>
        /// Handles the multi-file transfer traversing event.
        /// </summary>
        void ftp_Traversing(object sender, FtpTraversingEventArgs e)
        {
            lblFilesCount.Text = string.Format("0 / {0}", e.FilesTotal);
            lblBytesTotal.Text = e.BytesTotal.ToString();
            lblFromPath.Text = e.Item.Path;

            switch (e.TraversingState)
            {
                case TraversingState.HierarchyRetrieving:
                    statusLabel.Text = "Retrieving hierarchy...";
                    break;
                case TraversingState.DirectoryRetrieving:
                    statusLabel.Text = "Retrieving directory...";
                    break;
                case TraversingState.DirectoryRetrieved:
                    statusLabel.Text = "Directory retrieved.";
                    break;
                case TraversingState.HierarchyRetrieved:
                    statusLabel.Text = "Hierarchy retrieved.";
                    break;
            }

            // process any application events to prevent the window from freezing
            Application.DoEvents();
        }

        /// <summary>
        /// Handles the multi-file transfer progress changed event.
        /// </summary>
        void ftp_TransferProgressChanged(object sender, FtpTransferProgressChangedEventArgs e)
        {
            pbTotal.Value = Convert.ToInt32(e.ProgressPercentage);
            pbFile.Value = Convert.ToInt32(e.CurrentFileProgressPercentage);

            lblFilesCount.Text = string.Format("{0} / {1}", e.FilesProcessed, e.FilesTotal);

            lblFromPath.Text = e.SourceItem.Path;
            lblToPath.Text = e.TargetPath;

            switch (e.TransferState)
            {
                case TransferProgressState.DirectoryProcessing:
                    statusLabel.Text = "Processing directory...";
                    break;
                case TransferProgressState.FileTransferring:
                    statusLabel.Text = "Processing file...";
                    break;
                case TransferProgressState.DataBlockProcessed:
                    statusLabel.Text = "Transferring file...";
                    break;
                case TransferProgressState.FileTransferred:
                    statusLabel.Text = "File transferred.";
                    break;
                case TransferProgressState.TransferCompleted:
                    statusLabel.Text = "File transferred.";
                    break;
            }

            // process any application events to prevent the window from freezing
            Application.DoEvents();
        }

        /// <summary>
        /// Handles the multi-file transfer problem detected event.
        /// </summary>
        private void ftp_ProblemDetected(object sender, FtpProblemDetectedEventArgs e)
        {
            _problemForm.ShowModal(this, e);
        }
    }
}

