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

namespace FObjBase
{
    public enum SENSE_CONFIG
    {
        ADD, REMOVE
    }
    /// <summary>
    /// 建议使用方法:
    /// 做为客户端,都使用 FObjSys.Current 连接不同的客户端
    /// 做为服务器,当要提供2个Obj服务, 应该要使用 Currents[index]
    /// 这套逻辑已经潜入到 每个 FObj 中, FObj.CurrObjSys, 就是对应的 Obj服务
    /// </summary>
    public class FObjSys : IFObjSysAsClient, IFObjSysAsServer
    {
        public static FObjSys Current;
        public static List<FObjSys> Currents = new List<FObjSys>();
        
        
        TCPListen m_tcplisten;
        Dictionary<TCPCConn, List<UInt32>> m_cconns = new Dictionary<TCPCConn, List<UInt32>>();//管理连接到异地服务器的连接
        List<UInt32> m_serverConnectedNotifyObjID = new List<UInt32>();//作为服务器,当客户端断开,发送通知

        /// <summary>
        /// 交易列表
        /// </summary>
        List<Transaction> Transactions = new List<Transaction>();

        /// <summary>
        /// 消息推送的敏感对象
        /// </summary>
        class Sense
        {
            public IFConn conn;
            public UInt32 objid;
            public UInt32 sense_mask;
            //public bool hasPush;
        }
        Dictionary<IFObj, List<Sense>> Objs = new Dictionary<IFObj, List<Sense>>();

        static FObjSys() 
        {
            Currents.Add(new FObjBase.FObjSys());
            Current = Currents[0];
        }
        public FObjSys() {


        }
        #region IFObjSys
        /// <summary>
        /// 添加OBJ到系统
        /// </summary>
        /// <param name="obj"></param>
        public void ObjAdd(IFObj obj)
        {
            if (obj.ID == 0)
                obj.ID = GetFreeObjID();

            Objs.Add(obj, new List<Sense>());
        }
        /// <summary>
        /// 对外发送消息
        /// </summary>
        /// <param name="s1">远端对应的连接代理 </param>
        /// <param name="destid">远端的ID</param>
        /// <param name="srcid">本地的ID</param>
        /// <param name="magic">交易码</param>
        /// <param name="info_no">信息码</param>
        /// <param name="info_data">信息内容</param>
        public void SendMessageEx(IFConn s1, UInt32 destid, UInt32 srcid, UInt32 magic, UInt16 info_no, byte[] info_data)
        {
            if (s1 == null)
                return;
            if (s1 is FConnLocal)
            {
                return;
            }
            else
            {
                ((TCPConn)s1).SendPacket(new Pack_Proto()
                {
                    destid = destid,
                    srcid = srcid,
                    magic = magic,
                    info = info_no,
                    buf = info_data
                }.ToBytes());
                return;
            }
        }
        #region 服务端

        //启动本地OBJSys网络
        public void Start_Conn_Server(IPEndPoint ep, params UInt32[] objids)
        {
            m_serverConnectedNotifyObjID.AddRange(objids);
            if (m_tcplisten == null)
            {
                m_tcplisten = new TCPListen(ep)
                {
                    ParsePacket = new ParsePacketHandler(ParsePacketInServer),
                    ConnectAction = new ConnectHandler(SConnConnectAction),
                };
            }
            else
            {
                m_tcplisten.Enable = false;
                m_tcplisten.LocalEP = ep;
            }
            m_tcplisten.Enable = true;
        }

