import { v4 as uuid } from "uuid";
import { FindNode } from "./COMMON";
export default class ReflectSeviceClientAssistant
{
    constructor(){

        //#region public

        //#endregion

        //#region private
        /**
         * @description 发送数据
         * @type (data:string)=>void
         */
        this._send = null;
        /**
         * @description 代理对象
         * @type Reflect_SeviceClient
         */
        this._obj = null;

        /**
         * @description 缓存 发出 CALL_GetAllProperties指令，到收到回复 之间时段的 全部推送
         * @type Array<{name:string,data:object}>
         */
        this._pushInfoList = [];

        /**
         * @description method 的回调函数
         * @type Array<{
         * guid:string,
         * asyncDelegate:(context:object,retData:object)=>void,
         * asyncContext:object}>();
         */
        this._anyMethodInvokes = [];
        //#endregion
    }

    //#region public
    /**
     * 
     * @param {*} obj 
     */
    Init(obj, send)
    {
        this._obj = obj;
        this._send = send;
    }
    
    /**
     * @description 第1次连接成功
     */
    OnOpen(){

        console.log(`OnOpen`);
        //获取全部属性
        this.GetValue(null,(context,retData)=>{
            console.log(`获取全部属性 ${retData}`);

            //同步完成
            this._obj.IsSynced.value = true;

            //处理全部event
            this._dealPushInfoList();
        },null);
    }

    OnClose(){
        console.log(`OnClose`);
        this._obj.IsSynced.value = false;
    }

    OnMessage(data){

        var pkgData = JSON.parse(data);
        console.log(`OnMessage ${pkgData}`);

        //可能是 Event， 也可能是 Method
        if (!pkgData.guid){
            //EVENT
            if (!this._obj.IsSynced.value){
                //还没同步完成，先缓存
                this._pushInfoList.push({
                        name : pkgData.name,
                        data : pkgData.data
                    });
                return;
            }
            else{
                this._receive_EVENT(pkgData.name, pkgData.data);
            }
        }
        else{
            //METHOD
            var idx = this._anyMethodInvokes.findIndex(ami => ami.guid == pkgData.guid);
            if(idx==-1){
                //没有这个GUID
                //异常！！！应该有对应的回调
                throw new Error(`${pkgData.name} 异常！！！应该有回调`);
            }
            var anyMethodInvoke = this._anyMethodInvokes[idx];
            
            this._receive_CALL_MethodInvoke(
                pkgData.name, 
                pkgData.data, 
                anyMethodInvoke.asyncDelegate, 
                anyMethodInvoke.asyncContext);
            
            //删除
            this._anyMethodInvokes.splice(idx, 1);
        }
    }

    GetValue(nodePath, asyncDelegate, asyncContext){

        var parameters = nodePath;
        this._send_CALL_MethodInvoke("GetValue", parameters, (context,retData)=>{
            
            this._receive_EVENT_PropertyChanged(retData);

            if(context.asyncDelegate!=null){
                context.asyncDelegate(context.asyncContext,retData);
            }

        }, {asyncDelegate, asyncContext});
    }

    SetValue(value,nodePath,asyncDelegate, asyncContext){
        var parameters = {
            data:value
        };
        if(nodePath!=null){
            parameters.name = nodePath;
        }
        console.log(JSON.stringify(parameters));
        this._send_CALL_MethodInvoke("SetValue", parameters, asyncDelegate, asyncContext);
    }

    Call(methodName, parameters, asyncDelegate, asyncContext){
        this._send_CALL_MethodInvoke(methodName, parameters, asyncDelegate, asyncContext);
    }
    
    //#endregion


    //#region private

    /**
     * @description 处理全部 缓存的推送数据
     */
    _dealPushInfoList(){

        for (let i = 0; i < this._pushInfoList.length; i++){
            var pushInfoData = this._pushInfoList[i];
            this._receive_EVENT(pushInfoData.name, pushInfoData.data);
        }

        this._pushInfoList = [];
    }

    /**
     * @description 处理 从服务器 回复的 PUSH_PropertyChanged
     * @param {{name:string,data:object}} data 
     */
    _receive_EVENT_PropertyChanged(data){

        console.log(`属性改变 ${data}`);

        this._obj.IsInPushValue = true;

        //需要更新的 属性对象节点
        var nodePath = data.name;
        //数据
        var obj = data.data;
        
        if(nodePath == null || nodePath == '.'){
            //根
            for(let key in obj){
                var value = obj[key];
                //this._obj.Data 是VUE 的 reactive()
                this._obj.Data[key] = value;
            }
        }
        else{
            var path_str = FindNode(nodePath);
            for(let key in obj){
                var value = obj[key];
                var eval_str2 = `this._obj.Data${path_str}.${key}=value`;
                console.log(eval_str2);
                eval(eval_str2);
            }
        }
        this._obj.IsInPushValue = false;

    }

    /**
     * @description 处理 从服务器 回复的 EVENT 
     * @param {string} eventName  
     * @param {object} retData 
     */
    _receive_EVENT(eventName, retData){
        console.log(`事件触发 ${eventName} ${retData}`);
        if (eventName == "PropertyChanged"){
            this._receive_EVENT_PropertyChanged(retData);
        }
        else{
            this._obj.EventEmitter.emit(eventName,retData);
        }
    }

    /**
     * @description 处理 从服务器 回复的 CALL_MethodInvoke
     * @param {string} methodName 
     * @param {object} retData
     * @param {(context:object,retData:object)=>void} asyncDelegate 
     * @param {object} asyncContext 
     */
    _receive_CALL_MethodInvoke(methodName, retData, asyncDelegate, asyncContext){

        console.log(`函数触发 ${methodName} ${retData}`);

        if(asyncDelegate!=null)
            asyncDelegate(asyncContext, retData);
    }

    /**
     * @description 发送 CALL_MethodInvoke 请求到服务
     * @param {string} methodName 
     * @param {object} methodParams 
     * @param {(context:object,retData:object)=>void} asyncDelegate 
     * @param {object} asyncContext 
     */
    _send_CALL_MethodInvoke(methodName, methodParams,  asyncDelegate, asyncContext){
        var pkgData = {
            guid:uuid(),
            name:methodName
        };

        if(methodParams!=null)
            pkgData.data = methodParams;

        this._anyMethodInvokes.push(
        {
            guid:pkgData.guid,
            asyncDelegate:asyncDelegate,
            asyncContext:asyncContext
        });
        var json = JSON.stringify(pkgData);
        console.log(`send_CALL ${json}`);
        this._send(json);
    }
    //#endregion
}