using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections;
using System.Text.RegularExpressions;
using BitcasaDLL;

namespace bitcasaViewer
{
    public partial class Form1 : Form
    {
        private BitcasaServer bitcasa = new BitcasaServer();
        private ArrayList SelectedFiles = new ArrayList();
        private bool loadall_flag = false;
        private FormFind findform = new FormFind();
        private bool ongoing = false;

        public Form1()
        {
            InitializeComponent();
        }

        private void progress(int value)
        {
            toolStripProgressBar1.Value = value;
        }


        private void listFileItems(BitcasaFileInfo[] items, bool dotfiles)
        {
            listView1.BeginUpdate();
            listView1.Items.Clear();
            if (dotfiles)
            {
                string[] selfitem = { ".", "", "", "", "", "" };
                listView1.Items.Add(new ListViewItem(selfitem));
                string[] upitem = { "..", "", "", "", "", "" };
                listView1.Items.Add(new ListViewItem(upitem));
            }
            foreach (BitcasaFileInfo item in items)
            {
                string[] itemstr ={
                                       item.name,
                                       BitcasaFileInfo.mtimeToString(item.mtime),
                                       (item.category == "folders")? "<dir>": item.size.ToString(),
                                       item.fullpath,
                                       item.path,
                                       item.id
                                   };
                listView1.Items.Add(new ListViewItem(itemstr));
            }
            listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
            listView1.EndUpdate();
        }

        private void detailShowFileItems(BitcasaFileInfo item)
        {
            if (item == null) return;
            listBox1.Items.Clear();
            listBox1.Items.Add("category : " + item.category);
            listBox1.Items.Add("name : " + item.name);
            listBox1.Items.Add("path : " + item.path);
            listBox1.Items.Add("mtime : " + item.mtime.ToString());
            listBox1.Items.Add("        " + BitcasaFileInfo.mtimeToString(item.mtime));
            listBox1.Items.Add("type  : " + item.type.ToString());
            if (item.category == "folders")
            {
                listBox1.Items.Add("mount_point : " + item.mount_point);
                listBox1.Items.Add("mirrored : " + item.mirrored.ToString());
                listBox1.Items.Add("origin_device : " + item.origin_device);
                listBox1.Items.Add("origin_device_id : " + item.origin_device_id);
                listBox1.Items.Add("sync_type : " + item.sync_type);
            }
            else
            {
                listBox1.Items.Add("manifest_name : " + item.manifest_name);
                listBox1.Items.Add("id : " + item.id);
                listBox1.Items.Add("incomplete : " + item.incomplete.ToString());
                listBox1.Items.Add("size : " + item.size.ToString());
            }
            if (item.localinfo != null)
            {
                listBox1.Items.Add("local name : " + item.localinfo.name);
                listBox1.Items.Add("local size : " + item.localinfo.size);
                listBox1.Items.Add("local ctime : " + item.localinfo.CreationTime.ToString());
                listBox1.Items.Add("local mtime : " + item.localinfo.LastWriteTime.ToString());
            }
        }

        private BitcasaFileInfo SelectItemToFileinfo()
        {
            lock (typeof(BitcasaFileInfo))
            {
                var seletedItem = listView1.SelectedItems[0];
                var item = BitcasaFileInfo.dirTree[seletedItem.SubItems[3].Text];
                if (seletedItem.SubItems[0].Text == ".")
                {
                    item = BitcasaFileInfo.dirTree[treeView1.SelectedNode.FullPath.Substring(4)];
                }
                if (seletedItem.SubItems[0].Text == "..")
                {
                    var moveto = treeView1.SelectedNode.Parent;
                    if (moveto != null)
                        item = BitcasaFileInfo.dirTree[moveto.FullPath.Substring(4)];
                    else
                        item = BitcasaFileInfo.dirTree["\\"];
                }
                return item;
            }
        }

        public BitcasaFileInfo[] ListChildren(string parent)
        {
            lock (typeof(BitcasaFileInfo))
            {
                var treeparent = bitcasa.loadDir(parent, this.progress);
                return bitcasa.listChild(treeparent.fullpath);
            }
        }

        private void reloadview()
        {
            try
            {
                lock (bitcasa)
                {
                    if (ongoing)
                    {
                        MessageBox.Show("now processing...");
                        return;
                    }
                    var Node = treeView1.SelectedNode;
                    if (Node == null) return;
                    var selectItem = Node.FullPath.Substring(4);

                    toolStripStatusLabel1.Text = "loading...";
                    Update();
                    lock (typeof(BitcasaFileInfo))
                    {
                        try
                        {
                            Node.Nodes.Clear();
                            var treeitems = ListChildren(selectItem);
                            foreach (BitcasaFileInfo items in treeitems)
                            {
                                Node.Nodes.Add(items.name);
                            }
                            Node.Expand();

                            listFileItems(treeitems, true);
                        }
                        catch { return; }
                    }
                }
            }
            finally
            {
                toolStripStatusLabel1.Text = "";
            }
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            reloadview();
        }

