(function($){

  var window = this;

	MultipleSelect = window.MultipleSelect = function(el, options) {
    MultipleSelect.fn = MultipleSelect.prototype = {
      init: function(el, options) {
        // Handle $(DOMElement)
        if (el.nodeType) {
          _this = el;

          // cache jquery object to avoid multiple constructor call
          $_this = $(_this);

          // copy all public methods and propreties
          $.extend(_this, MultipleSelect.fn);
          _drawMultipleSelect();

          return _this;
        }
        // Handle HTML strings
        if (typeof el === "string") {
          return MultipleSelect(document.getElementById(el), options);
        }
      },
      val : function(val) {
        if(typeof val != 'undefined') {
          _IE6_resetIsNotMultiple();
          var result = $_this.val(val);
          _updateList();
          return result;
        }
        return $_this.val();
      },
      hide : function() {
        $_fake_select.hide();
      },
      show: function() {
        $_fake_select.show();
      },
      bind: function(event, handler) {
        $(this).bind(event, handler);
      },
      unbind: function(event) {
        $(this).unbind(event);
      },

      CLASSNAME:'MultipleSelect'
    }

  var _this; // select element
  var $_this;
  var _fake_select;
  var $_fake_select;
  var _selected = new Array();
  var _listItems = new Array();

  return new MultipleSelect.fn.init(el, options);

   function _drawMultipleSelect() {
      var parent = _this.parentNode;
      _fake_select = document.createElement('ul');
      $_fake_select = $(_fake_select);
      _this.fakeSelect = _fake_select;
      _fake_select.className = "multiple-select";
      parent.insertBefore(_fake_select, _this);
      var option, i;
      for(i=0; i<_this.options.length;i++) {
        option = _this.options[i];
        var li = document.createElement('li');
        li.innerHTML = '<div class="bg-checkbox"></div>' + option.text;
        li.option = option;
        li.className = option.className;
        _selected[i] = option.selected;
        if (_selected[i]) {
          $(li).addClass('selected');
        }
        $(li).bind('click',_toggleSelect);
        $(li).addClass('option');
        _fake_select.appendChild(li);
        _listItems[i] = li;
      }


      $_this.show(); // show/hide $_this element because of IE6
      $_this.bind('change', _updateList);
      $_this.hide();

   }

   function _toggleSelect(ev) {
     var li = ev.currentTarget;
     var $li = $(li);
     if(li.option.selected) {
       $li.removeClass('selected');
       li.option.selected = false;
     }
     else {
       $li.addClass('selected');
       _IE6_resetIsNotMultiple();
       li.option.selected = true;
     }
     _updateList();
     $_this.trigger('selected', _this);
  }

  function _updateList() {
    var option, i;
    for(i=0; i<_this.options.length;i++) {
      option = _this.options[i];
      var $li = $(_listItems[i]);
      _selected[i] = option.selected;
      if(_selected[i]) {
        $li.addClass('selected');
      }
      else {
        $li.removeClass('selected');
      }
    }
  }

  function _copyStylesheet() {
    // TODO: deos not work in IE
    var cssToCopy = ['width'];

    for(var i=0;i<cssToCopy.length;i++) {
      var key = cssToCopy[i];
      if ($_this.css(key)) {
        $_fake_select.css(key, $_this.css(key));
      }
    }
  }

  /**
   * Resets select's options in IE6 by deselecting each of them.
   * Note: This is an IE6 hack. Element _this doesn't want to transform from
   * multiple to singular select so we have to reset it each time it's value
   * changes.
   */
  function _IE6_resetIsNotMultiple() {

    if (!browser.isIE6down || _this.multiple !== false) {
      return;
    }

    for(var i=0; i<_this.options.length; i++) {
      _this.options[i].selected = false;
    }
  }

};
})(jQuery);




