var CAutoComplete	= {
	CSS_CLASS_NAME: 'extend_cautocomplete',

	/* constructor (of sorts) */
	initialize: function() {
		// new class properties
		this.__size		= 5;
		this.__select	= null;
		this.__timer	= null;
		this.__title	= '';
		this.__value	= this.value;

		// Remove default autocomplete
		this.setAttribute('autocomplete', 'off');

		// Get attributes
		if(!this.title.blank()) {
			attr	= this.title.toQueryParams();

			for(p in attr) {
				if((t = typeof this['__'+p]) != 'undefined') {
					switch(t) {
						case 'string':
							this['__'+p]	= attr[p];
							break;

						case 'number':
							this['__'+p]	= parseInt(attr[p]);
							break;
					}
				}
			}
		}

		this.title	= this.__title;

		// Attach callbacks
		this.observe('keydown', this.keyDown.bindAsEventListener(this));
		this.observe('click', this.click.bindAsEventListener(this));
		this.observe('blur', this.blur.bindAsEventListener(this));
		document.observe('click', this.documentClick.bindAsEventListener(this));

		// Create drop-down
		sel			= new Element('select', {className: this.CLASS_NAME});
		sel.size	= this.__size;
		sel.setStyle({
			position:	'absolute',
			display:	'none'
		});
		this.__select	= sel;

		// Add drop-down to body
		document.body.appendChild(this.__select);
	},

	showSelect: function() {
		// Get position & dimensions
		pos	= this.cumulativeOffset();	// left: num, top: num;
		dim	= this.getDimensions();		// height: num; width: num;

		// Set position
		this.__select.setStyle({
			top:	(parseInt(pos.top) + parseInt(dim.height)) + 'px',
			left:	pos.left + 'px',
			width:	dim.width + 'px'
		});

		this.__select.show();
	},

	hideSelect: function() {
		this.__select.hide();
		this.__select.selectedIndex	= -1;
	},

	getList: function() {
		if((v = this.value.strip()).length < 3) {
			this.hideSelect();
			return;
		}

		var	me	= this;

		new Ajax.Request('/ajax/autocomplete.php', {
			parameters:	'q=' + v,
			onSuccess:	function(t) {
				try {
					js	= t.responseText.evalJSON(true);
				} catch(e) {
					throw('CAutoComplete::getList() received invalid JSON.\n' + t.responseText);
				}

				if(js.m == 'ac') {
					me.generate(js.r);
				} else if(js.m == -1) {
					throw(js.r);
				} else {
					throw(t.responseText);
				}
			}
		});
	},

	generate: function(l) {

		while(this.__select.lastChild)
			this.__select.removeChild(this.__select.lastChild);

		for(i=0,c=l.length;i<c;i++) {
			o	= new Element('option', {className: this.CLASS_NAME}).update(l[i][0]);
			o.observe('mouseover', this.optionMouseOver.bindAsEventListener(this));
			o.observe('click', this.optionClick.bindAsEventListener(this));
			this.__select.appendChild(o);
		}

		if(c < this.__size) this.__select.size	= (c < 2) ? 2 : c;
		else				this.__select.size	= this.__size;

		this.showSelect();
	},

	keyDown: function(ev) {
		a	= ev.keyCode;

		switch(a) {
			case 38:	// Up arrow
				if(this.__select.selectedIndex == -1) {
					n	= this.__select.lastChild;
				} else {
					n	= this.__select.options[this.__select.selectedIndex].previous();
					if(!n)	n	= this.__select.lastChild;
				}
				n.selected	= true;
				this.updateValue(n.innerHTML);
				break;

			case 40:	// Down arrow
				if(this.__select.selectedIndex == -1) {
					n	= this.__select.firstChild;
				} else {
					n	= this.__select.options[this.__select.selectedIndex].next();
					if(!n)	n	= this.__select.firstChild;
				}
				n.selected	= true;
				this.updateValue(n.innerHTML);
				break;

			case 13:
			case 9:
				this.__select.up('form').submit();
				break;

			case 27:
				this.hideSelect();
				break;

			default:
				if(this.__timer != null)
					clearTimeout(this.__timer);

				this.__timer	= setTimeout(this.getList.bindAsEventListener(this), 500);
		}
	},

	click: function(ev) {
		if(this.value == this.__value && !this.value.blank()) {
			this.value	= '';
		}
	},

	blur: function(ev) {
		if(this.value.blank())
			this.value	= this.__value;
	},

	updateValue: function(v) {
		this.value	= v;
		this.activate();
	},

	optionMouseOver: function(ev) {
		ev.element().selected	= true;
		this.updateValue(ev.element().innerHTML);
	},

	optionClick: function(ev) {
		this.updateValue(ev.element().innerHTML);
	},

	documentClick: function(ev) {
		if(ev.element() != this.__select)
			this.hideSelect(); 
	}
}

Event.observe(window, 'load', function() {
	$$('input[type="text"].' + CAutoComplete.CSS_CLASS_NAME).each(function(i) {
		Object.extend(i, CAutoComplete);
		i.initialize();
	});
});
