var _ = require('underscore');

// Lazy-required.
var BaseView = null;

module.exports = function(Handlebars, getTemplate) {
  var oldEach = Handlebars.helpers.each;

  return {
    view: function(viewName, options) {
      var ViewClass, html, viewOptions, view;

      // it's lazy loaded, not a compile time dependency
      // hiding it from r.js compiler
      var lazyRequire_baseView = 'rendr/shared/base/view';
      BaseView = BaseView || require(lazyRequire_baseView);
      viewOptions = options.hash || {};

      // Pass through a reference to the app.
      var app = getProperty('_app', this, options);
      if (app) {
        viewOptions.app = app;
        viewName = app.modelUtils.underscorize(viewName);
      } else{
        throw new Error("An App instance is required when rendering a view, it could not be extracted from the options.")
      }

      // Pass through a reference to the parent view.
      var parentView = getProperty('_view', this, options);
      if (parentView) {
        viewOptions.parentView = parentView;
      }

      // get the Backbone.View based on viewName
      ViewClass = BaseView.getView(viewName, app.options.entryPath);
      view = new ViewClass(viewOptions);

      // create the outerHTML using className, tagName
      html = view.getHtml();
      return new Handlebars.SafeString(html);
    },

    partial: function(templateName, options) {
      var data, html, context, template;

      template = getTemplate(templateName);

      context = options.hash || {};

      // First try to use Handlebars' hash arguments as the context for the
      // partial, if present.
      //
      // ex: `{{partial "users/photo" user=user}}`
      if (_.isEmpty(context)) {
        // If there are no hash arguments given, then inherit the parent context.
        //
        // ex: `{{partial "users/photo"}}`
        context = this;
      } else {
        // If a hash argument is given with key `context`, then use that as the context.
        //
        // ex: `{{partial "users/photo" context=user}}`
        if (context.hasOwnProperty('context')) {
          context = context.context;
        }
      }
      context = _.clone(context);

      context._app = getProperty('_app', this, options);
      html = template(context);
      return new Handlebars.SafeString(html);
    },

    json: function(object, spacing) {
      return new Handlebars.SafeString(JSON.stringify(object, null, spacing) || 'null');
    },

    /**
     * Extend `each` to pass through important context.
     */
    each: function(context, options) {
      options.data = Handlebars.createFrame(options.data || {});

      // Make sure `this._app`, `this._view`, etc are available.
      _.extend(options.data, getOptionsFromContext(this));

      // Call the original helper with new context.
      return oldEach.call(this, context, options);
    }
  };
};

/**
 * Grab important underscored properties from the current context.
 * These properties come from BaseView::decorateTemplateData().
 */
function getOptionsFromContext(obj) {
  var options, keys, value;

  keys = [
    '_app',
    '_view',
    '_model',
    '_collection'
  ];

  options = keys.reduce(function(memo, key) {
    value = obj[key];
    if (value) {
      memo[key] = value;
    }
    return memo;
  }, {});

  return options;
}

/**
 * Get a property that is being passed down through helpers, such as `_app`
 * or `_view`. It can either live on the context, i.e. `this._app`, or in the
 * `options.data` object passed to the helper, i.e. `options.data._app`, in the
 * case of a block helper like `each`.
 */
function getProperty(key, context, options) {
  return context[key] || (options.data || {})[key];
}

@@ -62,16 +62,29 @@
 w = null
+,%0A    oldEach
 ;%0A%0Amodul
@@ -133,19 +133,25 @@
 te) %7B%0A  
-var
+oldEach =
  oldEach
@@ -151,17 +151,18 @@
 oldEach 
-=
+%7C%7C
  Handleb

save the original Handlebars each function module wide