        /// <summary>
        /// 指定推送到某个远端
        /// </summary>
        /// <param name="srcobj"></param>
        /// <param name="infoid"></param>
        /// <param name="infodata"></param>
        /// <param name="s1"></param>
        /// <param name="destid"></param>
        public void PushObjInfoEx(IFObj srcobj, UInt16 infoid, byte[] infodata, IFConn s1, UInt32 destid)
        {
            if (s1 is FConnLocal)
            {
                IFObj obj = Find(destid);
                if (obj != null)
                    obj.PushInfo(s1, srcobj.ID, infoid, infodata);

                return;
            }
            List<byte> buf = new List<byte>();
            buf.AddRange(BitConverter.GetBytes(infoid));
            buf.AddRange(infodata);
            SendMessageEx(s1, destid, srcobj.ID, 0x1234, Proto.INFO_PUSH_EVENT, buf.ToArray());
        }
        /// <summary>
        /// 推送到远端,系统判定根据敏感对象推送
        /// </summary>
        /// <param name="srcobj"></param>
        /// <param name="infoid"></param>
        /// <param name="infodata"></param>
        public void PushObjInfoEx(IFObj srcobj, UInt16 infoid, byte[] infodata)
        {
            if (!Objs.Keys.Contains(srcobj))
                return;
            List<Sense> senses = Objs[srcobj];

            //foreach (Sense sense in senses)
            //    sense.hasPush = false;

            int cnt = senses.Count();

            for (int i = 0; i < cnt; i++)
            {
                Sense sense = senses[i];
                //if (sense.hasPush == false)
                {
                    if ((sense.sense_mask & (1 << infoid)) == 0)
                        continue;
                    if (sense.conn is FConnLocal)
                    {
                        IFObj obj = Find(sense.objid);
                        if (obj != null)
                            obj.PushInfo(sense.conn, srcobj.ID, infoid, infodata);
                    }
                    else
                    {
                        List<byte> buf = new List<byte>();
                        buf.AddRange(BitConverter.GetBytes(infoid));
                        buf.AddRange(infodata);
                        SendMessageEx(sense.conn, sense.objid, srcobj.ID, 0x1234, Proto.INFO_PUSH_EVENT, buf.ToArray());
                    }
                    //sense.hasPush = true;
                }
            }
        }
        /// <summary>
        /// 推送到远端,系统判定根据敏感对象推送,但不推送给特定某对象
        /// </summary>
        /// <param name="srcobj"></param>
        /// <param name="infoid"></param>
        /// <param name="infodata"></param>
        /// <param name="except_s1"></param>
        /// <param name="except_destid"></param>
        public void PushObjInfoEx_except(IFObj srcobj, UInt16 infoid, byte[] infodata, IFConn except_s1, UInt32 except_destid)
        {

            if (!Objs.Keys.Contains(srcobj))
                return;
            List<Sense> senses = Objs[srcobj];

            //foreach (Sense sense in senses)
            //    sense.hasPush = false;

            int cnt = senses.Count();

            for (int i = 0; i < cnt; i++)
            {
                Sense sense = senses[i];
                //if (sense.hasPush == false)
                {
                    if ((sense.sense_mask & (1 << infoid)) == 0)
                        continue;
                    if ((sense.conn == except_s1) && (sense.objid == except_destid))
                        continue;

                    List<byte> buf = new List<byte>();
                    buf.AddRange(BitConverter.GetBytes(infoid));
                    buf.AddRange(infodata);
                    SendMessageEx(sense.conn, sense.objid, srcobj.ID, 0x1234, Proto.INFO_PUSH_EVENT, buf.ToArray());
                    //sense.hasPush = true;
                }
            }
        }

        /// <summary>
        /// 回复 客户端的CallFunction
        /// </summary>
        /// <param name="s1">客户端对应的连接代理 </param>
        /// <param name="destid">客户端的对象ID</param>
        /// <param name="srcid">本地服务端的对象ID</param>
        /// <param name="magic">交易码</param>
        /// <param name="funcid">函数ID</param>
        /// <param name="param">函数返回</param>
        public void PushCallFunctionEx(IFConn s1, UInt32 destid, UInt32 srcid, UInt32 magic, UInt16 funcid, byte[] retdata) 
        {
            if (s1 == null)
                return;

            if (s1 is FConnLocal)
            {
                var ts = from t in Transactions where t.Magic == magic && t.Conn == s1 select t;
                if (ts.Count() > 0)
                {
                    Transaction tran = ts.First();
                    Transactions.Remove(tran);
                    PushCallFunction(s1, srcid, destid, magic, funcid, retdata, tran.AsyncDelegate, tran.AsyncState);
                }
                else 
                {
                    PushCallFunction(s1, srcid, destid, magic, funcid, retdata, null, null);
                }
                return;
            }
            
            if ((retdata != null) && (retdata.Length > Transaction.PackSize)) //参数太大,需要分包多次发送
            {
                var ts = from t in Transactions where t.Magic == magic && t.Conn == s1 select t;
                if (ts.Count() == 0)
                {
                    Transaction t = new Transaction()
                    {
                        Conn = s1,
                        SrcObjID = destid,
                        Magic = magic,
                        Size = retdata.Length,
                        Buf = (byte[])retdata.Clone(),
                        FuncID = funcid
                    };
                    Transactions.Add(t);
                }
                
                PushCallFunctionEx_ReponseBigSize(s1, destid, srcid, magic);
            }
            else
            {
                Pack_GetSetPushCall p = new Pack_GetSetPushCall();
                p.infoid = funcid;
                p.infodata = retdata;
                SendMessageEx(s1, destid, srcid, magic, Proto.INFO_PUSH_CALL_FUNCTION, p.ToBytes());
            }
        }
        void PushCallFunctionEx_ReponseBigSize(
            IFConn conn, UInt32 destid, UInt32 srcid, UInt32 magic)
        {
            var ts = from t in Transactions where t.Magic == magic && t.Conn == conn select t;
            if (ts.Count() == 0)
                return;
            Transaction tran = ts.First();

            Pack_BigSize pack;
            if (tran.GetBigSize(out pack))
                Transactions.Remove(tran);//用完了,删除!!!

            SendMessageEx(conn, destid, srcid, magic,
                Proto.INFO_PUSH_CALL_FUNCTION_REPONSE_BIGSIZE, pack.ToBytes());
        }
        #endregion
        #region 客户端

