text: /* (c) 2015 Ari Porad (@ariporad) <ari@ariporad.com>. MIT Licensed */
  
  /**
   * Module dependencies.
   */
  
  var debug = require('debug')('koa.io:socket.io:router');
  var compose = require('koa-compose');
  var co = require('co');
  
  /**
   * create a event checker
   * @param {String|RegExp} name
   * @return {function}
   */
  
  function createChecker(_name) {
    if (!_name) {
      return function dummyChecker() {
        return true;
      };
    }
    var name = _name;
    if (typeof name === 'string') {
      name = name.replace(/\*/g, '.*?');
      name = new RegExp('^' + name + '$');
    }
  
    debug('regexp: %s', name);
    return function checker(event) {
      var match = event.match(name);
      // only match the whole event
      return match && match.index === 0 && match[0].length === event.length;
    };
  }
  
  /**
   * create a router with event match
   * @return {GeneratorFunction}
   */
  
  function createRoute(_event, _fn) {
    var fn = _fn;
    var event = _event;
    if (typeof event === 'function') {
      fn = event;
      event = null;
    }
  
    var checker = createChecker(event);
  
    return function* createdRoute(next) {
      debug('check `%s` to match `%s`, %s', this.event, event, checker(this.event));
      if (!checker(this.event)) {
        return yield* next;
      }
      var args = [next].concat(this.data);
      yield* fn.apply(this, args);
    };
  }
  
  /**
   * a simple event router object
   */
  
  function Router() {
    if (!(this instanceof Router)) return new Router();
    this.fns = [];
  }
  
  /**
   * create a socket.io middleware
   *
   * @return {GeneratorFunction}
   */
  
  Router.prototype.middleware = function middleware() {
    var router = this;
    var gen = compose(this.fns);
    return function* route(next) {
      debug('in router middleware');
      if (!router.fns.length) {
        debug('router not exist');
        return yield* next;
      }
      var self = this;
      var socket = this.socket;
  
      // replace socket.onevent to start the router
      socket._onevent = socket.onevent;
      socket.onevent = function monkeypatchedOnEvent(packet) {
        var args = packet.data || [];
        if (!args.length) {
          debug('event args not exist');
          return socket._onevent(packet);
        }
  
        self.event = args[0];
        self.data = args.slice(1);
  
        co.wrap(gen).call(self)
          .then(function genSuccess() {
            socket._onevent(packet);
          })
          .catch(function genError(err) {
            debug('error: ' + err.message);
            console.error(err.stack);
          });
      };
  
      yield* next;
    };
  };
  
  
  /**
   * add a route into router
   * @param {String|RegExp} event
   * @param {GeneratorFunction} fn
   */
  
  Router.prototype.route = function route(event, fn) {
    this.fns.push(createRoute(event, fn));
  };
  
  /**
   * Module expose.
   */
  
  module.exports = Router;
  