/**
 * hooker
 * TODO: 建设中...
 */
export default class tapableManager {
  constructor() {
    this._taps = {};
  }

  /**
   * 注册注入方法
   * @param {string} tag 标识
   * @param {Function} fun 方法
   */
  tap(tag, fun) {
    if (!fun || typeof fun !== 'function') {
      return false;
    }
    if (!this._taps[tag]) {
      this._taps[tag] = [];
    }
    this._taps[tag].push(fun);
    return true;
  }

  /**
   * 同步串行调用
   * @param {string} tag 标识
   * @param {...any} args 参数
   */
  call(tag, ...args) {
    const funs = this._taps[tag] || [];
    funs.map(fn => fn && fn(...args));
  }

  /**
   * 同步串行调用，返回值依次传递
   * @param {string} tag 标识
   * @param {...any} args 参数
   */
  callWaterfall(tag, ...args) {
    const funs = this._taps[tag] || [];
    let res = null;
    funs.map((fn, i) => {
      if (fn) {
        res = i === 0 ? fn(...args) : fn(res, ...args);
      }
    });
    return res;
  }

  /**
   * 并行异步调用
   * @param {string} tag 标识
   * @param {...any} args 参数
   */
  callAsync(tag, ...args) {
    const funs = this._taps[tag] || [];
    return Promise.all(funs.map(fn => fn && fn(...args)));
  }
}