        /// <summary>
        /// 获取没用使用的OBJID
        /// </summary>
        /// <returns></returns>
        public UInt32 GetFreeObjID()
        {
            if (Objs.Count > 0)
                return Objs.Max(obj => obj.Key.ID) + 1;
            else
                return 1;
        }

        /// <summary>
        /// 从系统删除OBJ
        /// </summary>
        /// <param name="obj"></param>
        public void ObjRemove(IFObj obj)
        {
            Objs.Remove(obj);//作为服务端,关闭推送服务
            foreach (var kv in m_cconns)
            {
                kv.Value.Remove(obj.ID);
            }
        }
        /// <summary>
        /// 作为客户端,从系统删除OBJ;
        /// 还会通知服务器,断开与这个 OBJ 的所有连接
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="conn"></param>
        public void ObjRemove(IFObj obj, IFConn conn)
        {
            ObjRemove(obj);

            Transactions.RemoveAll(t => t.SrcObjID == obj.ID);

            if (conn != null)
            {
                SendMessageEx(conn, 0, obj.ID, GetFreeMagic(),
                    Proto.INFO_OBJ_DISPOSE, null);
            }
        }

        /// <summary>
        /// 连接到远端的OBJSys连接
        /// </summary>
        /// <param name="ep">远端地址</param>
        /// <param name="objids">连接成功后,通知这些obj</param>
        /// <returns></returns>
        public TCPCConn Connect_to_Another_OBJSys(IPEndPoint ep, params UInt32[] objids)
        {
            try
            {
                KeyValuePair<TCPCConn, List<UInt32>> cc_kv;
                cc_kv = m_cconns.First(_cc => _cc.Key.RemoteEP.Equals(ep));
                cc_kv.Value.AddRange(objids);
                //已经存在此连接,通知
                if (cc_kv.Key.IsConnected)
                {
                    foreach (UInt32 objid in objids)
                    {
                        IFObj obj = Find(objid);
                        if (obj != null)
                            obj.ConnectNotify(cc_kv.Key);
                    }
                }
                return cc_kv.Key;
            }
            catch
            {
                TCPCConn conn = new TCPCConn(ep)
                {
                    ParsePacket = new ParsePacketHandler(ParsePacketInClient),
                    ConnectAction = new ConnectHandler(CConnConnectAction),
                    Enable = true
                };

                m_cconns.Add(conn, new List<uint>(objids));
                return conn;
            }
        }
        /// <summary>
        /// 断开到远端OBJSys的连接
        /// </summary>
        /// <param name="ep">远端地址</param>
        /// <param name="objids">连接成功后,通知这些obj</param>
        /// <returns></returns>
        public void Disconnect_to_Another_OBJSys(IPEndPoint ep, params UInt32[] objids)
        {
            try
            {
                KeyValuePair<TCPCConn, List<UInt32>> cc_kv;
                cc_kv = m_cconns.First(_cc => _cc.Key.RemoteEP.Equals(ep));
                
                cc_kv.Value.RemoveAll(objid => objids.Contains(objid));
                //删除大通讯的trans
                Transactions.RemoveAll(t => objids.Contains(t.SrcObjID));



                if (cc_kv.Key.IsConnected)//它的连接是正常的,通知objids,说连接断开了
                {
                    foreach (UInt32 objid in objids)
                    {
                        IFObj obj = Find(objid);
                        if (obj != null)
                            obj.ConnectNotify(
                                new TCPCConn(ep)
                                {
                                    Enable = false
                                });
                    }
                }
                if (cc_kv.Value.Count == 0)//已经没有obj需要连接了,删除conn
                {
                    cc_kv.Key.Enable = false;
                    m_cconns.Remove(cc_kv.Key);
                }
            }
            catch
            {
                
            }
        }



        /// <summary>
        /// 注册本地obj 为远端obj的敏感对象,得到远端obj的推送消息
        /// </summary>
        /// <param name="s1">远端对应的连接代理 </param>
        /// <param name="objid">远端的ID</param>
        /// <param name="senobjid">本地obj</param>
        /// <param name="sense_mask">注册的敏感源</param>
        /// <param name="action">动作,添加?删除?</param>
        public void SenseConfigEx(IFConn s1, UInt32 objid, UInt32 senobjid, UInt32 sense_mask, SENSE_CONFIG action)
        {
            if (s1 == null)
                return;

            List<byte> buf = new List<byte>();
            if (action == SENSE_CONFIG.ADD)
                buf.Add(0);
            else
                buf.Add(1);

            buf.AddRange(BitConverter.GetBytes(sense_mask));

            SendMessageEx(s1, objid, senobjid, GetFreeMagic(), Proto.INFO_CONFIG_SENSE_OBJ, buf.ToArray());
        }

