using BookmarkManager;
using bzit.bomg.Models;
using FizzyLauncher.Models;
using Newtonsoft.Json;
using RyzStudio.Drawing;
using RyzStudio.Windows.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FizzyLauncher
{
    public partial class MainForm : Form
    {
        public enum AppMode
        {
            Clear = 0,
            Open,
            New
        }


        protected IconDatabase iconDatabase = null;
        protected UpdateIconsForm updateIconsForm = null;
        protected OptionsForm optionsForm = null;
        protected FindForm findForm = null;

        protected AppMode appMode = AppMode.Clear;
        protected string sessionFilename = null;
        protected string sessionPassword = null;
        protected bool isBusy = false;

        protected readonly string jsonfigFilename;


        public MainForm()
        {
            InitializeComponent();

            jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig");

            if (iconDatabase == null) iconDatabase = new IconDatabase(Path.ChangeExtension(Application.ExecutablePath, "db"));

            this.AutoScaleMode = AutoScaleMode.None;
            this.StartPosition = FormStartPosition.WindowsDefaultLocation;
            this.ClientSize = new System.Drawing.Size(300, 580);
            //this.Visible = false;

            treeView1.IconDatabase = iconDatabase;
            treeView1.RootContextMenu = rootContextMenu;
            treeView1.FolderContextMenu = folderContextMenu;
            treeView1.PageContextMenu = pageContextMenu;
            treeView1.NodeMouseDoubleClick += treeView1_NodeMouseDoubleClick;
            treeView1.OnNodeChanged += treeView1_OnNodeChanged;
            treeView1.PreviewKeyDown += treeView1_PreviewKeyDown;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            //ThreadControl.SetVisible(this, false);
            UIControl.SetSize(this, 300, 580);

            List<string> supportedFileExtensions = GetSupportedFileTypes();

            openFileDialog1.Filter = BuildOpenFileSupportedFiles(supportedFileExtensions);
            saveFileDialog1.Filter = BuildSaveFileSupportedFiles(supportedFileExtensions);

            ApplicationMode = AppMode.Clear;
        }

        protected async override void OnShown(EventArgs e)
        {
            base.OnShown(e);

            //ThreadControl.SetVisible(this, false);

            await LoadAppSession(jsonfigFilename);

            InvalidateAppSession();

            string[] commandLineArgs = Environment.GetCommandLineArgs();

            bool hasCommands = await LoadCommandLine(commandLineArgs);
            if (!hasCommands)
            {
                newToolStripMenuItem_Click(null, null);
            }
        }

        protected async override void OnClosing(CancelEventArgs e)
        {
            e.Cancel = true;

            if (this.IsBusy)
            {
                return;
            }

            this.IsBusy = true;

            Result result = await CloseFile();
            if (!result.IsSuccess)
            {
                if (!string.IsNullOrWhiteSpace(result.Message))
                {
                    MessageBox.Show(result.Message, "Close", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                this.IsBusy = false;

                e.Cancel = true;

                return;
            }

            sessionFilename = null;
            sessionPassword = null;

            treeView1.Clear();
            iconDatabase?.Close();

            ApplicationMode = AppMode.Clear;

            this.IsBusy = false;

            Application.Exit();
        }

        public AppSession CurrentSession { get; set; } = null;

        public bool IsBusy
        {
            get => isBusy;
            set
            {
                treeView1.Enabled = !value;
            }
        }

        protected AppMode ApplicationMode
        {
            get => appMode;
            set
            {
                appMode = value;

                switch (value)
                {
                    case AppMode.Clear:
                        UIControl.SetText(this, AppResource.app_name);

                        UIControl.SetEnable(false, closeToolStripMenuItem, saveToolStripMenuItem, saveAsToolStripMenuItem, findToolStripMenuItem, toolStripMenuItem9, expandAllToolStripMenuItem, collapseAllToolStripMenuItem);
                        UIControl.SetEnable(false, toolStripButton3, toolStripButton4);
                        break;
                    case AppMode.Open:
                        UIControl.SetEnable(true, closeToolStripMenuItem, saveToolStripMenuItem, saveAsToolStripMenuItem, findToolStripMenuItem, toolStripMenuItem9, expandAllToolStripMenuItem, collapseAllToolStripMenuItem);
                        UIControl.SetEnable(true, toolStripButton3, toolStripButton4);
                        break;
                    case AppMode.New:
                        UIControl.SetText(this, AppResource.app_name);

                        UIControl.SetEnable(true, closeToolStripMenuItem, saveAsToolStripMenuItem, findToolStripMenuItem, toolStripMenuItem9, expandAllToolStripMenuItem, collapseAllToolStripMenuItem);
                        UIControl.SetEnable(saveToolStripMenuItem, false);
                        UIControl.SetEnable(toolStripButton3, false);
                        UIControl.SetEnable(toolStripButton4, true);

                        break;
                    default: break;
                }
            }
        }


#region main menu

        /// <summary>
        /// New
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            this.IsBusy = true;

            Result result = await CloseFile();
            if (!result.IsSuccess)
            {
                if (!string.IsNullOrWhiteSpace(result.Message))
                {
                    MessageBox.Show(result.Message, "New Session", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                this.IsBusy = false;
                return;
            }

            sessionFilename = null;
            sessionPassword = null;

            treeView1.Clear("Untitled");

            ApplicationMode = AppMode.New;

            this.IsBusy = false;
        }

        /// <summary>
        /// Open file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            this.IsBusy = true;

            Result result = await CloseFile();
            if (!result.IsSuccess)
            {
                if (!string.IsNullOrWhiteSpace(result.Message))
                {
                    MessageBox.Show(result.Message, "Open File", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                this.IsBusy = false;
                return;
            }

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                result = await LoadFile(openFileDialog1.FileName);
                if (result.IsSuccess)
                {
                    UIControl.SetText(this, Path.GetFileNameWithoutExtension(openFileDialog1.FileName) + " - " + AppResource.app_name);
                }
                else
                {
                    MessageBox.Show(result.Message, "Open File", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

            this.IsBusy = false;
        }

        /// <summary>
        /// Close
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            this.IsBusy = true;

            Result result = await CloseFile();
            if (!result.IsSuccess)
            {
                if (!string.IsNullOrWhiteSpace(result.Message))
                {
                    MessageBox.Show(result.Message, "Close File", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                this.IsBusy = false;
                return;
            }

            sessionFilename = null;
            sessionPassword = null;

            treeView1.Clear();

            ApplicationMode = AppMode.Clear;

            this.IsBusy = false;
        }

        /// <summary>
        /// Save
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            if (ApplicationMode == AppMode.Clear)
            {
                return;
            }

            this.IsBusy = true;

            Result result = await SaveFile(sessionFilename, sessionPassword);
            if (result.IsSuccess)
            {
                MessageBox.Show("File saved!", "Save File", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                MessageBox.Show(result.Message, "Save File", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            this.IsBusy = false;
        }

        /// <summary>
        /// Save As
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            if (ApplicationMode == AppMode.Clear)
            {
                return;
            }

            this.IsBusy = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                Result result = await SaveAsFile(saveFileDialog1.FileName);
                if (result.IsSuccess)
                {
                    MessageBox.Show("File saved!", "Save As File", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    MessageBox.Show(result.Message, "Save As File", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

            }

            this.IsBusy = false;
        }

        /// <summary>
        /// Exit
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            this.Close();
        }

        /// <summary>
        /// Find
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void findToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            if (findForm == null) findForm = new FindForm(treeView1);
            findForm.Show();
        }


        /// <summary>
        /// Expand all
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void expandAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy) return;
            if (ApplicationMode == AppMode.Clear) return;

            if (treeView1.SelectedNode == null)
            {
                treeView1.ExpandAll();
            }
            else
            {
                treeView1.SelectedNode.ExpandAll();
            }
        }

        /// <summary>
        /// Collapse all
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void collapseAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy) return;
            if (ApplicationMode == AppMode.Clear) return;

            if (treeView1.SelectedNode == null)
            {
                treeView1.CollapseAll();
            }
            else
            {
                treeView1.SelectedNode.Collapse(false);
            }
        }

        /// <summary>
        /// Always on top
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void alwaysOnTopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.TopMost = !this.TopMost;

            alwaysOnTopToolStripMenuItem.Checked = this.TopMost;
        }


        /// <summary>
        /// Update icons
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripMenuItem9_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            if (updateIconsForm == null) updateIconsForm = new UpdateIconsForm(this.CurrentSession, treeView1, iconDatabase);
            updateIconsForm.ShowDialog();
        }

        /// <summary>
        /// Options
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            if (optionsForm == null) optionsForm = new OptionsForm(this);
            if (optionsForm.ShowDialog() == DialogResult.OK)
            {
                await SaveAppSession(jsonfigFilename);
            }

            InvalidateAppSession();
        }


        /// <summary>
        /// View help
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void viewHelpToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            try
            {
                System.Diagnostics.Process.Start("https://www.hiimray.co.uk/software-bookmark-manager");
            }
            catch
            {
                // do nothing
            }
        }

        /// <summary>
        /// About
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            MessageBox.Show(Application.ProductName + " v" + Application.ProductVersion, "About", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

#endregion

#region context menu

        /// <summary>
        /// Add page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addPageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            if (treeView1.GetNodeType() == BookmarkTreeView.NodeType.Page)
            {
                return;
            }

            if (treeView1.SelectedNode == null)
            {
                return;
            }

            // add placeholder
            TreeNode node = treeView1.AddItem(treeView1.SelectedNode, new BookmarkItem()
            {
                SiteName = "New Bookmark"
            });
            node.EnsureVisible();
            treeView1.SelectedNode = node;

            UpdateBookmarkNode(true);
        }

        /// <summary>
        /// Add folder
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addFolderToolStripMenuItem_Click(object sender, EventArgs e) => treeView1.AddFolder();

        /// <summary>
        /// Edit root node
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void editToolStripMenuItem_Click(object sender, EventArgs e) => treeView1.EditNode();

        /// <summary>
        /// Sort
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sortToolStripMenuItem_Click(object sender, EventArgs e) => treeView1.Sort();


        /// <summary>
        /// Add page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addPageToolStripMenuItem1_Click(object sender, EventArgs e) => addPageToolStripMenuItem_Click(sender, e);

        /// <summary>
        /// Add folder
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addFolderToolStripMenuItem1_Click(object sender, EventArgs e) => treeView1.AddFolder();

        /// <summary>
        /// Open all pages
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void openAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            if (treeView1.SelectedNode == null)
            {
                return;
            }

            if (treeView1.SelectedNode.Nodes.Count <= 0)
            {
                return;
            }

            foreach (TreeNode item in treeView1.SelectedNode.Nodes)
            {
                await OpenBookmark(item);
            }
        }

        /// <summary>
        /// Edit folder name
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void editToolStripMenuItem1_Click(object sender, EventArgs e) => treeView1.EditNode();

        /// <summary>
        /// Delete folder and contents
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void deleteToolStripMenuItem_Click(object sender, EventArgs e) => treeView1.DeleteNode();

        /// <summary>
        /// Sort children
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sortToolStripMenuItem1_Click(object sender, EventArgs e) => treeView1.Sort();

        /// <summary>
        /// Move up
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void moveUpToolStripMenuItem_Click(object sender, EventArgs e) => treeView1.MoveUp();

        /// <summary>
        /// Move down
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void moveDownToolStripMenuItem_Click(object sender, EventArgs e) => treeView1.MoveDown();


        /// <summary>
        /// Open page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void openToolStripMenuItem1_Click(object sender, EventArgs e) => await OpenBookmark(treeView1.SelectedNode);

        /// <summary>
        /// Edit page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void editToolStripMenuItem2_Click(object sender, EventArgs e)
        {
            if (this.IsBusy)
            {
                return;
            }

            BookmarkTreeView.NodeType nodeType = treeView1.GetNodeType();
            if (nodeType == BookmarkTreeView.NodeType.Page)
            {
                UpdateBookmarkNode(false);
            }
        }

        /// <summary>
        /// Delete page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void deleteToolStripMenuItem1_Click(object sender, EventArgs e) => treeView1.DeleteNode();

        /// <summary>
        /// Move up
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void moveUpToolStripMenuItem1_Click(object sender, EventArgs e) => treeView1.MoveUp();

        /// <summary>
        /// Move down
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void moveDownToolStripMenuItem1_Click(object sender, EventArgs e) => treeView1.MoveDown();

#endregion


        private async void treeView1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            TreeNode tn = treeView1.SelectedNode;
            if (tn == null)
            {
                return;
            }

            BookmarkTreeView.NodeType nodeType = treeView1.GetNodeType();

            switch (e.KeyCode)
            {
                case Keys.Enter:
                    await OpenBookmark(tn);
                    break;
                case Keys.F2:
                    editToolStripMenuItem2_Click(sender, null);
                    break;
                case Keys.Insert:
                    if (e.Modifiers != Keys.Shift)
                    {
                        if ((nodeType == BookmarkTreeView.NodeType.Root) || (nodeType == BookmarkTreeView.NodeType.Folder))
                        {
                            // do nothing
                        }
                        else if (nodeType == BookmarkTreeView.NodeType.Page)
                        {
                            treeView1.SelectedNode = tn.Parent;
                        }

                        addPageToolStripMenuItem_Click(sender, null);
                    }

                    break;
                default: break;
            }
        }

        private async void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) => await OpenBookmark(e.Node);

        private void treeView1_OnNodeChanged(object sender, EventArgs e)
        {
            bool state = (treeView1.HasChanged && ApplicationMode == AppMode.Open);

            UIControl.SetEnable(saveToolStripMenuItem, state);
            UIControl.SetEnable(toolStripButton3, state);
        }

        protected string BuildOpenFileSupportedFiles(List<string> supportList)
        {
            StringBuilder rs = new StringBuilder();
            rs.Append("All supported files (*" + string.Join("; *", supportList) + ")");
            rs.Append("|*" + string.Join(";*", supportList));

            for (int i = 0; i < supportList.Count; i++)
            {
                rs.Append("|" + supportList[i].TrimStart('.')?.ToUpper() + " Bookmark files");
                rs.Append("|*" + supportList[i]);
            }

            return rs.ToString();
        }

        protected string BuildSaveFileSupportedFiles(List<string> supportList)
        {
            StringBuilder rs = new StringBuilder();

            for (int i = 0; i < supportList.Count; i++)
            {
                if (i > 0) rs.Append("|");

                rs.Append(supportList[i].TrimStart('.')?.ToUpper() + " Bookmark file");
                rs.Append("|*" + supportList[i]);
            }

            return rs.ToString();
        }

        protected async Task<Result> CloseFile()
        {
            return await Task.Run<Result>(async () =>
            {
                if (this.ApplicationMode == AppMode.Clear)
                {
                    return Result.Create(true);
                }

                if (!treeView1.HasChanged)
                {
                    return Result.Create(true);
                }

                if (this.ApplicationMode == AppMode.New)
                {
                    DialogResult response = MessageBox.Show("Save bookmarks", "Save?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                    if (response == DialogResult.Yes)
                    {
                        Result result = await SaveAsFile(sessionFilename);
                        if (!result.IsSuccess)
                        {
                            return Result.Create(false, result.Message);
                        }
                    }
                    else if (response == DialogResult.Cancel)
                    {
                        return Result.Create(false, "");
                    }
                }
                else if (this.ApplicationMode == AppMode.Open)
                {
                    DialogResult response = MessageBox.Show("Save changes to open bookmarks", "Save?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                    if (response == DialogResult.Yes)
                    {
                        Result result = await SaveFile(sessionFilename, sessionPassword);
                        if (!result.IsSuccess)
                        {
                            return Result.Create(false, result.Message);
                        }
                    }
                    else if (response == DialogResult.Cancel)
                    {
                        return Result.Create(false, "");
                    }
                }

                return Result.Create(true);
            });
        }

        protected SupportedFileBase GetSupportedFileHandler(string filename)
        {
            SupportedFileBase rs = null;

            List<Type> typeList = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsSubclassOf(typeof(SupportedFileBase))).ToList();
            foreach (Type t in typeList)
            {
                rs = (SupportedFileBase)Activator.CreateInstance(t);
                if (rs == null)
                {
                    continue;
                }

                if (rs.IsSupported(filename))
                {
                    break;
                }

                rs = null;
            }

            return rs;
        }

        protected List<string> GetSupportedFileTypes()
        {
            List<string> rs = new List<string>();

            List<Type> typeList = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsSubclassOf(typeof(SupportedFileBase))).ToList();
            foreach (Type t in typeList)
            {
                SupportedFileBase fileHandler = (SupportedFileBase)Activator.CreateInstance(t);
                if (fileHandler == null)
                {
                    continue;
                }

                rs.AddRange(fileHandler.SupportedExtensions ?? new List<string>());
            }

            return rs;
        }

        protected void InvalidateAppSession()
        {
            if (CurrentSession == null) CurrentSession = new AppSession();

            if (CurrentSession.EnableAutoPosition)
            {
                this.Height = Screen.PrimaryScreen.WorkingArea.Height;
                this.Location = Screen.PrimaryScreen.WorkingArea.Location;
            }

            toolStrip1.Visible = CurrentSession.ShowToolbar;

            this.TopMost = CurrentSession.AlwaysOnTop;
        }

        protected async Task<bool> LoadAppSession(string filename)
        {
            return await Task.Run(() =>
            {
                if (File.Exists(filename))
                {
                    string sourceCode = null;

                    try
                    {
                        sourceCode = File.ReadAllText(filename);
                    }
                    catch (Exception)
                    {
                        // do nothing
                    }

                    if (string.IsNullOrWhiteSpace(sourceCode))
                    {
                        this.CurrentSession = new AppSession();
                        return false;
                    }

                    try
                    {
                        this.CurrentSession = JsonConvert.DeserializeObject<AppSession>(sourceCode);
                    }
                    catch (Exception)
                    {
                        this.CurrentSession = null;
                    }

                    if (this.CurrentSession == null)
                    {
                        this.CurrentSession = new AppSession();
                        return false;
                    }
                }
                else
                {
                    this.CurrentSession = new AppSession();

                    try
                    {
                        File.WriteAllText(filename, JsonConvert.SerializeObject(this.CurrentSession));
                    }
                    catch (Exception)
                    {
                        // do nothing
                    }
                }

                return true;
            });
        }

        protected async Task<bool> LoadCommandLine(string[] args)
        {
            bool rs = false;

            if (args.Length > 1)
            {
                int i = 1;
                while (true)
                {
                    if (i > (args.Length - 1))
                    {
                        break;
                    }

                    switch (args[i].Trim().ToLower())
                    {
                        case "-o":
                        case "-open":
                            if ((i + 1) > (args.Length - 1)) break;

                            string openFilename = args[(i + 1)];
                            if (string.IsNullOrWhiteSpace(openFilename)) break;
                            if (!File.Exists(openFilename)) break;

                            await LoadFile(openFilename);

                            //LoadBookmarksForm loadFileForm = new LoadBookmarksForm(this, openFilename);
                            //loadFileForm.ShowDialog();

                            rs = true;

                            i++;
                            break;
                    }

                    i++;
                }
            }

            return rs;
        }

        protected async Task<Result> LoadFile(string filename)
        {
            return await Task.Run(() =>
            {
                sessionFilename = null;
                sessionPassword = null;
                ApplicationMode = AppMode.Clear;

                treeView1.Clear();

                if (string.IsNullOrWhiteSpace(filename))
                {
                    return Result.Create(false, "Filename is empty");
                }

                if (!File.Exists(filename))
                {
                    return Result.Create(false, "File not found");
                }

                sessionFilename = filename;

                SupportedFileBase fileHandler = GetSupportedFileHandler(sessionFilename);
                if (fileHandler == null)
                {
                    return Result.Create(false, "Handler not found for this file type");
                }

                if (fileHandler.IsEncrypted(sessionFilename))
                {
                    PasswordForm passwordForm = new PasswordForm();
                    if (passwordForm.ShowDialog() == DialogResult.OK)
                    {
                        sessionPassword = passwordForm.Password;
                    }
                }

                Result result = fileHandler.Load(treeView1, sessionFilename, sessionPassword);
                if (!result.IsSuccess)
                {
                    return result;
                }

                if (treeView1.Nodes.Count > 0)
                {
                    UIControl.Expand(treeView1.Nodes[0]);
                }

                ApplicationMode = AppMode.Open;

                if (result.IsSuccess)
                {
                    treeView1.SetNoChanges();
                }

                UIControl.SetFocus(treeView1);

                return result;
            });
        }

        protected async Task OpenBookmark(TreeNode node)
        {
            await Task.Run(() =>
            {
                if (BookmarkTreeView.GetNodeType(node) != BookmarkTreeView.NodeType.Page)
                {
                    return;
                }

                BookmarkItem viewModel = (BookmarkItem)node.Tag;
                if (viewModel == null)
                {
                    return;
                }

                if (string.IsNullOrWhiteSpace(viewModel.SiteAddress))
                {
                    return;
                }

                string cmd = (string.IsNullOrWhiteSpace(CurrentSession.RunCommand) ? viewModel.SiteAddress : CurrentSession.RunCommand.Replace("{0}", viewModel.SiteAddress));

                try
                {
                    System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo
                    {
                        FileName = cmd,
                        UseShellExecute = true
                    };
                    System.Diagnostics.Process.Start(psi);
                }
                catch (Exception exc)
                {
#if DEBUG
                    MessageBox.Show(exc.Message);
#endif
                }
            });
        }

        protected async Task<Result> SaveFile(string filename, string password = null)
        {
            return await Task.Run(() =>
            {
                if (string.IsNullOrWhiteSpace(filename))
                {
                    return Result.Create(false, "Filename is empty");
                }

                SupportedFileBase fileHandler = GetSupportedFileHandler(filename);
                if (fileHandler == null)
                {
                    return Result.Create(false, "Handler not found for this file type");
                }

                Result result = fileHandler.Save(treeView1, filename, password);
                if (result.IsSuccess)
                {
                    treeView1.SetNoChanges();
                }

                return result;
            });
        }

        protected async Task<bool> SaveAppSession(string filename)
        {
            return await Task.Run(() =>
            {
                if (this.CurrentSession == null) this.CurrentSession = new AppSession();

                try
                {
                    File.WriteAllText(filename, JsonConvert.SerializeObject(this.CurrentSession));
                }
                catch (Exception)
                {
                    return false;
                }

                return true;
            });
        }

        protected async Task<Result> SaveAsFile(string filename)
        {
            return await Task.Run(() =>
            {
                if (string.IsNullOrWhiteSpace(filename))
                {
                    return Result.Create(false, "Filename is empty");
                }

                SupportedFileBase fileHandler = GetSupportedFileHandler(filename);
                if (fileHandler == null)
                {
                    return Result.Create(false, "Handler not found for this file type");
                }

                string password = null;

                if (fileHandler.IsEncryptionSupported)
                {
                    PasswordForm passwordForm = new PasswordForm();
                    if (passwordForm.ShowDialog() == DialogResult.OK)
                    {
                        if (!string.IsNullOrWhiteSpace(passwordForm.Password))
                        {
                            password = passwordForm.Password;
                        }
                    }
                }

                Result result = fileHandler.Save(treeView1, filename, password);
                if (result.IsSuccess)
                {
                    this.ApplicationMode = AppMode.Open;
                    sessionFilename = filename;
                    sessionPassword = password;

                    treeView1.SetNoChanges();
                }

                return result;
            });
        }

        protected void UpdateBookmarkNode(bool deleteOnCancel)
        {
            BookmarkItem model = treeView1.GetNodeModel();
            Image icon = null;

            // retrieve icon from DB
            string iconID = model?.ToHash();

            icon = iconDatabase.FindIcon(iconID);

            BookmarkForm bookmarkForm = new BookmarkForm(this.CurrentSession, model, icon);
            if (bookmarkForm.ShowDialog() == DialogResult.OK)
            {
                //string iconID = bookmarkForm.Model.Item?.ToHash();
                iconID = bookmarkForm.Model.Item?.ToHash();
                if (!string.IsNullOrWhiteSpace(iconID))
                {
                    iconDatabase.AddIcon(iconID, bookmarkForm.Model.Icon);
                }

                treeView1.UpdateItem(treeView1.SelectedNode, bookmarkForm.Model.Item);
            }
            else
            {
                if (deleteOnCancel)
                {
                    treeView1.SelectedNode.Remove();
                }
            }
        }

    }
}