using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml;
using System.IO;

namespace OBJ_FileBus
{
    public class Converter
    {
        public static string BytesToString(byte[] bytes)
        {
            return FObjBase.Converter.BytesToString(bytes);
        }
        public static byte[] StringToBytes(string str)
        {
            return FObjBase.Converter.StringToBytes(str);
        }
        public static string DateTimeToString(DateTime dt)
        {
            return FObjBase.Converter.DateTimeToString(dt);
        }
    }
    /// <summary>
    /// 就只是提供给Server 使用
    /// </summary>
    public class FileSystemInfoRW
    {
        #region 获取文件信息

        public static bool GetInfo(string path, out FileAttributes fileattr, out DateTime createtime, out DateTime lastwritetime, out int size) 
        {
            string filePath = path;
            fileattr = FileAttributes.Normal;
            createtime = DateTime.MinValue;
            lastwritetime = DateTime.MinValue;
            size = 0;
            if (Directory.Exists(filePath))
            {
                DirectoryInfo info = new DirectoryInfo(filePath);
                fileattr = FileAttributes.Directory;
                createtime = info.CreationTime;
                lastwritetime = info.LastWriteTime;
                return true;
            }
            else if (File.Exists(filePath))
            {
                FileInfo info = new FileInfo(filePath);
                fileattr = FileAttributes.Normal;
                createtime = info.CreationTime;
                lastwritetime = info.LastWriteTime;
                size = (int)info.Length;
                return true;
            }
            else
            {
                return false;
            }
        }
        public static DateTime GetLastWriteTime(string path) 
        {
            FileAttributes fileattr;
            DateTime createtime;
            DateTime lastwritetime;
            int size;
            if (GetInfo(path, out fileattr, out createtime, out lastwritetime, out size)) 
            {
                return lastwritetime;
            }
            return DateTime.MinValue;
        }
        #endregion
        #region 获取文件内容
        public enum OptFileContentResult
        {
            /// <summary>
            /// GUID出错
            /// </summary>
            GUIDErr,
            /// <summary>
            /// 不能写
            /// </summary>
            CanntWrite,
            /// <summary>
            /// 不存在
            /// </summary>
            NoExist,
            /// <summary>
            /// 成功
            /// </summary>            
            OK,
            /// <summary>
            /// 正在写,或正在读
            /// </summary>            
            Doing
        }
        /// <summary>
        /// 获取文件夹 内容,输出 xml 的byte[]
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private OptFileContentResult GetDirectoryContent(string path, ref string guid, UInt16 package_size, out byte[] buf, out UInt32 filesize)
        {
            filesize = 0;
            string filePath = path;
            buf = null;
            DirectoryInfo dinfo;
            XmlDocument xmlDoc = new XmlDocument(); //load xml
            XmlElement xmlElem;


            dinfo = new DirectoryInfo(filePath);
            xmlElem = xmlDoc.CreateElement(FileAttributes.Directory.ToString());
            xmlElem.SetAttribute("name", dinfo.Name);
            xmlElem.SetAttribute("ctime", dinfo.CreationTime.ToString());
            xmlElem.SetAttribute("mtime", dinfo.LastWriteTime.ToString());
            xmlDoc.AppendChild(xmlElem);

            foreach (FileInfo info in dinfo.GetFiles())
            {
                XmlElement xmlElem1 = xmlDoc.CreateElement(FileAttributes.Normal.ToString());

                xmlElem1.SetAttribute("name", info.Name);
                xmlElem1.SetAttribute("ctime", info.CreationTime.ToString());
                xmlElem1.SetAttribute("mtime", info.LastWriteTime.ToString());
                xmlElem1.SetAttribute("size", info.Length.ToString());
                xmlElem.AppendChild(xmlElem1);
            }
            foreach (DirectoryInfo info in dinfo.GetDirectories())
            {
                XmlElement xmlElem1 = xmlDoc.CreateElement(FileAttributes.Directory.ToString());

                xmlElem1.SetAttribute("name", info.Name);
                xmlElem1.SetAttribute("ctime", info.CreationTime.ToString());
                xmlElem1.SetAttribute("mtime", info.LastWriteTime.ToString());
                xmlElem.AppendChild(xmlElem1);
            }
            buf = Converter.StringToBytes(xmlDoc.InnerXml);
            filesize = (UInt32)buf.Length;
            if (package_size < filesize)
            {
                //需要分多次获取
                //创建备份
                TempFileRW t = new TempFileRW(path, buf);
                guid = t.GUID;
                mTempFile.Add(t);
                buf = buf.Take(package_size).ToArray();
                return OptFileContentResult.Doing;
            }
            return OptFileContentResult.OK;
        }

        private OptFileContentResult GetContentPart(string guid, UInt16 package_no, UInt16 package_size, out byte[] buf, out UInt32 filesize) 
        {
            TempFileRW t;
            buf = null;
            filesize = 0;
            string g = guid;
            var fws = from _fw in mTempFile where _fw.GUID == g select _fw;
            if (fws.Count() > 0)
                t = fws.First();
            else
            {
                //出错!!!
                return OptFileContentResult.GUIDErr;
            }
            string filePath = t.Temp;


            FileStream sr = new FileStream(filePath, FileMode.Open);
            filesize = (UInt32)sr.Length;

            int count = package_size;
            int offset = package_no * package_size;
            if ((offset + count) > sr.Length)
                count = (int)(sr.Length - offset);


            if (count <= 0)
            {
                sr.Close();

            }
            else
            {
                buf = new byte[count];
                sr.Seek(offset, SeekOrigin.Begin);
                sr.Read(buf, 0, count);
                sr.Close();
            }
            if ((count + offset) == filesize)
            {

                //可以删除临时文件了
                if (t != null)
                {
                    t.Dispose();
                    mTempFile.Remove(t);
                }
                return OptFileContentResult.OK;
            }

            return OptFileContentResult.Doing;
        }