ExpandableMultipleSelect = function(el, options) {
  // private
  var _keys = {
    escape : 27,
    left : 37,
    up : 38,
    right : 39,
    down : 40,
    enter: 13
  }

  var _this;
  var $_this;
  var _expanded = true;
  var _fake_select;
  var $_fake_select;
  if (!options) {
    options = {};
  }
  var _parent_obj = {};// neded to inherit prototype
  var _cssToCopy = ['zIndex'];
  var _multiple = false;

  if (options.multiple === true) {
    _multiple = true;
  }

  var _allow_type_change = true;
  if (options.toggleType === false) {
    _allow_type_change = false;
  }

  var _mouseIsOver = false;

  // hadles onkeyup and onblur
  var $_keybord_listener = $('<div tabindex="-1" style="width:0px;height:0px;-moz-outline-style: none;outline:none; display:inline; position;absolute;"></div>');
  var $_option_list;// <ul> list
  var $_toggle_type;// <li> item
  var $_close;// <li> item
  var $_default_value;// <li> item

  var _lang = 'ro';
  if (options.lang) {
    _lang = options.lang;
  }
  var _words =  {
    ro: {
      'default': 'Toate',
      'single': 'Alege una',
      'multiple': 'Alege citeva',
      'change': 'Modifica',
      'close': 'Inchide'
    },
    en: {
      'default': 'All',
      'single': 'Select one',
      'multiple': 'Select some',
      'change': 'Change',
      'close': 'Close'
    },
    ru: {
      'default': 'Все',
      'single': 'Выбрать одно',
      'multiple': 'Выбрать несколько',
      'change': 'Изменить',
      'close': 'Закрыть'
    }
  }

  // public
  ExpandableMultipleSelect.prototype = {
    val: function(value) {
      // change type to multiple to avoid loosing any values
      if (value && typeof value[0] == "string"
        && _multiple === false && _allow_type_change === true) {
        _setType('multiple');
      }
      _parent_obj.val(value);
      _updateLabel();
    },

    collapse: function() {
      _collapse();
  },

    CLASSNAME:'ExpandableMultipleSelect'
  }

  return _create(el, options);

  function _create(el) {
    _this = new MultipleSelect(el);
    $_this = $(_this);
    _parent_obj.val = _this.val;
    $.extend(_this, ExpandableMultipleSelect.prototype);
    _draw();
    return _this;
  }

  function _draw() {
    var parent = _this.parentNode;

    $_fake_select = $('<div class="fake-select" style="-moz-outline-style: none;"></div>');
    _fake_select = $_fake_select[0];
    _fake_select.innerHTML = '<div class="header-left"></div>'
        +'<div class="header"><div class="label"></div><div class="bg-right"></div><div class="clear"></div></div>'
        +'<div class="header-right"></div><div class="clear"></div>';
    parent.insertBefore(_fake_select,_this.fakeSelect);
    _fake_select.appendChild(_this);
    _fake_select.appendChild(_this.fakeSelect);
    $_option_list = $_fake_select.find('.multiple-select');
    _this.collapse();
    _copyStylesheet();
    $_fake_select.find('.header')
    $_fake_select.find('.header').bind('click', _toggleView);
    // add toggle type button
    $_toggle_type = $('<li class="toggle-type">+toggle type</li>');
    $_close = $('<li class="close">' + _t('close') + '</li>');
    $_default_value = $('<li class="default option"><div class="bg-checkbox"></div>' + _t('default') + '</li>');

    if (_multiple) { // initialize as single select
      _setType('multiple');
    }
    else { // initialize as single select
      _setType('single');
    }
    $_option_list.prepend($_default_value);
    $_option_list.append($_close);
    if (_allow_type_change !== false) {
      $_option_list.prepend($_toggle_type);
    }

    $_fake_select.addClass('collapsed');
    _registerEvents();
    $_fake_select.append($_keybord_listener);
  }

  function _toggleView() {
    if (_expanded)
      _this.collapse();
    else
      _expand();
  }

  function _expand() {
    _expanded = true;
    $('.fake-select.expanded select').each(function(key, el) {el.collapse();})
    $_fake_select.removeClass('collapsed').addClass('expanded');
    $_keybord_listener.focus();// focus needed for keyup event
    $_option_list.show();
  }

  function _collapse() {

    if (_expanded === false) {
      return;
    }
    _expanded = false;
    _updateLabel();
    $(_fake_select).removeClass('expanded').addClass('collapsed');
    $_keybord_listener.blur();
    $_option_list.hide();
  }

  function _updateLabel() {
    var $label = $(_fake_select).find('.label');
    var vals = $_this.val();
    if (typeof vals == 'string') {
      vals = [vals];
    }
    var val = null;

    for (var i in vals) {
      var value = vals[i];
      for(var j=0; j<_this.options.length; j++) {
        var option = _this.options[j];
        if (option.value === value) {
          if (!val) val = new Array();
          val.push(option.text);
        }
      }
    }

    if (val && typeof val == 'object') {
      var str_val = "";
      var str_val_new = "";
      for(var i = 0; i < val.length; i++) {
        str_val_new = str_val + (str_val == "" ? "" : ", ") + val[i];
        if (str_val_new.length < 20) {
          str_val = str_val_new;
        }
        else {
          if (str_val.length < 17) {
            str_val += ', ...';
          }
          break;
        }
      }
      $label.html(str_val);
    }
    else {
      $label.html(_t('default'));
    }

  }

  function _copyStylesheet() {
    // TODO: deos not work in IE

    for(var i=0;i<_cssToCopy.length;i++) {
      var key = _cssToCopy[i];
      if ($_this.css(key)) {
        $_fake_select.css(key, $_this.css(key));
      }
    }
  }

  function _registerEvents() {
    $_toggle_type.bind('click', _toggleType);
    $_close.bind('click', _collapse);
    $_default_value.bind('click', _defaultClicked);
    $_this.bind('selected', _onSelect);
    $_keybord_listener.bind('keyup', _onKeyUp)
    $_keybord_listener.bind('blur', _onBlur);
    $_option_list.bind('mouseenter', _onMouseEnter);
    $_option_list.bind('mouseleave', _onMouseLeave);
  }

  // preserve focus is user presses a list item
  function _onBlur() {
    setTimeout(
      function() {
        if (!_mouseIsOver) {
          _this.collapse();
        }
        else {
          $_keybord_listener.focus();
        }
      },
      150
    );
  }

  function _onMouseEnter() {
    _mouseIsOver = true;
    $_keybord_listener.focus();// preserve focus
  }

  function _onMouseLeave() {
    _mouseIsOver = false;
  }

  function _onSelect() {
    if (!_multiple) {
      _this.collapse();
    }
  }

  function _toggleType() {
    if (_multiple) {
      _setType('single');
    }
    else {
      _setType('multiple');
    }
  }

  function _onKeyUp(evt) {
    if (evt.keyCode == _keys.escape) {
      _this.collapse();
    }
  }

  function _setType(type) {
    if(type == 'multiple') {
      $_option_list.find('li').each(function(key, el) {
        var $el = $(el);
        if (!$el.hasClass('toggle-type')) {
          $el.removeClass('single');
          $el.addClass('multiple');
        }
      });
      $_toggle_type.html('- <a href="#" onclick="return false;">' + _t('single') + '</a>');
      $_close.show();
      $_this.attr('multiple', "multiple");
      _multiple = true;
    }
    else {
      $_option_list.find('li').each(function(key, el) {
        var $el = $(el);
        if (!$el.hasClass('toggle-type')) {
          $el.removeClass('multiple');
          $el.addClass('single');
        }
      });
      $_toggle_type.html('+ <a href="#" onclick="return false;">' + _t('multiple') + '</a>');
      $_close.hide();

      $_this.attr('multiple', null);

      var old_val = $_this.val();
      if (old_val != null && typeof(old_val) == 'object' && typeof(old_val[0]) == 'string') {
        $_this.val(old_val[0]);
      }
      _multiple = false;
    }

    $_this.trigger('change');
    _updateLabel();
  }

  function _defaultClicked() {
    _this.val(null);
    $_this.trigger('selected');
    if (_multiple) {
      _this.collapse();
    }
  }

  function _t(word) {
    return _words[_lang][word];
  }

};
