/*
 * core.js: Core functionality for the Flatiron HTTP (with SPDY support) plugin.
 *
 * (C) 2011, Charlie Robbins & the Contributors
 * MIT LICENSE
 *
 */

var http = require('http'),
    https = require('https'),
    fs = require('fs'),
    stream = require('stream'),
    HttpStream = require('./http-stream'),
    RoutingStream = require('./routing-stream');

var core = exports;

core.createServer = function (options) {
  var isArray = Array.isArray(options.after),
      credentials;

  if (!options) {
    throw new Error('options is required to create a server');
  }

  function requestHandler(req, res) {
    var routingStream = new RoutingStream({
      before: options.before,
      buffer: options.buffer,
      //
      // Remark: without new after is a huge memory leak that
      // pipes to every single open connection
      //
      after: isArray && options.after.map(function (After) {
        return new After;
      }),
      request: req,
      response: res,
      limit: options.limit,
      headers: options.headers
    });

    routingStream.on('error', function (err) {
      var fn = options.onError || core.errorHandler;
      fn(err, routingStream, routingStream.target, function () {
        routingStream.target.emit('next');
      });
    });

    req.pipe(routingStream);
  }

  //
  // both https and spdy requires same params
  //
  if (options.https || options.spdy) {
    if (options.https && options.spdy) {
      throw new Error('You shouldn\'t be using https and spdy simultaneously.');
    }

    var serverOptions,
        credentials,
        key = !options.spdy
          ? 'https'
          : 'spdy';

    serverOptions = options[key];
    if (!serverOptions.key || !serverOptions.cert) {
      throw new Error('Both options.' + key + '.`key` and options.' + key + '.`cert` are required.');
    }

    credentials = {
      key:  fs.readFileSync(serverOptions.key),
      cert: fs.readFileSync(serverOptions.cert)
    };

    if (serverOptions.ca) {
      serverOptions.ca = !Array.isArray(serverOptions.ca)
        ? [serverOptions.ca]
        : serverOptions.ca

      credentials.ca = serverOptions.ca.map(function (ca) {
        return fs.readFileSync(ca);
      });
    }

    if (options.spdy) {
      // spdy is optional so we require module here rather than on top
      var spdy = require('spdy');
      return spdy.createServer(credentials, requestHandler);
    }

    return https.createServer(credentials, requestHandler);
  }

  return http.createServer(requestHandler);
};

core.errorHandler = function error(err, req, res) {
  if (err) {
    (this.res || res).writeHead(err.status || 500, err.headers || { "Content-Type": "text/plain" });
    (this.res || res).end(err.message + "\n");
    return;
  }

  (this.res || res).writeHead(404, {"Content-Type": "text/plain"});
  (this.res || res).end("Not Found\n");
};