        /// <summary>
        /// 向远端GetValue
        /// </summary>
        /// <param name="s1">远端对应的连接代理</param>
        /// <param name="destid">远端的ID</param>
        /// <param name="srcid">本地的ID</param>
        /// <param name="memid">成员ID</param>
        public void GetValueEx(IFConn s1, UInt32 destid, UInt32 srcid, UInt16 memid)
        {
            if (s1 == null)
                return;
            
            if (s1 is FConnLocal)
            {
                byte[] value;
                GetValue(s1, srcid, destid, memid, out value);
                if (value != null)
                    PushGetValue(s1, destid, srcid, memid, value);
                return;
            }
            else
            {
                UInt32 magic = GetFreeMagic();
                SendMessageEx(s1, destid, srcid, magic, Proto.INFO_GET_VALUE, BitConverter.GetBytes(memid));
            }
        }

        /// <summary>
        /// 向远端SetValue
        /// </summary>
        /// <param name="s1">远端对应的连接代理</param>
        /// <param name="destid">远端的ID</param>
        /// <param name="srcid">本地的ID</param>
        /// <param name="memid">成员ID</param>
        /// <param name="value">成员内容</param>
        public void SetValueEx(IFConn s1, UInt32 destid, UInt32 srcid, UInt16 memid, byte[] value)
        {
            if (s1 == null)
                return;

            if (s1 is FConnLocal)
            {
                SetValue(s1, srcid, destid, memid, value);
                return;
            }

            List<byte> buf = new List<byte>();
            buf.AddRange(BitConverter.GetBytes(memid));
            buf.AddRange(value);
            UInt32 magic = GetFreeMagic();
            SendMessageEx(s1, destid, srcid, magic, Proto.INFO_SET_VALUE, buf.ToArray());
            return;
        }
        
        /// <summary>
        /// 向远端CallFunction
        /// </summary>
        /// <param name="s1">远端对应的连接代理 </param>
        /// <param name="destid">远端对象ID</param>
        /// <param name="srcid">本地对象ID</param>
        /// <param name="funcid">函数ID</param>
        /// <param name="param">函数参数</param>
        /// <param name="AsyncDelegate">在其上调用异步调用的委托对象</param>
        /// <param name="AsyncState">作为 BeginInvoke 方法调用的最后一个参数而提供的对象</param>
        public UInt32 CallFunctionEx(IFConn s1, UInt32 destid, UInt32 srcid, UInt16 funcid, byte[] param, object AsyncDelegate, object AsyncState)
        {
            if (s1 == null)
                return 0;

            if (s1 is FConnLocal)
            {
                UInt32 magic = GetFreeMagic();
                if ((AsyncDelegate != null) || (AsyncState != null)) //需要返回参数!!!
                {
                    Transaction t = new Transaction()
                    {
                        Conn = s1,
                        SrcObjID = destid,
                        Magic = magic,
                        AsyncDelegate = AsyncDelegate,
                        AsyncState = AsyncState
                    };
                    Transactions.Add(t);
                }
                CallFunction(s1, srcid, destid, magic, funcid, param);
                return magic;
            }

            if ((param != null) && (param.Length > Transaction.PackSize)) //参数太大,需要分包多次发送
            {
                UInt32 magic = GetFreeMagic();
                Transaction t = new Transaction()
                {
                    Conn = s1,
                    SrcObjID = srcid,
                    Magic = magic,
                    AsyncDelegate = AsyncDelegate,
                    AsyncState = AsyncState,
                    
                    Size = param.Length,
                    Buf = (byte[])param.Clone(),
                    FuncID = funcid
                };
                Transactions.Add(t);
                CallFunctionEx_RequestBigSize(s1, destid, srcid, magic);
                return magic;
            }
            else
            {
                Pack_GetSetPushCall pack = new Pack_GetSetPushCall();
                pack.infoid = funcid;
                pack.infodata = param;

                UInt32 magic = GetFreeMagic();
                if ((AsyncDelegate != null) || (AsyncState != null)) //需要返回参数!!!
                {
                    Transaction t = new Transaction()
                    {
                        Conn = s1,
                        SrcObjID = srcid,
                        Magic = magic,
                        AsyncDelegate = AsyncDelegate,
                        AsyncState = AsyncState
                    };
                    Transactions.Add(t);
                }
                SendMessageEx(s1, destid, srcid, magic, Proto.INFO_CALL_FUNCTION, pack.ToBytes());
                return magic;
            }
        }

