/**
 * The handlebars reference
 * @external Handlebars
 * @see {@link https://handlebarsjs.com/|Handlebars}
 */
 /**
 * The handlebars Template reference
 * @external Handlebars-Template
 * @see {@link https://handlebarsjs.com/|Handlebars}
 */
(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['underscore'], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('underscore'));
  } else {
    root.Torso = root.Torso || {};
    root.Torso.Utils = root.Torso.Utils || {};
    root.Torso.Utils.handlebarsUtils = factory(root._);
  }
}(this, function(_) {
  'use strict';
  /**
   * Extensions to handlebars helpers.
   *
   * Adds additonal helpers to {@link external:Handlebars}
   *
   * @function handlebarsUtils
   * @param {external:Handlebars} Handlebars Add the helpers to this Handlebars object.
   *
   * @author ariel.wexler@vecna.com, kent.willis@vecna.com
   *
   * @see {@link HandlebarsHelper} for the added helpers.
   * @see <a href="../annotated/modules/handlebarsUtils.html">handlebarsUtils Annotated Source</a>
   */
  /** @namespace HandlebarsHelper */
  return function(Handlebars) {
    var FEEDBACK_KEY = 'feedback';
    var MODEL_KEY = 'model';
    /**
     * Usage: {{labelFor 'fieldName' value="suffix"}}
     *
     * Generates: for="field-name-suffix"
     *
     * Usage: {{labelFor 'fieldName[x].sub' value="demo" x=123}}
     *
     * Generates: for="field-name-123_sub-demo"
     *
     * Usage: {{labelFor 'fieldName[bar].sub' value="demo" bar="abc"}}
     *
     * Generates: for="field-name_abc_sub-demo"
     *
     * @method HandlebarsHelper.labelFor
     * @param {string} field The field name to convert to a compliant "for" attribute
     * @param {Object} options The handlebars context.  Always passed in as the final argument.
     * @param {string} [option.hash.value] The value tacked on to the end of the field string (useful for radio and checkbox)
     * @returns {string} Compliant HTML generating the "for" attribute
     */
    Handlebars.registerHelper('labelFor', function(field, options) {
      options = _.extend(options, {noValueAttr: true});
      return Handlebars.helpers.formAttr(field, 'for', options);
    });
    /**
     * Usage: {{bindModel 'fieldName' value='suffix'}}
     *
     * Generates: id="field-name-suffix" name="field-name" data-model="fieldName" data-feedback="fieldName" value="demo"
     *
     * Usage: {{bindModel 'fieldName[x].sub' value='demo' x=123}}
     *
     * Generates: data-model="fieldName[123].sub" data-feedback="fieldName[123].sub" name="field-name-123_sub"
     *            id="field-name-123_sub-demo" value="demo"
     *
     * Usage: {{bindModel 'fieldName[bar].sub' value='demo' bar='abc'}}
     *
     * Generates: data-model="fieldName.abc.sub" data-feedback="fieldName[abc].sub" name="field-name_abc_sub"
                  id="field-name_abc_sub-demo" value="demo"
     *
     * @method HandlebarsHelper.bindModel
     * @param {string} field The field name to convert to compliant id, name, data-model, and data-feedback attributes
     * @param {Object} options The handlebars context.  Always passed in as the final argument.
     * @param {string} [options.hash.value] The value tacked on to the end of the field string (useful for radio and checkbox)
     * @returns {string} Compliant HTML generating the id, name, data-model, and data-feedback attributes
     */
    Handlebars.registerHelper('bindModel', function(field, options) {
      return Handlebars.helpers.formAttr(field, MODEL_KEY + ', ' + FEEDBACK_KEY + ', name, id', options);
    });
    /**
     * Usage: {{feedback 'fieldName'}}
     *
     * Generates: data-feedback="fieldName"
     *
     * Usage: {{feedback 'fieldName[x].sub' value='demo' x=123}}
     *
     * Generates: data-feedback="fieldName[123].sub"
     *
     * Usage: {{feedback 'fieldName[bar].sub value='demo' bar='abc'}}
     *
     * Generates: data-feedback="fieldName[abc].sub"
     *
     * @method HandlebarsHelper.feedback
     * @param {string} field The field name to convert to a compliant data-feedback attribute
     * @param {Object} options The handlebars context.  Always passed in as the final argument.
     * @returns {string} Compliant HTML generating the data-feedback attribute
     */
    Handlebars.registerHelper('feedback', function(field, options) {
      options = _.extend(options, {noValueAttr: true});
      return Handlebars.helpers.formAttr(field, FEEDBACK_KEY, options);
    });
    /**
     * Usage: {{formAttr 'fieldName[x].sub' 'id, for' value='demo' x=123}}
     *
     * Generates: id="field-name-123_sub-demo" for="field-name-123_sub-demo" value="demo"
     *
     * Usage: {{feedback 'fieldName[bar].sub value='demo' bar='abc'}}
     *
     * Generates: id="field-name_abc_sub-demo" for="field-name_abc_sub-demo" value="demo"
     *
     * @method HandlebarsHelper.formAttr
     * @param {string} field The field name to convert to a compliant data-feedback attribute
     * @param {Object} options The handlebars context.  Always passed in as the final argument.
     * @param {string} [options.hash.value] The value tacked on to the end of the field string (useful for radio and checkbox)
     * @param {boolean} [options.noValueAttr] when options.noValueAttr is set to true,
                                              then it will not generate the "value" attribute in the DOM.
     * @returns {string} Compliant HTML generating the data-feedback attribute
     */
    Handlebars.registerHelper('formAttr', function(field, attrs, options) {
      var i, attrName,
        value = (options.hash ? options.hash.value : undefined),
        res = Handlebars.helpers.injectFieldIndices(field, options.hash),
        resWithArrayNotation = Handlebars.helpers.injectFieldIndices(field, options.hash, { forceArrayNotation: true }),
        attributes = '';
      attrs = attrs.split(',');
      for (i = 0; i < attrs.length; i++) {
        attrName = attrs[i].trim();
        var attrEnd = (i === attrs.length - 1) ? '"' : '" ';
        if (attrName === FEEDBACK_KEY) {