        /// <summary>
        /// 获取文件内容
        /// 一定要从头获取,当package_size小于filesize,也就是要多次获取时,复制一份临时文件;
        /// 读到的数据,都是对这个临时文件读取。
        /// 当读取到最后,全部读取完成,删除此文件.
        /// 
        /// 分段获取文件,第1次调用 path为文件路径
        /// 以后,path为guid
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="offset">文件游标</param>
        /// <param name="buf">输出数据</param>
        /// <returns></returns>
        private OptFileContentResult GetFileContent(string path, ref string guid, UInt16 package_size, out byte[] buf, out UInt32 filesize)
        {
            filesize = 0;
            buf = null;
            string filePath = path;

            FileStream sr = new FileStream(filePath, FileMode.Open);
            filesize = (UInt32)sr.Length;

            UInt32 count = package_size;
            if(count>filesize)
                count = filesize;
            
            if (count <= 0)
            {
                sr.Close();
            }
            else
            {
                buf = new byte[count];
                sr.Read(buf, 0, (int)count);
                sr.Close();
            }

            if(package_size<filesize)
            {
                //需要创建备份
                TempFileRW t = new TempFileRW(path);
                guid = t.GUID;
                mTempFile.Add(t);
                return OptFileContentResult.Doing;
            }
            return OptFileContentResult.OK;
        }

        /// <summary>
        /// 获取文件夹 或文件 的内容
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public OptFileContentResult GetContent(string path, ref string guid, UInt16 package_no, UInt16 package_size, out byte[] buf, out UInt32 filesize)
        {
            buf = null;
            filesize = 0;
            if (package_no == 0)
            {
                if (Directory.Exists(path))
                {
                    return GetDirectoryContent(path, ref guid, package_size, out buf, out filesize);
                }
                else if (File.Exists(path))
                {
                    return GetFileContent(path, ref guid, package_size, out buf, out filesize);
                }
                else
                {
                    return OptFileContentResult.NoExist;
                }
            }
            else 
            {
                return GetContentPart(guid, package_no, package_size, out buf, out filesize);
            }
        }
        #endregion
        #region 写文件内容
        /// <summary>
        /// 设置文件内容,当为虚拟文件时,不操作,直接返回
        /// </summary>
        /// <param name="path"></param>
        /// <param name="context"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        /// <param name="buf"></param>
        /// <returns></returns>
        public OptFileContentResult SetFileContent(string path, ref string guid, UInt32 filesize, UInt16 package_size, UInt16 package_no, byte[] context)
        {
            TempFileRW t;
            string filePath = path;
            if (package_no == 0)
            {
                //创建临时文件
                t = new TempFileRW();
                guid = t.GUID;
                mTempFile.Add(t);
            }
            else
            {
                string g = guid;
                var fws = from _fw in mTempFile where _fw.GUID == g select _fw;
                if (fws.Count() > 0)
                    t = fws.First();
                else
                {
                    //出错!!!
                    return OptFileContentResult.GUIDErr;
                }
            }
            try
            {
                FileStream sr = new FileStream(TempFileRW.TempDir+@"\" + guid, FileMode.OpenOrCreate);
                sr.Seek(package_no * package_size, SeekOrigin.Begin);
                sr.Write(context, 0, context.Length);
                sr.Flush();
                sr.Close();

            }
            catch
            {
                return OptFileContentResult.CanntWrite;
            }

            if ((package_no * package_size + context.Length) >= filesize)
            {
                //全部数据上传完
                try
                {
                    if (File.Exists(path))
                    {
                        //当文件已经存在,删除
                        File.Delete(path);
                    }
                    else 
                    {
                        //文件不存在,创建文件夹
                        string dir = Path.GetDirectoryName(path);
                        if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
                            Directory.CreateDirectory(dir);
                     }
                    File.Move(TempFileRW.TempDir + @"\" + guid, path);
                }
                catch
                {
                    //可以删除临时文件了
                    t.Dispose();
                    mTempFile.Remove(t);
                    return OptFileContentResult.CanntWrite;
                }

                //可以删除临时文件了
                t.Dispose();
                mTempFile.Remove(t);
                return OptFileContentResult.OK;
            }
            else 
            {

                return OptFileContentResult.Doing;
            }
        }
        List<TempFileRW> mTempFile = new List<TempFileRW>();
        class TempFileRW
        {
            public TempFileRW() 
            {
                //产生临时文件
                GUID = Guid.NewGuid().ToString();
                if (!Directory.Exists(TempDir))
                    Directory.CreateDirectory(TempDir);
            }
            public TempFileRW(string path) 
            {
                this.path = path;

                //产生临时文件
                GUID = Guid.NewGuid().ToString();

                FileInfo info = new FileInfo(path);
                if (!Directory.Exists(TempDir))
                    Directory.CreateDirectory(TempDir);
                info.CopyTo(TempDir+@"\" + GUID);
            }
            public TempFileRW(string path, byte[] buf) 
            {
                //产生临时文件
                GUID = Guid.NewGuid().ToString();

                if (!Directory.Exists(TempDir))
                    Directory.CreateDirectory(TempDir);
                this.path = path;

                FileStream fs = new FileStream(Temp, FileMode.Create);
                fs.Write(buf, 0, buf.Length);
                fs.Flush();
                fs.Close();
            }
            public string GUID;
            public string path;
            public string Temp {
                get {
                    return TempDir+@"\" + GUID;
                }
            }
            public void Dispose() 
            {
                if (File.Exists(Temp))
                    File.Delete(Temp);
            }
            public const string TempDir = @"filebus\tmp";
        }
        #endregion
    }
}