type ListenerCell = {
  listener: Function
  thisObject: any
  priority: number
}

type ListenerMap = {
  [type: string]: Array<ListenerCell>
}

export type Event = {
  type: string
  data: any
}

/**
 * 事件发射器（发布订阅）
 */
export default class EventDispatcher {
  public static EVENT_MAX: number = 100 // 最多能监听100个事件
  public static EVENT_CELL_MAX: number = 1000 // 同一个事件最多能添加1000个监听函数

  private listenerMap: ListenerMap = {}

  /**
   * 注册监听事件
   * 注意：注册监听函数时，会根据listener，thisObject来进行去重判断，
   * 当listener，thisObject都相同时，则会认为是同一个事件监听，不会将其注册进处理列表
   * @param type 监听事件的类型
   * @param listener 监听函数
   * @param thisObject 监听函数的this指向
   * @param priority 监听函数的优先级
   */
  addEventListener(type: string, listener: Function, thisObject: any, priority?: number) {
    if (!listener || !thisObject) {
      console.warn('EventDispatcher addEventListener listener or thisObject is null')
      return
    }

    const typeNum: number = Object.keys(this.listenerMap).length

    if (!this.listenerMap[type]) {
      if (!(typeNum >= EventDispatcher.EVENT_MAX)) {
        this.listenerMap[type] = []
        this._insertEventListener(this.listenerMap[type], listener, thisObject, priority)
      } else {
        console.warn(`addEventListener eventtype overflow limit:${EventDispatcher.EVENT_MAX}`)
      }
      return
    }

    if (this.listenerMap[type].length >= EventDispatcher.EVENT_CELL_MAX) {
      console.warn(
        `addEventListener eventCellType overflow limit:${EventDispatcher.EVENT_CELL_MAX}`
      )
      return
    }

    this._insertEventListener(this.listenerMap[type], listener, thisObject, priority)
  }

  /**
   * 移除监听函数
   * @param type 事件类型
   * @param listener 事件处理函数
   * @param thisObject 事件处理函数this指向
   */
  removeEventListener(type: string, listener: Function, thisObject: any) {
    if (!type || !listener) {
      return
    }

    let list: Array<ListenerCell> = this.listenerMap[type]
    if (!list || list.length <= 0) {
      return
    }

    for (let i = list.length - 1; i >= 0; --i) {
      if (list[i].listener === listener && list[i].thisObject === thisObject) {
        list.splice(i, 1)
        break
      }
    }
  }

  /**
   * 触发事件
   * @param event 事件数据
   */
  dispatchEvent(event: Event) {
    if (!event || !event.type) {
      console.log('dispatchEvent event is null')
      return
    }

    let eventList: Array<ListenerCell> = this.listenerMap[event.type]
    if (!eventList || eventList.length <= 0) {
      return
    }

    for (let i = 0; i < eventList.length; ++i) {
      if (eventList[i].listener) {
        eventList[i]
      }
    }
  }

  private _insertEventListener(
    list: Array<ListenerCell>,
    listener: Function,
    thisObject: any,
    priority?: number
  ) {
    if (priority) {
      priority = +priority | 0
    } else {
      priority = 0
    }

    let insertIndex = -1
    for (let i = 0; i < list.length; ++i) {
      let cell: ListenerCell = list[i]
      if (cell.listener === listener && cell.thisObject === thisObject) {
        return false
      }
      if (insertIndex === -1 && priority > cell.priority) {
        insertIndex = i
        break
      }
    }

    if (insertIndex === -1) {
      list.push({
        listener,
        thisObject,
        priority
      })
    } else {
      list.splice(insertIndex, 0, {
        listener,
        thisObject,
        priority
      })
    }

    return true
  }
}
