using FLY.OBJComponents.Common;
using FLY.OBJComponents.IService;
using FLY.OBJComponents.OBJ_INTERFACE;
using FObjBase;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;

namespace FLY.OBJComponents.Client
{
    public class SyncPropServiceClient : FObj
    {
        Dictionary<string, INotifyPropertyChanged> ObjNames;

        IFConn mConn;
        UInt32 mServerID;

        //public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 当前 INotifyPropertyChanged 对象 引发了 PropertyChanged,  是由于 接收到数据导致的
        /// </summary>
        public bool IsInPushValue { get; protected set; }

        /// <summary>
        /// 同步完成
        /// </summary>
        public bool IsSynced { get; private set; }

        /// <summary>
        /// 缓存 发出 GetAllData指令，到收到回复 之间时段的 全部推送
        /// </summary>
        List<Dictionary<string, Dictionary<string, object>>> pushDataList = new List<Dictionary<string, Dictionary<string, object>>>();
        /// <summary>
        /// Add 函数， 添加的 objname， 必须等全部 都返回。  只要 addObjNameList.Count() 不为0, 也是要缓存 推送的
        /// </summary>
        List<string> addObjNameList = new List<string>();

        public SyncPropServiceClient(UInt32 serverID, Dictionary<string, INotifyPropertyChanged> objnames)
        {
            mServerID = serverID;
            Init(objnames);
        }
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="objnames"></param>
        void Init(Dictionary<string, INotifyPropertyChanged> objnames)
        {
            ObjNames = objnames;

            foreach (INotifyPropertyChanged obj in ObjNames.Values)
            {
                obj.PropertyChanged += Data_PropertyChanged;
            }
        }
        /// <summary>
        /// 在Init后，删除某个obj
        /// </summary>
        /// <param name="objname"></param>
        public void Remove(string objname)
        {
            ObjNames[objname].PropertyChanged -= Data_PropertyChanged;
            ObjNames.Remove(objname);
        }
        /// <summary>
        /// 在Init后，添加某个obj
        /// </summary>
        public void Add(string objname, INotifyPropertyChanged obj)
        {
            ObjNames.Add(objname, obj);

            //向服务器，只获取这个对象的数据

            //暂停接收推送。。。。
            IsSynced = false;
            addObjNameList.Add(objname);

            string json = JsonConvert.SerializeObject(objname);
            FObjBase.FObjSys.Current.CallFunctionEx(mConn, mServerID, ID, SYNCPROP_OBJ_INTERFACE.CALL_GET_DATA,
                Misc.Converter.StringToBytes(json));
        }
        /// <summary>
        /// 属性变化时通知
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Data_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            PropertyInfo property = sender.GetType().GetProperty(e.PropertyName);
            if (!property.CanWrite)
            {
                return;
            }

            if (sender is IPropertyOpt)
            {
                var opt = (IPropertyOpt)sender;
                string[] sync = opt.GetSyncPropNames();
                if (sync != null && sync.Count() != 0)
                {
                    if (!sync.Contains(e.PropertyName))
                    {
                        //没有包含，不需要同步
                        return;
                    }
                }
                else
                {
                    string[] nosync = opt.GetNoSyncPropNames();
                    if (nosync != null && nosync.Count() != 0)
                    {
                        if (nosync.Contains(e.PropertyName))
                        {
                            //这个不需要同步
                            return;
                        }
                    }
                }
            }

            string objname = (from kv in ObjNames where kv.Value == sender select kv.Key).First();

            Dictionary<string, Dictionary<string, object>> DsDso = new Dictionary<string, Dictionary<string, object>>
            {
                {
                    objname, new Dictionary<string, object>
                    {
                        {e.PropertyName, Misc.PropertiesManager.GetValue(sender, e.PropertyName)}
                    }
                }
            };

            string json = JsonConvert.SerializeObject(DsDso);
            FObjBase.FObjSys.Current.CallFunctionEx(mConn, mServerID, ID, SYNCPROP_OBJ_INTERFACE.CALL_SET_DATA,
                Misc.Converter.StringToBytes(json));
        }

        public override void ConnectNotify(IFConn from)
        {
            mConn = from;

            IsSynced = false;
            pushDataList.Clear();

            if (from.IsConnected)
            {
                CurrObjSys.CallFunctionEx(mConn, mServerID, ID,
                    SYNCPROP_OBJ_INTERFACE.CALL_GET_ALL_DATA, null);


                CurrObjSys.SenseConfigEx(mConn, mServerID, ID,
                    0xffffffff, SENSE_CONFIG.ADD);
            }

        }



