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

    $$1 = $$1 && Object.prototype.hasOwnProperty.call($$1, 'default') ? $$1['default'] : $$1;
    _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
    __ = __ && 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, functionType="function", escapeExpression=this.escapeExpression, self=this;

    function program1(depth0,data) {
      
      var buffer = "", stack1, helper;
      buffer += "<label>";
      if (helper = helpers.comboboxLabel) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.comboboxLabel); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "</label>";
      return buffer;
      }

    function program3(depth0,data) {
      
      var buffer = "", stack1, helper;
      buffer += "\n        <option value=\"";
      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)
        + "\" data-categories=\"";
      if (helper = helpers.categories) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.categories); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\">";
      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)
        + "</option>\n        ";
      return buffer;
      }

      buffer += "<span class=\"cascading-combo-box\">\n    ";
      stack1 = helpers['if'].call(depth0, (depth0 && depth0.comboboxLabel), {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n    <select class=\"\" data-id=\"";
      if (helper = helpers.comboboxId) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.comboboxId); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\" data-has-search=\"false\">\n        <option></option>\n        ";
      stack1 = helpers.each.call(depth0, (depth0 && depth0.options), {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n    </select>\n</span>";
      return buffer;
      });
    function selectTpl(data, options, asString) {
      var html = Template(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) 2015 (original work) Open Assessment Technologies SA ;
     */
    var selectedValues = {};

    /**
     * Create a combobox and initialize it with select2
     *
     * @param {Number} level
     * @param {array} categoriesDefinitions - the array that defines the number and config for each level of combobox cascade
     * @param {array} categories - the array that contains nested array of categories
     * @param {array} selected - the array that contains options selected
     * @returns {jQuery}
     */
    function createCombobox(level, categoriesDefinitions, categories, selected) {
      if (categoriesDefinitions[level] && categories[level]) {
        selected = selected || [];
        const categoryDef = categoriesDefinitions[level];
        let $comboBox;
        if (categoryDef.id) {
          //init <select> DOM element
          $comboBox = $$1(selectTpl({
            comboboxId: categoryDef.id,
            comboboxLabel: categoryDef.label || '',
            options: categories[level]
          }));
          $comboBox.find('select').val(selected[level] || '');

          //add event handler
          $comboBox.on('change', function () {
            var $selected = $comboBox.find(':selected');
            selectedValues[categoryDef.id] = $selected.val();
            //trigger event
            $comboBox.trigger('selected.cascading-combobox', [selectedValues]);
          });

          //init select 2 on $comboBox
          $comboBox.find('select').select2({
            allowClear: true,
            dropdownAutoWidth: true,
            placeholder: categoryDef.placeholder || __('select...'),
            minimumResultsForSearch: -1
          });
          return $comboBox;
        }
      } else {
        throw new Error(`missing category definition on level : ${level}`);
      }
    }

    /**
     * @param {object} options
     * @param {Array} [options.categoriesDefinitions] - the array that defines the number and config for each level of combobox
     * @param {Array} [options.categories] - the array that contains array of categories
     * @param {Array} [options.selected] - the array that contains array of selected options
     * @returns {function}
     */
    function groupedComboBoxFactory(options) {
      return component().on('render', function render($container) {
        if (_.isArray(options.categoriesDefinitions) && _.isArray(options.categories)) {
          options.categoriesDefinitions.forEach(function (k, i) {
            var $comboBox = createCombobox(i, options.categoriesDefinitions, options.categories, options.selected);
            $container.append($comboBox);
          });
        }
      }).init(options);
    }

    return groupedComboBoxFactory;

});
