const Method = {
  None: 1,
  Auth: 2,
  Subscribe: 3,
  Invite: 4,
  Hangup: 5,
  Answer: 6,
  Dtmf: 7
};
const CallState = {
  Idle: 10,
  Outgoing: 11,
  Imcoming: 12,
  InCall: 13
};
const HangupReason = {
  Normal: "16",
  UserBusy: "17",
  Rejected: "21",
  NoAnswer: "19",
  NoLogin: "100"
};
const EventType = {
  None: 30,
  Answer: 31,
  Invite: 32,
  Hangup: 33,
  DTMF: 34,
  Ring: 35,
  NetWorkError: 36
};
const CallType = {
  WXApp: 40, //被叫是小程序
  Sip: 41 //被叫是sip坐席
};

const MAX_RE_CONNECT_TIME = 30;

var Base64 = {
  // private property
  _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  // public method for encoding
  encode: function (input) {
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;
    input = Base64._utf8_encode(input);

    while (i < input.length) {

      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);

      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;

      if (isNaN(chr2)) {
        enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
        enc4 = 64;
      }

      output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

    }

    return output;
  },

  // public method for decoding
  decode: function (input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

    while (i < input.length) {

      enc1 = this._keyStr.indexOf(input.charAt(i++));
      enc2 = this._keyStr.indexOf(input.charAt(i++));
      enc3 = this._keyStr.indexOf(input.charAt(i++));
      enc4 = this._keyStr.indexOf(input.charAt(i++));

      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;

      output = output + String.fromCharCode(chr1);

      if (enc3 != 64) {
        output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
        output = output + String.fromCharCode(chr3);
      }

    }

    output = Base64._utf8_decode(output);

    return output;
  },

  // private method for UTF-8 encoding
  _utf8_encode: function (string) {
    string = string.replace(/\r\n/g, "\n");
    var utftext = "";

    for (var n = 0; n < string.length; n++) {

      var c = string.charCodeAt(n);

      if (c < 128) {
        utftext += String.fromCharCode(c);
      } else if ((c > 127) && (c < 2048)) {
        utftext += String.fromCharCode((c >> 6) | 192);
        utftext += String.fromCharCode((c & 63) | 128);
      } else {
        utftext += String.fromCharCode((c >> 12) | 224);
        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
        utftext += String.fromCharCode((c & 63) | 128);
      }

    }

    return utftext;
  },

  // private method for UTF-8 decoding
  _utf8_decode: function (utftext) {
    var string = "";
    var i = 0;
    var c = 0;
    var c1 = 0;
    var c2 = 0;

    while (i < utftext.length) {

      c = utftext.charCodeAt(i);

      if (c < 128) {
        string += String.fromCharCode(c);
        i++;
      } else if ((c > 191) && (c < 224)) {
        c2 = utftext.charCodeAt(i + 1);
        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
        i += 2;
      } else {
        c2 = utftext.charCodeAt(i + 1);
        c3 = utftext.charCodeAt(i + 2);
        string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
        i += 3;
      }

    }

    return string;
  }
}

