// Chosen Order v1.2.1
// This plugin allows you to handle the order of the selection for Chosen multiple <select> dropdowns
// Full source at https://github.com/tristanjahier/chosen-order
// Copyright (c) 2013 - Tristan Jahier, http://tristan-jahier.fr

// DISCLAIMER
// Chosen Order is not associated with Harvest in any way.
// Chosen is an original software by Patrick Filler for Harvest, http://getharvest.com
// Full source at https://github.com/harvesthq/chosen
// Copyright (c) 2011 Harvest http://getharvest.com

// This file is generated by `grunt build`, do not edit it by hand.
(function() {
  var AbstractChosenOrder, _ref,
    __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  AbstractChosenOrder = (function() {
    var ERRORS;

    function AbstractChosenOrder() {}

    ERRORS = {
      invalid_select_element: "ChosenOrder::{{function}}: first argument must be a valid HTML Multiple Select element that has been Chosenified!",
      invalid_selection_array: "ChosenOrder::{{function}}: second argument must be an Array!",
      unreachable_chosen_container: "ChosenOrder::{{function}}: could not find the Chosen UI container! To solve the problem, try adding an \"id\" attribute to your <select> element.",
      ordering_unselected_option: "ChosenOrder::{{function}}: ignoring option '{{option}}' which is not selected. Set optional parameter \"force\" to 'true' to get the ordered selection forced first."
    };

    AbstractChosenOrder.insertAt = function(node, index, parentNode) {
      return parentNode.insertBefore(node, parentNode.children[index].nextSibling);
    };

    AbstractChosenOrder.getFlattenedOptionsAndGroups = function(select) {
      var flattened_options, opt, options, sub_opt, sub_options, _i, _j, _len, _len1;
      options = Array.prototype.filter.call(select.childNodes, function(o) {
        var _ref;
        return (_ref = o.nodeName.toUpperCase()) === 'OPTION' || _ref === 'OPTGROUP';
      });
      flattened_options = [];
      for (_i = 0, _len = options.length; _i < _len; _i++) {
        opt = options[_i];
        flattened_options.push(opt);
        if (opt.nodeName.toUpperCase() === 'OPTGROUP') {
          sub_options = Array.prototype.filter.call(opt.childNodes, function(o) {
            return o.nodeName.toUpperCase() === 'OPTION';
          });
          for (_j = 0, _len1 = sub_options.length; _j < _len1; _j++) {
            sub_opt = sub_options[_j];
            flattened_options.push(sub_opt);
          }
        }
      }
      return flattened_options;
    };

    AbstractChosenOrder.isValidMultipleSelectElement = function(element) {
      return element !== null && typeof element !== "undefined" && element.nodeName === "SELECT" && element.multiple;
    };

    AbstractChosenOrder.getChosenUIContainer = function(select) {
      if (select.id !== "") {
        return document.getElementById(select.id.replace(/-/g, "_") + "_chosen");
      } else {
        return this.searchChosenUIContainer(select);
      }
    };

    AbstractChosenOrder.isChosenified = function(select) {
      return this.getChosenUIContainer(select) != null;
    };

    AbstractChosenOrder.forceSelection = function(select, selection) {
      var i, opt, options, _ref;
      options = this.getFlattenedOptionsAndGroups(select);
      i = 0;
      while (i < options.length) {
        opt = options[i];
        if (_ref = opt.getAttribute("value"), __indexOf.call(selection, _ref) >= 0) {
          opt.selected = true;
          opt.setAttribute("selected", "");
        } else {
          opt.selected = false;
          opt.removeAttribute("selected");
        }
        i++;
      }
      return this.triggerEvent(select, "chosen:updated");
    };

    AbstractChosenOrder.getSelectionOrder = function(select) {
      var chosen_options, chosen_ui, close_btn, opt, option, options, order, rel, _i, _len;
      if (this.getDOMElement != null) {
        select = this.getDOMElement(select);
      }
      order = [];
      if (!this.isValidMultipleSelectElement(select)) {
        console.error(ERRORS.invalid_select_element.replace('{{function}}', 'getSelectionOrder'));
        return order;
      }
      chosen_ui = this.getChosenUIContainer(select);
      if (chosen_ui == null) {
        console.error(ERRORS.unreachable_chosen_container.replace('{{function}}', 'getSelectionOrder'));
        return order;
      }
      chosen_options = chosen_ui.querySelectorAll('.search-choice');
      options = this.getFlattenedOptionsAndGroups(select);
      for (_i = 0, _len = chosen_options.length; _i < _len; _i++) {
        opt = chosen_options[_i];
        close_btn = opt.querySelectorAll('.search-choice-close')[0];
        if (close_btn != null) {
          rel = close_btn.getAttribute(this.relAttributeName);
        }
        option = options[rel];
        order.push(option.value);
      }
      return order;
    };

    AbstractChosenOrder.setSelectionOrder = function(select, order, force) {
      var chosen_choices, chosen_options, chosen_ui, i, j, opt, opt_val, option, options, rel, relAttributeName, _i, _j, _len, _len1, _results;
      if (this.getDOMElement != null) {
        select = this.getDOMElement(select);
      }
      if (!this.isValidMultipleSelectElement(select)) {
        console.error(ERRORS.invalid_select_element.replace('{{function}}', 'setSelectionOrder'));
        return;
      }
      chosen_ui = this.getChosenUIContainer(select);
      if (chosen_ui == null) {
        console.error(ERRORS.unreachable_chosen_container.replace('{{function}}', 'setSelectionOrder'));
        return;
      }
      if (order instanceof Array) {
        order = order.map(Function.prototype.call, String.prototype.trim);
        options = this.getFlattenedOptionsAndGroups(select);
        if ((force != null) && force === true) {
          this.forceSelection(select, order);
        }
        _results = [];
        for (i = _i = 0, _len = order.length; _i < _len; i = ++_i) {
          opt_val = order[i];
          rel = null;
          for (j = _j = 0, _len1 = options.length; _j < _len1; j = ++_j) {
            opt = options[j];
            if (opt.value === opt_val) {
              rel = j;
            }
          }
          chosen_options = chosen_ui.querySelectorAll('.search-choice');
          relAttributeName = this.relAttributeName;
          option = Array.prototype.filter.call(chosen_options, function(o) {
            return o.querySelector("a.search-choice-close[" + relAttributeName + "=\"" + rel + "\"]") != null;
          })[0];
          if (option == null) {
            console.warn(ERRORS.ordering_unselected_option.replace('{{function}}', 'setSelectionOrder').replace('{{option}}', opt_val));
            continue;
          }
          chosen_choices = chosen_ui.querySelector("ul.chosen-choices");
          _results.push(this.insertAt(option, i, chosen_ui.querySelector('ul.chosen-choices')));
        }
        return _results;
      } else {
        return console.error(ERRORS.invalid_selection_array.replace('{{function}}', 'setSelectionOrder'));
      }
    };

    return AbstractChosenOrder;

  })();

  Element.addMethods({
    getSelectionOrder: function(element) {
      return ChosenOrder.getSelectionOrder(element);
    },
    setSelectionOrder: function(element, order, force) {
      return ChosenOrder.setSelectionOrder(element, order, force);
    }
  });

  this.ChosenOrder = (function(_super) {
    __extends(ChosenOrder, _super);

    function ChosenOrder() {
      _ref = ChosenOrder.__super__.constructor.apply(this, arguments);
      return _ref;
    }

    ChosenOrder.relAttributeName = "rel";

    ChosenOrder.searchChosenUIContainer = function(element) {
      return element.next(".chosen-container.chosen-container-multi");
    };

    ChosenOrder.triggerEvent = function(target, event_name) {
      return Event.fire($(target), event_name);
    };

    return ChosenOrder;

  })(AbstractChosenOrder);

}).call(this);
