/* AutoComplete Object */

function autoComplete( options ) {

	this.hoverIndex = -1;
	this.resultIndexes = new Array();
	this.data = new Array();
	this.URLData = ''; //%s will be replaced by search value
	this.minSimbols = 1;
	this.container = '';
	this.multivalue = false;
	this.itemsPerColumn = 3;
	this.key = 0;
	//this.maxFieldSize = 150;
	this.capitalize = false;
	this.getByURL = options.getByURL ? true : false;
	this.cache = {};
	this.requestTimeout = 0;
	this.moveCarret = false;
	
	this.events = {
		onEnter : false
	};
	
	this.element = document.getElementById( options.id );
	if (!this.element) 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 options.onEnter == 'function') {
		this.events.onEnter = options.onEnter;
	}
	
	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() {
	
		clearTimeout( this.requestTimeout );
		var pos = this.getSelectionPositions( this.element );
		var textLength = this.element.innerText == null ? this.element.textLength : this.element.innerText.length;
		var self = this;
		this.moveCarret = false;
		if (pos.start != textLength) {
			//this.moveCarret = pos.start;
		}
		if (typeof this.URLData == 'string' && !this.getByURL) {
			var url = this.URLData;
			this.URLData = null;
			$.get( url, {}, function(data, text) { self.getData( data, text );} );
		}

		if (!this.getByURL && 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) {	
				if (this.getByURL) {
					if (typeof this.cache[ inputValue ] != 'undefined') {
						this.showResult( this.cache[ inputValue ] );
					} else {
						var url = this.URLData.replace('%s', inputValue);
						this.requestTimeout = setTimeout(function() {
							$.get( url, {}, function(data, text) { 
								self.cache[ inputValue ] = data;
								self.showResult( data, text );} 
							);
						}, 500);
					}
				} else {
					this.showResult( this.data );
				}
			} else {
				this.hide();
			}
		
		}
		
		return false;
	
	}

	this.showResult = function( data ) {

		var element = this.element;
		
		if (typeof data == 'string') data = this.getData( data );
		
		if (typeof data == 'undefined' || !data.length) return false;
		
		this.hoverIndex = -1;
		this.resultIndexes = new Array();
		var autoCompleteHTML = '<div class="auto-complete" style="position:absolute;"><table><tr><td>';
		var j = 0;
		
		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 ];
		}

		for (var i = 0; i < data.length; i++) {

			//var sourceString = data[ cid ][ i ].toLowerCase();
			//if (sourceString.indexOf( searchValue ) > -1) {
			var re = new RegExp(inputValue, 'i');
			if (ar = re.exec(data[ i ]) || this.getByURL) {

				//complete from beginning
				if (!this.getByURL && data[ i ].indexOf( ar[0] ) != 0) continue;
				//it's already in values (multivalues)
				if (this.multivalue && this.in_array(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 + ');">' + data[ i ].replace( ar[0], '<b>'+ar[0]+'<\/b>' ) + '<\/div>';
				autoCompleteHTML += '<div id="ac_' + j + '" class="auto-complete-row">' + 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 && data[ this.resultIndexes[0] ] == inputValue) {
			this.hide();

		/* Show result and hover (hightlight) first value */
		} else {
			this.container.innerHTML = autoCompleteHTML;
			this.hover( 0 );
		}

		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 (this.moveCarret) {
				this.setSelectionPositions( this.element, this.moveCarret );
			}
		}

	}
	
	this.hide = function() {

		//if (!this.currentID) return;
		//$('#'+this.container[ this.currentID ]).fadeOut('fast');
		clearTimeout( this.requestTimeout );
		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 ) {

		clearTimeout( this.requestTimeout );
		if (!index) index = this.hoverIndex;
		if (index > -1) {
			var stat = true;
			if (typeof this.events.onEnter == 'function') {
				stat = this.events.onEnter( this.data[ this.resultIndexes[index] ] );
			}
			if (!stat) return false;
			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+'}');
			return this.data;
		} catch( e ) {
			return [];
		}
	}
	
	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() {
		var self = this;
		setTimeout(function() {
			self.attCompleter.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( element ) {
		if( document.selection && navigator.userAgent.toLowerCase().indexOf("msie") != -1 ) { //IS IE
			// The current selection
			var range = document.selection.createRange();
			// We'll use this as a 'dummy'
			var stored_range = range.duplicate();
			// Select all text
			//stored_range.moveToElementText( element );
			// Now move 'dummy' end point to end point of original range
			//stored_range.setEndPoint( 'EndToEnd', range );
			// Now we can calculate start and end points
			element.selectionStart = stored_range.text.length - range.text.length;
			element.selectionEnd = element.selectionStart + range.text.length;
		}
		return { start: element.selectionStart, end: element.selectionEnd };
	}
	
	function setSelectionPositions( element, start, end ) {

		if (!end || typeof end == 'undefined') end = start;
		// IE Support
		if ( document.selection && navigator.userAgent.toLowerCase().indexOf("msie") != -1 ) {

			// Set focus on the element
			element.focus ();

			// Create empty selection range
			var oSel = document.selection.createRange ();

			// Move selection start and end to 0 position
			//oSel.moveStart ('character', -element.value.length);

			// Move selection start and end to desired position
			oSel.moveStart ('character', start);
			oSel.moveEnd ('character', -element.value.length + end);
			oSel.select ();
			
		} else if (element.selectionStart || element.selectionStart == '0') {
		
			element.focus ();
			element.selectionStart = start;
			element.selectionEnd = end;
			
		}

	}
	
	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;
	}

}