        /// <summary>
        /// 向远端CallFunction
        /// </summary>
        /// <param name="s1">远端对应的连接代理 </param>
        /// <param name="destid">远端对象ID</param>
        /// <param name="srcid">本地对象ID</param>
        /// <param name="funcid">函数ID</param>
        /// <param name="param">函数参数</param>
        public UInt32 CallFunctionEx(IFConn s1, UInt32 destid, UInt32 srcid, UInt16 funcid, byte[] param) 
        {
            return CallFunctionEx(s1, destid, srcid, funcid, param, null, null);
        }
        void CallFunctionEx_RequestBigSize(
            IFConn conn, UInt32 destid, UInt32 srcid, UInt32 magic) 
        {
            var ts = from t in Transactions where t.Magic == magic && t.Conn == conn select t;
            if (ts.Count() == 0)
                return;
            Transaction tran = ts.First();
            Pack_BigSize pack;
            if (tran.GetBigSize(out pack)) 
            {
                if (tran.Reset()) 
                {
                    Transactions.Remove(tran);//完成,可以删除
                }
            }

            SendMessageEx(conn, destid, srcid, magic, 
                Proto.INFO_CALL_FUNCTION_REQUEST_BIGSIZE, pack.ToBytes());
        }
        #endregion

        #endregion
        /// <summary>
        /// 通过objid 查找 obj
        /// </summary>
        /// <param name="objid"></param>
        /// <returns></returns>
        IFObj Find(UInt32 objid) 
        {
            try
            {
                KeyValuePair<IFObj, List<Sense>> obj_kv = Objs.First(obj => obj.Key.ID == objid);
                return obj_kv.Key;
            }
            catch
            {
                return null;
            }
        }
        UInt32 free_magic = 1;
        /// <summary>
        /// 获取一个没有被分配的 交易码
        /// </summary>
        /// <returns></returns>
        UInt32 GetFreeMagic()
        {
            UInt32 f = free_magic;
            free_magic++;
            if (free_magic == 0)
                free_magic++;

            //if (free_magic > UInt32.MaxValue)
            //    freetranno = 1;
            return f;
        }

        /// <summary>
        /// 作为客户端,与服务器连续状态改变
        /// </summary>
        /// <param name="conn"></param>
        void CConnConnectAction(IFConn conn)
        {
            TCPCConn cc = (TCPCConn)conn;

            KeyValuePair<TCPCConn, List<UInt32>> cc_kv;
            try
            {
                cc_kv = m_cconns.First(_cc => _cc.Key == cc);
                foreach (UInt32 objid in cc_kv.Value) 
                {
                    IFObj obj = Find(objid);
                    if (obj != null)
                        obj.ConnectNotify(cc);
                }    
            }
            catch
            {
                
            }

        }
        /// <summary>
        /// 作为服务器端,客户的登陆与退出
        /// </summary>
        /// <param name="conn"></param>
        void SConnConnectAction(IFConn conn)
        {
            //通知obj 连接状态
            foreach (UInt32 objid in m_serverConnectedNotifyObjID)
            {
                IFObj obj = Find(objid);
                if (obj != null)
                    obj.ConnectNotify(conn);
            }

            //当通讯断开时,还要把关注的推送删除掉
            if(conn.IsConnected==false)
            {
                for (int i = 0; i < Objs.Keys.Count(); i++)
                {
                    List<Sense> senses = Objs.ElementAt(i).Value;
                    senses.RemoveAll(s => s.conn == conn);
                }
                //删除所有与它有关的 tran
                Transactions.RemoveAll(t => t.Conn == conn);
            }
        }
        /// <summary>
        /// 作为服务器端,客户端 的 某obj 注销了,把它相关的都删除
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="srcid"></param>
        void ClearRemoteObjConn(IFConn conn, UInt32 srcid) 
        {
            //删除推送
            for (int i = 0; i < Objs.Keys.Count(); i++)
            {
                List<Sense> senses = Objs.ElementAt(i).Value;
                senses.RemoveAll(s => (s.conn == conn) && (s.objid == srcid));
            }
            //删除所有与它有关的 tran
            Transactions.RemoveAll(t => t.Conn == conn && t.SrcObjID == srcid);
        }


        #region 本地,给Protocol的函数指针

