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

using System.ComponentModel;
using FObjBase;
using FLY.Thick.Base.OBJ_INTERFACE;
using FLY.Thick.Base.Common;
using FLY.Thick.Base.IService;
using Newtonsoft.Json;

namespace FLY.Thick.Base.Server.OBJProxy
{
    public class FlyAD_OBJProxy: FObj
    {
        #region 延时推送 MARKNO
        const int MARKNO_PUSH_PARAMS = 1;
        const int MARKNO_PUSH_ACCESS = 2;
        #endregion

        FlyADBase.FlyAD7 mFlyAD;
        AD2ThickHandler AD2Thick;
        public FlyAD_OBJProxy(int objsys_idx, UInt32 id, FlyADBase.FlyAD7 flyad,
            AD2ThickHandler AD2Thick )
            : base(objsys_idx)
        {
            ID = id;
            mFlyAD = flyad;
            this.AD2Thick = AD2Thick;
            mFlyAD.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(mFlyAD_PropertyChanged);
        }
        static string[] propertyname_params = new string[] {
            "LocalEP","HasCRC","GridSmooth","IsCalSpeed","PosOfGrid","PosLen","MotorType","Ratio01","Ratio02","PosOffset","JogVelocity"
        };
        void mFlyAD_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (propertyname_params.Contains(e.PropertyName))
            {
                FObjBase.PollModule.Current.Poll_JustOnce(
                    new PollModule.PollHandler(delegate()
                    {
                        byte[] buf;
                        GetValue(null, 0, FLYAD_OBJ_INTERFACE.GET_PARAMS, out buf);
                        CurrObjSys.PushObjInfoEx(
                            this, FLYAD_OBJ_INTERFACE.PUSH_PARAMS,
                            buf);
                    }), this, MARKNO_PUSH_PARAMS);
            }
        }
        #region FObj 重载
        public override void GetValue(IFConn from, uint srcid, ushort memid, out byte[] infodata)
        {
            infodata = null;
            switch (memid)
            {
                case FLYAD_OBJ_INTERFACE.GET_PARAMS:
                    {
                        
                        FLYAD_OBJ_INTERFACE.Pack_Params p = new FLYAD_OBJ_INTERFACE.Pack_Params()
                        {
                            ep = mFlyAD.LocalEP.ToString(),
                            hasCRC = mFlyAD.HasCRC,
                            gridsmooth = mFlyAD.GridSmooth,
                            IsCalSpeed = mFlyAD.IsCalSpeed,
                            posofgrid = mFlyAD.PosOfGrid,
                            motortype = (MOTORTYPE) mFlyAD.MotorType,
                            poslen = mFlyAD.PosLen,
                            ratio01 = mFlyAD.Ratio01,
                            ratio02 = mFlyAD.Ratio02,
                            posoffset = mFlyAD.PosOffset,
                            jogvelocity = mFlyAD.JogVelocity
                        };
                        string json = JsonConvert.SerializeObject(p);
                        
                        infodata = Misc.Converter.StringToBytes(json);
                    }
                    break;
                default:
                    infodata = null;
                    break;
            }
        }
        public override void SetValue(IFConn from, uint srcid, ushort memid, byte[] infodata)
        {
            switch (memid)
            {
                case FLYAD_OBJ_INTERFACE.SET_PARAMS:
                    {
                        string json = Misc.Converter.BytesToString(infodata);
                        var p = JsonConvert.DeserializeObject<FLYAD_OBJ_INTERFACE.Pack_Params>(json);
                        
                        mFlyAD.HasCRC = p.hasCRC;
                        mFlyAD.GridSmooth = p.gridsmooth;
                        mFlyAD.IsCalSpeed = p.IsCalSpeed;
                        var ep = Misc.StringConverter.ToIPEndPoint(p.ep);
                        if(!mFlyAD.LocalEP.Equals(ep))
                            mFlyAD.Connect(ep);
                        mFlyAD.PosOffset = p.posoffset;
                        mFlyAD.JogVelocity = p.jogvelocity;
                        mFlyAD.PosOfGrid = p.posofgrid;
                        mFlyAD.MotorType = (FlyADBase.MOTORTYPE)p.motortype;
                        mFlyAD.Ratio01 = p.ratio01;
                        mFlyAD.Ratio02 = p.ratio02;
                            
                        
                    } break;
            }
        }
        public override void CallFunction(IFConn from, uint srcid, uint magic, ushort funcid, byte[] infodata)
        {
            switch (funcid) 
            {
                case FLYAD_OBJ_INTERFACE.CALL_UPDATEPARAM:
                    {
                        mFlyAD.UpdateParam();
                    }break;
                case FLYAD_OBJ_INTERFACE.CALL_GETACCESSINFO:
                    {
                        GetAccessInfo(
                            new AsyncCBHandler(delegate(object AsyncState, object retdata)
                            {
                                ConnContext context = (ConnContext)AsyncState;
                                string json = JsonConvert.SerializeObject(retdata);

                                CurrObjSys.PushCallFunctionEx(
                                    context.from,
                                    context.srcid,
                                    ID,
                                    context.magic,
                                    FLYAD_OBJ_INTERFACE.CALL_GETACCESSINFO,
                                    Misc.Converter.StringToBytes(json)
                                    );
                            }), new ConnContext(from, srcid, magic));

                    } break;
                case FLYAD_OBJ_INTERFACE.CALL_SETACCESS:
                    {
                        string json = Misc.Converter.BytesToString(infodata);

                        var p = JsonConvert.DeserializeObject<FLYAD_OBJ_INTERFACE.Pack_SetAccessRequest>(json);

                        SetAccess(
                            p.data,
                            new AsyncCBHandler(delegate(object AsyncState, object retdata)
                            {
                                ConnContext context = (ConnContext)AsyncState;
                                string json_reponse = JsonConvert.SerializeObject(retdata);

                                CurrObjSys.PushCallFunctionEx(
                                    context.from,
                                    context.srcid,
                                    ID,
                                    context.magic,
                                    FLYAD_OBJ_INTERFACE.CALL_SETACCESS,
                                    Misc.Converter.StringToBytes(json_reponse)
                                    );
                            }), new ConnContext(from, srcid, magic));

                    } break;
                case FLYAD_OBJ_INTERFACE.CALL_GETGRID:
                    {
                        string json = Misc.Converter.BytesToString(infodata);

                        var p = JsonConvert.DeserializeObject<FLYAD_OBJ_INTERFACE.Pack_GetGridRequest>(json);
                        
                        GetGrid(
                            p.direction,
                            new AsyncCBHandler(delegate(object AsyncState, object retdata)
                            {
                                string json_reponse = JsonConvert.SerializeObject(retdata);

                                ConnContext context = (ConnContext)AsyncState;
                                CurrObjSys.PushCallFunctionEx(
                                    context.from,
                                    context.srcid,
                                    ID,
                                    context.magic,
                                    FLYAD_OBJ_INTERFACE.CALL_GETGRID,
                                    Misc.Converter.StringToBytes(json_reponse));
                            }), new ConnContext(from, srcid, magic));
                    }break;
            }
        }
        #endregion

