/**
 * @author Andrew Romashkan
 */

AutoComplete = function( objParams ){
	var error = false;
	
	if( !objParams ) error = "Please define constructor parameters";
	else if( !objParams.dom ) error = "Please define dom element";
	else if( !objParams.list ) error = "Please define list of values";
	
	if( error ){
		alert(error);
		return false;
	}
	
	this.list = objParams.list;
	this.dom  = $(objParams.dom);
	this.isListShowed = false;
	this.currentSelected = null;
	this.domLlistHolder = null;
	this.availableArea = $(document.body).getDimensions().height - Element.cumulativeOffset(this.dom)[1] - 80;
	
	var scope = this;

	function prepareQuery( event ) {
	  // If text typed
	  if( ( event.keyCode >= 65 &&  event.keyCode <= 90 ) || event.keyCode == 8 || event.keyCode == 46 ){
	  	var element = Event.element(event);
		scope.hide();
		
		if( element.value && element.value.length >= 2 ){
			scope.query( element.value );
		}
	  }else if( event.keyCode == 38 || event.keyCode == 40 ){ // Arrows keys pressed
	  	scope.onArrowKeysPressed( event.keyCode == 38 ? true : false );
	  }else if( event.keyCode == 13 ){
	  	scope.onEnterKeyPressed();
      }
	}

    function hideList(event) {
      if (scope.isListShowed) {
        if (scope.currentSelected) {
          scope.onSuggestionSelected(scope.currentSelected);
        } else {
          scope.onSuggestionSelected(scope.domLlistHolder.childElements().first().id);
        }
      }
    }

	this.dom.observe('keyup', prepareQuery);
    this.dom.observe('blur', hideList);
}

AutoComplete.prototype.query = function( search ){
	var result = [];
	var regExp = new RegExp( search, "i" );
	
	for( var i in this.list ){
		if (typeof(this.list[i]) != "function") {
			if (regExp.test(this.list[i])) {
				result.push({
					id : this.list[i],
					text : this.list[i].replace( regExp , "<b>"+this.list[i].match(regExp)+"</b>")
				});
			}
		}
	}
	
	if ( result.length ) {
		this.show( result );
	}
}

AutoComplete.prototype.show = function( matchesList ){
	
	this.isListShowed = true;
	
	var _x 		= Element.cumulativeOffset(this.dom)[0];
	var _y 		= Element.cumulativeOffset(this.dom)[1] + this.dom.getHeight();
	var _width 	= this.dom.getWidth();
	
	this.domLlistHolder = new Element('ul', { style: 'top : '+_y+'px; left : '+_x+'px; width : '+_width+'px' });
    this.domLlistHolder.className = 'ac_list';
	
	for(var i = 0; i < matchesList.length; i ++){
		this.domLlistHolder.insert( new Element('li',{'id':matchesList[i].id}).update( matchesList[i].text ) );;
	}
	
	Element.insert( $(document.body), this.domLlistHolder );
	
	// confirm list height
	var listHeight = this.domLlistHolder.getDimensions().height;
	if( listHeight > this.availableArea ){
		this.domLlistHolder.style.height = this.availableArea + "px";
		this.domLlistHolder.style.overflow = "auto";		
	}

	this.assignListeners();
}

AutoComplete.prototype.assignListeners = function(){
	var scope = this;
	
	function itemClicked( event ){
		var li = event.findElement("li");
		if( li )
			scope.onSuggestionSelected( li.id );
	}
	this.domLlistHolder.observe( 'click', itemClicked );
	
	function itemHover( event ){
		var li = event.findElement("li");
		if( li )
			scope.onSuggestionHover( li.id );
	}

	this.domLlistHolder.childElements().invoke( 'observe', 'mouseover', itemHover);
	
	function outClick(){
		scope.hide();
	}
	$(document.body).observe( 'click', outClick );
}

AutoComplete.prototype.removeListeners = function(){
	this.domLlistHolder.stopObserving( 'click' );
	this.domLlistHolder.childElements().invoke( 'stopObserving', 'mouseover');
	$(document.body).stopObserving( 'click');
}

AutoComplete.prototype.onSuggestionHover = function( suggestion ){
	if( this.currentSelected == suggestion )
		return;
		
	if( this.currentSelected ){
		$( this.currentSelected ).removeClassName("active");
	}
	
	this.currentSelected = suggestion;
	
	$( this.currentSelected ).addClassName("active");
}

AutoComplete.prototype.onSuggestionSelected = function( suggestion ){
	this.currentSelected = null;
	this.dom.value = suggestion;
	this.hide();
}

AutoComplete.prototype.onArrowKeysPressed = function( isUp ){
	if( this.isListShowed ){
		if(isUp){
			if( this.currentSelected ){
				if( $(this.currentSelected).previous() ){
					this.onSuggestionHover($(this.currentSelected).previous().id);
				}else{
					this.onSuggestionHover(this.domLlistHolder.childElements().last().id);
				}
			}else{
				this.onSuggestionHover(this.domLlistHolder.childElements().first().id);
			}
		}else{
			if( this.currentSelected ){
				if( $(this.currentSelected).next() ){
					this.onSuggestionHover($(this.currentSelected).next().id);
				}else{
					this.onSuggestionHover(this.domLlistHolder.childElements().first().id);
				}
			}else{
				this.onSuggestionHover(this.domLlistHolder.childElements().first().id);
			}
		}
	}
}

AutoComplete.prototype.onEnterKeyPressed = function(){
	if( this.isListShowed ){
		if( this.currentSelected ){
			this.onSuggestionSelected( this.currentSelected );
		}
	}
}

AutoComplete.prototype.hide = function(){
	if (this.domLlistHolder) {
		this.isListShowed = false;
		this.removeListeners();
		Element.remove(this.domLlistHolder);
		this.domLlistHolder = null;
	}
}
