define([

'jquery'

], function ($) {

function Tags (decorated, $element, options) {
  var tags = options.get('tags');

  var createTag = options.get('createTag');

  if (createTag !== undefined) {
    this.createTag = createTag;
  }

  var insertTag = options.get('insertTag');

  if (insertTag !== undefined) {
      this.insertTag = insertTag;
  }

  decorated.call(this, $element, options);

  if ($.isArray(tags)) {
    for (var t = 0; t < tags.length; t++) {
      var tag = tags[t];
      var item = this._normalizeItem(tag);

      var $option = this.option(item);

      this.$element.append($option);
    }
  }
}

Tags.prototype.query = function (decorated, params, callback) {
  var self = this;

  this._removeOldTags();

  if (params.term == null || params.page != null) {
    decorated.call(this, params, callback);
    return;
  }

  function wrapper (obj, child) {
    var data = obj.results;

    for (var i = 0; i < data.length; i++) {
      var option = data[i];

      var checkChildren = (
        option.children != null &&
        !wrapper({
          results: option.children
        }, true)
      );

      var optionText = (option.text || '').toUpperCase();
      var paramsTerm = (params.term || '').toUpperCase();

      var checkText = optionText === paramsTerm;

      if (checkText || checkChildren) {
        if (child) {
          return false;
        }

        obj.data = data;
        callback(obj);

        return;
      }
    }

    if (child) {
      return true;
    }

    var tag = self.createTag(params);

    if (tag != null) {
      var $option = self.option(tag);
      $option.attr('data-select2-tag', true);

      self.addOptions([$option]);

      self.insertTag(data, tag);
    }

    obj.results = data;

    callback(obj);
  }

  decorated.call(this, params, wrapper);
};

Tags.prototype.createTag = function (decorated, params) {
  var term = $.trim(params.term);

  if (term === '') {
    return null;
  }

  return {
    id: term,
    text: term
  };
};

Tags.prototype.insertTag = function (_, data, tag) {
  data.unshift(tag);
};

Tags.prototype._removeOldTags = function (_) {
  var tag = this._lastTag;

  var $options = this.$element.find('option[data-select2-tag]');

  $options.each(function () {
    if (this.selected) {
      return;
    }

    $(this).remove();
  });
};

return Tags;

});