var user_browser = '';

if (typeof(navigator) != 'undefined') {
  var appCodeName;
  var appName;
  if (typeof(navigator.appCodeName) != 'undefined') {
    appCodeName = navigator.appCodeName;
  }
  
  if (typeof(navigator.appName) != 'undefined') {
    appName = navigator.appName;
  }
  
  if (appCodeName == 'Mozilla' && appName =='Netscape') {
    user_browser = 'moz';
  }
}

var AjaxList = Class.create();
AjaxList.prototype = Object.extend(new KeyCallbacks(), {
  _dataSource        : null,  // page to get long bar separated info
  _listWrapper       : null,
  _field             : null,  // field that you type into
  _field_wrap        : null,  // div wrapping field so you can fix FF2 cursor
  _options_wrap      : null,  // div wrapping UL - for scroll detection
  _options           : null,  // ul for responses
  _options_down      : false, // if mouse is down on options or not (to stop blur)
  _option_items      : null,  // lis within ul
  _selections_wrap   : null,  // div wrapping UL - for scroll detection
  _selections        : null,  // ul for selections
  _selections_down   : false, // if mouse is down on options or not (to stop blur)
  _selection_items   : null,  // lis within ul
  _limit             : null,  // limit of allow selections (null = unlimited)
  _sendParams        : null,  // extra parameters to send through ajax
  _lastSearch        : null,  // the last search for throttle
  _myOps             : null,  // options
  _maxHeight         : 150,   // maximum height of responses for overflow
  _defaultTxt        : null,  // default text in field
	_onToggle          : null,  // function runs when you add or remove list item
  _onLimitHit        : null,  // if you hit the limit
  _onSelectedAlready : null,  // if you try to select an option that is selected already
  _open              : false,
  
  searchThrottle     : null,  // throttler from Throttle object
  defaultBlank       : null,  // DefaultBlankField object
  
  buildHTML : function() {
    var html = '<div id="'+this._listWrapper+'_field_wrap" name="'+this._listWrapper+'_field_wrap" class="ajax_list_field_wrap"><input type="text" id="'+this._listWrapper+'_field" name="'+this._listWrapper+'_field" class="ajax_list_field" autocomplete="off" /></div><div style="display: none;" id="'+this._listWrapper+'_optionsWrap" class="ajax_list_options_wrap"><ul id="'+this._listWrapper+'_options" class="ajax_list_options"></ul></div><div id="'+this._listWrapper+'_selections_wrap" class="ajax_list_selections_wrap" ><ul id="'+this._listWrapper+'_selections" class="ajax_list_selections"></ul></div>';
    $(this._listWrapper).update(html);
  },
	
	initialize : function(list_wrapper, data_source, myOptions) {
    if (!$(list_wrapper)) {
      return;
    }
    
    this._myOps       = (myOptions) ? $H(myOptions) : $H({ });
    this._listWrapper = list_wrapper;

    if (this._myOps.get('maxHeight') !== undefined) {
      this._maxHeight = this._myOps.get('maxHeight');
    }
    
    if (this._myOps.get('defaultTxt')) {
      this._defaultTxt = this._myOps.get('defaultTxt');
    } else {
      this._defaultTxt = '';
    }
    
    if (this._myOps.get('limit')) {
      this._limit = this._myOps.get('limit');
    }
    
    if (this._myOps.get('onToggle')) {
      this._onToggle = this._myOps.get('onToggle');
    }
    
    if (this._myOps.get('onLimitHit')) {
      this._onLimitHit = this._myOps.get('onLimitHit');
    }
    
    if (this._myOps.get('onSelectedAlready')) {
      this._onSelectedAlready = this._myOps.get('onSelectedAlready');
    }

    this.buildHTML();
    
    this._dataSource   = data_source;
    this._field        = $(this._listWrapper+'_field');
    this._field_wrap   = $(this._listWrapper+'_field_wrap');
    this._field.value  = this._defaultTxt;
    this._options_wrap = $(this._listWrapper+'_optionsWrap');
    this._options      = $(this._listWrapper+'_options');
    this._selections   = $(this._listWrapper+'_selections');
    this.defaultBlank  = new DefaultBlankField(this._field,this._defaultTxt);

    this.keyHandleClone = this.keyHandle.bindAsEventListener(this);
    this._field.observe('keyup', this.keyHandleClone);
    
    this.fieldBlurClone = this.fieldBlur.bindAsEventListener(this);
    this._field.observe('blur', this.fieldBlurClone);
    
    this.optionsDownClone = this.optionsDown.bindAsEventListener(this);
    this._options.observe('mousedown', this.optionsDownClone);
    
    this.optionsUpClone = this.optionsUp.bindAsEventListener(this);
    this._options.observe('mouseup', this.optionsUpClone);
    
    this.resetKeysClone = this.resetKeys.bindAsEventListener(this);
		this._options.observe('mouseover', this.resetKeysClone);

    this.userCallbacks(this._myOps);
    
    
	},
  
  resetKeys : function() {
    $(this._options).select('.keySelection').each(function(el) {
      $(el).removeClassName('keySelection');
    });
    $(this._selections).select('.keySelection').each(function(el) {
      $(el).removeClassName('keySelection');
    });
  },
  
  fieldBlur : function() {
    if (!this._options_down) {
      this.resetField();
      this.resetKeys();
    }
  },
  
  optionsDown : function() {
    this._options_down = true;
  },
  
  optionsUp : function() {
    this._options_down = false;
  },
  
	stopList : function() {
    this.searchThrottle = null;
    this.defaultBlank   = null;
		Event.stopObserving($(this._field), 'keyup', this.keyHandleClone);
	},
  
  keyEsc : function(e) {
    this.resetField();
    this.focusNextInput(this._field);
    Event.stop(e);
  },
	
	keyAccess : function(e) {
    if (this.searchThrottle == null) {
      this.searchThrottle = new Throttler(this.keyAccessAction, 250, $H({listObj:this}));
    }
    
    this.searchThrottle.setNewValue($F(this._field));
  },
  keyAccessAction : function(params) {
		var self        = params.get('listObj');
		var myOptions   = self._myOps;
    var params      = (self._sendParams) ? self._sendParams : $H({});
    var searchVal   = $F(self._field).replace(/^\s+|\s+$/g,"");
    
    params.set(self._listWrapper+'_values',self.getDelimited());
    params.set(self._field.id, $F(self._field));
    
    self.resetKeys();

		if (searchVal == '') {
      self.refocusField();
      return;
    }
    
    if ($F(self._field) != self._lastSearch && $F(self._field) != self._defaultTxt) {
      var paramStr     = params.toQueryString();
      self._lastSearch = $F(self._field);
      
      new Ajax.Request(self._dataSource, {
        parameters : paramStr,
        onComplete : function (transport) {
          self._options_wrap.show();
          self.updateResponses(transport.responseText);
        }
      });
    }
	},
	
	updateResponses : function(txt) {
    
		var txt = (txt) ? txt : '';
    this._open = (txt == '') ? false : true;
    $(this._options).innerHTML = txt;
    this._option_items = $$('#'+this._options.id+' li');
    
    if (this._option_items.length > 0) {
      var self = this;
      this._option_items.each(function(el) {
        if (!$(el).hasClassName('notOption')) {
          self.makeSelectionClone = self.makeSelection.bindAsEventListener(self);
          $(el).observe('click', self.makeSelectionClone);
        }
      });
    }
    
		this.decideOverflow();
	},
  
  makeForeignSelection : function(selectedValue, selectionDisplay,isGroup) { // not from dropdown 
    if (this._selection_items && this._limit && this._selection_items.length == this._limit) {
      if (this._onLimitHit) this._onLimitHit();
      return;
    }
    var isGroup   = (isGroup) ? isGroup : false;
    
    
    
    if (this._selection_items) {
      var curValue         = '';
      for (var i=0;i<this._selection_items.length;i++) {
        curValue = this._selection_items[i].getAttribute('value');
        if (curValue == selectedValue) {
          if (this._onSelectedAlready) this._onSelectedAlready();
          return;
        }
      }
    }
  
    
    
    this.createSelection(selectedValue,selectionDisplay, isGroup);
  },
  
  correctSelection : function(passedVal) {
    var curEl = Event.element(passedVal);
    var selection;
    if (curEl.tagName != 'LI') {
      selection = Event.findElement(passedVal, 'LI');
    } else {
      selection = curEl;	
    }
    
    return selection;
  },
  
  getSelectionDisplay: function(selection) {
    return selection.select('.ajax_list_option_main')[0].innerHTML;
  },
  
  makeSelection : function(passedVal, fromKey) {
    if (this._selection_items && this._limit && this._selection_items.length == this._limit) {
      if (this._onLimitHit) this._onLimitHit();
      return;
    }
    var fromKey   = (fromKey) ? fromKey : false;
    var selection = passedVal;
    var isGroup   = false;
    
    if (!fromKey) {
      selection = this.correctSelection(passedVal);
    }
    
    var selectedValue    = selection.getAttribute('value');
    if (user_browser == 'moz' && selection.hasClassName('group') && !selectedValue.match('g_')) {
      isGroup = true;
    }
    
    
    if (this._selection_items) {
      var curValue         = '';
      for (var i=0;i<this._selection_items.length;i++) {
        curValue = this._selection_items[i].getAttribute('value');
        if (curValue == selectedValue) {
          if (this._onSelectedAlready) this._onSelectedAlready();
          return;
        }
      }
    }
  
    
    var selectionDisplay = this.getSelectionDisplay(selection);
    
    this.createSelection(selectedValue,selectionDisplay, isGroup);

  },
  
  createSelection : function(selectedValue,selectionDisplay, isGroup) {
    var isGroup = (isGroup) ? isGroup : false;
    var li  = '<li value="'+selectedValue+'"';
    if (isGroup) li += ' class="group"';
    li     += '>';
    li     += '<div class="closeX" alt="Remove" title="Remove" id="remove_'+selectedValue+'"></div><div class="display">'+selectionDisplay+'</div>';
    li     += '</li>';
    this._selections.insert({bottom:li});
    
    this.removeSelectionClone = this.removeSelection.bindAsEventListener(this);
    $('remove_'+selectedValue).observe('click', this.removeSelectionClone);
    
    this._selection_items = $(this._selections).select('li');
    this.refocusField();
    
    if (this._onToggle) this._onToggle();
  },
  
  removeSelection : function(passedVal, fromKey) {
    var fromKey   = (fromKey) ? fromKey : false;
    var selection = passedVal;
    if (!fromKey) {
      var curEl = Event.element(passedVal);
			if (curEl.tagName != 'LI') {
				selection = Event.findElement(passedVal, 'LI');
			} else {
				selection = curEl;	
			}
    }
    $(selection).remove();
    this._selection_items = $(this._selections).select('li');
    this.refocusField();
    
    if (this._onToggle) this._onToggle();
    
  },
	
	decideOverflow : function() {
		var maxHeight = this._maxHeight;
    if (maxHeight == 0) { return } ;
		var newHeight = 0;
		$(this._options).select('li').each(function(el) {
			newHeight += $(el).getHeight();
		});
		if (newHeight > maxHeight) {
			$(this._options).setStyle({
										  overflow:'auto',
										  overflowX:'hidden',
										  overflowY:'auto',
										  height: maxHeight+'px'
										  });
		} else {
			
			$(this._options).setStyle({
										  overflow:'hidden',
										  overflowX:'hidden',
										  overflowY:'hidden',
										  height: newHeight+'px'
										  });	
		}
    this._options.scrollTop = 0
	},
  
  keyEnter : function(e) {
    var options      = this._options.select('.keySelection');
    var keySelection = (options) ? options[0] : false;
    if (keySelection) {
      this.makeSelection(keySelection, true);
    }
  },
  
  keyDelete : function(e) {
    var selections   = this._selections.select('.keySelection');
    var keySelection = (selections) ? selections[0] : false;
    if (keySelection) {
      this.removeSelection(keySelection, true);
    } else {
      if ($F(this._field) == '') {
        this.refocusField();
      }
    }
  },
  
  keyBackspace : function(e) {
    var selections   = this._selections.select('.keySelection');
    var keySelection = (selections) ? selections[0] : false;
    if (keySelection) {
      this.removeSelection(keySelection, true);
    } else {
      if ($F(this._field) == '') {
        this.refocusField();
      } else {
        this.keyAccess(e);
      }
    }
  },
  
  keyUp : function() {
    if (this._options_wrap.visible()) {
      this.decidePreviousKeySelection(this._options,this._option_items,'li');
    } else {
      this.decidePreviousKeySelection(this._selections,this._selection_items,'li');
    }
  },
  
  keyDown : function() {
    if (this._options_wrap.visible()) {
      this.decideNextKeySelection(this._options,this._option_items,'li');
    } else {
      this.decideNextKeySelection(this._selections,this._selection_items,'li');
    }
  },
	
	refocusField : function () {
		this.updateResponses();
		this._options_wrap.hide();
		this._field.value     = '';
		this._lastSearch = '';
    this._field.focus();
    
	},
  
  resetField : function () {
		this.updateResponses();
		this._options_wrap.hide();
		this._field.value = this._defaultTxt;
	},
  
  getNumSelected : function() {
		return (this._selection_items) ? this._selection_items.length : 0;
	},
  getDelimited : function() {
    if (!this._selection_items) return '';
    
    var curVal;
    var delimited = '';
    for (var i=0;i<this._selection_items.length;i++) {
      curVal = this._selection_items[i].getAttribute('value');
      
      if (user_browser == 'moz' && this._selection_items[i].hasClassName('group') && !curVal.match('g_')) {
        curVal = 'g_'+curVal;
      }

      delimited += '|'+curVal;
    }
    delimited = delimited.substr(1);
    
    return delimited;
  },
  clearSelections : function() {
    this._selections.update();
    this._selection_items = null;
  }
});