
/*!
 * express-expose
 * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var express = require('express')
  , HTTPSServer = express.HTTPSServer
  , HTTPServer = express.HTTPServer;

/**
 * Library version.
 */

exports.version = '0.0.1';

/**
 * Default local variable name.
 */

exports.name = 'javascript';

/**
 * Expose the given `obj` to the client-side, with
 * the given `namespace`.
 *
 * @param {Object|String} obj
 * @param {String} namespace
 * @param {String} name
 * @return {HTTPServer} for chaining
 * @api public
 */

HTTPServer.prototype.expose =
HTTPSServer.prototype.expose = function(obj, namespace, name){
  this._exposed = this._exposed || {};

  // support second arg as name
  // when a string is given
  if ('string' == typeof obj) {
    name = namespace || exports.name;
  } else {
    name = name || exports.name;
    if (!namespace) throw new Error('namespace required');    
  }


  // register dynamic helper
  if (!this._exposed[name]) {
    this._exposed = {};
    var helpers = {};
    helpers[name] = function(){ return this.exposed(name); };
    this.dynamicHelpers(helpers);
  }

  // buffer string
  if ('string' == typeof obj) {
    this.js = this.js || {};
    var buf = this.js[name] = this.js[name] || [];
    buf.push(obj);
  // buffer object
  } else {
    this.expose(renderNamespace(namespace) + ' = (function(){', name);
    this.expose('  var exports = {};', name);
    this.expose(renderObject(obj), name);
    this.expose('  return exports;', name);
    this.expose('})();\n', name);
  }

  return this;
};

/**
 * Render the exposed javascript.
 *
 * @return {String}
 * @api private
 */

HTTPServer.prototype.exposed =
HTTPSServer.prototype.exposed = function(name){
  name = name || exports.name;
  if (!this.js[name]) throw new Error('no javascript buffered for "' + name + '"');
  return this.js[name].join('\n');
};

/**
 * Render the given `obj`.
 *
 * @param {Object} obj
 * @return {String}
 * @api private
 */

function renderObject(obj) {
  return Object.keys(obj).map(function(key){
    var val = obj[key];
    return '  exports["' + key + '"] = ' + string(val) + ';';
  }).join('\n');
}

/**
 * Render a namespace from the given `str`.
 *
 * Examples:
 *
 *    renderNamespace('foo.bar.baz');
 *
 *    var foo = foo || {};
 *    foo.bar = foo.bar || {};
 *    foo.bar.baz
 *
 * @param {String} str
 * @return {String}
 * @api private
 */

function renderNamespace(str){
  var parts = []
    , split = str.split('.')
    , len = split.length;
 
  return str.split('.').map(function(part, i){
    parts.push(part);
    part = parts.join('.');
    var js = i ? '' : 'var ';
    if (i < len - 1) {
      js += part + ' = ' + part + ' || {};';
    } else {
      js += part;
    }
    return js;
  }).join('\n');
};

/**
 * Return a string representation of `obj`.
 *
 * @param {Mixed} obj
 * @return {String}
 * @api private
 */

function string(obj) {
  if ('function' == typeof obj) {
    return obj.toString();
  } else {
    return JSON.stringify(obj);
  }
}
@@ -1350,36 +1350,36 @@
  else %7B%0A    
-this.expose(
+namespace = 
 renderNamesp
@@ -1396,74 +1396,42 @@
 ace)
- + ' = (function()%7B', name);%0A    this.expose('  var exports = %7B%7D;'
+;%0A    this.expose(namespace.string
 , na
@@ -1471,53 +1471,25 @@
 (obj
-)
 , name
-);%0A    this.expose('  return exports;'
+space.prop)
 , na
@@ -1514,22 +1514,11 @@
 se('
-%7D)();%5Cn', name
+%5Cn'
 );%0A 
@@ -1880,24 +1880,44 @@
  given %60obj%60
+ against %60namespace%60
 .%0A *%0A * @par
@@ -1928,24 +1928,53 @@
 Object%7D obj%0A
+ * @param %7BString%7D namespace%0A
  * @return %7B
@@ -2023,24 +2023,35 @@
 erObject(obj
+, namespace
 ) %7B%0A  return
@@ -2126,18 +2126,21 @@
 urn 
-'  exports
+namespace + '
 %5B%22' 
@@ -2379,16 +2379,37 @@
 .bar.baz
+ = foo.bar.baz %7C%7C %7B%7D;
 %0A *%0A * @
@@ -2573,20 +2573,41 @@
 ngth
-;%0A %0A  return
+%0A    , ret = %7B%7D;%0A %0A  ret.string =
  str
@@ -2699,169 +2699,119 @@
     
-var js = i ? '' : 'var ';%0A    if (i %3C len - 1) %7B%0A      js += part + ' = ' + part + ' %7C%7C %7B%7D;';%0A    %7D else %7B%0A      js += part;%0A    %7D%0A    return js;%0A  %7D).join('%5Cn')
+ret.prop = part;%0A    return (i ? '' : 'var ') + part + ' = ' + part + ' %7C%7C %7B%7D;';%0A  %7D).join('%5Cn');%0A%0A  return ret
 ;%0A%7D;

switch up render to allow for patching namespaces