define(['lodash', 'i18n', 'jquery', 'ui/component/placeable', 'handlebars', 'lib/handlebars/helpers', 'css!ui/component/css/windowComponent.css'], function (_, __, $$1, makePlaceable, Handlebars, Helpers0, windowComponent_css) { 'use strict';

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


      buffer += "<div class=\"window-component\">\n    <div class=\"window-component-title-bar\">\n        <div class=\"window-component-title\">";
      if (helper = helpers.windowTitle) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.windowTitle); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "</div>\n        <div class=\"window-component-controls\"> </div>\n    </div>\n    <div class=\"window-component-body\"></div>\n</div>\n";
      return buffer;
      });
    function windowTpl(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) 2016 (original work) Open Assessment Technologies SA;
     */
    var eventNs = '.windowed',
      cssNs = '.window-component',
      defaultConfig = {
        hasCloser: true,
        hasBin: false
      };
    var controlsPresets = {
      bin: {
        id: 'bin',
        order: 100,
        icon: 'bin',
        description: __('Delete'),
        event: 'delete'
      },
      closer: {
        id: 'closer',
        order: 200,
        icon: 'result-nok',
        description: __('Close'),
        event: 'close',
        onclick: function onclick() {
          this.hide();
        }
      }
    };
    var windowedComponentAPI = {
      /**
       * @returns {jQuery} - the container where the title bar controls are rendered
       */
      getControls: function getControls() {
        var $component = this.getElement();
        return $component.find(cssNs + '-controls');
      },
      /**
       * @returns {jQuery} - the container where the title is rendered
       */
      getTitle: function getTitle() {
        var $component = this.getElement();
        return $component.find(cssNs + '-title');
      },
      /**
       * @returns {jQuery} - the content area of the window
       */
      getBody: function getBody() {
        var $component = this.getElement();
        return $component.find(cssNs + '-body');
      },
      /**
       * Adds a control to the control area
       * @param {String} controlOptions.id
       * @param {String} controlOptions.icon
       * @param {Number} [controlOptions.order] - position relative to the other controls
       * @param {String} [controlOptions.description] - link description on mouse over
       * @param {Function} [controlOptions.onclick] - what to do when the control is clicked. Optional if event is specified.
       * @param {Function} [controlOptions.event] - event to trigger when the control is clicked. Optional if onclick is specified
       * @returns {component}
       */
      addControl: function addControl(controlOptions) {
        if (!_.isString(controlOptions.id) || _.isEmpty(controlOptions.id)) {
          throw new Error('control must have an id');
        }
        if (!_.isString(controlOptions.icon) || _.isEmpty(controlOptions.icon)) {
          throw new Error('control must have an icon');
        }
        if (!_.isFunction(controlOptions.onclick) && !(_.isString(controlOptions.event) && controlOptions.event.trim() !== '')) {
          throw new Error('control must have valid onclick or event parameter');
        }
        if (!_.isArray(this._windowControls)) {
          this._windowControls = [];
        }
        this._windowControls.push(controlOptions);
        return this;
      },
      /**
       * Add pre-configured controls to the title bar
       * @returns {component}
       */
      addPresets: function addPresets() {
        if (this.config.hasCloser) {
          this.addControl(controlsPresets.closer);
        }
        if (this.config.hasBin) {
          this.addControl(controlsPresets.bin);
        }
        return this;
      },
      /**
       * Render the controls buttons in the title bar
       * @returns {component}
       * @private
       */
      _renderControls: function _renderControls() {
        var self = this,
          $controlsArea = this.getControls(),
          controlsCallbacks = {},
          controlsEvents = {};
        if (_.isArray(this._windowControls)) {
          $controlsArea.empty();

          // sort controls
          this._windowControls.sort(function sortAscending(a, b) {
            return (a.order || 0) - (b.order || 0);
          });

          // render controls
          this._windowControls.forEach(function (control) {
            var $control = $$1('<button>', {
              class: 'icon-' + control.icon,
              'data-control': control.id,
              title: control.description
            });
            $controlsArea.append($control);
            controlsCallbacks[control.id] = control.onclick;
            controlsEvents[control.id] = control.event;
          });

          // add behavior
          $controlsArea.off('click' + eventNs).on('click' + eventNs, function (e) {
            var controlId = $$1(e.target).data('control');
            e.stopPropagation();
            if (_.isFunction(controlsCallbacks[controlId])) {
              controlsCallbacks[controlId].call(self);
            }
            if (_.isString(controlsEvents[controlId])) {
              self.trigger(controlsEvents[controlId]);
            }
          });
        }
        return this;
      }
    };

    /**
     * @param {Component} component - an instance of ui/component
     * @param {Object} config
     * @param {Boolean} hasCloser - auto-add the closer control to the title bar
     * @param {Boolean} hasBin - auto-add the delete control to the title bar
     * @param {String} windowTitle - to be rendered in the title bar
     */
    function makeWindowed(component, config) {
      _.assign(component, windowedComponentAPI);
      if (!makePlaceable.isPlaceable(component)) {
        makePlaceable(component);
      }
      return component.setTemplate(windowTpl).off(eventNs).on('init' + eventNs, function () {
        _.defaults(this.config, config || {}, defaultConfig);
        this.addPresets();
      }).on('render' + eventNs, function () {
        this._renderControls();
      }).on('destroy' + eventNs, function () {
        var $controlsArea = this.getControls();
        $controlsArea.off(eventNs);
      });
    }

    return makeWindowed;

});
