import { FrameworkConf } from "../../framework/config/FrameworkConf";
import { Framework } from "../../framework/Framework";
import { GameEvent } from "../data/GameEvent";
import { StringUtil } from "../../framework/util/StringUtil";
import { ViewID } from "../../framework/config/LayerConf";


export let NetMgr: NetManager = null;

export class NetManager {
    private _socket: WebSocket = null;
    private _web_url = "";                              //服务器地址
    private _callback: Function = null;

    private _hear_time = 5;                            //心跳时间
    private _hear_time_out = 2;                        //心跳超次数()
    private _hear_time_cur = 0;                         //心跳超时次数
    private _hear_uuid = 0;                             //心跳定时器
    private _is_connect = false;                        //网络是否连接

    private _bReconnect = false;                            //是否重连
    private _bHandShake = false;                        //是否握手
    private _bProClose = false;                        //是否主动断开   
    
    private _uid = 0;
    private _seq = 0;

    //心跳超时 自动重连,超过5次则不再重连
    private _auto_reconnect_time = 0;
    private _auto_reconnect_time_out = 5;

    private _socketId = 0;

    static get instance() {
        if (NetMgr == null) {
            NetMgr = new NetManager();
        }
        return NetMgr;
    }


    //网络是否连接
    get is_connect() {
        return this._is_connect;
    }

    get is_handShake() {
        return this._bHandShake;
    }

    get bReconnect() {
        return this._bReconnect;
    }

    get bProClose() {
        return this._bProClose;
    }

    connect(url: string, callback: Function) {
        //this.close(false);

        let socketId = ++this._socketId
        this._clearHeart();
        this._web_url = url;
        this._callback = callback;
        this._socket = new WebSocket(this._web_url, 'default-protocol');
        this._socket.binaryType = "arraybuffer";

        this._socket.onopen = (event: any) => {
            if(socketId != this._socketId){
                return
            }
            callback && callback(0);
            callback = null;
            this._is_connect = true;
            this._bProClose = false

            this._auto_reconnect_time = 0
            this._hear_time_cur = 0
            
        };

        this._socket.onerror = (event: any) => {
            if(socketId != this._socketId){
                return
            }
            console.log("onerror:", event," socketId:",socketId);
            callback && callback(1);
            callback = null;
            this._is_connect = false;
            this._bHandShake = false
            this._clearHeart();
            // this._socket = null
            // this._autoReconnect(3)
            Framework.event.fireEvent(FrameworkConf.Event.NET_ERROR, event);
        };

        this._socket.onclose = (event: any) => {
            if(socketId != this._socketId){
                return
            }
            console.log("onclose1:", event," socketId:",socketId);
            this._is_connect = false;
            this._bHandShake = false
            this._bReconnect = false
            this._clearHeart();
            this._socket = null
            Framework.layer.open(ViewID.MaskUI,()=>{});
            if(!this._bProClose){
                this._autoReconnect(3)
            }
            else Framework.event.fireEvent(FrameworkConf.Event.NET_CLOSE, event);
        };

        this._socket.onmessage = (event: any) => {

            let Json = JSON.parse(event.data)
            // console.log(Json);
            
            if (Json.mod == 'user' && Json.act == 'handshake') {
                
                this._startHeart();
                
                if (Json.code == 0) {
                    Framework.layer.close(ViewID.MaskUI);
                    this._bHandShake = true
                   // if(Framework.layer.getUIView(ViewID.BombUI)){
                        //window.parent.postMessage(FrameworkConf.Event.NET_RECONNECT, "*");
                        this._uid = Json.data._id
                        Framework.event.fireEvent(FrameworkConf.Event.NET_RECONNECT, {});
                        this._bReconnect = false
                    //}
                    // if(!Framework.layer.getUIView(ViewID.BombUI)){
                    //     var args = { 'uid': Json.data._id, 'cash': Json.data.cash, 'state': 1 };
                    //     Framework.layer.open(ViewID.BombUI, null, args);
                    // }
                    
                }else {
		            this.close(false)

                    Framework.event.fireEvent(FrameworkConf.Event.NET_HANDSHAKE_ERROR, Json.code);
                    // 弹窗提示登陆失败
                    Framework.tips.setTips(Json.desc);
                }
            }else if (Json.mod == 'user' && Json.act == 'heart_beat') {
                this._hear_time_cur = 0;
                //console.error(Json)

            } else {
                if (Json.seq == this._seq) {
                    // 解开遮罩
                }

                // console.log("onmessage:",event.data);
                Framework.event.fireEvent(FrameworkConf.Event.NET_MSG, Json);
            }
        };
    }