        private void loginToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                lock (bitcasa)
                {
                    toolStripStatusLabel1.Text = "Login...";
                    Update();
                    progress(50);
                    if (!bitcasa.login())
                    {
                        MessageBox.Show("Login failed.");
                        progress(0);
                        return;
                    }
                    progress(100);
                    reloadToolStripMenuItem.Enabled = true;
                    scanAllToolStripMenuItem.Enabled = true;
                    treeView1.Nodes.Add("root");
                    loginToolStripMenuItem.Enabled = false;
                    loginToolStripMenuItem.Text = "done.";
                }
            }
            finally {
                toolStripStatusLabel1.Text = "";
            }
        }

        private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {
            lock (typeof(BitcasaFileInfo))
            {
                if (listView1.SelectedItems.Count > 1)
                {
                    listBox1.Items.Clear();
                    listBox1.Items.Add(listView1.SelectedItems.Count.ToString() + " items");
                    Int64 sizesum = 0;
                    int dircount = 0;
                    if (listView1.SelectedItems.Count > 1000) return;
                    foreach (ListViewItem selectitem in listView1.SelectedItems)
                    {
                        try
                        {
                            var item = BitcasaFileInfo.dirTree[selectitem.SubItems[3].Text];
                            sizesum += item.size;
                            if (item.category == "folders") dircount++;
                        }
                        catch { continue; }
                    }
                    listBox1.Items.Add(sizesum.ToString() + " bytes");
                    listBox1.Items.Add(dircount.ToString() + " dirs");
                    return;
                }
                else
                {
                    if (listView1.SelectedItems.Count == 0)
                    {
                        listBox1.Items.Clear();
                        return;
                    }
                    try
                    {
                        var item = BitcasaFileInfo.dirTree[listView1.SelectedItems[0].SubItems[3].Text];

                        if (listView1.SelectedItems[0].SubItems[0].Text == ".")
                        {
                            var self = treeView1.SelectedNode.FullPath.Substring(4);
                            if (self == "") return;
                            item = BitcasaFileInfo.dirTree[self];
                        }
                        if (listView1.SelectedItems[0].SubItems[0].Text == "..")
                        {
                            var upitem = treeView1.SelectedNode.Parent;
                            if (upitem == null) return;
                            var self = upitem.FullPath.Substring(4);
                            if (self == "") return;
                            item = BitcasaFileInfo.dirTree[self];
                        }
                        detailShowFileItems(item);
                    }
                    catch { return; }
                }
            }
        }

        private void decendTree(string fullpath)
        {
            if(fullpath == "") return;
            if (fullpath.StartsWith("\\"))
            {
                treeView1.SelectedNode = treeView1.Nodes[0];
                decendTree(fullpath.Substring(1));
                return;
            }
            var pos = fullpath.IndexOf('\\');
            var target = (pos < 0)? fullpath: fullpath.Substring(0, pos);
            foreach (TreeNode tn in treeView1.SelectedNode.Nodes)
            {
                if (tn.Text == target)
                {
                    treeView1.SelectedNode = tn;
                    if (pos > 0)
                        decendTree(fullpath.Substring(pos + 1));
                    return;
                }
            }
            treeView1.SelectedNode.Nodes.Add(target);
            if (pos > 0)
                decendTree(fullpath.Substring(pos + 1));
        }

        private void listView1_DoubleClick(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count == 1)
            {
                lock (typeof(BitcasaFileInfo))
                {
                    if (ongoing)
                    {
                        MessageBox.Show("now processing...");
                        return;
                    }
                    try
                    {
                        var item = listView1.SelectedItems[0].SubItems[0].Text;
                        if (item == ".") return;
                        if (item == "..")
                        {
                            var moveto = treeView1.SelectedNode.Parent;
                            if (moveto != null) treeView1.SelectedNode = moveto;
                            treeView1.Focus();
                            return;
                        }
                        var diritem = BitcasaFileInfo.dirTree[listView1.SelectedItems[0].SubItems[3].Text];
                        listView1.Items.Clear();
                        listView1.BeginUpdate();
                        decendTree(diritem.fullpath);
                        listView1.EndUpdate();
                        treeView1.Focus();
                    }
                    catch { return; }
                }
            }
        }

        private async void reloadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (ongoing)
            {
                MessageBox.Show("now processing...");
                return;
            }
            toolStripStatusLabel1.Text = "reload...";
            Update();
            var selectItem = treeView1.SelectedNode.FullPath.Substring(4);
            toolStripProgressBar1.Style = ProgressBarStyle.Marquee;
            ongoing = true;
            await Task.Run(
                () =>
                {
                    lock (bitcasa)
                    {
                        bitcasa.reloadDir(
                            selectItem,
                            (int p) => this.BeginInvoke(
                                (BitcasaServer.delegateProgressBar)(
                                            (int x) =>
                                            {
                                                progress(x);
                                            }),
                                        new object[] { p }
                            )
                        );
                    }
                });
            ongoing = false;
            toolStripProgressBar1.Style = ProgressBarStyle.Continuous;
            reloadview();
            toolStripStatusLabel1.Text = "";
        }

        private async void scanAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (ongoing)
            {
                MessageBox.Show("now processing...");
                return;
            }
            if (loadall_flag)
            {
                FindFiles();
                return;
            }
            toolStripStatusLabel1.Text = "search all subfolders...";
            Update();
            toolStripProgressBar1.Style = ProgressBarStyle.Marquee;
            ongoing = true;
            listView1.Enabled = false;
            treeView1.Enabled = false;
            await Task.Run(
                () =>
                {
                    lock (bitcasa)
                    {
                        bitcasa.loadALL(
                            (int p) => this.BeginInvoke(
                                (BitcasaServer.delegateProgressBar)(
                                            (int x) =>
                                            {
                                                progress(x);
                                            }),
                                        new object[] { p }
                            )
                        );
                    }
                });
            ongoing = false;
            listView1.Enabled = true;
            treeView1.Enabled = true;
            scanAllToolStripMenuItem.Text = "Find...";
            overlyToolStripMenuItem.Enabled = true;
            Update();
            loadall_flag = true;
            reloadview();
            toolStripProgressBar1.Style = ProgressBarStyle.Continuous;
            toolStripStatusLabel1.Text = "";
        }

        private bool Timetest(string key)
        {
            if (findform.datemin != FormFind.InvalidDate)
            {
                if (BitcasaFileInfo.DateTimeTomtime(findform.datemin) > BitcasaFileInfo.dirTree[key].mtime)
                {
                    return false;
                }
            }
            if (findform.datemax != FormFind.InvalidDate)
            {
                if (BitcasaFileInfo.DateTimeTomtime(findform.datemax) < BitcasaFileInfo.dirTree[key].mtime)
                {
                    return false;
                }
            }
            return true;
        }
        private bool Sizetest(string key)
        {
            lock (typeof(BitcasaFileInfo))
            {
                if (findform.sizemin >= 0)
                {
                    if (findform.sizemin > BitcasaFileInfo.dirTree[key].size)
                    {
                        return false;
                    }
                }
                if (findform.sizemax >= 0)
                {
                    if (findform.sizemax < BitcasaFileInfo.dirTree[key].size)
                    {
                        return false;
                    }
                }
                return true;
            }
        }

        private void FindFiles()
        {
            if (findform.ShowDialog() == DialogResult.OK)
            {
                lock (typeof(BitcasaFileInfo))
                {
                    toolStripStatusLabel1.Text = "find...";
                    Update();

                    ArrayList hit = new ArrayList();
                    progress(25);
                    toolStripProgressBar1.Style = ProgressBarStyle.Marquee;
                    listView1.Items.Clear();
                    if (findform.IsRegular)
                    {
                        Regex regtest = new Regex(findform.findstr);
                        foreach (string key in BitcasaFileInfo.dirTree.Keys)
                        {
                            if (!regtest.IsMatch(key))
                                continue;
                            if (!Sizetest(key))
                                continue;
                            if (!Timetest(key))
                                continue;
                            hit.Add(BitcasaFileInfo.dirTree[key]);
                        }
                    }
                    else
                    {
                        foreach (string key in BitcasaFileInfo.dirTree.Keys)
                        {
                            if (key.IndexOf(findform.findstr) < 0)
                                continue;
                            if (!Sizetest(key))
                                continue;
                            if (!Timetest(key))
                                continue;
                            hit.Add(BitcasaFileInfo.dirTree[key]);
                        }
                    }
                    progress(50);
                    listFileItems((BitcasaFileInfo[])hit.ToArray(typeof(BitcasaFileInfo)), false);
                    progress(100);
                    toolStripProgressBar1.Style = ProgressBarStyle.Continuous;
                    toolStripStatusLabel1.Text = "";
                }
            }
        }

        private void biToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (ongoing)
            {
                MessageBox.Show("now processing...");
                return;
            }
            const string infstr = "Bitcasa Infinite Drive";
            lock (typeof(BitcasaFileInfo))
            {
                using (var diff = new FormDiff())
                {
                    progress(50);
                    toolStripStatusLabel1.Text = "loading...";
                    Update();
                    diff.diff("I:\\", "\\" + infstr, true);
                    diff.ShowDialog();
                }

                progress(100);
                toolStripStatusLabel1.Text = "";
            }
        }

        private void otherToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (ongoing)
            {
                MessageBox.Show("now processing...");
                return;
            }
            lock (typeof(BitcasaFileInfo))
            {
                string left;
                string right;
                using (var selecttree = new BitcasaTreeSelect(this))
                {
                    if (selecttree.ShowDialog() != DialogResult.OK) return;
                    right = selecttree.SelectedPath;
                }
                if (right == "") right = "\\";
                using (var localtree = new FolderBrowserDialog())
                {
                    localtree.Description = "Select local root folder";
                    if (localtree.ShowDialog() != DialogResult.OK) return;
                    left = localtree.SelectedPath;
                }

                using (var diff = new FormDiff())
                {
                    progress(50);
                    toolStripStatusLabel1.Text = "loading...";
                    Update();
                    diff.diff(left + "\\", right, false);
                    diff.ShowDialog();
                }

                progress(100);
                toolStripStatusLabel1.Text = "";
            }
        }

    }
}
