Ajax.implement({
	responseIsSuccess: function(status){
		try {
			if(this.transport.readyState != 4 || this.transport.status == "undefined" || (this.transport.status <= 200 || this.transport.status >= 300)) {
				return true;
			}
		} catch(e) {
			return false;
		}
	},
	responseIsFailure: function(){
		return !this.responseIsSuccess();
	},
	onStateChangeAC: function(){
		if (this.transport.readyState == 4 && this.responseIsSuccess()){
			if (this.options.update) $(this.options.update).setHTML(this.transport.responseText);
			this.options.onComplete.pass([this.transport.responseText, this.transport.responseXML], this).delay(20);
			if (this.options.evalScripts) this.evalScripts.delay(30, this);
			this.transport.onreadystatechange = Class.empty;
			this.callChain();
		} else if(this.transport.readyState == 4 && this.responseIsFailure()) {
			if($type(this.options.onFailure)=='function') this.options.onFailure.pass(this.transport, this).delay(20); 
		}
	}
});

Element.extend({
	hide: function() {
		this.style.display = 'none';
		return this;
	},
	show: function() {
		this.style.display = '';
		return this;
	}
});

var AjaxAutoCompleter = new Class({ 
	initialize: function(element, choices, url, options) { 
		this.options = Object.extend({ 
			minChars: 3, 
			delay: 400, 
			indicator: null,
			method: 'get'
		}, options || {}); 
		if (this.options.indicator != null) {
			this.indicator = $(this.options.indicator); 
		}

		this.element = $(element);
		this.choices = $(choices);
		this.url = url;
		this.choices.hide();
		this.currentValue = '';
		this.element.setAttribute("autocomplete", "off");
		this.element.addEvent('keyup', this.onTextChange.bindAsEventListener(this));
		this.element.addEvent('blur', this.onTextBlur.bindAsEventListener(this));
		// need keydown for IE as it will not fire for arrow keys
		this.element.onkeydown = this.onKeyDown.bind(this);
		// will fire for enter key on all browsers
		this.element.onkeypress = this.onKeyPress.bind(this);
	}, 
	
	onKeyPress: function(e) { 
		if (window.event) { 
			var keyCode = window.event.keyCode;
		} else { 
			var keyCode = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode; 
		} 
		if (keyCode == 13) { 
			if (this.choices.style.display == '') { 
				var currentSel = $E('div.selected', this.choices); 
				if (currentSel) {
					this.choiceSelect(currentSel); 
				} 
			} 
			return false; 
		} 
		return true; 
	}, 
	
	onKeyDown: function(e) { 
		if (window.event) { 
			var keyCode = window.event.keyCode; 
		} else { 
			var keyCode = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode; 
		} 
		if (keyCode == 40 || keyCode == 38) { 
			if (this.choices.style.display == '') { 
				// 40 = Down, 38 = Up 
				var currentSel = $E('div.selected', this.choices); 
				if (keyCode == 38) { 
					// Up 
					if (currentSel && currentSel.getPrevious()) { 
						currentSel.removeClass('selected'); 
						currentSel.getPrevious().addClass('selected'); 
					} else if (!currentSel) { 
						var tempSel = $ES('div', this.choices); 
						if (tempSel && tempSel.length > 0) { 
							tempSel[tempSel.length-1].addClass('selected'); 
						} 
					} 
				} else if (keyCode == 40) { 
					// Down 
					if (currentSel && currentSel.getNext()) { 
						currentSel.removeClass('selected'); 
						currentSel.getNext().addClass('selected'); 
					} else if (!currentSel) { 
						var tempSel = $ES('div', this.choices); 
						if (tempSel && tempSel.length > 0) { 
							tempSel[0].addClass('selected'); 
						} 
					}
				} 
			} 
			return false; 
		} 
		return true; 
	}, 
	
	onTextChange: function() { 
		if (this.fetchDelay) { 
			this.fetchDelay = $clear(this.fetchDelay); 
		} 
		this.fetchDelay = this.fetch.delay(this.options.delay, this); 
	}, 
	
	fetch: function() { 
		if (this.element.value.length <= this.options.minChars) { 
			this.choices.hide(); 
		} else { 
			if (this.element.value != this.currentValue) {
				this.currentValue = this.element.value; 
				this.clearSelected(); 
				this.choices.show(); 
				if (this.indicator) { 
					this.indicator.show(); 
				} 
				
				thistag = this.element.value.trim();
				if(this.options.method == 'get'){
					new Ajax(this.url + thistag, { method: 'get', onFailure:this.onFailure, onComplete:this.onSuccess.bindAsEventListener(this)}).request(); 
				}else if(this.options.method == 'post'){ /* NOT TESTED!!!!!! */
					new Ajax(this.url, { method: 'post', data:'tag='+thistag, onFailure:this.onFailure, onComplete:this.onSuccess.bindAsEventListener(this)}).request(); 
				}
			} 
		} 
	}, 
		
	onFailure: function(response) { 
		if (this.indicator) { 
			this.indicator.hide(); 
		} 
		alert('There was a problem! \n' + response.status + ' -- ' + response.statusText);
	}, 
	
	onSuccess: function(response) { 
		if (this.indicator) { 
			this.indicator.hide(); 
		} 
		if (response.trim() == '') { 
			this.choices.hide(); 
		} else { 
			this.choices.setHTML(response); 
			$ES('div', this.choices).each(function (el) { 
				el.addEvent('mouseover', function() {this.choiceOver(el);}.bind(this)); 
				el.addEvent('mousedown', function() {this.choiceSelect(el);}.bind(this)); 
			}.bind(this)); 
		} 
	}, 
	
	onTextBlur: function() { 
		this.choices.hide(); 
	}, 
	
	choiceOver: function(element) { 
		this.clearSelected(); 
		element.addClass('selected'); 
	}, 
	
	choiceSelect: function(element) {
		tags = this.element.value.split(',');
		tags.pop();
		tags.extend([element.id]);
		this.element.value = tags.toString();
		
		this.currentValue = this.element.value; 
		this.choices.hide(); 
	}, 
	
	clearSelected: function() { 
		$ES('div.selected', this.choices).each(function (el) { 
			el.removeClass('selected'); 
		}); 
	}
});