using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using BitcasaDLL;

namespace bitcasaViewer
{
    class LocalFileInfo
    {
        public string name;
        public Int64 size;
        public DateTime CreationTime;
        public DateTime LastWriteTime;

        public static List<LocalFileInfo> ListDir(string rootdir)
        {
            List<LocalFileInfo> diritem = new List<LocalFileInfo>();
            foreach (string entry in Directory.GetDirectories(rootdir))
            {
                LocalFileInfo aDir = new LocalFileInfo();
                var info = new DirectoryInfo(entry);
                aDir.name = info.FullName;
                aDir.CreationTime = info.CreationTime;
                aDir.LastWriteTime = info.LastWriteTime;
                diritem.Add(aDir);
                diritem.AddRange(ListDir(aDir.name));
            }
            foreach (string entry in Directory.GetFiles(rootdir))
            {
                LocalFileInfo aDir = new LocalFileInfo();
                var info = new FileInfo(entry);
                aDir.name = info.FullName;
                aDir.CreationTime = info.CreationTime;
                aDir.LastWriteTime = info.LastWriteTime;
                diritem.Add(aDir);
            }
            return diritem;
        }
    }

    public class BitcasaFileInfo
    {
        public static SortedDictionary<string, BitcasaFileInfo> dirTree;
        public static SortedDictionary<string, string> PathDirMap;
        public static SortedDictionary<string, bool> dirLoaded;
        public static SortedDictionary<string, BitcasaFileInfo> BitcasaDrive;
        public static void clearDictionary()
        {
            dirTree.Clear();
            PathDirMap.Clear();
            dirLoaded.Clear();
            BitcasaDrive.Clear();
            BitcasaFileInfo newItem = new BitcasaFileInfo();
            newItem.name = "\\";
            newItem.path = "/";
            dirTree[newItem.fullpath] = newItem;
            dirTree[""] = newItem;
            PathDirMap[""] = "";
            PathDirMap["/"] = "";
            dirLoaded[""] = false;
            dirLoaded["\\"] = false;
        }

        public string parentpath;
        public ListLocalBitcasa localinfo;
        //common
        public string category;
        public string name;
        public double mtime;
        public double ctime;
        public double birth_time;
        public string path;
        public int type;
        //folder
        public string mount_point;
        public bool mirrored;
        public string origin_device;
        public string origin_device_id;
        public string sync_type;
        //file
        public string manifest_name;
        public string id;
        public bool incomplete;
        public Int64 size;

        public string fullpath
        {
            get { return parentpath + name; }
        }

        static BitcasaFileInfo()
        {
            dirTree = new SortedDictionary<string, BitcasaFileInfo>();
            PathDirMap = new SortedDictionary<string, string>();
            dirLoaded = new SortedDictionary<string, bool>();
            BitcasaDrive = new SortedDictionary<string, BitcasaFileInfo>();
            clearDictionary();
        }

        public static string pathtoparent(string path)
        {
            lock (typeof(BitcasaFileInfo))
            {
                string parent = path.Substring(0, path.LastIndexOf('/'));
                return PathDirMap[parent] + "\\";
            }
        }
        public static string fullpathToBitcasaPath(string fullpath)
        {
            lock (typeof(BitcasaFileInfo))
            {
                var pos = fullpath.IndexOf("\\", 1);
                string parent = fullpath.Substring(0, (pos < 0)? 0: pos);
                string child = fullpath.Substring(parent.Length);
                if (parent == "")
                {
                    parent = child;
                    child = "";
                }
                BitcasaFileInfo rootitem;
                if (!dirTree.TryGetValue(parent, out rootitem)) return "";
                const string infstr = "Bitcasa Infinite Drive";
                if (rootitem.name == infstr)
                {
                    return (child == "") ? ("\\" + infstr) : ("\\" + infstr + child);
                }
                const string submount = "%%%HOME%%%/Bitcasa";
                if (rootitem.mount_point.IndexOf(submount) == 0)
                {
                    return "\\" + infstr + rootitem.mount_point.Substring(submount.Length).Replace('/', '\\') + child;
                }
                if (rootitem.mount_point != "")
                {
                    return "\\" + rootitem.name + child;
                }
                return "";
            }
        }

        public static BitcasaFileInfo GetItem(json_objectWrapper Item, string parent)
        {
            BitcasaFileInfo newItem = new BitcasaFileInfo();

            try
            {
                newItem.parentpath = (parent == "") ? pathtoparent(Item["path"].GetString()) : parent;

                jsonitemWrapper entry;
                entry = Item["category"];
                newItem.category = entry.GetString();
                entry = Item["name"];
                newItem.name = entry.GetString();
                entry = Item["mtime"];
                newItem.mtime = entry.GetDouble();
                entry = Item["ctime"];
                newItem.ctime = entry.GetDouble();
                entry = Item["birth_time"];
                newItem.birth_time = entry.GetDouble();
                entry = Item["path"];
                newItem.path = entry.GetString();
                entry = Item["type"];
                newItem.type = (int)entry.GetDouble();
                //folder
                entry = Item["mount_point"];
                newItem.mount_point = entry.GetString();
                entry = Item["mirrored"];
                newItem.mirrored = entry.GetBool();
                entry = Item["origin_device"];
                newItem.origin_device = entry.GetString();
                entry = Item["origin_device_id"];
                newItem.origin_device_id = entry.GetString();
                entry = Item["sync_type"];
                newItem.sync_type = entry.GetString();
                //file
                entry = Item["manifest_name"];
                newItem.manifest_name = entry.GetString();
                entry = Item["id"];
                newItem.id = entry.GetString();
                entry = Item["incomplete"];
                newItem.incomplete = entry.GetBool();
                entry = Item["size"];
                newItem.size = entry.GetInteger();

                lock (typeof(BitcasaFileInfo))
                {
                    dirTree[newItem.fullpath] = newItem;
                    PathDirMap[newItem.path] = newItem.fullpath;
                    dirLoaded[newItem.fullpath] = false;

                    BitcasaFileInfo olditem;
                    if (BitcasaDrive.TryGetValue(BitcasaFileInfo.fullpathToBitcasaPath(newItem.fullpath), out olditem))
                    {
                        newItem.localinfo = olditem.localinfo;
                    }
                    BitcasaDrive[BitcasaFileInfo.fullpathToBitcasaPath(newItem.fullpath)] = newItem;
                }
            }
            catch { return new BitcasaFileInfo(); }
            return newItem;
        }
        public static BitcasaFileInfo GetItem(json_objectWrapper Item)
        {
            return GetItem(Item, "\\");
        }
        private readonly static DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        public static string mtimeToString(double mtime)
        {
            DateTime mtime2 = UnixEpoch.AddMilliseconds(mtime).ToLocalTime();
            return mtime2.ToString("yyyy/MM/dd HH:mm:ss");
        }
        public static double DateTimeTomtime(DateTime t)
        {
            return t.ToUniversalTime().Subtract(UnixEpoch).TotalMilliseconds;
        }
    }
}