        /// <summary>
        /// 本地,给Protocol的函数指针;
        /// GetValue 
        /// </summary>
        /// <param name="from">远端对应的连接代理</param>
        /// <param name="srcid">远端对象ID</param>
        /// <param name="destid">本地对象ID</param>
        /// <param name="memid"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        void GetValue(IFConn from,UInt32 srcid,UInt32 destid, UInt16 memid,out byte[] value)
        {
            value = null;

            IFObj destobj = Find(destid);
            if (destobj == null)
                return;

            destobj.GetValue(from, srcid,memid,out value);
        }
        /// <summary>
        /// 本地,给Protocol的函数指针;
        /// SetValue
        /// </summary>
        /// <param name="from">远端对应的连接代理</param>
        /// <param name="srcid">远端对象ID</param>
        /// <param name="destid">本地对象ID</param>
        /// <param name="memid"></param>
        /// <param name="value"></param>
        void SetValue(IFConn from, UInt32 srcid, UInt32 destid, UInt16 memid, byte[] value)
        {
            IFObj destobj = Find(destid);
            if (destobj == null)
                return;

           destobj.SetValue(from, srcid, memid, value);
        }
        /// <summary>
        /// 本地,给Protocol的函数指针;
        /// CallFunction
        /// </summary>
        /// <param name="from">远端对应的连接代理</param>
        /// <param name="srcid">远端对象ID</param>
        /// <param name="destid">本地对象ID</param>
        /// <param name="funcid"></param>
        /// <param name="param"></param>
        /// <param name="ret"></param>
        /// <returns></returns>        
        void CallFunction(IFConn from, UInt32 srcid, UInt32 destid, UInt32 magic, UInt16 funcid, byte[] param)
        {
            IFObj destobj = Find(destid);
            if (destobj == null)
                return;

            destobj.CallFunction(from, srcid, magic, funcid, param);
        }
        /// <summary>
        /// 本地,给Protocol的函数指针;
        /// Sense_Config
        /// </summary>
        /// <param name="from">远端对应的连接代理</param>
        /// <param name="srcid">远端对象ID</param>
        /// <param name="destid">本地对象ID</param>
        /// <param name="sense_mask">远端对象 关注 本地对象 的敏感源</param>
        /// <param name="action">动作,添加?删除?</param>
        void Sense_Config(IFConn from, UInt32 srcid, UInt32 destid, UInt32 sense_mask, SENSE_CONFIG action)
        {
            try
            {
                KeyValuePair<IFObj, List<Sense>> obj_kv = Objs.First(obj => obj.Key.ID == destid);
                
                Sense sense = obj_kv.Value.Find(s=>s.conn == from && s.objid==srcid);
                if (sense == null)
                {
                    if (action == SENSE_CONFIG.ADD)
                    {
                        Sense s = new Sense() { conn = from, objid = srcid, sense_mask = sense_mask };
                        obj_kv.Value.Add(s);
                    }
                }
                else 
                {
                    if (action == SENSE_CONFIG.ADD)
                    {
                        sense.sense_mask |= sense_mask;
                    }
                    else 
                    {
                        sense.sense_mask &= ~sense_mask;
                    }
                }
 
            }
            catch
            {
                //不能找到对应的objid
            }
        }
        
