using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

using LumiSoft.Net;
using LumiSoft.Net.Log;
using LumiSoft.Net.FTP;
using LumiSoft.Net.FTP.Client;
using ftp_client_app.Resources;

namespace ftp_client_app
{
    /// <summary>
    /// Application main window.
    /// </summary>
    public class wfrm_Main : Form
    {
        private TabControl m_pTab = null;
        // Tabpage FTP
        private ToolStrip  m_pTabFtp_ListToobar = null;
        private ListView   m_pTabFtp_List       = null;
        // Tabpage Log
        private RichTextBox m_pTabLog_LogText = null;

        private FTP_Client m_pFtp = null;

        /// <summary>
        /// Default constructor.
        /// </summary>
        public wfrm_Main()
        {
            InitUI();

            this.Visible = true;

            wfrm_Connect frm = new wfrm_Connect(new EventHandler<WriteLogEventArgs>(FTP_WriteLog));
            if(frm.ShowDialog(this) == DialogResult.OK){
                m_pFtp = frm.FTP;                

                LoadCurrentFolder();
            }
            else{
                Dispose();
            }
        }

        #region method Dispose

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            // Clean up POP3 client.
            if(m_pFtp != null){
                m_pFtp.Dispose();
                m_pFtp = null;
            }
        }

        #endregion

        #region method InitUI

        /// <summary>
        /// Creates and initializes UI.
        /// </summary>
        private void InitUI()
        {
            this.ClientSize = new Size(600,400);
            this.StartPosition = FormStartPosition.CenterScreen;
            this.Text = "FTP client";

            m_pTab = new TabControl();
            m_pTab.Dock = DockStyle.Fill;

            #region Tabpage FTP

            m_pTab.TabPages.Add("FTP");
            m_pTab.TabPages[0].ClientSize = new Size(592,374); 

            m_pTabFtp_ListToobar = new ToolStrip();
            
            ImageList m_pTabFtp_List_ImageList = new ImageList();
            m_pTabFtp_List_ImageList.ImageSize = new Size(16,16);
            m_pTabFtp_List_ImageList.Images.Add(ResManager.GetIcon("folderup.ico").ToBitmap());
            m_pTabFtp_List_ImageList.Images.Add(ResManager.GetIcon("folder.ico").ToBitmap());
            m_pTabFtp_List_ImageList.Images.Add(ResManager.GetIcon("file.ico").ToBitmap());
            //
            m_pTabFtp_List = new ListView();
            m_pTabFtp_List.Size = new Size(590,340);
            m_pTabFtp_List.Location = new Point(0,30);
            m_pTabFtp_List.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
            //m_pTabFtp_List.BorderStyle = BorderStyle.None;
            m_pTabFtp_List.View = View.Details;
            m_pTabFtp_List.HideSelection = false;
            m_pTabFtp_List.FullRowSelect = true;
            m_pTabFtp_List.GridLines = true;
            m_pTabFtp_List.SmallImageList = m_pTabFtp_List_ImageList;          
            m_pTabFtp_List.DoubleClick += new EventHandler(m_pTabFtp_List_DoubleClick);
            m_pTabFtp_List.MouseClick += new MouseEventHandler(m_pTabFtp_List_MouseClick);
            m_pTabFtp_List.Columns.Add("Name",240);
            m_pTabFtp_List.Columns.Add("Date modified",120);
            m_pTabFtp_List.Columns.Add("Type",100);
            m_pTabFtp_List.Columns.Add("Size",100);

            m_pTab.TabPages[0].Controls.Add(m_pTabFtp_List);

            #endregion

            #region TabPage Log

            m_pTab.TabPages.Add("Log");
            m_pTab.TabPages[1].ClientSize = new Size(700,500); 

            m_pTabLog_LogText = new RichTextBox();
            m_pTabLog_LogText.Dock = DockStyle.Fill;
            m_pTabLog_LogText.ReadOnly = true;
            m_pTabLog_LogText.BorderStyle = BorderStyle.None;

            m_pTab.TabPages[1].Controls.Add(m_pTabLog_LogText);

            #endregion

            this.Controls.Add(m_pTab);
        }
                                
        #endregion


        #region Events Handling

        #region method m_pTabFtp_List_DoubleClick

