/**
 * 事件扩展
 * @module zrender/mixin/Eventful
 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
 *         pissang (https://www.github.com/pissang)
 */
module.exports = function (require) {
  /**
   * 事件分发器
   * @alias module:zrender/mixin/Eventful
   * @constructor
   */
  var Eventful = function () {
    this._handlers = {};
  };
  /**
   * 单次触发绑定，dispatch后销毁
   * 
   * @param {string} event 事件名
   * @param {Function} handler 响应函数
   * @param {Object} context
   */


  Eventful.prototype.one = function (event, handler, context) {
    var _h = this._handlers;

    if (!handler || !event) {
      return this;
    }

    if (!_h[event]) {
      _h[event] = [];
    }

    _h[event].push({
      h: handler,
      one: true,
      ctx: context || this
    });

    return this;
  };
  /**
   * 绑定事件
   * @param {string} event 事件名
   * @param {Function} handler 事件处理函数
   * @param {Object} [context]
   */


  Eventful.prototype.bind = function (event, handler, context) {
    var _h = this._handlers;

    if (!handler || !event) {
      return this;
    }

    if (!_h[event]) {
      _h[event] = [];
    }

    _h[event].push({
      h: handler,
      one: false,
      ctx: context || this
    });

    return this;
  };
  /**
   * 解绑事件
   * @param {string} event 事件名
   * @param {Function} [handler] 事件处理函数
   */


  Eventful.prototype.unbind = function (event, handler) {
    var _h = this._handlers;

    if (!event) {
      this._handlers = {};
      return this;
    }

    if (handler) {
      if (_h[event]) {
        var newList = [];

        for (var i = 0, l = _h[event].length; i < l; i++) {
          if (_h[event][i]['h'] != handler) {
            newList.push(_h[event][i]);
          }
        }

        _h[event] = newList;
      }

      if (_h[event] && _h[event].length === 0) {
        delete _h[event];
      }
    } else {
      delete _h[event];
    }

    return this;
  };
  /**
   * 事件分发
   * 
   * @param {string} type 事件类型
   */


  Eventful.prototype.dispatch = function (type) {
    if (this._handlers[type]) {
      var args = arguments;
      var argLen = args.length;

      if (argLen > 3) {
        args = Array.prototype.slice.call(args, 1);
      }

      var _h = this._handlers[type];
      var len = _h.length;

      for (var i = 0; i < len;) {
        // Optimize advise from backbone
        switch (argLen) {
          case 1:
            _h[i]['h'].call(_h[i]['ctx']);

            break;

          case 2:
            _h[i]['h'].call(_h[i]['ctx'], args[1]);

            break;

          case 3:
            _h[i]['h'].call(_h[i]['ctx'], args[1], args[2]);

            break;

          default:
            // have more than 2 given arguments
            _h[i]['h'].apply(_h[i]['ctx'], args);

            break;
        }

        if (_h[i]['one']) {
          _h.splice(i, 1);

          len--;
        } else {
          i++;
        }
      }
    }

    return this;
  };
  /**
   * 带有context的事件分发, 最后一个参数是事件回调的context
   * @param {string} type 事件类型
   */


  Eventful.prototype.dispatchWithContext = function (type) {
    if (this._handlers[type]) {
      var args = arguments;
      var argLen = args.length;

      if (argLen > 4) {
        args = Array.prototype.slice.call(args, 1, args.length - 1);
      }

      var ctx = args[args.length - 1];
      var _h = this._handlers[type];
      var len = _h.length;

      for (var i = 0; i < len;) {
        // Optimize advise from backbone
        switch (argLen) {
          case 1:
            _h[i]['h'].call(ctx);

            break;

          case 2:
            _h[i]['h'].call(ctx, args[1]);

            break;

          case 3:
            _h[i]['h'].call(ctx, args[1], args[2]);

            break;

          default:
            // have more than 2 given arguments
            _h[i]['h'].apply(ctx, args);

            break;
        }

        if (_h[i]['one']) {
          _h.splice(i, 1);

          len--;
        } else {
          i++;
        }
      }
    }

    return this;
  }; // 对象可以通过 onxxxx 绑定事件

  /**
   * @event module:zrender/mixin/Eventful#onclick
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#onmouseover
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#onmouseout
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#onmousemove
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#onmousewheel
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#onmousedown
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#onmouseup
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#ondragstart
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#ondragend
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#ondragenter
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#ondragleave
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#ondragover
   * @type {Function}
   * @default null
   */

  /**
   * @event module:zrender/mixin/Eventful#ondrop
   * @type {Function}
   * @default null
   */


  return Eventful;
}(require);