/*
 * response-stream.js: A Stream focused on writing any relevant information to
 * a raw http.ServerResponse object.
 *
 * (C) 2011, Charlie Robbins & the Contributors
 * MIT LICENSE
 *
 */

var util = require('util'),
    HttpStream = require('./http-stream');

var STATUS_CODES = require('http').STATUS_CODES;

//
// ### function ResponseStream (options)
//
//
var ResponseStream = module.exports = function (options) {
  var self = this,
      key;

  options = options || {};
  HttpStream.call(this, options);

  this.writeable = true;
  this.response = options.response;

  if (options.headers) {
    for (key in options.headers) {
      this.response.setHeader(key, options.headers[key]);
    }
  }

  //
  // Proxy `statusCode` changes to the actual `response.statusCode`.
  //
  Object.defineProperty(this, 'statusCode', {
    get: function () {
      return self.response.statusCode;
    },
    set: function (value) {
      self.response.statusCode = value;
    },
    enumerable: true,
    configurable: true
  });

  if (this.response) {
    this._headers = this.response._headers = this.response._headers || {};

    // Patch to node core
    this.response._headerNames = this.response._headerNames || {};

    //
    // Proxy to emit "header" event
    //
    this._renderHeaders = this.response._renderHeaders;
    this.response._renderHeaders = function () {
      if (!self._emittedHeader) {
        self._emittedHeader = true;
        self.headerSent = true;
        self._header = true;
        self.emit('header');
      }

      return self._renderHeaders.call(self.response);
    };
  }
};

util.inherits(ResponseStream, HttpStream);

ResponseStream.prototype.writeHead = function (statusCode, statusMessage, headers) {
  if (typeof statusMessage === 'string') {
    this.response.statusMessage = statusMessage;
  } else {
    this.response.statusMessage = this.response.statusMessage
      || STATUS_CODES[statusCode] || 'unknown';
    headers = statusMessage;
  }

  this.response.statusCode = statusCode;

  if (headers) {
    var keys = Object.keys(headers);
    for (var i = 0; i < keys.length; i++) {
      var k = keys[i];
      if (k) this.response.setHeader(k, headers[k]);
    }
  }
};

//
// Create pass-thru for the necessary
// `http.ServerResponse` methods.
//
['setHeader', 'getHeader', 'removeHeader', '_implicitHeader', 'addTrailers'].forEach(function (method) {
  ResponseStream.prototype[method] = function () {
    return this.response[method].apply(this.response, arguments);
  };
});

ResponseStream.prototype.json = function (obj) {
  if (!this.response.writable) {
    return;
  }

  if (typeof obj === 'number') {
    this.response.statusCode = obj;
    obj = arguments[1];
  }

  this.modified = true;

  if (!this.response._header && this.response.getHeader('content-type') !== 'application/json') {
    this.response.setHeader('content-type', 'application/json');
  }

  this.end(obj ? JSON.stringify(obj) : '');
};

ResponseStream.prototype.html = function (str) {
  if (!this.response.writable) {
    return;
  }

  if (typeof str === 'number') {
    this.response.statusCode = str;
    str = arguments[1];
  }

  this.modified = true;

  if (!this.response._header && this.response.getHeader('content-type') !== 'text/html') {
    this.response.setHeader('content-type', 'text/html');
  }

  this.end(str ? str: '');
};

ResponseStream.prototype.text = function (str) {
  if (!this.response.writable) {
    return;
  }

  if (typeof str === 'number') {
    this.response.statusCode = str;
    str = arguments[1];
  }

  this.modified = true;

  if (!this.response._header && this.response.getHeader('content-type') !== 'text/plain') {
    this.response.setHeader('content-type', 'text/plain');
  }

  this.end(str ? str: '');
};

ResponseStream.prototype.end = function (data) {
  if (data && this.writable) {
    this.emit('data', data);
  }

  this.modified = true;
  this.emit('end');
};

ResponseStream.prototype.pipe = function () {
  var self = this, 
      dest;

  self.dest = dest = HttpStream.prototype.pipe.apply(self, arguments);
  
  dest.on('drain', function() {
    self.emit('drain')
  })
  return dest;
};

ResponseStream.prototype.write = function (data) {
  this.modified = true;

  if (this.writable) {
    return this.dest.write(data);
  }
};

ResponseStream.prototype.redirect = function (path, status) {
  var url = '';

  if (~path.indexOf('://')) {
    url = path;
  } else {
    url += this.req.connection.encrypted ? 'https://' : 'http://';
    url += this.req.headers.host;
    url += (path[0] === '/') ? path : '/' + path;
  }

  this.res.writeHead(status || 302, { 'Location': url });
  this.end();
};