var async = require('async');
var paths = require('../internal/paths');
var strings = require('../internal/strings');

/**
 * The Lambda object represents a Lambda function in the application. It is returned by
 * {@link Application#lambda} when a new function is registered. You should not call this
 * constructor directly.
 *
 * The Lambda object has methods for:
 *   * Routing HTTP and S3 requests; see {@link Lambda#get}, {@link Lambda#s3put}, etc.
 *   * Adding middleware; see {@link Lambda#use}
 *
 * @constructor
 */
var Lambda = function(app, opts) {
  strings.checkIdentifier(opts.name, 'lambda name');
  this.name = opts.name;
  this.description = opts.description || (opts.name + ' (generated by Lambdafai)');
  this.ram = opts.ram || 128;
  this.timeout = opts.timeout || 10;
  this.routes = [];
  this.handlers = [];
};

/**
 * Routes HTTP GET requests for a given path to the handler. Paths can include placeholders
 * prefixed with a colon, e.g. `/items/:id`, which will match paths like `/items/123`
 * @param path {string} the path to register the handler at
 * @param handler {function} function with signature `function(req, res)` for handling the request
 */
Lambda.prototype.get = function(path, handler) {
  this._addHandler({method: 'GET', path: path, handler: handler });
  return this;
};

/**
 * Routes HTTP POST requests for a given path to the handler. Paths can include placeholders
 * prefixed with a colon, e.g. `/items/:id`, which will match paths like `/items/123`
 * @param path {string} the path to register the handler at
 * @param handler {function} function with signature `function(req, res)` for handling the request
 */
Lambda.prototype.post = function(path, handler) {
  this._addHandler({method: 'POST', path: path, handler: handler });
  return this;
};

/**
 * Routes HTTP PUT requests for a given path to the handler. Paths can include placeholders
 * prefixed with a colon, e.g. `/items/:id`, which will match paths like `/items/123`
 * @param path {string} the path to register the handler at
 * @param handler {function} function with signature `function(req, res)` for handling the request
 */
Lambda.prototype.put = function(path, handler) {
  this._addHandler({method: 'PUT', path: path, handler: handler });
  return this;
};

/**
 * Routes HTTP DELETE requests for a given path to the handler. Paths can include placeholders
 * prefixed with a colon, e.g. `/items/:id`, which will match paths like `/items/123`
 * @param path {string} the path to register the handler at
 * @param handler {function} function with signature `function(req, res)` for handling the request
 */
Lambda.prototype.delete = function(path, handler) {
  this._addHandler({method: 'DELETE', path: path, handler: handler });
  return this;
};

/**
 * Routes HTTP OPTIONS requests for a given path to the handler. Paths can include placeholders
 * prefixed with a colon, e.g. `/items/:id`, which will match paths like `/items/123`
 * @param path {string} the path to register the handler at
 * @param handler {function} function with signature `function(req, res)` for handling the request
 */
Lambda.prototype.options = function(path, handler) {
  this._addHandler({method: 'OPTIONS', path: path, handler: handler });
  return this;
};

/**
 * Routes S3 PUT requests for a given path to the handler. S3 paths will be the key in the bucket,
 * and can include placeholders prefixed with a colon, e.g. `/items/:id`
 * @param path {string} the path to register the handler at
 * @param handler {function} function with signature `function(req, res)` for handling the request
 */
Lambda.prototype.s3put = function(path, handler) {
  this._addHandler({method: 'S3PUT', path: path, handler: handler });
  return this;
};

/**
 * Mounts specified Lambda-level middleware function. Middleware are functions that intercept
 * the request before or after the handler. Middleware must call `res.next()` to pass control to
 * the next middleware in the chain.
 *
 * @param {function} middleware - the middleware function
 */
Lambda.prototype.use = function(middleware) {
  this._addHandler({ handler: middleware });
  return this;
};

Lambda.prototype._addHandler = function(handler) {
  this.handlers.push(handler);
  if (handler.method && handler.path) {
    checkConflictingRoutes(this.routes, handler);
    this.routes.push(handler);
  }
};

Lambda.prototype._handleRequest = function(req, res) {
  var handlers = this.handlers.filter(function(handler) {
    return canHandleRequest(handler, req);
  });
  var callback = res._callback;
  async.eachSeries(handlers, function(handler, next) {
    res._callback = next;
    handler.handler(req, res);
  }, callback);
};

function canHandleRequest(handler, req) {
  return !req.isDone &&
      (!handler.method || handler.method == req.method) &&
      (!handler.path || paths.matchPath(handler.path, req.path));
}

function checkConflictingRoutes(routes, route) {
  for (var i = 0; i < routes.length; i++) {
    var r = routes[i];
    if (r.method == route.method &&
        (paths.matchPath(r.path, route.path) || paths.matchPath(route.path, r.path))) {
      throw new Error('Conflicting routes: ' + JSON.stringify(r) + ' and ' + JSON.stringify(route));
    }
  }
}

module.exports = Lambda;

@@ -4479,16 +4479,31 @@
   return
+ !res.isDone &&
  canHand
@@ -4752,29 +4752,8 @@
 urn 
-!req.isDone &&%0A      
 (!ha

Fix error in isDone checking