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

using System.ComponentModel;
using System.Text.RegularExpressions;
using System.IO;
using System.Xml.Serialization;
using FObjBase;

namespace OBJ_FileBus
{
    public class Server : INotifyPropertyChanged
    {
        private string sMsg;
        public string Msg 
        {
            get {
                return sMsg;
            }
            set {
                sMsg = value;
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Msg"));
                }
            }
        }

        /// <summary>
        /// 根路径 如 System.Environment.CurrentDirectory 不包含最后的"\\" 
        /// </summary>
        public string RootPath
        {
            set;
            get;
        }

        /// <summary>
        /// 文件系统读写 
        /// </summary>
        FileSystemInfoRW mFileSystemInfo = new FileSystemInfoRW();

        public class ClientInfo 
        {
            //public IPEndPoint ep;
            public IFConn conn=null;// 连接的 ID
            public UInt32 destid;// 远端的 ID
            public int CompareTo(ClientInfo client) 
            {
                if ((client.conn == conn) && (client.destid == destid))
                {
                    return 0;
                }
                else if (client.conn == conn)
                {
                    return 1;
                }
                //else if (client.ep.ToString() == ep.ToString()) 
                //{
                //    return 2;
                //}
                else
                {
                    return -1;
                }
            }
        }
        
        /// <summary>
        /// 客户端推送设置,所有客户都在里面,对于不需要推送的,List(string).Count=0
        /// </summary>
        Dictionary<ClientInfo, List<string>> mClientPushEn =
            new Dictionary<ClientInfo, List<string>>();
        
        /// <summary>
        /// 用于调试，需要推送的文件，上一次的最后写入时间
        /// </summary>
        Dictionary<string, DateTime> mLastWriteTime = 
            new Dictionary<string, DateTime>();

        private delegate void FuncHandle(ClientInfo client, Message message);

        Dictionary<string, FuncHandle> m_service =
            new Dictionary<string, FuncHandle>();