        private void m_pTabFtp_List_DoubleClick(object sender,EventArgs e)
        {
            if(m_pTabFtp_List.SelectedItems.Count == 0){
                return;
            }

            try{
                if(m_pTabFtp_List.SelectedItems[0].Text == ".."){
                    m_pFtp.SetCurrentDir("..");
                }
                else{
                    FTP_ListItem listItem = (FTP_ListItem)m_pTabFtp_List.SelectedItems[0].Tag;
                    if(listItem.IsDir){
                        m_pFtp.SetCurrentDir(m_pTabFtp_List.SelectedItems[0].Text);
                    }
                }

                LoadCurrentFolder();
            }
            catch(Exception x){
                MessageBox.Show(this,"Error:\n" + x.ToString(),"Error:",MessageBoxButtons.OK,MessageBoxIcon.Error);
            }
        }

        #endregion

        #region method m_pTabFtp_List_MouseClick

        private void m_pTabFtp_List_MouseClick(object sender,MouseEventArgs e)
        {
            if(e.Button != MouseButtons.Right){
                return;
            }
            
            FTP_ListItem listItem = null;
            if(m_pTabFtp_List.SelectedItems.Count > 0 && m_pTabFtp_List.SelectedItems[0].Tag != null){
                listItem = (FTP_ListItem)m_pTabFtp_List.SelectedItems[0].Tag;
            }

            ContextMenuStrip menu = new ContextMenuStrip();
            menu.Items.Add(new ToolStripMenuItem("Create Folder",ResManager.GetIcon("add.ico").ToBitmap()));
            menu.Items.Add(new ToolStripMenuItem("Delete Folder",ResManager.GetIcon("delete.ico").ToBitmap()));
            menu.Items.Add(new ToolStripMenuItem("Rename Folder",ResManager.GetIcon("edit.ico").ToBitmap()));
            menu.Items.Add(new ToolStripSeparator());
            menu.Items.Add(new ToolStripMenuItem("Upload file",ResManager.GetIcon("add.ico").ToBitmap()));
            menu.Items.Add(new ToolStripMenuItem("Append to file",ResManager.GetIcon("write.ico").ToBitmap()));
            menu.Items.Add(new ToolStripMenuItem("Download file",ResManager.GetIcon("save.ico").ToBitmap()));
            menu.Items.Add(new ToolStripMenuItem("Delete file",ResManager.GetIcon("delete.ico").ToBitmap()));
            menu.Items.Add(new ToolStripMenuItem("Rename file",ResManager.GetIcon("edit.ico").ToBitmap()));
            menu.ItemClicked += new ToolStripItemClickedEventHandler(m_pTabFtp_List_MenuItemClicked);

            if(listItem == null || !listItem.IsDir){
                menu.Items[1].Enabled = false;
                menu.Items[2].Enabled = false;
            }
            else if(listItem == null || listItem.IsDir){
                menu.Items[5].Enabled = false;
                menu.Items[6].Enabled = false;
                menu.Items[7].Enabled = false;
                menu.Items[8].Enabled = false;
            }
            menu.Show(Control.MousePosition);
        }
                
        #endregion

        #region method m_pTabFtp_List_MenuItemClicked