    /**
     * 关闭socket
     * @param bReconnect 是否重连 
     */
    close(bReconnect) {

        console.log("close test");
        this._socket && this._socket.close();
        this._socket = null;
        this._is_connect = false;
        this._bHandShake = false
        this._bProClose = true;
        this._clearHeart();
        // window.parent.postMessage(FrameworkConf.Event.NET_CLOSE, "*");
        

        if(bReconnect){
            Framework.layer.open(ViewID.MaskUI);
            this._autoReconnect()
        }
        else{
            Framework.layer.open(ViewID.MaskUI,()=>{},{closeTime:0});
            console.error("断开连接")
        }
    }

    send(msg: any) {
        //msg.uid = UserData['_id'];
        let msgStr = JSON.stringify(msg)
        // console.log(msgStr);
        // console.log(this._socket);
        if (this._socket) {

            //     // let strBuf = this.protoEncode(cmd, msg);
            //     // let buf = this.packet(strBuf);
            this._socket.send(msgStr)
        }
    }
    // uint8Array转typedArray
    typedArray(uint8Array) {
        var hex = Array.prototype.map
            .call(uint8Array, (x) => ('00' + x.toString(16)).slice(-2))
            .join('');
        var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {
            return parseInt(h, 16)
        }))
        var buffer = typedArray.buffer;
        return buffer;
    }

    private _clearHeart() {
        (this._hear_uuid != 0) && Framework.time.unschedule(this._hear_uuid);
        this._hear_uuid = 0;
    }

    private _startHeart() {
        this._clearHeart();
        this._hear_uuid = Framework.time.schedule(() => {
            this._hear_time_cur += 1;

            if(this._hear_time_cur > this._hear_time_out){
                console.error("心跳超时",this._hear_time_cur);
                this.close(true);
                //this._autoReconnect()
            }
            else if (this._socket) {
                // this._hear_uuid = 0;
                this.netApiSend("user","heart_beat",{});
            }
        }, this._hear_time);
    }

    // 自动重连
    // delay:延迟时间
    private _autoReconnect(delay?:number) {
        if(this._bReconnect) {
            console.error("自动重连中",new Date());
            return
        }
        if (this._is_connect) {
            return;
        }
        if (this._auto_reconnect_time > this._auto_reconnect_time_out) {

            Framework.tips.setTips("Reconnection failed");
            console.error("多少次重连失败1")

            //window.parent.postMessage(FrameworkConf.Event.NET_ERROR, "*");
            Framework.layer.open(ViewID.MaskUI,()=>{},{closeTime:0});

            return;
        }



        delay = delay || 0
        if(delay > 0){
            Framework.time.scheduleOnce(()=>{
                this._autoReconnect()
            },delay)
            return 
        }



        console.log("自动重连");
        this._auto_reconnect_time += 1;
        this._bReconnect = true
        this.connect(this._web_url,this._callback)
    }


    netApiSend(mod, act, args) {
        let req = {
            mod: mod,
            act: act,
            args: args,
            uid: this._uid,
            seq: this._seq++,
        }
        Framework.event.fireEvent('cid', args);
        // if(act != "heart_beat"){
        //     console.log("发送", req);
        // }
        this.send(req);// 握手消息,返回在netmanger里面处理

        // 启动loading 遮罩id

    }
}