import ListenerUtil from '../../utils/ListenerUtil'

let ConnectionStates = {
  CLOSED: 3,
  CLOSING: 2,
  OPEN: 1,
  CONNECTING: 0
}

ConnectionStates.isClosed = function (connectionState) {
  console.log('websocket连接状态')
  console.log(connectionState)
  return ConnectionStates.CLOSED === connectionState
}
ConnectionStates.isClosing = function (connectionState) {
  console.log('websocket连接状态')
  console.log(connectionState)
  return ConnectionStates.CLOSING === connectionState
}
ConnectionStates.isOpen = function (connectionState) {
  console.log('websocket连接状态')
  console.log(connectionState)
  return ConnectionStates.OPEN === connectionState
}
ConnectionStates.isConnecting = function (connectionState) {
  console.log('websocket连接状态')
  console.log(connectionState)
  return ConnectionStates.CONNECTING === connectionState
}

// Define builtin message type
const BuiltinMsgType = {
  OPEN: -1,
  CLOSE: -2,
  ERROR: -3,
  UNKNOWN: -4
}
// 增加创建消息监听器的方法

let emptyBuiltinListenerRegistry = ListenerUtil.parseListenerRegistry(BuiltinMsgType)

function WebsocketService (SocketApi, websocketConfig) {
  if (!('WebSocket' in window)) {
    // 浏览器不支持 WebSocket
    return null
  }

  class _WebsocketService {
    constructor (socketConfig) {
      this.status = {
        connectionState: ConnectionStates.CLOSED
      }
      this.config = socketConfig
    }

    isClosed () {
      return ConnectionStates.isClosed(this.status.connectionState)
    }

    isClosing () {
      return ConnectionStates.isClosing(this.status.connectionState)
    }

    isOpen () {
      return ConnectionStates.isOpen(this.status.connectionState)
    }

    isConnecting () {
      return ConnectionStates.isConnecting(this.status.connectionState)
    }

    get $listenerRegistry () {
      if (typeof this._listenerRegistry === 'undefined') {
        this._listenerRegistry = SocketApi.createMessageListenerRegistry()
      }
      return this._listenerRegistry
    }

    get $builtinListenerRegistry () {
      if (typeof this._builtinListenerRegistry === 'undefined') {
        this._builtinListenerRegistry = Object.assign({}, emptyBuiltinListenerRegistry)
      }
      return this._builtinListenerRegistry
    }

    get URL () {
      return this.config.URL
    }

    /**
     * 打开websocket
     * @returns {boolean} 打开请求是否被接受
     */
    open () {
      if (this.isClosed()) {
        this._createNewConnection()
      } else if (this.isClosing()) {
        // 前面已经请求了关闭，现在又请求打开，那么请求打开不成功
        console.log('websocket ', this.URL, ' is closing. Fail to open it now and open it later please.')
        return false
      } else {
        // CONNECTING和OPEN状态下直接忽略打开请求即可
      }
      return true
    }

    /**
     * 关闭websocket
     * @returns {boolean} 关闭请求是否被接受
     */
    close () {
      if (this.isOpen()) {
        this._socket.close()
        this._updateConnectionState()
      } else if (this.isConnecting()) {
        // 前面已经请求了连接，现在又请求关闭，那么请求关闭不成功
        console.log('websocket ', this.URL, ' is connecting. Fail to close it now and close it later please.')
        return false
      } else {
        // CLOSING和CLOSED状态下直接忽略关闭请求即可
      }
      return true
    }

    /**
     * 发送数据
     * @param message 待发送的数据
     * @returns {boolean} 发送请求是否被接受
     */
    send (message) {
      // if (this.isOpen()) {
      // this._socket.send(JSON.stringify(message))
      // TODO 暂时注掉，将来打开
      this._socket.send(message);

      return true
      // }
      // console.log('Fail to send message "', message, '" : Websocket ', this.URL, ' is not open yet.')
      // return false
    }

    /**
     * 注册消息监听器
     * @param msgType 注册监听的消息类型
     * @param listener 监听器对象
     * @param handler 监听处理函数
     */
    subscribe (msgType, listener, handler) {
      this._subscribe(this.$listenerRegistry, msgType, listener, handler)
    }

    /**
     * 取消消息的监听器
     * @param msgType 被监听的消息类型
     * @param listener 申请取消的监听器
     */
    unsubscribe (msgType, listener) {
      this._unsubscribe(this.$listenerRegistry, msgType, listener)
    }

    subscribeToOpen (listener, handler) {
      this._subscribe(this.$builtinListenerRegistry, BuiltinMsgType.OPEN, listener, handler)
    }

    unsubscribeToOpen (listener) {
      this._unsubscribe(this.$builtinListenerRegistry, BuiltinMsgType.OPEN, listener)
    }

    subscribeToClose (listener, handler) {
      this._subscribe(this.$builtinListenerRegistry, BuiltinMsgType.CLOSE, listener, handler)
    }

    unsubscribeToClose (listener) {
      this._unsubscribe(this.$builtinListenerRegistry, BuiltinMsgType.CLOSE, listener)
    }

    subscribeToUnknownMessage (listener, handler) {
      this._subscribe(this.$builtinListenerRegistry, BuiltinMsgType.UNKNOWN, listener, handler)
    }

    unsubscribeToUnknownMessage (listener) {
      this._unsubscribe(this.$builtinListenerRegistry, BuiltinMsgType.UNKNOWN, listener)
    }

    subscribeToError (listener, handler) {
      this._subscribe(this.$builtinListenerRegistry, BuiltinMsgType.ERROR, listener, handler)
    }

    unsubscribeToError (listener) {
      this._unsubscribe(this.$builtinListenerRegistry, BuiltinMsgType.ERROR, listener)
    }

    _subscribe (listenerRegistry, msgType, listener, handler) {
      let msgRegistry = listenerRegistry[msgType]
      let listenerIdx = msgRegistry.listeners.findIndex(l => {
        return (l === listener)
      })

      if (listenerIdx === -1) {
        // 新注册的监听器，将其记录下来
        msgRegistry.listeners.push(listener)
        msgRegistry.handlers.push(handler)
      } else {
        // 监听器已经注册，更新器监听函数即可
        msgRegistry.handlers[listenerIdx] = handler
        console.log('warning : subscribe message (type=', msgType, ') with another handler on websocket ', this.URL)
      }
    }

    _unsubscribe (listenerRegistry, msgType, listener) {
      let msgRegistry = listenerRegistry[msgType]
      let listenerIdx = msgRegistry.listeners.findIndex(l => {
        return (l === listener)
      })

      if (listenerIdx !== -1) {
        // 删除找到的监听器
        msgRegistry.listeners.splice(listenerIdx, 1)
        msgRegistry.handlers.splice(listenerIdx, 1)
      } else {
        // 没有找到监听器，什么也不做
        console.log('warning : fail to unsubscribe message (type=', msgType, ') for listener on websocket ', this.URL)
      }
    }

    _createNewConnection () {
      let _this = this
      // 无论有没有以前创建的this._socket，这里都要重新创建websocket对象，因为这是唯一发起socket连接的方法
      this._socket = new WebSocket(this.URL)
      // 设置好socket的回调函数
      this._socket.onopen = function (e) {
        _this._onSocketOpen(e)
      }
      this._socket.onmessage = function (e) {
        _this._onSocketMessage(e)
      }
      this._socket.onerror = function (e) {
        _this._onSocketError(e)
      }
      this._socket.onclose = function (e) {
        _this._onSocketClose(e)
      }
      // 更新状态
      this._updateConnectionState()
    }

    _updateConnectionState () {
      if (this._socket) {
        this.status.connectionState = this._socket.readyState
      }
    }

    _onSocketOpen (event) {
      // console.log('websocket', this.URL, 'is open with event :', event.type)
      this._updateConnectionState()
      let openRegistry = this.$builtinListenerRegistry[BuiltinMsgType.OPEN]
      openRegistry.handlers.forEach(function (handler) {
        handler()
      })
    }

    _onSocketMessage (event) {
      console.log('收到websocket消息')
      let message = JSON.parse(event.data)
      let msgType = SocketApi.getMessageType(message)
      console.log('websocket message')
      console.log(message)
      console.log(msgType)
      // Dispatch by message type.
      let msgRegistry = this.$listenerRegistry[msgType]

      if (!msgRegistry) {
        // 未定义的消息类型，使用内置的未定义消息处理函数
        console.log('websocket', this.URL, 'found an unknown message:', message, ' with type:', msgType)
        msgRegistry = this.$builtinListenerRegistry[BuiltinMsgType.UNKNOWN]
      }

      msgRegistry.handlers.forEach(function (handler) {
        handler(message.returnObject)
      })
    }

    _onSocketClose (event) {
      this._updateConnectionState()
      console.log('websocket', this.URL, 'is closed with event : ', event.type)
      if (this._socket.bufferedAmount > 0) {
        console.log('websocket ', this.URL, ' still has remaining ', this._socket.bufferedAmount,
          ' bytes data to send when it is closed.')
      }
      // 此时无需注销socket的回调函数，因为关闭的socket没有办法再有任何状态变化了
      // 通知socket关闭
      let closeRegistry = this.$builtinListenerRegistry[BuiltinMsgType.CLOSE]
      closeRegistry.handlers.forEach(function (handler) {
        handler()
      })
    }

    _onSocketError (event) {
      this._updateConnectionState()
      console.log('websocket ', this.URL, ' has an error : ', event)
      let errorRegistry = this.$builtinListenerRegistry[BuiltinMsgType.ERROR]
      errorRegistry.handlers.forEach(function (handler) {
        handler()
      })
    }
  }
  return new _WebsocketService(websocketConfig)
}

WebsocketService.ConnectionStates = Object.freeze(ConnectionStates)

export default WebsocketService
