// Generated by CoffeeScript 1.12.7
(function() {
  var checkForRedirect, connect, createRoutingProxy, fs, http, httpProxy, log, mime, patchServerResponseForRedirects, server, utils;

  connect = require('connect');

  mime = require('connect')["static"].mime;

  httpProxy = require('http-proxy');

  http = require('http');

  fs = require('fs');

  utils = require('./utils');

  log = require('./log');

  server = {};

  server.start = function(hem) {
    var app, options;
    app = connect();
    app.use(server.middleware(hem));
    options = hem.options.hem;
    if (options.host === "*") {
      http.createServer(app).listen(options.port);
    } else {
      http.createServer(app).listen(options.port, options.host);
    }
    return app;
  };

  server.middleware = function(hem) {
    var app, backend, display, i, j, k, l, len, len1, len2, len3, options, pkg, ref, ref1, ref2, ref3, ref4, route, statics, value;
    backend = connect();
    options = hem.options.hem;
    statics = [];
    ref = options != null ? options["static"] : void 0;
    for (route in ref) {
      value = ref[route];
      statics.push({
        url: route,
        path: value
      });
    }
    ref1 = hem.apps;
    for (i = 0, len = ref1.length; i < len; i++) {
      app = ref1[i];
      log.info("> Apply route mappings for application: <green>" + app.name + "</green>");
      ref2 = app.packages;
      for (j = 0, len1 = ref2.length; j < len1; j++) {
        pkg = ref2[j];
        if (options.baseAppRoute) {
          pkg.route = utils.cleanRoute(options.baseAppRoute, pkg.route);
        }
        log.info(" - Mapping route  <yellow>" + pkg.route + "</yellow> to <yellow>" + pkg.target + "</yellow>");
      }
      ref3 = app["static"];
      for (k = 0, len2 = ref3.length; k < len2; k++) {
        route = ref3[k];
        if (options.baseAppRoute) {
          route.url = utils.cleanRoute(options.baseAppRoute, route.url);
        }
        log.info(" - Mapping static <yellow>" + route.url + "</yellow> to <yellow>" + route.path + "</yellow>");
        statics.push(route);
      }
    }
    for (l = 0, len3 = statics.length; l < len3; l++) {
      route = statics[l];
      if (!fs.existsSync(route.path)) {
        log.errorAndExit("The resource <yellow>" + route.path + "</yellow> not found for static mapping <yellow>" + route.url + "</yellow>");
      }
      if (fs.lstatSync(route.path).isDirectory()) {
        backend.use(route.url, checkForRedirect());
        backend.use(route.url, connect["static"](route.path));
      } else {
        backend.use(route.url, (function(route) {
          return function(req, res) {
            return fs.readFile(route.path, function(err, data) {
              if (err) {
                res.writeHead(404);
                return res.end(JSON.stringify(err));
              } else {
                res.writeHead(200);
                return res.end(data);
              }
            });
          };
        })(route));
      }
    }
    ref4 = options.proxy;
    for (route in ref4) {
      value = ref4[route];
      display = value.host + ":" + (value.port || 80) + value.path;
      log.info("> Proxy requests <yellow>" + route + "</yellow> to <yellow>" + display + "</yellow>");
      backend.use(route, createRoutingProxy(value, options.host + ":" + options.port));
    }
    return function(req, res, next) {
      var len4, m, ref5, ref6, str, url;
      url = ((ref5 = require("url").parse(req.url)) != null ? ref5.pathname.toLowerCase() : void 0) || "";
      if (url.match(/(\.js|\.css)$/)) {
        ref6 = hem.apps;
        for (m = 0, len4 = ref6.length; m < len4; m++) {
          app = ref6[m];
          if (pkg = app.isMatchingRoute(url)) {
            str = pkg.build();
            res.charset = 'utf-8';
            res.setHeader('Content-Type', mime.lookup(pkg.target));
            res.setHeader('Content-Length', Buffer.byteLength(str));
            res.end((req.method === 'HEAD' && null) || str);
            return;
          }
        }
      }
      return backend.handle(req, res, next);
    };
  };

  checkForRedirect = function() {
    return function(req, res, next) {
      var pathname;
      pathname = require("url").parse(req.originalUrl).pathname;
      if (req.url === "/" && !utils.endsWith(pathname, "/")) {
        pathname += '/';
        res.statusCode = 301;
        res.setHeader('Location', pathname);
        return res.end('Redirecting to ' + pathname);
      } else {
        return next();
      }
    };
  };

  createRoutingProxy = function(options, returnHost) {
    var defaultPort, proxy, routingProxyOptions;
    if (options.https) {
      routingProxyOptions = {
        target: {
          https: true
        }
      };
      defaultPort = 443;
    } else {
      routingProxyOptions = {};
      defaultPort = 80;
    }
    proxy = new httpProxy.RoutingProxy(routingProxyOptions);
    options.path || (options.path = "");
    options.port || (options.port = defaultPort);
    options.patchRedirect || (options.patchRedirect = true);
    if (options.patchRedirect) {
      proxy.once("start", function(req, res) {
        return patchServerResponseForRedirects(options.host, returnHost);
      });
    }
    return function(req, res, next) {
      req.url = "" + options.path + req.url;
      req.headers.host = options.host;
      return proxy.proxyRequest(req, res, options);
    };
  };

  patchServerResponseForRedirects = function(fromHost, returnHost) {
    var writeHead;
    writeHead = http.ServerResponse.prototype.writeHead;
    return http.ServerResponse.prototype.writeHead = function(status) {
      var cookie, headers, i, len, newLocation, newSetCookie, oldLocation, ref;
      headers = this._headers || {};
      if (status === 301 || status === 302) {
        oldLocation = new RegExp("s?:\/\/" + fromHost + ":?[0-9]*");
        newLocation = "://" + returnHost;
        headers.location = headers.location.replace(oldLocation, newLocation);
      }
      if ('set-cookie' in headers) {
        newSetCookie = [];
        ref = headers['set-cookie'];
        for (i = 0, len = ref.length; i < len; i++) {
          cookie = ref[i];
          newSetCookie.push(cookie.replace(/; Secure; HttpOnly/, ''));
        }
        headers['set-cookie'] = newSetCookie;
      }
      return writeHead.apply(this, arguments);
    };
  };

  module.exports = server;

}).call(this);