        private void m_pTabFtp_List_MenuItemClicked(object sender,ToolStripItemClickedEventArgs e)
        {
            ((ContextMenuStrip)sender).Close();

            #region Create Folder

            if(e.ClickedItem.Text == "Create Folder"){
                wfrm_Input frm = new wfrm_Input("Create Folder","");
                if(frm.ShowDialog(this) == DialogResult.OK){
                    try{
                        m_pFtp.CreateDirectory(frm.Value);

                        m_pTabFtp_List.SelectedItems.Clear();
                        FTP_ListItem listItem = new FTP_ListItem(frm.Value,0,DateTime.Now,true);
                        ListViewItem item = new ListViewItem(listItem.Name);
                        item.SubItems.Add(listItem.Modified.ToString());
                        item.SubItems.Add("Folder");                        
                        item.SubItems.Add(Convert.ToDecimal(0).ToString("f2") + " kb");
                        item.ImageIndex = 1;
                        item.Tag = listItem;
                        item.Selected = true;
                        m_pTabFtp_List.Items.Add(item);
                        item.EnsureVisible();
                    }                    
                    catch(Exception x){
                        MessageBox.Show(this,"Error:\n" + x.ToString(),"Error:",MessageBoxButtons.OK,MessageBoxIcon.Error);
                    }
                }
            }

            #endregion

            #region Delete Folder

            else if(e.ClickedItem.Text == "Delete Folder"){
                if(MessageBox.Show(this,"Are you sure you want to delete selected folders ?","Confirm delete:",MessageBoxButtons.YesNo,MessageBoxIcon.Question) == DialogResult.Yes){
                    try{
                        while(m_pTabFtp_List.SelectedItems.Count > 0){
                            m_pFtp.DeleteDirectory(m_pTabFtp_List.SelectedItems[0].Text);
                            m_pTabFtp_List.SelectedItems[0].Remove();
                        }
                    }
                    catch(Exception x){
                        MessageBox.Show(this,"Error:\n" + x.ToString(),"Error:",MessageBoxButtons.OK,MessageBoxIcon.Error);
                    }
                }
            }

            #endregion

            #region Rename Folder

            else if(e.ClickedItem.Text == "Rename Folder"){
                wfrm_Input frm = new wfrm_Input("Rename Folder",m_pTabFtp_List.SelectedItems[0].Text);
                if(frm.ShowDialog(this) == DialogResult.OK){
                    try{
                        m_pFtp.Rename(m_pTabFtp_List.SelectedItems[0].Text,frm.Value);
                        m_pTabFtp_List.SelectedItems[0].Text = frm.Value;
                        m_pTabFtp_List.SelectedItems[0].Tag = new FTP_ListItem(frm.Value,0,DateTime.Now,true);
                    }                    
                    catch(Exception x){
                        MessageBox.Show(this,"Error:\n" + x.ToString(),"Error:",MessageBoxButtons.OK,MessageBoxIcon.Error);
                    }
                }
            }

            #endregion

            #region Upload file

            else if(e.ClickedItem.Text == "Upload file"){
                OpenFileDialog dlg = new OpenFileDialog();
                if(dlg.ShowDialog(this) == DialogResult.OK){
                    try{
                        wfrm_Upload frm = new wfrm_Upload(m_pFtp,dlg.FileName);
                        if(frm.ShowDialog(this) == DialogResult.OK){
                            foreach(FTP_ListItem listItem in m_pFtp.GetList(Path.GetFileName(dlg.FileName))){
                                ListViewItem item = new ListViewItem(listItem.Name);
                                item.SubItems.Add(listItem.Modified.ToString());
                                item.SubItems.Add("File");                        
                                item.SubItems.Add(Convert.ToDecimal(listItem.Size / 1000).ToString("f2") + " kb");
                                item.ImageIndex = 2;
                                item.Tag = listItem;
                                m_pTabFtp_List.Items.Add(item);
                            }
                        }
                    }
                    catch(Exception x){
                        MessageBox.Show(this,"Error:\n" + x.ToString(),"Error:",MessageBoxButtons.OK,MessageBoxIcon.Error);
                    }
                }
            }

            #endregion

            #region Append to file

            else if(e.ClickedItem.Text == "Append to file"){
                OpenFileDialog dlg = new OpenFileDialog();
                if(dlg.ShowDialog(this) == DialogResult.OK){
                    try{
                        wfrm_Append frm = new wfrm_Append(m_pFtp,(FTP_ListItem)m_pTabFtp_List.SelectedItems[0].Tag,dlg.FileName);
                        if(frm.ShowDialog(this) == DialogResult.OK){
                            foreach(FTP_ListItem listItem in m_pFtp.GetList(m_pTabFtp_List.SelectedItems[0].Text)){
                                ListViewItem item = new ListViewItem(listItem.Name);
                                item.SubItems.Add(listItem.Modified.ToString());
                                item.SubItems.Add("File");                        
                                item.SubItems.Add(Convert.ToDecimal(listItem.Size / 1000).ToString("f2") + " kb");
                                item.ImageIndex = 2;
                                item.Tag = listItem;
                                m_pTabFtp_List.Items.Add(item);
                            }
                            m_pTabFtp_List.SelectedItems[0].Remove();
                        }
                    }
                    catch(Exception x){
                        MessageBox.Show(this,"Error:\n" + x.ToString(),"Error:",MessageBoxButtons.OK,MessageBoxIcon.Error);
                    }
                }
            }

            #endregion

            #region Download file

            else if(e.ClickedItem.Text == "Download file"){
                SaveFileDialog dlg = new SaveFileDialog();
                dlg.FileName = m_pTabFtp_List.SelectedItems[0].Text;
                if(dlg.ShowDialog(this) == DialogResult.OK){
                    wfrm_Download frm = new wfrm_Download(m_pFtp,(FTP_ListItem)m_pTabFtp_List.SelectedItems[0].Tag,dlg.FileName);
                    frm.ShowDialog(this);
                }
            }

            #endregion

            #region Delete file

            else if(e.ClickedItem.Text == "Delete file"){
                if(MessageBox.Show(this,"Are you sure you want to delete selected files ?","Confirm delete:",MessageBoxButtons.YesNo,MessageBoxIcon.Question) == DialogResult.Yes){
                    try{
                        while(m_pTabFtp_List.SelectedItems.Count > 0){
                            m_pFtp.DeleteFile(m_pTabFtp_List.SelectedItems[0].Text);
                            m_pTabFtp_List.SelectedItems[0].Remove();
                        }
                    }
                    catch(Exception x){
                        MessageBox.Show(this,"Error:\n" + x.ToString(),"Error:",MessageBoxButtons.OK,MessageBoxIcon.Error);
                    }
                }
            }

            #endregion

            #region method Rename file

            else if(e.ClickedItem.Text == "Rename file"){
                wfrm_Input frm = new wfrm_Input("Rename file",m_pTabFtp_List.SelectedItems[0].Text);
                if(frm.ShowDialog(this) == DialogResult.OK){
                    try{
                        FTP_ListItem currentListItem = (FTP_ListItem)m_pTabFtp_List.SelectedItems[0].Tag;
                        m_pFtp.Rename(m_pTabFtp_List.SelectedItems[0].Text,frm.Value);
                        m_pTabFtp_List.SelectedItems[0].Text = frm.Value;
                        m_pTabFtp_List.SelectedItems[0].Tag = new FTP_ListItem(frm.Value,currentListItem.Size,DateTime.Now,false);
                    }                    
                    catch(Exception x){
                        MessageBox.Show(this,"Error:\n" + x.ToString(),"Error:",MessageBoxButtons.OK,MessageBoxIcon.Error);
                    }
                }
            }

            #endregion
        }