let XYTCallEngine = {
  appKey: null,
  provCode: null,
  companyId: null,
  cityCode: null,
  username: null,
  password: null,
  url: null,
  fsUrl: null,
  rtmpUrl: null,
  signalId: 1,
  sessionId: null,
  fsChannel: null,
  wxappChannel: null,
  dstNumber: null,

  addNetworkLinstening: false,
  lastNetWorkType: 'none',
  timer: null, //重连定时器
  reConnecTime: 0, //重连次数
  isAuth: false, //是否认证
  callType: CallType.WXApp,
  isCaller: false,
  isConnect: false, //网络是否连接
  isOldSocketClose: false, //是否关闭上一次的ws
  callState: CallState.Idle,
  useLastSession: false, //是否使用上次的sessionid  断网重连
  useSSL: false,
  useWxappServer: false,
  loginTimer: null,
  
  websocketTask: null,
  ws_callbacks: {},
  loginCallBack: null,
  inviteCallBack: null,
  answerCallBack: null,
  eventCallBacks: [],


  setRtmpServer(rtmpUrl) {
    this.rtmpUrl = rtmpUrl;
  },

  /**
  登录
  @param username 用户名
  @param password 密码
  @param appKey appKey
  @param provCode provCode
  @param companyId companyId
  @param cityCode cityCode
  @param url 服务器地址
  @param callback 回调 success:是否成功 data:失败或者成功数据
  */
  login(username, password, appKey, provCode, companyId, cityCode, url, callback) {
    if (!(username && username.length > 0)) return;
    if (!(password && password.length > 0)) return;
    if (!(url && url.length > 0)) return;
    this.username = username;
    this.password = password;
    this.appKey = appKey == null ? "" : appKey;
    this.provCode = provCode == null ? "" : provCode;
    this.companyId = companyId == null ? "" : companyId;
    this.cityCode = cityCode == null ? "" : cityCode;

    this.url = url;
    this.isOldSocketClose = false;
    this.useLastSession = false;
    this.loginCallBack = callback;

    if (url.indexOf("https://") == 0) {
      this.useSSL = true;
      this.useWxappServer = true;
    } else if (url.indexOf("http://") == 0) {
      this.useSSL = false;
      this.useWxappServer = true;
    } else if (url.indexOf("ws://") == 0) {
      this.useSSL = false;
      this.useWxappServer = false;
    } else if (url.indexOf("wss://") == 0) {
      this.useSSL = true;
      this.useWxappServer = false;
    } else {
      this.url =  "wss://" + url + ":443";
      url = "wss://" + url + ":443";
      this.useSSL = true;
      this.useWxappServer = false;
    }
    //request fs url
    if (this.useWxappServer) {
      this._requestUrl(1, (success, url) => {
        if (success) {
          let prefix = this.useSSL ? "https://" : "http://";
          let wsPrefix = this.useSSL ? "wss://" : "ws://";
          let baseUrl = this.url.substring(prefix.length, this.url.length);
          this.fsUrl = wsPrefix + baseUrl + "/wxapp?url=" + url;
          this._createWebSocket();
          this._addNetworkLinstening();
        } else {
          if (callback) {
            callback(false, "failed to get fs url");
          }
        }
      });
    } else {
      this.fsUrl = url;
      this._requestSipNumber((success) => {
        if (success) {
          this._createWebSocket();
          this._addNetworkLinstening();
        } else {
          if (callback) {
            callback(false, "login error");
          }
        }
      });
    }
  },
  
  /**
  登出
  */
  logout() {
    if (this.callState != CallState.Idle) {
      this.hangup(HangupReason.Normal);
    }
    this._realseCallInfo();
    this._stopPing();
    this.ws_callbacks = {};
    this.isAuth = false;
    this.isConnect = false;
    this.isOldSocketClose = true;
    this.sessionId = null;
    this.loginCallBack = null;
    this.eventCallBack = [];
    this.signalId = 1;
    this.username = null;
    this.password = null;
    this.fsUrl = null;
    this.url = null;
    this.appKey = null;
    this.provCode = null;
    this.companyId = null;
    this.cityCode = null;
    if (this.isConnect || this.websocketTask) {
      this._releaseLastWebsocket();
    }
  },
  /**
  呼叫
  @param dstNumber 被叫号码
  @param isVideo 是否是视频
  @param orderNumber 工单号
  @param vdnNumber 技能号
  @param callType 呼叫类型
  @param callBack 回调 success:是否成功 data:失败原因，或者成功数据（拉流地址）
  */
  newCall(dstNumber, isVideo, orderNumber, vdnNumber, callType, callBack) {
    if (this.useWxappServer) {
      this._requestUrl(0, (success, url) => {
        if (success) {
          this.rtmpUrl = url;
          this._newCall(dstNumber, isVideo, orderNumber, vdnNumber, callType, callBack);
        } else {
          if (callBack) {
            callBack(false, "failed to get srs url");
          }
        }
      });
    } else {
      this._newCall(dstNumber, isVideo, orderNumber, vdnNumber, callType, callBack);
    }
  },
  /**
  挂断
  @param reason 挂断原因，详见HangupReason
  */
  hangup(reason) {
    if (this.callState != CallState.Idle && this.isAuth && this.isConnect) {
      let params = {
        "func": "bye",
        "fsChannel": this.fsChannel,
        "cidNumber": this.username,
        "cidName": this.username,
        "destNumber": this.dstNumber,
        "byeCode": reason ? reason : "16"
      };
      this._sendMsg(params, Method.Hangup);
    }
    this._realseCallInfo();
  },
  /**
  接听
  @param callBack 回调 success:是否成功 data:失败原因，或者成功数据（拉流地址）
  */
  answer(callBack) {
    let error = null;
    if (!this.isConnect) error = "websocket is close";
    if (!this.isAuth) error = "no login";
    if (this.callState != CallState.Imcoming) error = "current call not over";
    if (error) {
      if (callBack) callBack(false, error);
      return;
    }

    this.answerCallBack = callBack;
    let params = {
      "func": "answer",
      "fsChannel": this.fsChannel,
      "cidNumber": this.username,
      "cidName": this.username,
      "destNumber": this.dstNumber
    };
    this._sendMsg(params, Method.Answer);
  },

  /**
  *发送按键
  @param dtmf 按键 0-9 * #
  */
  dtmf(dtmf) {
    if (!this.isConnect) return;
    if (!this.isAuth) return;
    if (this.callState != CallState.InCall) return;
    let params = {
      "func": "dtmf",
      "dtmf": dtmf,
      "fsChannel": this.fsChannel,
      "cidNumber": this.username,
      "cidName": this.username
    };
    this._sendMsg(params, Method.Dtmf);
  },

  /**
  添加事件监听回调 调用者需在合适的时机移除callback
  @param callBack 回调 eventtype: 详见EventType, data:事件数据
  */
  addEventCallBack(callBack) {
    if (callBack) this.eventCallBacks.push(callBack);
  },

  /**
  移除事件监听回调
  @param callBack
  */
  removeEventCallBack(callBack) {
    if (!callBack) return;
    let index = -1;
    for (var i = 0; i < this.eventCallBacks.length; i++) {
      let ck = this.eventCallBacks[i];
      if (ck == callBack) {
        index = i;
        break;
      }
    }
    if (index > -1) {
      this.eventCallBacks.splice(index, 1);
    }
  },

  /**
  重新登录
  */
  _relogin() {
    if (this.fsUrl == null) {
      return;
    }
    this.reConnecTime++;
    this.useLastSession = true;
    this._createWebSocket();
  },

  //发起呼叫
  _newCall(dstNumber, isVideo, orderNumber, vdnNumber, callType, callBack) {
    let error = null;
    if (!(dstNumber && dstNumber.length > 0)) error = "dstNumber can not be null";
    if (!(this.rtmpUrl && this.rtmpUrl.length > 0)) error = "rtmpUrl can not be null";
    if (!this.isConnect) error = "websocket is close";
    if (!this.isAuth) error = "no login";
    if (this.callState != CallState.Idle) error = "callstate is error";
    if (error) {
      if (callBack) callBack(false, error);
      return;
    }

    if (callType != CallType.WXApp && callType != CallType.Sip) {
      callType = CallType.WXApp;
    }
    this.callType = callType;
    this.dstNumber = dstNumber;
    this.fsChannel = this._createUid();
    this.wxappChannel = this._createUid();
    this.inviteCallBack = callBack;
    let params = {
      "sip_h_ext": orderNumber ? orderNumber : "",
      "sip_h_vdn": vdnNumber ? vdnNumber : "",
      "func": "invite",
      "video": isVideo,
      "fsChannel": this.fsChannel,
      "wxappChannel": this.wxappChannel,
      "cidNumber": this.username,
      "cidName": this.username,
      "destNumber": this.dstNumber,
      "rtmpUrl": this.rtmpUrl,
      "bypassMedia": this.callType == CallType.WXApp ? true : false
    };
    this.isCaller = true;
    this.callState = CallState.Outgoing;
    this._sendMsg(params, Method.Invite);
  },

  //create websocket
  _createWebSocket() {
    this.isAuth = false;
    this.signalId = 1;
    this.websocketTask = wx.connectSocket({
      url: this.fsUrl,
      fail: () => {
        this._doLoginCallBack(false, "websocket connect error");
        this._stopPing();
      }
    });
    this._setWebsocketCallBack();
  },
  _releaseLastWebsocket() {
    let websocketTask = this.websocketTask;
    this.websocketTask = null;
    websocketTask && websocketTask.close();
  },
  _handleNetWorkError() {
    if (this.isOldSocketClose) {
      console.log("close last websocket");
      // this.isOldSocketClose = false;
      return;
    }
    //断网重连
    if (this.reConnecTime < MAX_RE_CONNECT_TIME && this.url && this.username && this.password) {
      if (!this.timer) {
        this.timer = setInterval(() => {
          this._relogin();
        }, 1000);
      }
    } else {
      this.isConnect = false;
      this.isAuth = false;
      this.websocketTask = null;
      this._doEventCallBacks(EventType.NetWorkError, "websocket close");
      this._realseCallInfo();
      this._stopPing();
      console.log("websocket close");
    }
  },
  _setWebsocketCallBack() {
    this.websocketTask.onError((e) => {
      this._handleNetWorkError();
    });
    this.websocketTask.onClose((e) => {
      this._handleNetWorkError();
    });
    this.websocketTask.onMessage((res) => {
      let data = res.data;
      if (!data) return;

      let json = JSON.parse(data);
      if (!json) return;

      if (json.error) {
        this._handleError(json);
      } else if (json.result) {
        this._handleRespones(json);
      } else if (json.method) {
        this._handleEvent(json);
      }

      let signalId = json.id;
      delete this.ws_callbacks[signalId];
    });
    this.websocketTask.onOpen(() => {
      console.log("websocket open");
      this._realseTimer();
      this._startPing();
      this.isConnect = true;
      //do auth
      this._doAuth();
    });
  },
  _doAuth() {
    if (!(this.useLastSession && this.sessionId)) {
      this.sessionId = this._createUid();
    }
    this.useLastSession = false;
    let json = {
      "jsonrpc":"2.0",
      "method":"login",
      "params":{
        "login":this.username,
        "passwd":this.password,
        "appKey": this.appKey,
        "provCode": this.provCode,
        "companyId": this.companyId,
        "cityCode": this.cityCode,
        "loginParams":{},
        "userVariables":{},
        "sessid":this.sessionId
      },
      "id":this.signalId
    };
    this.ws_callbacks[this.signalId] = Method.Auth;
    let jsonStr = JSON.stringify(json);
    console.log(jsonStr);
    this.websocketTask.send({
      data:jsonStr,
      fail:()=>{
        delete this.ws_callbacks[this.signalId];
        this._doLoginCallBack(false, "login error");
      }
    });
  },
  
  _doSubscribe() {
    this.signalId++;
    let json = {
      "jsonrpc": "2.0",
      "method": "verto.subscribe",
      "params": {
        "eventChannel": "wxapp.callstate."+this.sessionId,
        "sessid": this.sessionId
      },
      "id": this.signalId
    };
    this.ws_callbacks[this.signalId] = Method.Subscribe;
    let jsonStr = JSON.stringify(json);
    console.log(jsonStr);
    this.websocketTask.send({
      data: jsonStr,
      fail: () => {
        delete this.ws_callbacks[this.signalId];
      }
    });
  },

  _sendMsg(params, method) {
    this.signalId++;
    let json = {
      "jsonrpc" : "2.0",
      "method": "jsapi",
      "id": this.signalId,
      "params":{
        "command": "wxapp",
        "data": params,
        "sessid": this.sessionId
      }
    }
    this.ws_callbacks[this.signalId] = method;
    let jsonStr = JSON.stringify(json);
    console.log(jsonStr);
    this.websocketTask.send({
      data: jsonStr,
      fail: () => {
        delete this.ws_callbacks[this.signalId];
        this._handleSelfError(method);
      }
    });
  },
  
  _realseCallInfo() {
    this._realseTimer();
    this.isCaller = false;
    this.callState = CallState.Idle;
    this.fsChannel = null;
    if (this.useWxappServer) {
      this.rtmpUrl = null;
    }
    this.wxappChannel = null;
    this.dstNumber = null;
    this.inviteCallBack = null;
    this.answerCallBack = null;
  },
  _realseTimer() {
    this.timer && clearInterval(this.timer);
    this.timer = null;
    this.reConnecTime = 0;
  },

  _handleEvent(json) {
    console.log("event==>" + JSON.stringify(json));
    let data = json.params.data;
    if (!data) return;
    let func = data.func;
    let fsChannel = data.fsChannel;
    
    if (!(fsChannel && fsChannel.length > 0)) return;
    if (this.fsChannel != fsChannel && func != "invite") return;
    
    if (func == 'ring') {
      this._doEventCallBacks(EventType.Ring, "ring");
    } else if (func == 'answer') {
      if (this.callState == CallState.Idle) return;
      this.callState = CallState.InCall;
      this._doEventCallBacks(EventType.Answer, { "playUrl": this._getPlayUrl() });
    } else if (func == 'bye') {
      this.callState = CallState.Idle;
      let byCode = data.byeCode;
      if (byCode != HangupReason.Rejected && byCode != HangupReason.NoAnswer && byCode != HangupReason.UserBusy) {
        byCode = HangupReason.Normal;
      }
      if (data.byeCause && data.byeCause == "USER_NOT_REGISTERED") {
        byCode = HangupReason.NoLogin;
      }
      this._doEventCallBacks(EventType.Hangup, byCode);
      this._realseCallInfo();
    } else if (func == 'invite') {
      if (this.callState != CallState.Idle) {
        this._sendUserBusy(data);
        return;
      }
      if (data.rtmpUrl == null && this.useWxappServer) {
        this._sendUserBusy(data);
        return;
      }
      if (data.bypassMedia) {
        this.callType = CallType.WXApp;
      } else {
        this.callType = CallType.Sip;
      }
      this.fsChannel = data.fsChannel;
      this.dstNumber = data.destNumber;
      this.wxappChannel = data.wxappChannel;
      if (this.useWxappServer) {
        this.rtmpUrl = data.rtmpUrl;
      }
      let callerName = data.cidName;
      let callerNumber = data.cidNumber;
      let video = data.video;
      this.callState = CallState.Imcoming;
      this._doEventCallBacks(EventType.Invite, { "callerName": callerName, "callerNumber": callerNumber, "video": video });
    } else if (func == 'dtmf') {
      let dtmf = data.digit;
      if (!(dtmf && dtmf.length > 0)) return;
      this._doEventCallBacks(EventType.DTMF, dtmf)
    }
  },
  _handleError(json) {
    console.log("error==>" + JSON.stringify(json));
    let signalId = json.id;
    let method = this.ws_callbacks[signalId];
    if (method == Method.Auth) {
      this._doLoginCallBack(false, json.error.message);
      this.logout();
    } else if (method == Method.Invite) {
      this._doInviteCallBack(false, json.error.message);
    } else if (method == Method.Answer) {
      //应答失败
      this._doAnswerCallBack(false, "answer error");
      this._realseCallInfo();
    }
  },
  _handleRespones(json) {
    console.log("responses==>" + JSON.stringify(json));
    let signalId = json.id;
    let method = this.ws_callbacks[signalId];
    if (method == Method.Auth) {
      this.isAuth = true;
      this._doSubscribe();
      this._doLoginCallBack(true, json.result.message);
    } else if (method == Method.Invite) {
      if (json.result.message != "+OK") {
        this._handleSelfError(Method.Invite);
      } else {
        this._doInviteCallBack(true, { "pushUrl": this._getPushUrl() });
      }
    } else if (method == Method.Answer) {
      if (json.result.message != "+OK") {
        this._handleSelfError(Method.Answer);
      } else {
        this._doAnswerCallBack(true, { "pushUrl": this._getPushUrl(), "playUrl": this._getPlayUrl() });
      }
    }
  },
  _sendUserBusy(data) {
    this.signalId++;
    let json = {
      "id": this.signalId,
      "jsonrpc": "2.0",
      "method": "jsapi",
      "params":{
        "command": "wxapp",
        "data":{
          "func": "bye",
          "fsChannel": data.fsChannel,
          "cidNumber": data.cidNumber,
          "cidName": data.cidName,
          "destNumber": data.dstNumber,
          "byeCode": "17"
        }
      }
    };
    let jsonStr = JSON.stringify(json);
    console.log("send==>" + jsonStr);
    this.websocketTask.send({
      data: jsonStr
    });
  },
  _handleSelfError(method) {
    if (method == Method.Invite) {
      //呼叫失败
      this.callState = CallState.Idle;
      this._doInviteCallBack(false, "invite error");
    } else if (method == Method.Hangup) {
      //挂断失败 不做处理
    } else if (method == Method.Answer) {
      //应答失败
      this.callState = CallState.Idle;
      this._doAnswerCallBack(false, "answer error");
    }
  },

  _doLoginCallBack(success, data) {
    if (this.loginCallBack) {
      this.loginCallBack(success, data);
    }
  },
  _doInviteCallBack(success, data) {
    if (this.inviteCallBack) {
      this.inviteCallBack(success, data);
    }
  },
  _doAnswerCallBack(success, data) {
    if (this.answerCallBack) {
      this.answerCallBack(success, data);
    }
  },
  _getPushUrl() {
    let pushUrl;
    if (this.callType == CallType.WXApp) {
      pushUrl = this.rtmpUrl + "/" + this.wxappChannel + "-0" + "?key=" + this.fsChannel + "&user=" + this.username;
      if (!this.isCaller) {
        pushUrl = this.rtmpUrl + "/" + this.wxappChannel + "-1" + "?key=" + this.fsChannel+ "&user=" + this.username;
      }
    } else {
      pushUrl = this.rtmpUrl + "/" + this.wxappChannel + "/" + this.fsChannel + "-0" + "?key=" + this.fsChannel + "&user=" + this.username;
    }
    return pushUrl;
  },
  _getPlayUrl() {
    let playUrl;
    if (this.callType == CallType.WXApp) {
      playUrl = this.rtmpUrl + "/" + this.wxappChannel + "-1" + "?key=" + this.fsChannel + "&user=" + this.username;
      if (!this.isCaller) {
        playUrl = this.rtmpUrl + "/" + this.wxappChannel + "-0" + "?key=" + this.fsChannel + "&user=" + this.username;
      }
    } else {
      playUrl = this.rtmpUrl + "/" + this.wxappChannel + "/" + this.fsChannel + "-1" + "?key=" + this.fsChannel + "&user=" + this.username;
    }
    return playUrl;
  },

  _createUid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
      let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  },

  _addNetworkLinstening() {
    if (this.addNetworkLinstening) {
      return;
    }
    wx.onNetworkStatusChange((res) => {
      const network = res.networkType;
      if (this.lastNetWorkType != network && res.isConnected) {
        //网络切换
        // if (this.url && this.username && this.password && this.fsUrl) {
        //   this.isOldSocketClose = true;
        //   this._releaseLastWebsocket();
        //   this._relogin();
        // }
      }else if (!res.isConnected) {
        this.isConnect = false;
        this.isAuth = false;
      }
      this.lastNetWorkType = network;
    });
  },

  _doEventCallBacks(eventType, data) {
    for (var i = 0; i < this.eventCallBacks.length; i++) {
      let callback = this.eventCallBacks[i];
      callback(eventType, data);
    }
  },

  _requestUrl(type, callBack) {
    let url = this.url + '/wxapp_server/fs';
    if (type == 0) {
      url = this.url + '/wxapp_server/srs';
    }
    wx.request({
      url: url,
      method: "GET",
      success: (res) => {
        if (res.data['code'] == 0) {
          let url = res.data['url'];
          if (!(url && url.length > 0)) {
            if (callback) {
              callback(false, null);
            }
            return;
          }
          if (callBack) {
            callBack(true, url);
          }
        } else {
          if (callBack) {
            callBack(false, null);
          }
        }
      },
      fail: () => {
        if (callBack) {
          callBack(false, null);
        }
      }
    });
  },

  _requestSipNumber(callBack) {
    var time = new Date();
    var year = time.getFullYear();
    var month = time.getMonth() + 1;
    var day = time.getDate();

    var time_str = year + "" + (month > 9 ? month : ("0" + month)) + "" + day;
    
    var auth_str = this.username + ":" + this.password + ":" + time_str;

    const base64_str = Base64.encode(auth_str);

    wx.request({
      url: 'https://api.yunzongji.cn/uas/20141201/accounts/calls/login.json',
      header:{
        "Authorization": base64_str
      },
      method:"POST",
      success: (res) => {
        let code = res['data']['statuscode'];
        console.log(res)
        console.log(code)
        if (code == '000000') {
          var objects = res['data']['body']['self']['objects'];
          if (objects) {
            for (var i = 0; i < objects.length; i++) {
              var item = objects[i];
              if (item['type'] == 'sip') {
                this.username = item['account'];
                this.password = item['pswd'];
                if (callBack) callBack(true);
                return;
              }
            }
          }
        }
        if (callBack) callBack(false);
      },
      fail: () => {
        if (callBack) callBack(false);
      }
    })
  },

  _startPing() {
    this._stopPing();
    this.loginTimer = setInterval(()=>{
      if (this.isConnect) {
        this.websocketTask.send({
          data: "1"
        })
      }
    }, 30000);

  },

  _stopPing() {
    this.loginTimer && clearInterval(this.loginTimer);
    this.loginTimer = null;
  }

}


// module.exports = XYTCallEngine;
export { XYTCallEngine, HangupReason, CallState, EventType, CallType};

