using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Windows.Forms;
using BitcasaDLL;

namespace bitcasaViewer
{
    class BitcasaServer
    {
        private BitcasaWrapper bitcasa = new BitcasaWrapper();
        public bool loadall_flag { get; protected set; }

        public delegate void delegateProgressBar(int v);

        public bool login()
        {
            return bitcasa.prepare();
        }

        public FileInfo reloadDir(string fullpath, delegateProgressBar callback)
        {
            lock (typeof(FileInfo))
            {
                fullpath = fullpath.TrimEnd('\\');
                FileInfo.dirLoaded[fullpath] = false;
                return loadDir(fullpath, callback);
            }
        }

        public FileInfo loadDir(string fullpath, delegateProgressBar callback)
        {
            lock (typeof(FileInfo))
            {
                fullpath = fullpath.TrimEnd('\\');
                var dirItem = FileInfo.dirTree[fullpath];
                if (!FileInfo.dirLoaded[fullpath])
                {
                    if (callback != null) callback(50);
                    var result = bitcasa.ListFolder(dirItem.path);
                    if (callback != null) callback(75);
                    FileInfo.dirLoaded[fullpath] = true;
                    var root = result["result"]["items"];
                    for (ulong i = 0; i < root.size; i++)
                    {
                        var item = root.Items(i);
                        FileInfo.GetItem((item as json_objectWrapper), "");
                    }
                }
                if (callback != null) callback(100);
                return dirItem;
            }
        }

        public void loadALL(delegateProgressBar callback)
        {
            lock (typeof(FileInfo))
            {
                FileInfo.clearDictionary();
                if (callback != null) callback(25);
                var result = bitcasa.ListFolder("/", true);
                var root = result["result"]["items"];
                if (callback != null) callback(75);
                FileInfo.dirLoaded[""] = true;
                FileInfo.dirLoaded["\\"] = true;
                for (ulong i = 0; i < root.size; i++)
                {
                    var item = root.Items(i);
                    var path = FileInfo.GetItem((item as json_objectWrapper), "").fullpath;
                    FileInfo.dirLoaded[path] = true;
                }
                loadall_flag = true;
                if (callback != null) callback(100);
            }
        }

        public FileInfo[] listChild(string parentpath)
        {
            lock (typeof(FileInfo))
            {
                ArrayList result = new ArrayList();
                foreach (var item in FileInfo.dirTree.SkipWhile(x => !x.Key.StartsWith(parentpath)).TakeWhile(x => x.Key.StartsWith(parentpath)))
                {
                    if ((item.Key != parentpath) && (item.Key.Substring(parentpath.Length + 1).IndexOf('\\') < 0))
                        result.Add(item.Value);
                }

                return (FileInfo[])result.ToArray(typeof(FileInfo));
            }
        }

        public bool download(FileInfo target, string localfilename, delegateProgressBar callback)
        {
            if (target.id == "") return false;
            return bitcasa.DownloadFile(
                target.id, 
                localfilename,
                target.size,
                new filetrans(
                    (Int64 pos)=>{
                        if (callback != null)
                        {
                            callback((int)(100.0 * pos / target.size));
                        }
                    })
                );
        }

        public bool upload(FileInfo targetdir, string localfilename, delegateProgressBar callback)
        {
            if(callback != null) callback(0);
            if (targetdir.path == "") return false;
            Int64 filesize = 1;
            return bitcasa.UploadFile(
                targetdir.path, 
                localfilename,
                new filetrans(
                    (Int64 pos) =>
                    {
                        if (callback != null)
                        {
                            if ((pos >= 0) && (filesize < pos)) filesize = pos;
                            if (pos < 0) callback((int)pos);
                            else callback((int)(100.0 * (filesize-pos) / filesize));
                        }
                    })
                );
        }

        public bool rename(FileInfo target, string newname, delegateProgressBar callback)
        {
            bool ret;
            if(callback != null) callback(0);
            if(newname == "") return false;
            if(callback != null) callback(25);
            if (target.category == "folders")
            {
                ret = bitcasa.RenameFolder(target.path, newname);
            }
            else
            {
                ret = bitcasa.RenameFile(target.path, newname);
            }
            lock (typeof(FileInfo))
            {
                FileInfo.dirTree.Remove(target.fullpath);
            }
            if(callback != null) callback(50);
            reloadDir(FileInfo.pathtoparent(target.path), null);
            if (callback != null) callback(100);
            return ret;
        }
        
        public bool moveitem(FileInfo[] oldpaths, FileInfo newpath, delegateProgressBar callback)
        {
            bool ret = true;
            int progress = 25;
            if(callback != null) callback(progress);
            if (newpath.path == "") return false;
            foreach(FileInfo oldpath in oldpaths){
                if (oldpath.category == "folders")
                {
                    ret = bitcasa.MoveFolder(oldpath.path, newpath.path, oldpath.name);
                }
                else
                {
                    ret = bitcasa.MoveFile(oldpath.path, newpath.path, oldpath.name);
                }
                lock (typeof(FileInfo))
                {
                    FileInfo.dirTree.Remove(oldpath.fullpath);
                }
                if (!ret) break;
                if (callback != null) callback(progress+=(50/oldpaths.Length));
            }
            reloadDir(newpath.fullpath, null);
            if(callback != null) callback(100);
            return ret;
        }
        
        public bool copyitem(FileInfo[] oldpaths, FileInfo newpath, delegateProgressBar callback)
        {
            bool ret = true;
            int progress = 25;
            if (callback != null) callback(progress);
            if (newpath.path == "") return false;
            foreach (FileInfo oldpath in oldpaths)
            {
                if (oldpath.category == "folders")
                {
                    ret = bitcasa.CopyFolder(oldpath.path, newpath.path, oldpath.name);
                }
                else
                {
                    ret = bitcasa.CopyFile(oldpath.path, newpath.path, oldpath.name);
                }
                lock (typeof(FileInfo))
                {
                    FileInfo.dirTree.Remove(oldpath.fullpath);
                }
                if (!ret) break;
                if (callback != null) callback(progress += (50 / oldpaths.Length));
            }
            reloadDir(newpath.fullpath, null);
            if (callback != null) callback(100);
            return ret;
        }

        public bool mkDir(FileInfo targetdir, string newname, delegateProgressBar callback)
        {
            bool ret;
            if (callback != null) callback(0);
            if (newname == "") return false;
            if (targetdir.category != "folders") return false;
            if (callback != null) callback(25);
            ret = bitcasa.AddFolder(targetdir.path, newname);
            if (callback != null) callback(50);
            lock (typeof(FileInfo))
            {
                reloadDir(FileInfo.pathtoparent(targetdir.path), null);
            }
            if (callback != null) callback(100);
            return ret;
        }
        public bool deleteitem(FileInfo[] targets, delegateProgressBar callback)
        {
            bool ret = true;
            int progress = 25;
            if (callback != null) callback(progress);
            foreach (FileInfo target in targets)
            {
                if (target.category == "folders")
                {
                    ret = bitcasa.DeleteFolder(target.path);
                }
                else
                {
                    ret = bitcasa._DeleteFile(target.path);
                }
                lock (typeof(FileInfo))
                {
                    FileInfo.dirTree.Remove(target.fullpath);
                }
                if (!ret) break;
                if (callback != null) callback(progress += (50 / targets.Length));
            }
            if (callback != null) callback(100);
            return ret;
        }
    }
}