        public override void PushInfo(IFConn from, uint srcid, ushort infoid, byte[] infodata)
        {
            switch (infoid)
            {
                case SYNCPROP_OBJ_INTERFACE.PUSH_DATA:
                    {
                        string json = Misc.Converter.BytesToString(infodata);
                        Dictionary<string, Dictionary<string, object>> DsDso = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, object>>>(json);

                        if (!IsSynced)
                        {
                            //还没同步完成，先缓存
                            pushDataList.Add(DsDso);
                            return;
                        }

                        IsInPushValue = true;

                        foreach (var Dso in DsDso)
                        {
                            INotifyPropertyChanged obj = ObjNames[Dso.Key];
                            obj.PropertyChanged -= Data_PropertyChanged;

                            foreach (var dv in Dso.Value)
                            {
                                PropertiesManager_JSON.SetValue(obj, dv.Key, dv.Value);
                            }

                            obj.PropertyChanged += Data_PropertyChanged;
                        }
                        IsInPushValue = false;
                    }
                    break;
            }
        }
        /// <summary>
        /// 处理全部 缓存的推送数据
        /// </summary>
        void DealPushDataList()
        {
            IsInPushValue = true;
            for (int i = 0; i < pushDataList.Count(); i++)
            {
                var DsDso = pushDataList[i];

                foreach (var Dso in DsDso)
                {
                    INotifyPropertyChanged obj = ObjNames[Dso.Key];
                    obj.PropertyChanged -= Data_PropertyChanged;

                    foreach (var dv in Dso.Value)
                    {
                        PropertiesManager_JSON.SetValue(obj, dv.Key, dv.Value);
                    }

                    obj.PropertyChanged += Data_PropertyChanged;
                }
            }
            IsInPushValue = false;

            pushDataList.Clear();
        }
        public override void PushCallFunction(IFConn from, uint srcid, uint magic, ushort funcid, byte[] retdata, AsyncCBHandler asyncDelegate, object asyncContext)
        {
            switch (funcid)
            {
                case SYNCPROP_OBJ_INTERFACE.CALL_GET_ALL_DATA:
                    {
                        //这个可能是大包来的，很慢，需要记录中途全部 push
                        string json = Misc.Converter.BytesToString(retdata);
                        //log.Debug("GetAllData:" +json);
                        Dictionary<string, Dictionary<string, object>> DsDso = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, object>>>(json);
                        IsInPushValue = true;
                        foreach (var Dso in DsDso)
                        {
                            if (ObjNames.ContainsKey(Dso.Key))
                            {
                                INotifyPropertyChanged obj = ObjNames[Dso.Key];
                                obj.PropertyChanged -= Data_PropertyChanged;
                                foreach (var dv in Dso.Value)
                                {
                                    PropertiesManager_JSON.SetValue(obj, dv.Key, dv.Value);
                                }
                                obj.PropertyChanged += Data_PropertyChanged;
                            }
                        }
                        IsInPushValue = false;
                        //完成同步
                        IsSynced = true;
                        //处理之前的推送事件
                        DealPushDataList();
                    }
                    break;
                case SYNCPROP_OBJ_INTERFACE.CALL_GET_DATA:
                    {
                        string json = Misc.Converter.BytesToString(retdata);
                        Dictionary<string, Dictionary<string, object>> DsDso = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, object>>>(json);
                        IsInPushValue = true;
                        foreach (var Dso in DsDso)
                        {
                            if (ObjNames.ContainsKey(Dso.Key))
                            {
                                INotifyPropertyChanged obj = ObjNames[Dso.Key] as INotifyPropertyChanged;
                                obj.PropertyChanged -= Data_PropertyChanged;
                                foreach (var dv in Dso.Value)
                                {
                                    PropertiesManager_JSON.SetValue(obj, dv.Key, dv.Value);
                                }
                                obj.PropertyChanged += Data_PropertyChanged;
                            }

                            addObjNameList.Remove(Dso.Key);
                        }
                        IsInPushValue = false;

                        //全部接收完！！！
                        if (addObjNameList.Count() == 0)
                        {
                            //完成同步
                            IsSynced = true;
                            //处理之前的推送事件
                            DealPushDataList();
                        }
                    }
                    break;
            }
        }
    }

}
