// JavaScript Document
DCsAutocomplete = Class.create();



DCsAutocomplete.prototype={
	// variables -------------------------

	activated:false,
	startResult:0,
	//-----------------------------------------------------------------------------------------------
	// INITIALIZE AUTOCOMPLETE OBJECT
	//-----------------------------------------------------------------------------------------------
	initialize: function(options) {
		this.options = options;
		this.is_gecko = /gecko/i.test(navigator.userAgent);
		this.is_ie    = /MSIE/.test(navigator.userAgent);

		if(!options){
			throw('AUTOCOMPLETE - ERROR : you didn\'t set any params for the object !');
			return;
		}
		if(String(typeof(options)).toUpperCase()!="OBJECT"){
			throw('AUTOCOMPLETE - ERROR : the params must be declared like an Object !');
			return;
		}

		//----------------------
		if(!$(this.options.autocompleteField)){
			throw('AUTOCOMPLETE - ERROR : "autocompleteField" is mandatory ! ['+options.autocompleteField+']');
			return;
		}
		if(!this.options.url){
			throw('AUTOCOMPLETE - ERROR : "url" is mandatory !');
			return;
		}

		/* FIELDS INITIALIZATION */
		this.autocompleteField = $(this.options.autocompleteField);

		this.autocompleteFieldValue = $(this.options.autocompleteFieldValue);
		this.autocompleteFieldCode = $(this.options.autocompleteFieldCode);


		//----------------------
		this.autocompleteField.setAttribute("autocomplete", "off");
		this.autocompleteField.addClassName("autocomplete");


		//----------------------
		/* EVENTS */
		Event.observe(this.autocompleteField, 'dblclick', 	this.autocompleteDblClick.bindAsEventListener(this));
		Event.observe(this.autocompleteField, 'keydown', 	this.autocompleteKeyDown.bindAsEventListener(this));
		Event.observe(this.autocompleteField, 'keyup', 		this.autocompleteKeyUp.bindAsEventListener(this));
		Event.observe(this.autocompleteField, 'keypress', 	this.autocompleteKeyPress.bindAsEventListener(this));
		Event.observe(this.autocompleteField, 'blur',  		this.autocompleteBlur.bindAsEventListener(this));
		Event.observe(this.autocompleteField, 'focus', 		this.autocompleteFocus.bindAsEventListener(this));

		//Event.observe(this.autocompleteField, 'change',  	this.autocompleteInputChange.bind(this) );
		if(this.autocompleteField.form!=null){
			Event.observe(this.autocompleteField.form, 'submit',  function(){return !this.isActive();}.bindAsEventListener(this));
		}

		Event.observe(window, 'resize', this.resizeWindow.bindAsEventListener(this)  );
		//----------------------
		/* SETTINGS */
		this.options.resultsPerPage=this.options.resultsPerPage!=null?this.options.resultsPerPage:10;
		this.options.extraFilters=this.options.extraFilters!=null?this.options.extraFilters:'';
		this.options.gatherExtraFilters=this.options.gatherExtraFilters!=null?this.options.gatherExtraFilters:'';
		this.options.offsetX=this.options.offsetX!=null?this.options.offsetX:0;
		this.options.offsetY=this.options.offsetY!=null?this.options.offsetY:0;
		this.options.width=this.options.width!=null?this.options.width:0;
		this.options.debug=this.options.debug!=null?this.options.debug:false;
		this.options.highlight=this.options.highlight!=null?this.options.highlight:true;
		this.options.clearOnCancel=this.options.clearOnCancel!=null?this.options.clearOnCancel:false;
		this.options.clearOnSelect=this.options.clearOnSelect!=null?this.options.clearOnSelect:false;
		this.options.noResultsText=this.options.noResultsText!=null?this.options.noResultsText:'';
		this.options.extendedXML=this.options.extendedXML!=null?this.options.extendedXML:false;
		//----------------------

	},

	//-----------------------------------------------------------------------------------------------
	// WINDOW EVENTS
	//-----------------------------------------------------------------------------------------------
	appendToBody:function(){
		if(this.maskIframe) return;

		var objBody = document.getElementsByTagName("body").item(0);

		this.maskIframe=Builder.node('iframe', {id:"autocompleteMaskIframe", style:'display:none;',  frameborder:0} );
		this.maskIframe=$(this.maskIframe);

		this.mainDiv=Builder.node('div', {id:"autocompleteMainDiv", style:'display:none;'} );
		this.mainDiv=$(this.mainDiv);

		objBody.appendChild(this.maskIframe);
		objBody.appendChild(this.mainDiv);

		return true;
	},
	resizeWindow:function(event){
		if(!this.isActive()) return;
		setTimeout(function(){
			this.mainDiv.style.left=1+$(this.autocompleteField).getLeft()+this.options.offsetX+'px';
			this.mainDiv.style.top=$(this.autocompleteField).getTop()+$(this.autocompleteField).getHeight()+this.options.offsetY+'px';
		}.bind(this),200);
		nd();
	},

	//-----------------------------------------------------------------------------------------------
	// REQUEST
	//-----------------------------------------------------------------------------------------------

	requestData:function(triggerText){
		this.activate();
		setTimeout(this.requestDataDelayed.bind(this,triggerText) ,200);
	},
	requestDataDelayed:function(triggerText){

		if(!this.isActive()) return;

		//---------------------
		this.appendToBody();
		//---------------------
		if(this.autocompleteField.value != triggerText)  return;

		var pars = '';

		//----------------------
		// gather extra filters
		//----------------------
		var extraFiltersFromFields='';
		if(this.options.gatherExtraFilters!=''){
			stringChunks=this.options.gatherExtraFilters.split(',');
			$A(stringChunks).each(
				function(stringField){
					if((pos=stringField.indexOf('='))>=0){
						// check strings with '=' (name+id)
						tempArr=stringField.split('=');
						field=$(tempArr[1]);
						if(field!=null){
							extraFiltersFromFields+='&'+tempArr[0]+'='+$F(field);
						}
					}else{
						// check strings without '=' (only id)
						field=$(stringField);
						if(field!=null){
							extraFiltersFromFields+='&'+field.name+'='+$F(field);
						}
					}
				}
			);
		}


		//----------------------
		// form the URL with all components
		//----------------------
		var url=this.options.url+'?&search='+this.autocompleteField.value+
				'&start='+this.startResult+
				'&resultsPerPage='+this.options.resultsPerPage+
				extraFiltersFromFields+
				'&'+this.options.extraFilters;
		this.lastUrl=url;
		this.requester = new Ajax.Request(
			url,
			{
				method: 'get',
				parameters: pars,
				onSuccess: this.displayData.bind(this)
			});

	},

	loadPreviousPage:function(event){
		if(this.startResult>0){
			this.startResult-=this.options.resultsPerPage;
			this.requestDataDelayed(this.autocompleteField.value);
		}
	},
	loadNextPage:function(event){
		if(this.startResult+this.options.resultsPerPage<this.totalResults){
			this.startResult+=this.options.resultsPerPage;
			this.requestDataDelayed(this.autocompleteField.value);
		}
	},

	//-----------------------------------------------------------------------------------------------
	// LOAD & DISPLAY
	//-----------------------------------------------------------------------------------------------

	displayData:function(request){

		if(!this.isActive()) return;

		// clear div
		this.mainDiv.innerHTML='';
		this.pageSize=getPageSize();

		var nodeList=request.responseXML.getElementsByTagName("element");
		var resultsCount=nodeList.length;

		if(resultsCount){

			// form the regular expresion for highligh
			if(this.options.highlight && $F(this.autocompleteField) ){
				var searchElem=$F(this.autocompleteField);
				searchElem=searchElem.replace(/^\ +|\ +$/g,''); // TRIM
				if(searchElem!=''){
					searchElem=searchElem.replace('\\','\\\\').replace('^','\\^').replace('$','\\$').replace('*','\\*').replace('+','\\+').replace('?','\\?');
					searchElem='(^| )'+searchElem.replace(/\ +/g,'|(^| )'); // separate in words
				}
			}

			// add menu items
			for(i=0;i<nodeList.length;i++){
				var itemValue='';


				for(k=0;k<nodeList[i].childNodes.length;k++){
					if(nodeList[i].childNodes[k].nodeType==3)
						itemValue+=nodeList[i].childNodes[k].nodeValue;
				}
				itemValue=itemValue.replace(/^[\ \t\n\r]+|[\ \t\n\r]+$/g,''); // TRIM

				var newElement=Builder.node('a', {className:'option', href:"#;",
					title:nodeList[i].getAttribute("title")},[itemValue]
				);


				if(this.options.highlight && $F(this.autocompleteField) && searchElem!='' ){
					var regExp=new RegExp(searchElem, "ig");
					var nodeValue=itemValue;
					var offset=0;
					var ar;
					while( ( ar = regExp.exec(itemValue))!=null){
						var replacement='<span class="highlight">'+ar[0]+'</span>';
						nodeValue=nodeValue.substr(0,offset+ar.index)+replacement+nodeValue.substr(offset+ar.index+ar[0].length);
						offset+=replacement.length-ar[0].length;
					}

					newElement.innerHTML=nodeValue;
				}else{
					newElement.innerHTML=itemValue;
				}

				newElement.insertBefore(Builder.node('div',	{style:"float:right"}, nodeList[i].getAttribute("extra") ),newElement.firstChild);
				newElement=$(newElement);


				newElement.code=nodeList[i].getAttribute("code");
				newElement.value=itemValue;
				newElement.onmousedown=this.optionClick.bind(newElement);
				var extraInfo=nodeList[i].getElementsByTagName('info');
				if(extraInfo!=null && extraInfo.length){
					newElement.extraInfo=extraInfo[0];
				}

				// add extended data
				if(this.options.extendedXML){
					newElement.autocompleteValues=new Object;
					for(k=0;k<nodeList[i].attributes.length;k++){
						newElement.autocompleteValues[nodeList[i].attributes[k].name]=nodeList[i].attributes[k].value;
					}
				}

				newElement.autocompleteObj=this;


				// select the first option
				if(!i){
					newElement.addClassName('selected');
				}

				this.mainDiv.appendChild(newElement);

				// remember the first and the last option
				if(!i) this.firstOption=newElement;
				if(i==nodeList.length-1) this.lastOption=newElement;
			}

			//--- add footer = if result count exists  ----
			this.totalResults=request.responseXML.documentElement.getAttribute("totalResults");
			if(this.totalResults!=null && this.totalResults){
				var newElement=Builder.node('div', {className:'pages'},
					[
						prevButton=Builder.node('a',{className:'prevPage'}),
						nextButton=Builder.node('a',{className:'nextPage'}),
						(this.startResult+1)+".."+Math.min(this.startResult+this.options.resultsPerPage,this.totalResults)+" / "+this.totalResults
					]
				);
				$(prevButton).update('&laquo;&laquo;');
				$(nextButton).update('&raquo;&raquo;');

				newElement.onclick=newElement.onmousedown=newElement.onmouseup=function(event){
					this.autocompleteField.focus();
				}.bindAsEventListener(this);

				if(this.startResult>0){
					prevButton.href='#;';
					prevButton.onclick=this.loadPreviousPage.bindAsEventListener(this);
				}else{
					$(prevButton).addClassName('disabled');
				}

				if(this.startResult+this.options.resultsPerPage<this.totalResults){
					nextButton.href='#;';
					nextButton.onclick=this.loadNextPage.bindAsEventListener(this);
				}else{
					$(nextButton).addClassName('disabled');
				}
				this.mainDiv.appendChild(newElement);
			}


		}else{
			// no results are found -> show the 'no results' message
			if(this.options.noResultsText){

				this.mainDiv.appendChild(Builder.node('div',	{style:"text-align:center;",className:'noResults'}, this.options.noResultsText ));
			}
		}

		// -- debug textarea
		if(this.options.debug){
			var newElement=Builder.node('textarea', {className:'debug',readonly:1, wrap:'hard'},
				[
				 request.responseXML.documentURI?request.responseXML.documentURI:this.lastUrl,
				 "\n\r\n\r",
				 request.responseText
				]
			);
			//newElement.autocompleteObj=this;
			//newElement.onclick=function(event){this.autocompleteObj.autocompleteField.focus();this.autocompleteObj.canClose=false;};
			this.mainDiv.appendChild(newElement);
		}


		//---
		this.displayMenu();
	},

	displayMenu:function(){
		// loading was cancel
		if(!this.isActive()) return;

		// no data is displayed
		if(!this.mainDiv.childNodes.length) return;

		//---------------------
		this.mainDiv.style.left=1+$(this.autocompleteField).getLeft()+this.options.offsetX+'px';
		this.mainDiv.style.top=$(this.autocompleteField).getTop()+$(this.autocompleteField).getHeight()+this.options.offsetY+'px';
		//new Effect.Appear($(this.mainDiv), { duration: 0.2} );

		if(this.options.width){
			$(this.mainDiv).style.width=this.options.width;
		}else{
			$(this.mainDiv).style.width=($(this.autocompleteField).getWidth()-2)+'px';
		}

		$(this.mainDiv).show();
		//---------------------
		this.maskIframe.style.left=this.mainDiv.style.left;
		this.maskIframe.style.top=this.mainDiv.style.top;
		this.maskIframe.style.height=$(this.mainDiv).getHeight()+'px';
		this.maskIframe.style.width=$(this.mainDiv).getWidth()+'px';
		//new Effect.Appear($(this.maskIframe), { duration: 0.2} );
		$(this.maskIframe).show();

		selectedItems=$(this.mainDiv).getElementsByClassName("option selected");
		if(selectedItems.length) this.doOptionSelect(null,selectedItems[0])
	},


	//-----------------------------------------------------------------------------------------------
	activate:function(status){
		if(status==null) status=true;
		this.activated=status;

		// abort ajax request
		try{
			this.requester.transport.abort();
		}catch(err){}
	},
	isActive:function(){
		return this.activated;
	},


	//-----------------------------------------------------------------------------------------------
	// close() -  close the autocomplete menu
	//-----------------------------------------------------------------------------------------------
	close:function(canceled){
		nd();

		if(!this.canClose) return;

		if(canceled){
			if(this.isActive()){
				this.doCancel();
			}
		}
		this.activate(false);

		//new Effect.Fade($(this.mainDiv), {duration:.2});
		if(this.mainDiv) this.mainDiv.hide();
		if(this.maskIframe) this.maskIframe.hide();

	},

	//-----------------------------------------------------------------------------------------------
	// optionClick(event) - click on some option
	//-----------------------------------------------------------------------------------------------
	optionClick:function(event){
		//selectedOption=Event.element(event);
		this.autocompleteObj.doSelect(this);
	},

	//-----------------------------------------------------------------------------------------------
	//	option Select
	//-----------------------------------------------------------------------------------------------
	doOptionSelect :function(oldOption, newOption){
		nd();
		oldOption=$(oldOption);
		newOption=$(newOption)
		if(oldOption!=null){
			oldOption.removeClassName('selected');
		}
		if(newOption!=null){
			newOption.addClassName('selected');

			if(newOption.extraInfo!=null){

				delayOverlibTooltip=function(selectedElement){
					if(this==null || !this.isActive()) return;
					if(selectedElement==null) return;
					if(!selectedElement.hasClassName('selected')) return;
					if(selectedElement.extraInfo==null || !selectedElement.extraInfo.childNodes.length) return;
					if(!selectedElement.getWidth()) return;

					try{
						var extraText=selectedElement.extraInfo.childNodes[0].nodeValue;
						if(extraText == null) return;
						extraText=extraText.replace(/^[\ \t\n\r]+|[\ \t\n\r]+$/g,''); // TRIM
						if(extraText=='') return;
					}catch(err){}

					try{
						var overlibWidth=selectedElement.extraInfo.getAttribute('width');
						if(overlibWidth==null || !overlibWidth) overlibWidth=selectedElement.getWidth();
						overlibWidth= parseInt(overlibWidth);
						//
						var x=this.autocompleteField.getLeft();
						var y=selectedElement.getTop();


						if(this.pageSize!=null){
							if(this.pageSize[0]>=x+selectedElement.getWidth()+overlibWidth){
								x+=selectedElement.getWidth();
								overlib(extraText,FIXX,x,FIXY,y, WIDTH, overlibWidth);
							}else{
								x-=overlibWidth;
								overlib(extraText,FIXX,x,FIXY,y, WIDTH, overlibWidth);
							}
						}else{
							x+=selectedElement.getWidth();
							overlib(extraText,FIXX,x,FIXY,y, WIDTH, overlibWidth);
						}

					}catch(err){}
				}

				setTimeout(delayOverlibTooltip.bind(this, $(newOption)), 700);
			}
		}

	},
	//-----------------------------------------------------------------------------------------------
	//	INPUT EVENTS
	//-----------------------------------------------------------------------------------------------
	getSelectionStart:function(input) {
		if (this.is_gecko) return input.selectionStart;
		var range = document.selection.createRange();
		var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0;
		if (!isCollapsed)
			range.collapse(true);
		var b = range.getBookmark();
		return b.charCodeAt(2) - 2;
	},

	getSelectionEnd:function (input) {
		if (this.is_gecko) return input.selectionEnd;
		var range = document.selection.createRange();
		var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0;
		if (!isCollapsed)
			range.collapse(false);
		var b = range.getBookmark();
		return b.charCodeAt(2) - 2;
	},

	autocompleteKeyPress:function(event){


		if(!this.isActive()) return;

		switch(event.keyCode){
			case Event.KEY_UP:

					selectedElementsArr=this.mainDiv.getElementsByClassName('option selected');
					if(selectedElementsArr.length){
						var selectedElement;
						if(selectedElementsArr[0].previousSibling && selectedElementsArr[0].previousSibling.nodeName=='A'){
							this.doOptionSelect(selectedElementsArr[0],selectedElementsArr[0].previousSibling)
						}else{
							this.doOptionSelect(selectedElementsArr[0],this.lastOption)
						}

					}

				break;
			case Event.KEY_DOWN:

					selectedElementsArr=this.mainDiv.getElementsByClassName('option selected');
					if(selectedElementsArr.length){
						var selectedElement;
						if(selectedElementsArr[0].nextSibling && selectedElementsArr[0].nextSibling.nodeName=='A'){
							this.doOptionSelect(selectedElementsArr[0],selectedElementsArr[0].nextSibling)
						}else{
							this.doOptionSelect(selectedElementsArr[0],this.firstOption)
						}


					}

				break;
			 case Event.KEY_PAGEUP:
					selectedElementsArr=this.mainDiv.getElementsByClassName('option selected');
					if(selectedElementsArr.length){
						this.doOptionSelect(selectedElementsArr[0],this.firstOption)
					}
			 	break;
			case Event.KEY_PAGEDOWN:
					selectedElementsArr=this.mainDiv.getElementsByClassName('option selected');
					if(selectedElementsArr.length){
						this.doOptionSelect(selectedElementsArr[0],this.lastOption)
					}
				break;
		}


	},

	autocompleteKeyDown:function(event){

		switch(event.keyCode){
			case Event.KEY_RETURN:
					Event.stop(event);
				break;
			case Event.KEY_ESC:
				break;
			case Event.KEY_TAB:	case Event.KEY_LEFT: case Event.KEY_UP:	case Event.KEY_RIGHT: case Event.KEY_DOWN:
			case Event.KEY_PAGEDOWN:  case Event.KEY_PAGEUP:
				break;
			case Event.KEY_BACKSPACE:
			case Event.KEY_DELETE:
			default:
					this.activate();
				break;
		}

	},

	autocompleteKeyUp:function(event){

		switch(event.keyCode){
			case Event.KEY_RETURN:
					Event.stop(event);


					if(!this.isActive()){
						this.requestData(this.autocompleteField.value);
					}
					else
					if(this.mainDiv && this.mainDiv.visible()){
						optionsCount=this.mainDiv.getElementsByClassName('option selected').length;
						this.doSelect();
						if(!optionsCount){
							this.doCancel();
						}
					}else{
						this.doCancel();
					}

				break;
			case Event.KEY_ESC:
					this.canClose=true;
					this.close(true);
				break;
			case Event.KEY_LEFT:
					if(this.getSelectionStart(this.autocompleteField)==0){
						this.loadPreviousPage();
					}
				break;
			case Event.KEY_RIGHT:
					if(this.getSelectionEnd(this.autocompleteField)==this.autocompleteField.value.length){
						this.loadNextPage();
					}
				break;

			case Event.KEY_TAB:
			case Event.KEY_UP:case Event.KEY_DOWN: case Event.KEY_PAGEDOWN: case Event.KEY_PAGEUP:
				break;

			case Event.KEY_BACKSPACE:
			case Event.KEY_DELETE:
			default:
					this.startResult=0;
					this.requestData(this.autocompleteField.value);
				break;
		}

	},

	autocompleteDblClick:function(event){
		if(!this.isActive()){
			this.requestData(this.autocompleteField.value);
		}
	},

	autocompleteBlur:function(event){
		this.focused=false;

		if(!this.options.debug){
			this.canClose=true;

			setTimeout(function(){
				if(this.focused) return;
				this.close(true);
			}.bind(this),150);
		}
	},
	autocompleteFocus:function(event){
		this.focused=true;
	},

	autocompleteInputChange:function(event){
		this.canClose=true;
		this.close(true);
	},
	//-----------------------------------------------------------------------------------------------
	//	SELECT & CANCEL
	//-----------------------------------------------------------------------------------------------
	doSelect:function(selectedElement){

		if(!selectedElement){
			selectedElementsArr=this.mainDiv.getElementsByClassName('option selected');
			if(selectedElementsArr.length){
				selectedElement=selectedElementsArr[0];
			}
		}

		if(!selectedElement){
			this.canClose=true;
			this.close(false);
			return;
		}
		this.canClose=true;
		this.close(false);

		this.startResult=0;
		//-------------------------------------------
		selectedElement=$(selectedElement);
		//alert(selectedElement.code+"\n"+selectedElement.value);
		if(this.autocompleteFieldValue){
			this.autocompleteFieldValue.value=selectedElement.value;
		}
		if(this.autocompleteFieldCode){
			this.autocompleteFieldCode.value=selectedElement.code;
		}


		//-------------------------------------------
		if(this.options.onSelect){
			switch(String(typeof(this.options.onSelect)).toUpperCase()){
				case 'STRING':{
					selectedElement.evalString=this.options.onSelect;
					var onSelect=function(){eval(this.evalString)}.bind(selectedElement);
					onSelect();
					break;
				}
				case 'FUNCTION':{
					var onSelect=this.options.onSelect.bind(selectedElement);
					onSelect();
					break;
				}
			}
		}
		//-------------------------------------------
		if(this.options.clearOnSelect){
			this.autocompleteField.value='';
		}
		//-------------------------------------------
		return;
	},

	doCancel:function(){
		//-------------------------------------------
		if(this.options.onCancel){
			switch(String(typeof(this.options.onCancel)).toUpperCase()){
				case 'STRING':{
					eval(this.options.onCancel);
					break;
				}
				case 'FUNCTION':{
					this.options.onCancel();
					break;
				}
			}
		}
		//-------------------------------------------
		if(this.options.clearOnCancel){
			this.autocompleteField.value='';

			if(this.autocompleteFieldValue!=null)
				this.autocompleteFieldValue.value = '';

			if(this.autocompleteFieldCode!=null)
				this.autocompleteFieldCode.value = '';
		}
		//-------------------------------------------
	}

}