        void PushObjInfo(IFConn from, UInt32 srcid, UInt32 destid, UInt16 infoid, byte[] infodata) 
        {

            IFObj destobj = Find(destid);
            if (destobj == null)
                return;

            destobj.PushInfo(from, srcid, infoid, infodata);      
        }
        void PushGetValue(IFConn from, UInt32 srcid, UInt32 destid, UInt16 infoid, byte[] infodata)
        {
            IFObj destobj = Find(destid);
            if (destobj == null)
                return;
            destobj.PushGetValue(from, srcid, infoid, infodata);
        }
        void PushCallFunction(IFConn from, UInt32 srcid, UInt32 destid, UInt32 magic, UInt16 infoid, byte[] infodata, object AsyncDelegate, object AsyncState)
        {
            IFObj destobj = Find(destid);
            if (destobj == null)
                return;
            destobj.PushCallFunction(from, srcid, magic, infoid, infodata, AsyncDelegate, AsyncState);
        }
        int Process(IFConn from, UInt32 srcid, UInt32 destid, UInt32 magic, UInt16 info_no, byte[] infodata, out byte[] retdata)
        {
            retdata = null;
            IFObj destobj = Find(destid);
            if (destobj == null)
                return -1;
            return destobj.ProcessEx(from, srcid, magic, info_no, infodata,out retdata);  
        }
        #endregion
        DateTime dtlast = DateTime.Now;
        /// <summary>
        /// 从异端接收的数据,解释数据
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="conn"></param>
        /// <returns></returns>
        bool ParsePacketInClient(byte[] packet, IFConn conn)
        {
            //DateTime dt2 = DateTime.Now;
            Pack_Proto p = new Pack_Proto();
            if (!p.TryParse(packet))
                return false;

            conn.TranID = p.magic;
            {
                byte[] idata = p.buf;

                byte[] retdata;
                if (Process(conn, p.srcid, p.destid, p.magic, p.info, idata, out retdata) == 0)
                {
                    if (retdata != null)
                    {
                        SendMessageEx(conn,p.srcid,p.destid,p.magic,p.info,retdata);
                    }
                    return true;
                }
            }

            switch (p.info)
            {
                case Proto.INFO_PUSH_EVENT:
                    {
                        Pack_GetSetPushCall pack = new Pack_GetSetPushCall();
                        if (!pack.TryParse(p.buf))
                            return false;
                        PushObjInfo(conn, p.srcid, p.destid, pack.infoid, pack.infodata);
                    }break;
                case Proto.INFO_PUSH_GET_VALUE:
                    {
                        Pack_GetSetPushCall pack = new Pack_GetSetPushCall();
                        if (!pack.TryParse(p.buf))
                            return false;
                        PushGetValue(conn, p.srcid, p.destid, pack.infoid, pack.infodata);
                    }break;
                case Proto.INFO_PUSH_CALL_FUNCTION:
                    {
                        Pack_GetSetPushCall pack = new Pack_GetSetPushCall();
                        if (!pack.TryParse(p.buf))
                            return false;

                        var ts = from t in Transactions where (t.Magic == p.magic) && (t.Conn == conn) select t;
                        if (ts.Count() > 0)
                        {
                            Transaction tran = ts.First();
                            Transactions.Remove(tran);//用完,删除
                            PushCallFunction(conn, p.srcid, p.destid, p.magic, pack.infoid, pack.infodata, tran.AsyncDelegate, tran.AsyncState);
                        }
                        else 
                        {
                            PushCallFunction(conn, p.srcid, p.destid, p.magic, pack.infoid, pack.infodata, null, null);
                        }
                    } break;
                case Proto.INFO_PUSH_CALL_FUNCTION_REQUEST_BIGSIZE:
                    {
                        CallFunctionEx_RequestBigSize(conn, p.srcid, p.destid, p.magic);
                    } break;
                case Proto.INFO_PUSH_CALL_FUNCTION_REPONSE_BIGSIZE:
                    {
                        Pack_BigSize pack = new Pack_BigSize();
                        if (!pack.TryParse(p.buf))
                            return false;
                        var ts = from t in Transactions where t.Conn == conn && t.Magic == p.magic select t;
                        Transaction tran;
                        if (ts.Count() == 0)
                        {
                            tran = new Transaction()
                            {
                                Conn = conn,
                                SrcObjID = p.destid,
                                Magic = p.magic
                            };
                            Transactions.Add(tran);
                        }
                        else
                        {
                            tran = ts.First();
                        }

                        if (!tran.ToBuf(pack))
                        {
                            //继续获取参数!!!!!!!!!
                            SendMessageEx(conn, p.srcid, p.destid, p.magic,
                                Proto.INFO_CALL_FUNCTION_REPONSE_BIGSIZE, null);
                        }
                        else
                        {
                            Transactions.Remove(tran);//用完了,删除!!!
                            

                            PushCallFunction(conn, p.srcid, p.destid, p.magic, tran.FuncID, tran.Buf, tran.AsyncDelegate, tran.AsyncState);
                        }
                    } break;
            }

            //DateTime dt1 = DateTime.Now;
            //Console.WriteLine("FObjSys ParsePacketInClient " + "p.info=" + p.info.ToString() + " " + (dt1 - dt2).TotalMilliseconds.ToString() + " " + (dt1 - dtlast).TotalMilliseconds.ToString());
            //dtlast = dt1;

            return true;
        }

