class EventBus {
  constructor() {
    // 初始化事件列表
    this.eventObject = {};
    // 回调函数列表的id
    this.callbackId = 0;
  }
  // 发布事件
  publish(eventName, ...args) {
    // 取出当前事件所有的回调函数
    const callbackObject = this.eventObject[eventName];
    if (!callbackObject) return console.warn(eventName + " not found!");
    // 执行每一个回调函数
    for (let id in callbackObject) {
      // 执行时传入参数
      callbackObject[id](...args);
      // 只订阅一次的回调函数需要删除
      if (id[0] === "d") {
        delete callbackObject[id];
      }
    }
  }
  // 订阅事件
  subscribe(eventName, callback) {
    // 初始化这个事件
    if (!this.eventObject[eventName]) {
      // 使用对象存储，注销回调函数的时候提高删除的效率
      this.eventObject[eventName] = {};
    }

    const id = this.callbackId++;

    // 存储订阅者的回调函数
    // callbackId使用后需要自增，供下一个回调函数使用
    this.eventObject[eventName][id] = callback;

    // 每一次订阅事件，都生成唯一一个取消订阅的函数
    const unSubscribe = () => {
      // 清除这个订阅者的回调函数
      delete this.eventObject[eventName][id];

      // 如果这个事件没有订阅者了，也把整个事件对象清除
      if (Object.keys(this.eventObject[eventName]).length === 0) {
        delete this.eventObject[eventName];
      }
    };

    return { unSubscribe };
  }

  // 只订阅一次
  subscribeOnce(eventName, callback) {
    // 初始化这个事件
    if (!this.eventObject[eventName]) {
      // 使用对象存储，注销回调函数的时候提高删除的效率
      this.eventObject[eventName] = {};
    }

    // 标示为只订阅一次的回调函数
    const id = "d" + this.callbackId++;

    // 存储订阅者的回调函数
    // callbackId使用后需要自增，供下一个回调函数使用
    this.eventObject[eventName][id] = callback;

    // 每一次订阅事件，都生成唯一一个取消订阅的函数
    const unSubscribe = () => {
      // 清除这个订阅者的回调函数
      delete this.eventObject[eventName][id];

      // 如果这个事件没有订阅者了，也把整个事件对象清除
      if (Object.keys(this.eventObject[eventName]).length === 0) {
        delete this.eventObject[eventName];
      }
    };

    return { unSubscribe };
  }

  // 清除事件
  clear(eventName) {
    // 未提供事件名称，默认清除所有事件
    if (!eventName) {
      this.eventObject = {};
      return;
    }

    // 清除指定事件
    delete this.eventObject[eventName];
  }
}

// 测试
const eventBus = new EventBus();

// 订阅事件eventX
// eventBus.subscribe("eventX", (obj, num) => {
//   console.log("模块A", obj, num);
// });
// eventBus.subscribe("eventX", (obj, num) => {
//   console.log("模块B", obj, num);
// });
// eventBus.subscribe("eventX", (obj, num) => {
//   console.log("模块C", obj, num);
// });

// 发布事件eventX
// eventBus.publish("eventX", { msg: "EventX published!" }, 1);

// 清除
// eventBus.clear("eventX");

// 再次发布事件eventX，由于已经清除，所有模块都不会再收到消息了
// eventBus.publish("eventX", { msg: "EventX published again!" }, 2);

export default eventBus;
