Event.KEY_SPACE = 32;
Event.KEY_PGUP = 33;
Event.KEY_PGDOWN = 34;
Event.KEY_END = 35;
Event.KEY_HOME = 36;

var ListBoxClass = Class.create();
ListBoxClass.prototype = {
	initialize: function(listboxid, multiple) {
		this.listboxid = listboxid;
		this.multiple = multiple;
		this.options = [];
		this.labels = [];
		this.selected = [];
		this.last = -1;
		this.focused = -1;

		this.onselect = null;
		this.onclickFunction = null;
		this.onselectFunction = null;

		new Insertion.Bottom(this.listboxid, '<table cellpadding="0" cellspacing="0"><tbody></tbody></table>');
		new Insertion.Bottom(this.listboxid, '<input type="hidden" id="' + this.listboxid + '_hidden" name="' + this.listboxid + '_hidden">');

		this.table = $(this.listboxid).getElementsByTagName('table')[0];
		this.table.onclick = this.my_onclick.bindAsEventListener(this);
	},
	my_onclick: function(evnt){
		this.changeValue(evnt);
		this.onclickFunction && eval(this.onclickFunction);
	},
	onSelection: function(sel){
		(this.onselect || Prototype.emptyFunction).apply(sel, arguments);
		this.onselectFunction && eval(this.onselectFunction);
	},
	addOption: function(text, value, selected){
		selected && this.selected.push(this.options.length);
		this.options.push(value);
		this.labels.push(text);
		new Insertion.Bottom(this.table.childNodes[0], "<tr><td UNSELECTABLE='ON'>" + text + "</td></tr>");
	},
	reset: function(){
		while(this.options.length){
			this.options.pop();
		}
		while(this.selected.length){
			this.selected.pop();
		}
		while(this.labels.length){
			this.labels.pop();
		}
		this.last = -1;
		var _rows = this.table.getElementsByTagName('tr');
		for(var i = _rows.length - 1; i >= 0; i--){
			Element.remove(_rows[i]);
		}
		$(this.listboxid + '_hidden').value = '';
	},
	resetLast: function(){
		var _rows = this.table.getElementsByTagName('tr');
		for (var i = _rows.length - 1; i >= 0; i--)
			Element.removeClassName(_rows[i], "last");
	},
	searchInitial: function(keyc){
		var schar = String.fromCharCode(keyc),
			_rows = this.table.getElementsByTagName('tr'),
			_rowslen = _rows.length
		;
		for(var i = 0; i < _rowslen; i++){
			var labl = "" + this.labels[i];
			if(!labl.indexOf(schar)){
				this.scrollTo(i);
				this.moveFocus(i, this.focused, true);
				break;
			}
		}
	},
	setValue: function(current){
		var _rows = this.table.getElementsByTagName('tr'),
			_rowslen = _rows.length
		;
		for(var i = 0; i < _rowslen; i++){
			if(i == current){
				Element.addClassName(_rows[i], "last");
				Element.addClassName(_rows[i], "selected");
				var val = this.options[i];
				$(this.listboxid + '_hidden').value = encodeURIComponent(val);
				this.onSelection(this.listboxid);
			}else{
				Element.removeClassName(_rows[i], "last");
				Element.removeClassName(_rows[i], "selected");
			}
		}
	},
	moveFocus: function(current, old, sc, st){
		var _rows = this.table.getElementsByTagName('tr'),
			_rowslen = _rows.length
		;
		if(current >= 0 && current < _rowslen){
			for(var i = 0; i < _rowslen; i++){
				if(i == old){
					Element.removeClassName(_rows[old], "last");
				}
				if(i == current){
					Element.addClassName(_rows[current], "last");
					this.focused = current;
					if(!sc){
						this.scrollControl(current);
					}
					if(st){
						this.scrollTo(current);
					}
				}
			}
		}
	},
	scrollTo: function(current){
		var _rows = this.table.getElementsByTagName('tr'),
			off = Element.getDimensions(this.listboxid),
			elheight = new Number()
		;
		for (var i = 0; i < current; i++){
			var dim = Element.getDimensions(_rows[i]),
				h = new Number(dim.height)
			;
			elheight += h;
		}
		document.getElementById(this.listboxid).scrollTop = elheight;
	},
	scrollControl: function(current){
		var _rows = this.table.getElementsByTagName('tr'),
			off = Element.getDimensions(this.listboxid),
			elheight = new Number()
		;
		for(var i = 0; i <= current; i++){
			var dim = Element.getDimensions(_rows[i]),
				h = new Number(dim.height);
			;
			elheight += h;
		}
		var topline = new Number(document.getElementById(this.listboxid).scrollTop + h),
			bottomline = new Number(topline + off.height - h)
		;
		if(elheight > bottomline){
			document.getElementById(this.listboxid).scrollTop += h;
		}
		if(elheight < topline){
			document.getElementById(this.listboxid).scrollTop -= h;
		}
	},
	changeValue: function(evnt){
		var elem = Event.element(evnt),
			currtr = elem.parentNode
		;
		while (currtr.tagName != 'TR'){
			currtr = currtr.parentNode;
		}
		var pos = -1,
			_rows = this.table.getElementsByTagName('tr'),
			_rowslen = _rows.length
		;
		for(var i = 0; i < _rowslen; i++){
			if(_rows[i] == currtr){
				pos = i;
				break;
			}
		}
		for(i = 0; i < _rowslen; i++){
			Element.removeClassName(_rows[i], "last");
		}
		if(pos >= 0){
			var formElem = null,
				form = currtr
			;
			while(form != undefined && form != null){
				if(form.tagName == 'FORM'){
					formElem = Form.getElements(form);
					break;
				}
				form = form.parentNode;
			}
			if(formElem != null){
				for(var j = 0; j < formElem.length; j++){
					formElem[j].blur();
				}
			}
		}
		var newselected = [],
			done = false
		;
		newselected.push(pos);
		if(this.multiple){
			if(evnt.ctrlKey){
				if(!this.selected.include(pos)){
					done = true;
				}else{
					newselected = newselected.without(pos);
					this.selected = this.selected.without(pos);
					Element.removeClassName(_rows[pos], "selected");
					done = true;
				}
			}else if (evnt.shiftKey){
				if(pos < this.last){
					for(var i = pos + 1; i < this.last; i++){
						if(!this.selected.include(i)){
							newselected.push(i);
						}
					}
				}else if(pos > this.last){
					for(var i = pos - 1; i > this.last; i--){
						if(!this.selected.include(i))
							newselected.push(i);
					}
				}
				done = true;
			}
		}
		if(!done){
			while(this.selected.length){
				this.selected.pop();
			}
			var selected = $(this.listboxid).select('tr.selected'),
				len = selected.length
			;
			for (var i = 0; i < len; i++)
				selected[i].removeClassName("selected");
		}
		var len = newselected.length;
		for(i = 0; i < len; i++){
			var rowidx = newselected[i];
			if(rowidx >= 0 && rowidx < _rowslen){
				Element.addClassName(_rows[rowidx], "selected");
				try{
					document.getElementById(this.listboxid.substring(0, this.listboxid.indexOf('_')) + '_focusctrl').focus();
				}catch(e){}
				this.focused = rowidx;
			}
		}
		this.selected = this.selected.concat(newselected);

		if(pos != this.last){
			if(this.last >= 0 && this.last < _rowslen){
				Element.removeClassName(_rows[this.last], "last");
			}
			this.last = pos;
			Element.addClassName(currtr, "last");
		}

		var value = [];
		len = this.selected.length;
		for(i = 0; i < len; i++){
			value.push(this.options[this.selected[i]]);
		}
		$(this.listboxid + '_hidden').value = encodeURIComponent(value);
		this.onSelection(this.listboxid);
	},
	setSelected: function(idx){
		var _rows = this.table.getElementsByTagName('tr'),
			_rowslen = _rows.length
		;
		while(this.selected.length){
			this.selected.pop();
		}
		for(var i = 0; i < _rowslen; i++){
			Element.removeClassName(_rows[i], "selected");
			Element.removeClassName(_rows[i], "last");
		}
		this.last = idx;
		this.selected.push(idx);
		Element.addClassName(_rows[0], "selected");
		$(this.listboxid + '_hidden').value = encodeURIComponent(this.options[0]);
	},
	getSelectedIndex: function(){
		return $F(this.listboxid + "_hidden");
	},
	getSelectedValues: function(){
		var selectedValues = [];
		for (var i = 0, l = this.selected.length; i < l; i++){
			selectedValues.push(this.options[this.selected[i]]);
		}
		if(selectedValues.length){
			return selectedValues;
		}else{
			return false;
		}
	},
	getIndexFromValue: function(value){
		for (var a = 0; a < this.options.length; a++){
			try{
				if(this.options[a] == value){
					return a;
				}
			}catch(e){
				return -1;
			}
		}
		return -1;
	},
	handleKeyPress: function(evnt){
		var keycode = evnt.keyCode || evnt.which;
		if ((keycode > 64 && keycode < 91)){
			this.searchInitial(keycode);
		}
		switch (keycode) {
			case Event.KEY_HOME:
			case Event.KEY_END:
				var cur = (keycode == Event.KEY_HOME ? 0 : this.options.length - 1);
				this.moveFocus(cur, this.focused, false, true);
				break;
			case Event.KEY_UP:
			case Event.KEY_DOWN:
			case Event.KEY_PGUP:
			case Event.KEY_PGDOWN:
				var cur = (keycode == Event.KEY_UP ? this.focused - 1 : (keycode == Event.KEY_DOWN ? this.focused + 1 :
				          (keycode == Event.KEY_PGUP ? this.focused - 10 : this.focused + 10)));
				var st = ( (keycode == Event.KEY_PGUP || keycode == Event.KEY_PGDOWN) ? true : false);
				this.moveFocus(cur, this.focused, false, st);
				break;
			case Event.KEY_RETURN:
			case Event.KEY_SPACE:
				this.setValue(this.focused);
				break;
			case Event.KEY_TAB:
				this.resetLast();
				return;
				break;
		}
		if(document.all && document.getElementById){
			evnt.returnValue = false;
		}else{
			evnt.preventDefault();
			return false;
		}
	}
};
