import globalState from "./global-state";

interface FunctionList {
  [propName : string] : Array<Function>,
}

interface SubscriberMap {
  [propName : string] : Array<number>,
}

export class ObserverClass {
  private funcList: FunctionList;
  private funcMap: any;
  private subscriberMap: SubscriberMap;

  constructor() {
    this.funcList = {};
    this.funcMap = {};
    this.subscriberMap = {};
  }
  // 注册特殊的标记到订阅者池
  registerAsSubscriber(name: string) {
    if (!this.subscriberMap[name]) this.subscriberMap[name] = [];
  }
  // 批量释放订阅者池的监听器
  removeEventListenerInBatch(subscriberName: string) {
    if (!this.subscriberMap[subscriberName]) return;
    while (this.subscriberMap[subscriberName].length) {
      const index = this.subscriberMap[subscriberName].pop();
      this.removeEventListener(index || -1);
    }
  }

  addEventListener(name: string, func: Function, subscriberName?: string) {
    if (!this.funcList[name]) this.funcList[name] = [];
    if (typeof func === 'function') {
      this.funcList[name].push(func);
      const randomIndex = Math.round(Math.random() * 1000000);
      this.funcMap[randomIndex] = { name, index: this.funcList[name].length - 1 };
      if (subscriberName && this.subscriberMap[subscriberName]) this.subscriberMap[subscriberName].push(randomIndex);
      return randomIndex;
    }
    return 0;
  }

  removeEventListener(randomIndex: number) {
    if (!Object.hasOwnProperty.call(this.funcMap, randomIndex)) return;
    const info = this.funcMap[randomIndex];
    this.funcList[info.name].splice(info.index, 1);
    delete this.funcMap[randomIndex];
  }
  /**
   * 对全局派发一个事件，返回一个布尔值标记是否有订阅者响应事件
   * @param name 事件名称
   * @param arg 事件参数
   */
  dispatchEvent(name: string, arg?: any): boolean {
    let hasBeenResponse = false;
    const currentPage = globalState.getState('currentPage', {
      context: {},
      id: -1,
    });
    const { context } = currentPage;
    if (typeof context[name] === 'function') {
      // 异步执行
      setTimeout(() => {
        context[name].bind(context)(arg);
      }, 0);
      hasBeenResponse = true;
    }
    if (this.funcList[name] && this.funcList[name].length) {
      this.funcList[name].forEach((ele: Function) => {
        // 异步执行
        setTimeout(() => ele(arg), 0);
      });
      hasBeenResponse = true;
    }
    return hasBeenResponse;
  }
}

export default new ObserverClass();
