/* AutoComplete Object */

function autoComplete( options ) {

	this.hoverIndex = -1;
	this.resultIndexes = new Array();
	this.data = new Array();
	this.minSimbols = 1;
	this.container = '';
	this.multivalue = false;
	this.itemsPerColumn = 6;
	this.key = 0;
	this.maxFieldSize = 150;
	this.capitalize = false;

	this.element = document.getElementById( options.id );
	if (typeof this.element == 'undefined') return; //can't find input element;
	if (this.element.tagName.toLowerCase() != 'input' && this.element.tagName.toLowerCase() != 'textarea') return; //<input> elements allowed

	this.container = document.getElementById( options.container );
	if (typeof this.container == 'undefined') return; //can't find container

	this.data = options.data;
	this.URLData = options.url;
	if (typeof this.data == 'undefined' && typeof this.URLData == 'undefined') return; //unknown complete words array or URL
	
	if (typeof options.symbols != 'undefined') {
		this.minSimbols = options.symbols;
	}
	if (typeof options.multivalue != 'undefined') {
		this.multivalue = options.multivalue;
	}
	
	if (typeof this.element.defaultSize == 'undefined' && this.element.tagName.toLowerCase() == 'input') {
		this.element.defaultSize = this.element.size;
	}
	
	this.element.attCompleter = this;

	//disable Browser's AutoComplete
	this.element.autocomplete = "off"; //IE
	this.element.setAttribute("autocomplete", "off"); //FF
	
	this.show = function() {
	
		var pos = this.getSelectionPositions( this.element );
		var textLength = this.element.innerText == null ? this.element.textLength : this.element.innerText.length;
		var moveCarret = false;
		if (pos.start != textLength) {
			moveCarret = pos.start;
		}
		if (typeof this.URLData == 'string') {
			var url = this.URLData;
			var self = this;
			this.URLData = null;
			$.get( url, {}, function(data, text) { self.getData( data, text );} );
		}

		if (typeof this.data == 'undefined') return false;
		
		if (this.key == 40) { //down
			this.hover( this.hoverIndex + 1 );
		} else if (this.key == 38) { //up
			this.hover( this.hoverIndex - 1 );
		} else if (this.key == 39) { //right
			this.hover( this.hoverIndex + this.itemsPerColumn );
		} else if (this.key == 37) { //left
			this.hover( this.hoverIndex - this.itemsPerColumn );
		} else if (this.key == 13) { //enter
			return this.exec();
		} else if (this.key == 27) { //escape
			return this.hide();
		} else if (this.key == 32) { //space
			return true;
		} else {

			inputValue = this.element.value;
			if (this.multivalue) {
				var inputValues = inputValue.split(this.trim( this.multivalue) );
				for (var i in inputValues) { inputValues[i] = this.trim( inputValues[i] ); }
				inputValue = inputValues[ inputValues.length - 1 ];
			}
			//trim
			inputValue = this.trim( inputValue );

			if (inputValue.length >= this.minSimbols) {

				this.hoverIndex = -1;
				this.resultIndexes = new Array();
				var autoCompleteHTML = '<div class="auto-complete" style="position:absolute;"><table><tr><td>';
				var j = 0;

				for (var i = 0; i < this.data.length; i++) {

					//var sourceString = this.data[ cid ][ i ].toLowerCase();
					//if (sourceString.indexOf( searchValue ) > -1) {
					var re = new RegExp(inputValue, 'i');
					if (ar = re.exec(this.data[ i ])) {

						//complete from beginning
						if (this.data[ i ].indexOf( ar[0] ) != 0) continue;
						//it's already in values (multivalues)
						if (this.multivalue && this.in_array(this.data[ i ], inputValues)) continue;

						this.resultIndexes[ this.resultIndexes.length ] = i;
						//autoCompleteHTML += '<div id="ac_' + j + '" class="auto-complete-row" onmouseover="this.autoComplete.hover( ' + j + ' );" onclick="this.autoComplete.exec(' + j + ');">' + this.data[ i ].replace( ar[0], '<b>'+ar[0]+'<\/b>' ) + '<\/div>';
						autoCompleteHTML += '<div id="ac_' + j + '" class="auto-complete-row">' + this.data[ i ].replace( ar[0], '<b>'+ar[0]+'<\/b>' ) + '<\/div>';
						j++;

						if (j % this.itemsPerColumn == 0) {
							autoCompleteHTML += "<\/td><td>";
						}

					}

				}
				autoCompleteHTML += '</td></tr></table></div>';

				/* Nothing Founded */
				if (j == 0) {
					this.hide();

				/* Founded ONLY the same value as input value (hide founded result) */
				} else if (j == 1 && this.data[ this.resultIndexes[0] ] == inputValue) {
					this.hide();

				/* Show result and hover (hightlight) first value */
				} else {
					this.container.innerHTML = autoCompleteHTML;
					this.hover( 0 );
				}

			} else {
				this.hide();
			}

			if (this.multivalue && this.key != 8) {
				var scrollTop = this.element.scrollTop;
				//var selectionStart = _$( cid ).selectionStart;
				
				/* Capitalize first character :) it's fun! */
				if (this.capitalize) {
					for (var i in inputValues) {
						inputValues[i] = inputValues[i].substring(0,1).toUpperCase() + inputValues[i].substring(1, inputValues[i].length);
					}
				}
				this.element.value = inputValues.join( this.multivalue );
				this.element.scrollTop = scrollTop;
				if (moveCarret) {
					//setSelectionPositions( this.element, moveCarret );
				}
			}

		}
	
	}
	
	this.hide = function() {

		//if (!this.currentID) return;
		//$('#'+this.container[ this.currentID ]).fadeOut('fast');
		this.container.innerHTML = '';
		this.hoverIndex = -1;

	}

	this.hover = function( index ) {

		if (this.resultIndexes.length <= index) {
			index = this.resultIndexes.length - 1;
		} else if (index < 0) {
			index = 0;
		}

		if (this.hoverIndex > -1) {
			document.getElementById('ac_'+this.hoverIndex).className = 'auto-complete-row';
		}
		document.getElementById('ac_'+index).className = 'auto-complete-row-hover';
		this.hoverIndex = index;

	}

	this.exec = function( index ) {

		if (!index) index = this.hoverIndex;
		if (index > -1) {
			if (this.multivalue) {
				var inputValues = this.element.value.split(this.trim( this.multivalue ));
				for (var i in inputValues) { inputValues[i] = this.trim( inputValues[i] ); }
				inputValues[ inputValues.length - 1 ] = this.data[ this.resultIndexes[index] ];
				this.element.value = inputValues.join( this.multivalue );
			} else {
				this.element.value = this.data[ this.resultIndexes[index] ];
			}

			this.hide();
		}
		return false;

	}
	
	this.getData = function( data, textStatus) {
		try {
			this.data = eval('{'+data+'}');
		} catch( e ) {
		}
	}
	
	this.element.onfocus = function( e ) {
		/* because document onClick closes float window, it must be here */
		this.attCompleter._noBubbling( e );
		this.attCompleter.key = 0;
		this.attCompleter.show();
	}
	this.element.onblur = function() {
		//setTimeout("autoComplete.hide()", 100);
	}
	this.element.onkeyup = function( e ) {
		e = this.attCompleter._fixE( e );
		this.attCompleter._noBubbling( e );
		this.attCompleter.key = e.whith ? e.whith : e.keyCode;
		this.attCompleter.show();
		return false;
	}
	this.element.onkeydown = function( e ) {
		e = this.attCompleter._fixE( e );
		this.attCompleter._noBubbling( e );
		this.attCompleter.key = e.whith ? e.whith : e.keyCode;
		if (this.attCompleter.hoverIndex >= 0 && this.attCompleter.key == 13) {
			this.attCompleter.exec();
			return false;
		}
	}
	
	this._noBubbling = function( e ) {
		e = this._fixE( e );
		if (e.cancelBubble) e.cancelBubble = true;
		if (e.stopPropagation) e.stopPropagation();
	    return false;
	}
	
	this._fixE = function( e ) {
		if (!e) e = window.event;
		return e;
	}
	
	this.getSelectionPositions = function( oTextarea ) {
		var docObj = oTextarea.ownerDocument;
		var result = {start:0, end:0, caret:0};
		
		if (navigator.appVersion.indexOf("MSIE")!=-1) {
			if (oTextarea.tagName.toLowerCase() == "textarea") {
				if (oTextarea.value.charCodeAt(oTextarea.value.length-1) < 14) {
					oTextarea.value=oTextarea.value.replace(/34/g,'')+String.fromCharCode(28);
				}
				var oRng = docObj.selection.createRange();
				var oRng2 = oRng.duplicate();
				oRng2.moveToElementText(oTextarea);
				oRng2.setEndPoint('StartToEnd', oRng);
				result.end = oTextarea.value.length-oRng2.text.length;
				oRng2.setEndPoint('StartToStart', oRng);
				result.start = oTextarea.value.length-oRng2.text.length; 
				result.caret = result.end;
				if (oTextarea.value.substr(oTextarea.value.length-1) == String.fromCharCode(28)) {
					oTextarea.value = oTextarea.value.substr(0, oTextarea.value.length-1);
				}			
			} else {
				var range = docObj.selection.createRange();
				var r2 = range.duplicate();			
				result.start = 0 - r2.moveStart('character', -100000);
				result.end = result.start + range.text.length;	
				result.caret = result.end;
			}			
		} else {
			result.start = oTextarea.selectionStart;
			result.end = oTextarea.selectionEnd;
			result.caret = result.end;
		}
		if (result.start < 0) {
			 result = {start:0, end:0, caret:0};
		}	
		return result;
	}
	
	this.trim = function( str ) {
		return str.replace(/^\s+|\s+$/g,"");
	}
	
	this.in_array = function( myValue, myArray) {
		function equals(a,b) {
			return (a == b);
		}

		for (var i in myArray) {
			if (equals( myArray[i], myValue ))
				return true;
		}
		return false;
	}

}
