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
        }, options || {});
        if (this.options.indicator != null) {
        	this.indicator = $(this.options.indicator);
        }
		this.element = $(element);
        this.selected = false;
		this.hider_name = this.element.id + "hider";
		this.choices = $(choices);
		this.url = url;
		this.setPos(this.choices, this.element);
		if (document.all) {
			this.createIFrame();
		}
        this.element._ac = this;
		this.hideMenu();
		this.searching = false;
		// this.currentValue = '';
		if (this.element.setAttribute) {
			this.element.setAttribute("autocomplete", "off");
			this.element.addEvent('keyup', this.onTextChange.bindAsEventListener(this));
			this.element.addEvent('blur', this.onTextBlur.bindAsEventListener(this));
			this.element.addEvent('focus', this.onFocus.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);
		}

        this.errormsg = new Element('div').setProperty('id', this.element.id.replace(/_input$/, "") + '_error')
                                          .addClass('i1')
                                          .injectBefore($E('label', $(this.element).getParent()));

	},
	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 && 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.previousSibling) {
						this.removeClass(currentSel, 'selected');
						this.addClass(currentSel.previousSibling, 'selected');
					} else if (!currentSel) {
						var tempSel = $ES('div', this.choices);
						if (tempSel && tempSel.length > 0) {
							this.addClass(tempSel[tempSel.length-1],'selected');
						}
					}
				} else if (keyCode == 40) {
					// Down
					if (currentSel && currentSel.nextSibling) {
						this.removeClass(currentSel, 'selected');
						this.addClass(currentSel.nextSibling, 'selected');
					} else if (!currentSel)  {
						var tempSel = $E('div', this.choices);
						if (tempSel) {
							this.addClass(tempSel,'selected');
						}
					}
				}
			}
			return false;
		}
		return true;
	},
	onTextChange: function(e) {
		if (window && 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 && keyCode != 13) {
			if (this.fetchDelay) {
				this.fetchDelay = $clear(this.fetchDelay);
			}
			this.fetchDelay = this.fetch.delay(this.options.delay, this);
		}
	},
	onFocus: function(e) {
		if (!this.searching) {
			this.onTextChange(e);
		}
    	this.selected = true;
	},
	fetch: function() {
		if (this.element.value.length < this.options.minChars || !this.selected) {
			// this.currentValue = this.element.value;
			this.choices.setHTML("");
			this.hideMenu();
		} else {
			// if (this.element.value != this.currentValue)
			{
				// this.currentValue = this.element.value;
				this.clearSelected();
				this.choices.show();
				if (this.indicator) {
					this.indicator.show();
				}
				this.searching = true;
				new Ajax(this.url + this.element.value,
							{onFailure:this.onFailure,
							 onComplete:this.onSuccess.bindAsEventListener(this)}).request();
			}
		}
	},
	
	hideMenu: function() {
		this.choices.hide();
		if (document.all) {
			$(this.hider_name).setStyle('height', '0');
			$(this.hider_name).hide();
		}
	},
	showMenu: function() {
	    if (this.selected) {
            this.setPos(this.choices, this.element);
        }
		if (document.all) {
			this.showIFrame();			
		}
	},
	onFailure: function(response) {
		if (this.indicator) {
			this.indicator.hide();
		}
		if (this.hideMenu) {
			this.hideMenu();
		}
		this.searching = false;
		// alert('There was a problem! ' + response);
	},
	onSuccess: function(response) {
		if (this.indicator) {
			this.indicator.hide();
		}
		if (!response || response.trim() == '' || !this.selected) {
			this.hideMenu();
		} else {
			this.choices.setHTML(response);
			$ES('div', this.choices).each(function (el) {
					if (el.addEvent) {
						el.addEvent('mouseover', function() {this.choiceOver(el);}.bind(this));
						el.addEvent('mousedown', function() {this.choiceSelect(el);}.bind(this));
					} else {
						// handle IE7
						el.onmouseover = function() {this.choiceOver(el);}.bind(this);
						el.onmousedown = function() {this.choiceSelect(el);}.bind(this);
					}
				}.bind(this));
			this.showMenu();
		}
		this.searching = false;
	},
	onTextBlur: function() {
		this.hideMenu();
		this.selected = false;
	},
	choiceOver: function(element) {
		this.clearSelected();
		this.addClass(element,'selected');
	},
	choiceSelect: function(element) {
		eval(element.id);
		this.hideMenu();
		this.selected = true;
		if (this.errormsg) {
		    this.errormsg.setStyle('display', 'none').setHTML('');
		}
	},

	clearSelected: function() {
		var currentSel = $E('div.selected', this.choices);
		this.removeClass(currentSel, 'selected');
	},	

	selectNext: function() {
		var currentSel = $E('div.selected', this.choices);
		if (currentSel && currentSel.nextSibling) {
			this.removeClass(currentSel, 'selected');
			this.addClass(currentSel.nextSibling, 'selected');
		} else if (!currentSel)  {
			var tempSel = $E('div', this.choices);
			if (tempSel) {
				this.addClass(tempSel, 'selected');
			}
		}
	},

	removeClass: function(e1,className){
		if (this.hasClass(e1,className)) e1.className = e1.className.replace(className.trim(), '').clean();
		return e1;
	},

	hasClass: function(e1,className){
		if (e1 && e1.className) {
			return !!e1.className.test("\\b"+className+"\\b");
		} else {
			return false;
		}
	},

	addClass: function(e1,className){
		if (!this.hasClass(e1,className)) e1.className = (e1.className+' '+className.trim()).clean();
		return e1;
	},
	
	findPos: function(obj) {
		var curleft = curtop = 0;
		if (obj.offsetParent) {
			curleft = obj.offsetLeft
			curtop = obj.offsetTop
			while (obj = obj.offsetParent) {
				curleft += obj.offsetLeft
				curtop += obj.offsetTop
			}
		}
		return [curleft,curtop];
	},
	setPos: function(element, reference)
	{
		var elementCoors = this.findPos(element);
		var referenceCoors = this.findPos(reference);
		var divLeft = referenceCoors[0] - elementCoors[0];
		var divTop = referenceCoors[1] - elementCoors[1];
		element.style.left = (element.offsetLeft + divLeft) + 'px';
		if (reference) {
			element.style.top = (element.offsetTop + divTop + reference.offsetHeight) + 'px';
			element.style.width = reference.offsetWidth + 'px';
		}
	},
	showIFrame: function(){
		var element = $(this.hider_name);
		var reference = $(this.choices);
		
		element.show();
		var elementCoors = this.findPos(element);
		var referenceCoors = this.findPos(reference);
		var divLeft = referenceCoors[0] - elementCoors[0];
		var divTop = referenceCoors[1] - elementCoors[1];
		element.style.left = (element.offsetLeft + divLeft) + 'px';
		element.style.top = (element.offsetTop + divTop) + 'px';
		element.style.width = reference.offsetWidth + 'px';
		element.style.height = reference.offsetHeight + 'px';
	},
	
	createIFrame: function(){
		if(!$(this.hider_name)) {
			var _1 = new Element("iframe");
			_1.id = this.hider_name;
		}
		else _1 = $(this.hider_name);

		_1.addClass(".hider");
		_1.setStyle('display', 'inline');
		_1.setStyle('display', 'block');
		_1.setStyle('height', '0');
		_1.setStyle('position', 'absolute');
		_1.setStyle('z-index', '5');
		_1.inject(this.choices, 'before');
	}
	 
});
