/**
 * Go的Socket客户端
 */
export default class GoSocketClient {
    private _url: string = null;
    private _ws: WebSocket = null;

    public connect(url: string) {
        if (!url) throw "url can not be null";
        this._url = url;
        this._ws = new WebSocket(url);
        this._ws.onopen = this.loadEntity.bind(this);
        this._ws.onclose = this.destroyEntity.bind(this);
        this._ws.onmessage = (e) => {
            this.invoke(JSON.parse(e.data));
        };
    }

    public reconnect() {
        if (this._url != null) {
            this.connect(this._url);
        }
    }

    public close()
    {
        if (this._ws != null) {
            this._ws.close();
            this._ws = null;
        }
    }
    
    public isValid = false;
    public loaded = false;

    protected onLoad() {}

    protected onReload() {}

    protected onDestroy() {}

    protected onMiss() {}

    public call(func: string, ...args: any[]) {
        if (args == undefined) args = [];
        let data: GoSocketDataPack = {type: 1, func: func, args: args};
        this._ws.send(JSON.stringify(data));
    }

    private invoke(dataPack: GoSocketDataPack) {
        if (dataPack.type == 1) {
            let theFunc = this[dataPack.func] as Function;
            if (theFunc instanceof Function) theFunc.apply(this, dataPack.args);
            else console.error(`invoke fail: can not find func [${dataPack.func}]`);
        }
    }

    private loadEntity() {
        this.isValid = true;
        try {
            if (this.loaded) {
                this.onReload();
            } else {
                this.onLoad();
            }
        } catch (e) { console.error(e); }
        this.loaded = true;
    }

    private destroyEntity() {
        try {
            if (this.isValid) {
                this.isValid = false;
                this.onDestroy();            
            } else {
                this.onMiss();
            }
        } catch (e) { console.error(e); }
    }
}
/**
 * 数据包结构
 */
class GoSocketDataPack {
    public type: number;
    public func: string;
    public args: any[];
}