define(['jquery', 'lodash', 'ui/component', 'handlebars', 'lib/handlebars/helpers'], function ($$1, _, component, Handlebars, Helpers0) { 'use strict';

    $$1 = $$1 && Object.prototype.hasOwnProperty.call($$1, 'default') ? $$1['default'] : $$1;
    _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
    component = component && Object.prototype.hasOwnProperty.call(component, 'default') ? component['default'] : component;
    Handlebars = Handlebars && Object.prototype.hasOwnProperty.call(Handlebars, 'default') ? Handlebars['default'] : Handlebars;
    Helpers0 = Helpers0 && Object.prototype.hasOwnProperty.call(Helpers0, 'default') ? Helpers0['default'] : Helpers0;

    if (!Helpers0.__initialized) {
      Helpers0(Handlebars);
      Helpers0.__initialized = true;
    }
    var Template = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
      this.compilerInfo = [4,'>= 1.0.0'];
    helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
      var buffer = "", stack1, helper, helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, self=this, functionType="function";

    function program1(depth0,data) {
      
      
      return " no-border";
      }

    function program3(depth0,data) {
      
      var buffer = "", helper, options;
      buffer += "\n    <label class=\"fold pseudo-label-box\">\n        <span class=\"check-txt hide\">"
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Hide detailed report", options) : helperMissing.call(depth0, "__", "Hide detailed report", options)))
        + "</span>\n        <span class=\"check-txt show\">"
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Show detailed report", options) : helperMissing.call(depth0, "__", "Show detailed report", options)))
        + "</span>\n        <input type=\"checkbox\"/>\n        <span class=\"icon-checkbox\"></span>\n    </label>\n    ";
      return buffer;
      }

      buffer += "<div class=\"component-report";
      stack1 = helpers['if'].call(depth0, (depth0 && depth0.noBorder), {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\">\n    ";
      stack1 = helpers['if'].call(depth0, (depth0 && depth0.detailsButtonVisible), {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n    <div class=\"content\">";
      if (helper = helpers.content) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.content); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "</div>\n</div>";
      return buffer;
      });
    function layoutTpl(data, options, asString) {
      var html = Template(data, options);
      return (asString || true) ? html : $(html);
    }

    if (!Helpers0.__initialized) {
      Helpers0(Handlebars);
      Helpers0.__initialized = true;
    }
    var Template$1 = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
      this.compilerInfo = [4,'>= 1.0.0'];
    helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
      var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, self=this, helperMissing=helpers.helperMissing;

    function program1(depth0,data) {
      
      
      return "hierarchical";
      }

    function program3(depth0,data) {
      
      
      return "leaf";
      }

    function program5(depth0,data) {
      
      
      return " hierarchical-icon";
      }

    function program7(depth0,data) {
      
      var buffer = "", stack1;
      buffer += "\n        ";
      stack1 = (typeof depth0 === functionType ? depth0.apply(depth0) : depth0);
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n    ";
      return buffer;
      }

    function program9(depth0,data) {
      
      var buffer = "", stack1, helper;
      buffer += "\n        <button data-trigger=\"";
      if (helper = helpers.id) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.id); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\" class=\"action btn-info\" title=\"";
      if (helper = helpers.title) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.title); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\"><span class=\"icon-";
      if (helper = helpers.icon) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.icon); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\"></span>";
      if (helper = helpers.label) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.label); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "</button>\n        ";
      return buffer;
      }

      buffer += "<div class=\"feedback-";
      if (helper = helpers.type) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.type); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + " ";
      stack1 = helpers['if'].call(depth0, (depth0 && depth0.hasChildren), {hash:{},inverse:self.program(3, program3, data),fn:self.program(1, program1, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\">\n    <span class=\"icon-";
      if (helper = helpers.type) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.type); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1);
      stack1 = helpers['if'].call(depth0, (depth0 && depth0.hasChildren), {hash:{},inverse:self.noop,fn:self.program(5, program5, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\"></span>\n    <div class=\"message\">";
      stack1 = (helper = helpers.dompurify || (depth0 && depth0.dompurify),options={hash:{},data:data},helper ? helper.call(depth0, (depth0 && depth0.message), options) : helperMissing.call(depth0, "dompurify", (depth0 && depth0.message), options));
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "</div>\n    ";
      stack1 = helpers.each.call(depth0, (depth0 && depth0.children), {hash:{},inverse:self.noop,fn:self.program(7, program7, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n    <div class=\"actions\">\n        ";
      stack1 = helpers.each.call(depth0, (depth0 && depth0.actions), {hash:{},inverse:self.noop,fn:self.program(9, program9, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n    </div>\n</div>";
      return buffer;
      });
    function feedbackTpl(data, options, asString) {
      var html = Template$1(data, options);
      return (asString || true) ? html : $(html);
    }

    /**
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * as published by the Free Software Foundation; under version 2
     * of the License (non-upgradable).
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
     *
     * Copyright (c) 2017 (original work) Open Assessment Technologies SA ;
     */
    var _defaults = {
      showDetailsButton: true,
      actions: []
    };

    /**
     * Array of authorized report types
     * @type {Array}
     */
    var authorizedTypes = ['success', 'info', 'warning', 'error'];

    /**
     * Recursive function to render report messages
     *
     * @private
     * @param {Object} data - a standard report object sent by the backend
     * @param {String} data.type - the error type
     * @param {String} data.message - the feedback message
     * @param {Array} [data.children] - children report object
     * @param {Array} [actions] - the actions buttons to be added, only for the first level of the hierarchy
     * @returns {*}
     */
    var _renderFeebacks = function _renderFeebacks(data, actions) {
      var children = [];
      if (!data.type || authorizedTypes.indexOf(data.type) === -1) {
        throw new TypeError('Unkown report type: ' + data.type);
      }
      if (_.isArray(data.children) && data.children.length) {
        _.each(data.children, function (child) {
          children.push(_renderFeebacks(child));
        });
      }
      data.hasChildren = children.length > 0;
      data.children = children;
      data.actions = actions;
      return feedbackTpl(data);
    };
    var report = {
      /**
       * Check if the details of the report are currently visible
       * @returns {Boolean}
       */
      isDetailed: function isDetailed() {
        return this.is('detailed');
      },
      /**
       * Show the report details
       *
       * @returns {this}
       * @fires reportComponent#showDetails
       */
      showDetails: function showDetails() {
        if (this.is('rendered')) {
          this.setState('detailed', true);
          this.getElement().find('.fold input').prop('checked', true);
          this.trigger('showDetails');
        }
        return this;
      },
      /**
       * Hide the report details
       *
       * @returns {this}
       * @fires reportComponent#hideDetails
       */
      hideDetails: function hideDetails() {
        if (this.is('rendered')) {
          this.setState('detailed');
          this.getElement().find('.fold input').prop('checked', false);
          this.trigger('hideDetails');
        }
        return this;
      }
    };

    /**
     * Create a simple report component
     *
     * @param {Object} config
     * @param {Boolean} [config.showDetailsButton=true] - display the show/hide details toggle
     * @param {Array} [config.actions] - possibility to add more button controls
     * @param {Object} data - a standard report object
     * @param {String} data.type - the type of the report
     * @param {String} data.message - the message to be included in the report body (html allowed)
     * @param {Array} [data.children] - children report object
     * @returns {reportComponent}
     */
    var reportComponentFactory = function reportComponentFactory(config, data) {
      var initConfig = _.defaults(config || {}, _defaults);
      if (data && _.isArray(data.children) && data.children.length) {
        initConfig.detailsButtonVisible = initConfig.showDetailsButton;
      }

      /**
       * THe report component
       * @typedef reportComponent
       * @fires reportComponent#action
       * @fires reportComponent#action-{custom action name}
       */
      return component(report).setTemplate(layoutTpl).on('render', function () {
        var self = this;
        var $content = this.getElement().find('.content');
        var $checkbox = this.getElement().find('.fold input');
        $content.append(_renderFeebacks(_.cloneDeep(data), this.config.actions));

        //init actions:
        $content.on('click', '.action', function () {
          var actionId = $$1(this).data('trigger');
          self.trigger('action-' + actionId);
          self.trigger('action', actionId);
        });

        //ensure multiple fast clicks only activate the toggle once
        $checkbox.on('change', _.throttle(function () {
          if (self.isDetailed()) {
            self.hideDetails();
          } else {
            self.showDetails();
          }
        }, 100));
      }).init(initConfig);
    };

    return reportComponentFactory;

});