        public Server(string rootpath)
        {
            RootPath = rootpath;
            m_service.Add("readinfo", new FuncHandle(ReadInfo));
            m_service.Add("read", new FuncHandle(Read));
            m_service.Add("write", new FuncHandle(Write));
            m_service.Add("addpush", new FuncHandle(AddPush));
            m_service.Add("rmpush", new FuncHandle(RmPush));
            m_service.Add("rm", new FuncHandle(Rm));

            PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD, new PollModule.PollHandler(OnPoll));
        }
        /// <summary>
        /// 用于测试，定期检查哪个需要推送的文件，被更新了。
        /// </summary>
        /// <returns></returns>
        void OnPoll()
        {
            var path = from p in mLastWriteTime.AsEnumerable() where p.Value < FileSystemInfoRW.GetLastWriteTime(GetAbsPath(p.Key)) select p;
            for (int i = 0; i < path.Count(); i++)
            {
                string k = path.ElementAt(i).Key;
                mLastWriteTime[k] = FileSystemInfoRW.GetLastWriteTime(GetAbsPath(k));
                PushMsg(k);
            }
        }
        /// <summary>
        /// 获取绝对路径
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private string GetAbsPath(string path) 
        {
            if (path.StartsWith(@"\"))
            {
                path = path.Substring(1);
            }

           

            if (string.IsNullOrEmpty(RootPath))
            {
                if (string.IsNullOrEmpty(path))
                {
                    return @".";
                }
                else 
                {
                    return path;
                }
            }
            else 
            {
                return RootPath + @"\" + path;
            }
        }



        #region 功能
        public delegate void SendMessageEventHandler(ClientInfo client, byte[] buf);
        public event SendMessageEventHandler SendMessageEvent;
        private void Return(ClientInfo client, Message message) 
        {
            Stream fStream = new MemoryStream();

            XmlSerializer xmlFormat = new XmlSerializer(
                typeof(Message),
                new Type[] { 
                    typeof(MessageArgs), 
                    typeof(FileOptMessageArgs),
                    typeof(RetMessageArgs),
                    typeof(ReadInfoRetMessageArgs),
                    typeof(ReadParamMessageArgs),
                    typeof(ReadRetMessageArgs),
                    typeof(WriteParamMessageArgs),
                    typeof(WriteRetMessageArgs),
                    typeof(PushParamMessageArgs),
                    typeof(PushMessageArgs)
                });//创建XML序列化器，需要指定对象的类型

            xmlFormat.Serialize(fStream, message);
            fStream.Seek(0, SeekOrigin.Begin);
            byte[] buf=new byte[fStream.Length];
            fStream.Read(buf, 0, (int)fStream.Length);
            fStream.Close();

            if (SendMessageEvent != null)
                SendMessageEvent(client, buf);
           
        }

        /// <summary>
        /// 功能号分发
        /// </summary>
        /// <param name="ADUBuffer"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        public void RequestService(ClientInfo client, byte[] order_bytes, out byte[] retdata)
        {

            //DateTime dt1 = DateTime.Now;
            //转换为xml 解码
            Message message = Message.Bytes2Message(order_bytes);
            //获取指令
            string order = message.order;

            retdata = null;
            if (m_service.ContainsKey(order))
            {
                m_service[order](client, message);
                retdata = message.ToBytes();
            }
            //DateTime dt2 = DateTime.Now;
            //System.Diagnostics.Debug.WriteLine((dt2 - dt1).TotalMilliseconds.ToString());
        }

        private void ReadInfo(ClientInfo client, Message message ) 
        {
            //uint16 order_len 指令字符串长度
            //N bytes order 指令字符串
            //order 格式 
            //"readinfo" 
            //path路径
            //如 readinfo sysparam.ini

            //获取文件路径
            FileOptMessageArgs args = (FileOptMessageArgs)message.args;
            string path = args.path;

            
            ReadInfoRetMessageArgs ret_args = new ReadInfoRetMessageArgs();
            message.args = ret_args;
            ret_args.path = path;

            if(FileSystemInfoRW.GetInfo(
                GetAbsPath(path),
                out ret_args.fileattr, 
                out ret_args.createtime, 
                out ret_args.lastwritetime, 
                out ret_args.size))
            {
                ret_args.errno = ERRNO.OK;
            }
            else
            {
                ret_args.errno = ERRNO.NOEXIST;
            }
            
            return;
        }
        private void Read(ClientInfo client, Message message )
        {
            //获取文件路径
            ReadParamMessageArgs args = (ReadParamMessageArgs)message.args;
            string path = args.path;

            ReadRetMessageArgs ret_args = new ReadRetMessageArgs();
            message.args = ret_args;

            byte[] filecontent_bytes;
            UInt32 filesize=0;
            FileSystemInfoRW.OptFileContentResult ret = mFileSystemInfo.GetContent(
                GetAbsPath(path),
                ref args.guid,
                args.package_no,
                args.package_size,
                out filecontent_bytes,
                out filesize);
            


            ret_args.path = path;
            int s;
            FileSystemInfoRW.GetInfo(
                GetAbsPath(path),
                out ret_args.fileattr,
                out ret_args.createtime,
                out ret_args.lastwritetime,
                out s);

            ret_args.filesize = filesize;
            ret_args.package_size = args.package_size;
            ret_args.package_no = args.package_no;
            ret_args.filecontent = filecontent_bytes;
            ret_args.guid = args.guid;
            
            if (ret == FileSystemInfoRW.OptFileContentResult.OK)
            {
                ret_args.errno = ERRNO.OK;
            }
            else if(ret == FileSystemInfoRW.OptFileContentResult.Doing)
            {
                ret_args.errno = ERRNO.DOING;
            }
            else if (ret == FileSystemInfoRW.OptFileContentResult.NoExist)
            {
                ret_args.errno = ERRNO.NOEXIST;
            }
            else//if (ret == FileSystemInfoRW.OptFileContentResult.GUIDErr)
            {
                ret_args.errno = ERRNO.ERROR;
            }
            return;
        }
        private void Write(ClientInfo client, Message message )
        {
            WriteParamMessageArgs args = message.args as WriteParamMessageArgs;
            string path = args.path;
            FileSystemInfoRW.OptFileContentResult ret =
                mFileSystemInfo.SetFileContent(
                GetAbsPath(path),
                ref args.guid,
                args.filesize,
                args.package_size,
                args.package_no,
                args.filecontent);

            WriteRetMessageArgs ret_args = new WriteRetMessageArgs();
            message.args = ret_args;

            ret_args.path = path;
            ret_args.guid = args.guid;
            ret_args.createtime = DateTime.MinValue;
            ret_args.lastwritetime = DateTime.Now;

            if (ret == FileSystemInfoRW.OptFileContentResult.OK)
            {
                //推送
                PushMsg(path);
                ret_args.errno = ERRNO.OK;
                int s;
                FileSystemInfoRW.GetInfo(
                    GetAbsPath(path),
                    out ret_args.fileattr,
                    out ret_args.createtime,
                    out ret_args.lastwritetime,
                    out s);
            }
            else if (ret == FileSystemInfoRW.OptFileContentResult.Doing)
            {
                ret_args.errno = ERRNO.DOING;
            }
            else if (ret == FileSystemInfoRW.OptFileContentResult.NoExist)
            {
                ret_args.errno = ERRNO.NOEXIST;
            }
            else if (ret == FileSystemInfoRW.OptFileContentResult.CanntWrite)
            {
                ret_args.errno = ERRNO.ERROR;
            }
        }
        private void AddPush(ClientInfo client, Message message ) 
        {
            //uint16 order_len 指令字符串长度
            //N bytes order 指令字符串
            //order 格式 
            //"addpush"
            //path 路径，多个路径以 ; 隔开
            PushParamMessageArgs args = message.args as PushParamMessageArgs;

            RegistPush(client, args.path);
            
            PushRetMessageArgs ret_args = new PushRetMessageArgs();
            message.args = ret_args;
            ret_args.path = args.path;
            ret_args.errno = ERRNO.OK;
        }
        private void RmPush(ClientInfo client, Message message )
        {
            PushParamMessageArgs args = message.args as PushParamMessageArgs;

            var cl = from cpe in mClientPushEn
                     where cpe.Key.CompareTo(client) == 0
                     select cpe;
            List<string> plist;
            if (cl.Count() > 0)
            {
                plist = cl.First().Value;

                if (string.IsNullOrEmpty(args.path))
                {
                    //没有路径，全删除
                    plist.Clear();
                }
                else
                {
                    string path = args.path;

                    if (plist.Contains(path))
                        plist.Remove(path);
                }
            }

            PushRetMessageArgs ret_args = new PushRetMessageArgs();
            message.args = ret_args;
            ret_args.path = args.path;
            ret_args.errno = ERRNO.OK;
        }
        private void Rm(ClientInfo client, Message message )
        {
            FileOptMessageArgs args = (FileOptMessageArgs)message.args;
            string path = args.path;

            string path2 = GetAbsPath(path);
            if (System.IO.Directory.Exists(path2)) 
            {
                System.IO.Directory.Delete(path2);
            }
            else if (System.IO.File.Exists(path2)) 
            {
                System.IO.File.Delete(path2);
            }

            //推送
            PushMsg(System.IO.Path.GetDirectoryName(path));

            RetMessageArgs ret_args = new RetMessageArgs();
            message.args = ret_args;
            ret_args.errno = ERRNO.OK;
            ret_args.path = path;
        }        


        /// <summary>
        /// path 为相对路径
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        void PushMsg(string path)
        {
            var need = from _ps in mClientPushEn.AsEnumerable()
                     where _ps.Value.Contains(path)
                     select _ps.Key;

            if (need.Count() > 0)//需要推送
            {
                PushMessageArgs ret_args = new PushMessageArgs();
                ret_args.path = path;
                FileSystemInfoRW.GetInfo(
                    GetAbsPath(path),
                    out ret_args.fileattr,
                    out ret_args.createtime,
                    out ret_args.lastwritetime,
                    out ret_args.size);
                
                Message message = new Message() { order = "push", args = ret_args };
                foreach (ClientInfo client in need)
                {
                    if (client.conn == null)
                    {
                        FileChangedEvent(this,
                            new FileChangedEventArgs()
                            {
                                path = path,
                                fileattr = ret_args.fileattr,
                                modified_dt = ret_args.lastwritetime
                            });
                    }
                    else
                    {
                        Return(client, message);
                    }
                }
            }
        }
        public void ClientRemove(ClientInfo client)
        {
            var cl = from cpe in mClientPushEn where cpe.Key.CompareTo(client)>=0  select cpe.Key;

            for (int i = 0; i < cl.Count(); i++)
            {
                ClientInfo ci = cl.ElementAt(i);
                mClientPushEn.Remove(ci);
            }
        }
        public void RegistPush(ClientInfo client, string path) 
        {
            var cl = from cpe in mClientPushEn
                     where cpe.Key.CompareTo(client) == 0
                     select cpe;
            List<string> plist;
            if (cl.Count() > 0)
            {
                plist = cl.First().Value;
            }
            else
            {
                plist = new List<string>();
                mClientPushEn.Add(client, plist);
            }

            if (plist.Contains(path) == false)
                plist.Add(path);

            if (!mLastWriteTime.ContainsKey(path))
            {
                mLastWriteTime.Add(path, FileSystemInfoRW.GetLastWriteTime(GetAbsPath(path)));
            }
            
        }
        
        public class FileChangedEventArgs:EventArgs
        {
            /// <summary>
            /// 路径
            /// </summary>
            public string path;
            /// <summary>
            /// 文件类型
            /// </summary>
            public FileAttributes fileattr;
            /// <summary>
            /// 修改时间
            /// </summary>
            public DateTime modified_dt;
        }
        public delegate void FileChangedEventHandler(object sender, FileChangedEventArgs e);
        public event FileChangedEventHandler FileChangedEvent;

        
        #endregion


        #region INotifyPropertyChanged 成员

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
