define(['jquery', 'lodash', 'i18n', 'core/pluginifier', 'core/dataattrhandler', 'handlebars', 'lib/handlebars/helpers'], function ($$1, _, __, Pluginifier, DataAttrHandler, Handlebars, Helpers0) { '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'] : __;
    Pluginifier = Pluginifier && Object.prototype.hasOwnProperty.call(Pluginifier, 'default') ? Pluginifier['default'] : Pluginifier;
    DataAttrHandler = DataAttrHandler && Object.prototype.hasOwnProperty.call(DataAttrHandler, 'default') ? DataAttrHandler['default'] : DataAttrHandler;
    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, options, functionType="function", escapeExpression=this.escapeExpression, helperMissing=helpers.helperMissing;


      buffer += "<div class=\"undobox\">\n    <span class=\"icon-info\"></span>\n        ";
      if (helper = helpers.undoMessage) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.undoMessage); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\n        <a class=\"undo\" href=\"#\">"
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Undo", options) : helperMissing.call(depth0, "__", "Undo", options)))
        + "</a>\n    <span title=\""
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Remove Message", options) : helperMissing.call(depth0, "__", "Remove Message", options)))
        + "\" class=\"icon-close\" data-close=\":parent .undobox\"></span>\n</div>\n";
      return buffer;
      });
    function undoTmpl(data, options, asString) {
      var html = Template(data, options);
      return (asString || true) ? html : $(html);
    }

    /**
     * @author Bertrand Chevrier <bertrand@taotesting.com>
     * @requires jquery
     * @requires core/pluginifier
     * @requires core/dataattrhandler
     */
    var ns = 'deleter';
    var dataNs = 'ui.' + ns;
    var defaults = {
      bindEvent: 'click',
      undo: false,
      undoTimeout: 5000,
      undoMessage: __('Element deleted.'),
      undoContainer: false,
      confirm: false,
      confirmMessage: __('Are you sure you want to delete it?'),
      disableClass: 'disabled'
    };

    /**
     * The deleter component, that helps you to close a new element.
     * @exports ui/deleter
     */
    var deleter = {
      /**
       * Initialize the plugin.
       *
       * Called the jQuery way once registered by the Pluginifier.
       * @example $('selector').deleter({target : $('target')});
       * @public
       *
       * @constructor
       * @param {Object} options - the plugin options
       * @param {jQueryElement} options.target - the element to close
       * @param {string|boolean} [options.bindEvent = 'click'] - the event that trigger the close
       * @param {Boolean} [options.undo = false] - enable to undo the deletion
       * @param {Number}  [options.undoTimeout = 5000] - the time the undo remains available
       * @param {String} [options.undoMessage = '...'] - the message to display in the undo box
       * @param {String|jQueryElement} [options.undoContainer = 'body'] - the element that will contain the undo box
       * @param {boolean} [options.confirm = false] - display a popup to confirm the closing
       * @param {string} [options.confirmMessage = '...'] - the confirmation message
       * @fires deleter#create.deleter
       * @returns {jQueryElement} for chaining
       */
      init: function (options) {
        options = _.defaults(options, defaults);
        return this.each(function () {
          var $elt = $$1(this);
          if (!$elt.data(dataNs)) {
            //add data to the element
            $elt.data(dataNs, options);

            //bind an event to trigger the close
            if (options.bindEvent !== false) {
              $elt.on(options.bindEvent, function (e) {
                e.preventDefault();
                deleter._delete($elt);
              });
            }

            /**
             * The plugin have been created.
             * @event deleter#create.deleter
             */
            $elt.trigger('create.' + ns);
          }
        });
      },
      /**
       * Trigger the delete.
       *
       * Called the jQuery way once registered by the Pluginifier.
       * @example $('selector').closer('close');
       * @param {jQueryElement} $elt - plugin's element
       * @fires deleter#delete.deleter
       * @fires delete
       * @fires deleter#deleted.deleter
       * @fires deleted
       * @fires deleter#undo.deleter
       */
      _delete: function ($elt) {
        var performDelete = true;
        var $target, $parent, $evtTrigger, $placeholder, $undoBox;
        var options = $elt.data(dataNs);
        var undoRemove, timeout;
        var realRemove = function realRemove() {
          if (performDelete && $target) {
            $target.remove();

            /**
             * The target has been closed/removed.
             * @event deleter#deleted.deleter
             */
            $evtTrigger.trigger('deleted.' + ns, [$target]);
          }
        };
        if (options && !$elt.hasClass(options.disableClass)) {
          $target = options.target;
          if (options.confirm === true) {
            //eslint-disable-next-line no-alert
            performDelete = window.confirm(options.confirmMessage);
          }
          if (performDelete) {
            $parent = $target.parent();

            //if elt is inside target, we get the parent to simulate the bubbing
            $evtTrigger = $target.has($elt).length > 0 ? $parent : $elt;

            /**
             * The plugin is removing the target.
             * Those eventes are fired just before the removal
             * to be able to listen them
             * (if $elt is inside the closed elt for instance)
             * @event deleter#deleted.deleter
             * @param {jQueryElement} $target - the element being closed/removed
             */
            $elt.trigger('delete.' + ns, [$target]);
            $target.trigger('delete', [options.undo]); //global event for consistensy

            //create a placeholder to retrieve the target position in case of undo
            $placeholder = $$1('<span style="display:none;" />').insertAfter($target);
            $target.detach();
            if (options.undo) {
              //show the feedback
              $$1(document).off(`.unundo.${ns}`);
              $undoBox = deleter._createUndoBox(options);
              $undoBox.find('.undo').click(function (e) {
                e.preventDefault();
                if (typeof timeout === 'number') {
                  clearTimeout(timeout);
                }
                performDelete = false;
                $undoBox.remove();
                $target.insertBefore($placeholder);
                $placeholder.remove();

                /**
                 * The delete has been undone
                 * @event deleter#undo.deleter
                 */
                $elt.trigger(`undo.${ns}`, [$target]);
                $target.trigger(`undo.${ns}`);
              });
              undoRemove = () => {
                if ($undoBox && $undoBox.length) {
                  $undoBox.remove();
                  $placeholder.remove();
                }
                realRemove();
                $$1(document).off(`.unundo.${ns}`);
              };

              //clicking on the document force the delete
              $$1(document).one(`mousedown.unundo.${ns}`, function (e) {
                e.preventDefault();
                e.stopImmediatePropagation();
                if (($undoBox.find(e.target).length === 0 || !$$1(e.target).hasClass('undo')) && typeof timeout === 'number') {
                  clearTimeout(timeout);
                  undoRemove();
                }

                //retrigger the click then
                _.delay(function () {
                  $$1(e.target).trigger('mousedown');
                }, 10);
                return false;
              });

              //remove the target once the atteched events may be terminated (no guaranty, this happens after in the event loop)
              timeout = setTimeout(function () {
                undoRemove();
              }, options.undoTimeout);
            } else {
              realRemove();
            }
          }
        }
      },
      /**
       * Create the undo message box
       * @private
       * @param {Object} options - the plugin options
       * @returns {jQueryElement} the undo box
       */

      _createUndoBox: function (options) {
        var $undoContainer = options.undoContainer || $$1('#feedback-messages-main');
        if (!$undoContainer.length) {
          //create a global feedback container

          $undoContainer = $$1('<div id="feedback-messages-main" class="tao-scope"></div>').appendTo('body');
        }
        return $$1(undoTmpl(options)).appendTo($undoContainer);
      },
      /**
       * Destroy completely the plugin.
       *
       * Called the jQuery way once registered by the Pluginifier.
       * @example $('selector').deleter('destroy');
       * @public
       * @fires deleter#destroy.deleter
       */
      destroy: function () {
        this.each(function () {
          var $elt = $$1(this);
          var options = $elt.data(dataNs);
          if (options.bindEvent !== false) {
            $elt.off(options.bindEvent);
          }
          $elt.removeData(dataNs);

          /**
           * The plugin have been destroyed.
           * @event deleter#destroy.deleter
           */
          $elt.trigger('destroy.' + ns);
        });
      }
    };

    //Register the toggler to behave as a jQuery plugin.
    Pluginifier.register(ns, deleter, {
      expose: ['delete']
    });

    /**
     * The only exposed function is used to start listening on data-attr
     *
     * @public
     * @example define(['ui/deleter'], function(deleter){ deleter($('rootContainer')); });
     * @param {jQueryElement} $container - the root context to listen in
     */
    function listenDataAttr($container) {
      //handle data-delete
      new DataAttrHandler('delete', {
        container: $container,
        listenerEvent: 'click',
        namespace: dataNs,
        bubbled: true
      }).init(function ($elt, $target) {
        var options = {
          target: $target,
          bindEvent: false,
          undo: true
        };
        var confirm = $elt.data('delete-confirm');
        var undo = $elt.data('delete-undo');
        if (confirm) {
          options.confirm = true;
          options.undo = false;
          if (confirm.length > 0) {
            options.confirmMessage = confirm;
          }
        }
        if (typeof undo !== 'undefined' && undo !== null) {
          if (undo === false) {
            options.undo = false;
          } else {
            options.confirm = false;
            options.undo = true;
            if (undo.length > 0) {
              options.undoMessage = undo;
            }
          }
        }
        $elt.deleter(options);
      }).trigger(function ($elt) {
        $elt.deleter('delete');
      });
    }

    return listenDataAttr;

});
