Ajax.implement({
    responseIsSuccess: function(status){
        try {
            if(this.transport.readyState != 4 || 
                 this.transport.status == "undefined" || 
                (this.transport.status < 200 || this.transport.status >= 300))
                    return false;
            return true;
        } catch(e) {
            return false;
        }
    },
    responseIsFailure: function(){
        return !this.responseIsSuccess();        
    },
    onStateChange: 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: 1,
			delay: 400,
            indicator: null,
            post_load_func: null
        }, options || {});
        if (this.options.indicator != null) {
        	this.indicator = $(this.options.indicator);
        }
        
        if (this.options.post_load_func != null) {
            this.post_load_func = this.options.post_load_func;
        }
                
		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 = $E('div', this.choices);
						if (tempSel) {
							$(tempSel).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();
				}
				new Ajax(this.url + this.element.value, {onFailure:this.onFailure, onComplete:this.onSuccess.bindAsEventListener(this)}).request();
			}
		}
	},
	onFailure: function(response) {
		if (this.indicator) {
					this.indicator.hide();
				}
		alert('There was a problem! ' + response);
	},
	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) {
	    mysel = element.innerHTML;
	    this.element.value = mysel;
        if (this.post_load_func) {
          eval(this.post_load_func);
        }
		this.choices.hide();
	},
	clearSelected: function() {
		$ES('div.selected', this.choices).each(function (el) {
        $(el).removeClass('selected');
		});
	}
});