        /// <summary>
        /// 获取序列码
        /// </summary>
        /// <param name="AsyncDelegate">返回类型为 AccessInfo</param>
        /// <param name="AsyncState">可为null</param>
        void GetAccessInfo(AsyncCBHandler AsyncDelegate, object AsyncState)
        {
            AccessInfo ainfo = new AccessInfo()
            {
                status = (AREA_STATUS)mFlyAD.AreaStatus,
                ret = (AREA_ERR)mFlyAD.AreaRet,
                surplus = (UInt16)mFlyAD.Surplus,
                code = mFlyAD.Code,
                access = mFlyAD.Access
            };
            AsyncDelegate(AsyncState, ainfo);
        }
        class AsyncDelegateObj
        {
            public AsyncCBHandler AsyncDelegate;
            public object AsyncState;
        }
        List<AsyncDelegateObj> setAccessRetList = new List<AsyncDelegateObj>();

        PropertyChangedEventHandler mFlyAD_PropertyChangedHandler = null;
        /// <summary>
        /// 设置授权码
        /// </summary>
        /// <param name="access">授权码</param>
        /// <param name="AsyncDelegate">返回类型为 AccessInfo</param>
        /// <param name="AsyncState">可为null</param>
        void SetAccess(byte[] access, AsyncCBHandler AsyncDelegate, object AsyncState)
        {
            mFlyAD.SetAccess(access);
            setAccessRetList.Add(new AsyncDelegateObj() { AsyncDelegate = AsyncDelegate, AsyncState = AsyncState });

            if (mFlyAD_PropertyChangedHandler == null)
            {
                mFlyAD_PropertyChangedHandler = new PropertyChangedEventHandler(delegate(object sender, PropertyChangedEventArgs e)
                {
                    if ((e.PropertyName == "AreaStatus") ||
                        (e.PropertyName == "Code") ||
                        (e.PropertyName == "Surplus") ||
                        (e.PropertyName == "Access") ||
                        (e.PropertyName == "AreaRet"))
                    {
                        FObjBase.PollModule.Current.Poll_JustOnce(
                                new PollModule.PollHandler(delegate()
                                {
                                    mFlyAD.PropertyChanged -= mFlyAD_PropertyChangedHandler;
                                    AccessInfo ainfo = new AccessInfo()
                                    {
                                        status = (AREA_STATUS)mFlyAD.AreaStatus,
                                        ret = (AREA_ERR)mFlyAD.AreaRet,
                                        surplus = (UInt16)mFlyAD.Surplus,
                                        code = mFlyAD.Code,
                                        access = mFlyAD.Access
                                    };
                                    for (int i = 0; i < setAccessRetList.Count(); i++)
                                    {
                                        setAccessRetList[i].AsyncDelegate(setAccessRetList[i].AsyncState, ainfo);
                                    }
                                    setAccessRetList.Clear();
                                }), this, MARKNO_PUSH_ACCESS);
                    };
                });
            }
            mFlyAD.PropertyChanged += mFlyAD_PropertyChangedHandler;
        }

        /// <summary>
        /// 获取grid
        /// </summary>
        /// <param name="direction">方向</param>
        /// <param name="AsyncDelegate">返回类型为 byte[]</param>
        /// <param name="AsyncState">可为null</param>
        void GetGrid(Misc.DIRECTION direction, AsyncCBHandler AsyncDelegate, object AsyncState) 
        {
            mFlyAD.GetGrid(direction, out int[] dat);
            double[] thicks = null;
            if (dat != null)
            {
                thicks = dat.Select(ad =>
                {
                    int thick100 = AD2Thick(ad);
                    if (Misc.MyBase.ISVALIDATA(thick100))
                        return Math.Round(thick100 / 100.0, 2);
                    else
                        return double.NaN;
                }).ToArray();
            }
           
            GridInfo p = new GridInfo()
            {
                direction = direction,
                data = dat,
                thick = thicks
            };
            AsyncDelegate(AsyncState, p);
        }
    }
}