        /// <summary>
        /// 从异端接收的数据,解释数据
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="conn"></param>
        /// <returns></returns>
        bool ParsePacketInServer(byte[] packet, IFConn conn)
        {
            //DateTime dt2 = DateTime.Now;
            Pack_Proto p = new Pack_Proto();
            if (!p.TryParse(packet))
                return false;

            conn.TranID = p.magic;
            {
                byte[] idata = p.buf;

                byte[] retdata;
                if (Process(conn, p.srcid, p.destid, p.magic, p.info, idata, out retdata) == 0)
                {
                    if (retdata != null)
                    {
                        SendMessageEx(conn, p.srcid, p.destid, p.magic, p.info, retdata);
                    }
                    return true;
                }
            }

            switch (p.info)
            {
                case Proto.INFO_SET_VALUE:
                    {
                        int index = 0;
                        UInt16 memid = BitConverter.ToUInt16(p.buf, index);
                        index += 2;
                        int len = p.buf.Length - index;
                        byte[] value = new byte[len];
                        Array.Copy(p.buf, index, value, 0, value.Length);

                        SetValue(conn, p.srcid, p.destid, memid, value);
                    } break;
                case Proto.INFO_GET_VALUE:
                    {
                        int index = 0;
                        UInt16 memid = BitConverter.ToUInt16(p.buf, index);
                        index += 2;

                        byte[] value;
                        GetValue(conn, p.srcid, p.destid, memid, out value);
                        if (value != null)
                        {
                            List<byte> buf = new List<byte>();
                            buf.AddRange(BitConverter.GetBytes(memid));
                            buf.AddRange(value);

                            SendMessageEx(conn, p.srcid, p.destid, p.magic,
                                Proto.INFO_PUSH_GET_VALUE,
                                buf.ToArray());
                        }
                    } break;
                case Proto.INFO_CALL_FUNCTION:
                    {
                        int index = 0;
                        UInt16 memid = BitConverter.ToUInt16(p.buf, index);
                        index += 2;
                        int len = p.buf.Length - index;
                        byte[] value = null;
                        if (len > 0)
                        {
                            value = new byte[len];
                            Array.Copy(p.buf, index, value, 0, value.Length);
                        }

                        CallFunction(conn, p.srcid, p.destid, p.magic, memid, value);
                    } break;
                case Proto.INFO_CALL_FUNCTION_REQUEST_BIGSIZE:
                    {
                        Pack_BigSize pack = new Pack_BigSize();
                        if (!pack.TryParse(p.buf))
                            return false;
                        var ts = from t in Transactions where t.Conn == conn && t.Magic == p.magic select t;
                        Transaction tran;
                        if (ts.Count() == 0)
                        {
                            tran = new Transaction()
                            {
                                Conn = conn,
                                SrcObjID = p.srcid,
                                Magic = p.magic
                            };
                            Transactions.Add(tran);
                        }
                        else
                        {
                            tran = ts.First();
                        }

                        if (!tran.ToBuf(pack))
                        {
                            //继续获取参数!!!!!!!!!
                            SendMessageEx(conn, p.srcid, p.destid, p.magic,
                                Proto.INFO_PUSH_CALL_FUNCTION_REQUEST_BIGSIZE,null);
                        }
                        else 
                        {
                            Transactions.Remove(tran);//用完了,删除!!!
                            CallFunction(conn, p.srcid, p.destid, p.magic, tran.FuncID, tran.Buf);
                        }
                    }break;
                case Proto.INFO_CALL_FUNCTION_REPONSE_BIGSIZE:
                    {
                        PushCallFunctionEx_ReponseBigSize(conn, p.srcid, p.destid, p.magic);
                    }break;
                case Proto.INFO_CONFIG_SENSE_OBJ:
                    {
                        SENSE_CONFIG action;

                        if (p.buf[0] == 0)
                            action = SENSE_CONFIG.ADD;
                        else
                            action = SENSE_CONFIG.REMOVE;

                        UInt32 mask = BitConverter.ToUInt32(p.buf, 1);
                        Sense_Config(conn, p.srcid, p.destid, mask, action);
                    } break;
                case Proto.INFO_OBJ_DISPOSE:
                    {
                        ClearRemoteObjConn(conn, p.srcid);
                    } break;
            }
            //DateTime dt1 = DateTime.Now;
            //Console.WriteLine("FObjSys ParsePacketInServer " + "p.info=" + p.info.ToString() + " " + (dt1 - dt2).TotalMilliseconds.ToString() + " " + (dt1 - dtlast).TotalMilliseconds.ToString());
            //dtlast = dt1;
            return true;
        }
        class Transaction
        {
            #region 成员变量
            public UInt32 SrcObjID;//客户端发起的 源ID
            public IFConn Conn;
            /// <summary>
            /// 包总大小, -1 ,大小未知
            /// </summary>
            public int Size = -1;
            public int Position = 0;

            /// <summary>
            /// 交易号, 服务器分配的
            /// </summary>
            public UInt32 Magic;

            /// <summary>
            /// 数据
            /// </summary>
            public byte[] Buf;

            public object AsyncDelegate;

            public object AsyncState;

            public UInt16 FuncID;

            public const UInt16 PackSize = 0x4000;
            #endregion
            public Transaction()
            {
                Size = 0;
                Position = 0;
                Magic = 0;
                Buf = null;
            }

            byte[] GetBuf()
            {
                int len = Buf.Length - Position;
                if (len > PackSize)
                    len = PackSize;
                byte[] buf = new byte[len];
                Array.Copy(Buf, Position, buf, 0, len);
                return buf;
            }

            public bool GetBigSize(out Pack_BigSize p)
            {
                p = new Pack_BigSize();
                p.funcid = FuncID;
                p.size = Size;
                p.position = Position;
                p.buf = GetBuf();

                Position += p.buf.Length;
                if (Position == Size)
                    return true;
                else

                    return false;
            }
            public bool Reset()
            {
                Buf = null;
                Size = -1;
                Position = 0;
                if ((AsyncDelegate == null) && (AsyncState == null))
                {
                    return true;
                }
                return false;
            }
            public bool ToBuf(Pack_BigSize p)
            {
                if (Buf == null)
                {
                    FuncID = p.funcid;
                    Size = p.size;
                    Buf = new byte[Size];
                    Array.Copy(p.buf, 0, Buf, p.position, p.buf.Length);
                    Position = p.position + p.buf.Length;
                    return false;
                }
                else
                {
                    Array.Copy(p.buf, 0, Buf, p.position, p.buf.Length);
                    Position = p.position + p.buf.Length;
                    if (Position == Size)
                    {
                        return true;
                    }
                    return false;
                }
            }
        }
    }


}