        #endregion

        #endregion


        #region method FTP_WriteLog

        private delegate void AppendText(string text);

        /// <summary>
        /// This method is called when FTP client has new log entry.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void FTP_WriteLog(object sender,WriteLogEventArgs e)
        {
            try{
                if(e.LogEntry.EntryType == LogEntryType.Read){
                    m_pTabLog_LogText.Invoke(new AppendText(m_pTabLog_LogText.AppendText),ObjectToString(e.LogEntry.RemoteEndPoint) + " >> " + e.LogEntry.Text + "\r\n");
                }
                else if(e.LogEntry.EntryType == LogEntryType.Write){
                    m_pTabLog_LogText.Invoke(new AppendText(m_pTabLog_LogText.AppendText),ObjectToString(e.LogEntry.RemoteEndPoint) + " << " + e.LogEntry.Text + "\r\n");
                }
                else if(e.LogEntry.EntryType == LogEntryType.Text){
                    m_pTabLog_LogText.Invoke(new AppendText(m_pTabLog_LogText.AppendText),ObjectToString(e.LogEntry.RemoteEndPoint) + " xx " + e.LogEntry.Text + "\r\n");
                }
            }
            catch(Exception x){
                MessageBox.Show(x.ToString());
            }
        }

        #endregion


        #region method LoadCurrentFolder

        /// <summary>
        /// Loads FTP server current working directory items to UI.
        /// </summary>
        private void LoadCurrentFolder()
        {
            this.Cursor = Cursors.WaitCursor;

            try{
                m_pTabFtp_List.BeginUpdate();
                m_pTabFtp_List.Items.Clear();

                if(m_pFtp.GetCurrentDir().Length > 2){
                    m_pTabFtp_List.Items.Add("..",0);
                }
                foreach(FTP_ListItem listItem in m_pFtp.GetList()){
                    ListViewItem item = new ListViewItem(listItem.Name);
                    item.SubItems.Add(listItem.Modified.ToString());
                    if(listItem.IsDir){
                        item.SubItems.Add("Folder");
                    }
                    else{
                        item.SubItems.Add("File");
                    }
                    item.SubItems.Add(Convert.ToDecimal(listItem.Size / 1000).ToString("f2") + " kb");
                    if(listItem.IsDir){
                        item.ImageIndex = 1;
                    }
                    else{
                        item.ImageIndex = 2;
                    }
                    item.Tag = listItem;
                    m_pTabFtp_List.Items.Add(item);
                }

                m_pTabFtp_List.EndUpdate();
            }
            catch(Exception x){
                MessageBox.Show(this,"Error:\n" + x.ToString(),"Error:",MessageBoxButtons.OK,MessageBoxIcon.Error);
            }

            this.Cursor = Cursors.Default;
        }

        #endregion

        #region method ObjectToString

        /// <summary>
        /// Calls obj.ToSting() if obj is not null, otherwise returns "".
        /// </summary>
        /// <param name="obj">Object.</param>
        /// <returns>Returns obj.ToSting() if obj is not null, otherwise returns "".</returns>
        private string ObjectToString(object obj)
        {
            if(obj == null){
                return "";
            }
            else{
                return obj.ToString();
            }
        }

        #endregion

    }
}
