﻿// README
//
// There are two steps to adding a property:
//
// 1. Create a member variable to store your property
// 2. Add the get_ and set_ accessors for your property.
//
// Remember that both are case sensitive!
//

Type.registerNamespace('AdvancedAutoSuggestControlExtender');

AdvancedAutoSuggestControlExtender.AdvancedAutoSuggestControlExtenderBehavior = function(element) {

    AdvancedAutoSuggestControlExtender.AdvancedAutoSuggestControlExtenderBehavior.initializeBase(this, [element]);

    this.inputFieldId; //An id of a textfield where user inputs
	this.updateFieldId; //An id of a textfield to update from click often a hidden field for ID to validate
	this.delay=100; //a delay between server calls in ms, We don't want to kill the server if a user types fast
	this.serviceUrl; //URL where to make the server call	
	this.lastCall = new Date().getTime(); //last call to the server
	this.additionalFields=new Array(0);	
	this.suggestionsDivId='suggestionsDiv';//an id of container for suggestions
	this.suggestionsDiv = $extend(this.suggestionsDivId); //a container of suggestions table
	
	if (!this.suggestionsDiv)
	{
	    //add the suggestion div to the DOM
	    this.suggestionsDiv = document.createElement("div");
	    this.suggestionsDiv.style.display="none";
	    this.suggestionsDiv.style.position="absolute";
	    this.suggestionsDiv.id = this.suggestionsDivId;
	    document.body.appendChild(this.suggestionsDiv);
	}
	
	this.doHide = true; //indicates if we need to hide the suggestions box
	
	this.selectedIndex=0; 
	this.suggestionsList = new Array();
	this.suggestionsIdList = new Array();
	this.suggestionsTrList = new Array();
	
	this._saveDesableSelect = new Array(0); //an array of select boxes to disable when IE6
	this._iframeElement;//an iframe to hide DDL IE6 fix
	
	//CSS		
	this.tableCss = "suggestionsTable";
	this.tableTrCss = "suggestionsTr";
	this.tableTdCss = "suggestionsTd";
	this.titleTrCss = "titleTr";
	this.titleTdCss = "titleTd";
	this.commentsTrCss = "commentsTr";
	this.commentsTdCss = "commentsTd";
	this.hilightedTrCss = "suggestionsHilightedTr";
	
	//events
	this.OnCleanValue = null;
	this.OnReplaceValue = null;

	this.UpdateAdditionalFields = function UpdateAdditionalFields(textboxId){
		this.additionalFields.push($extend(textboxId));
	}
	/*
	main function which makes the server call, parses results and shows them on screen
	*/
	this.ShowSuggestions = function ShowSuggestions(ev){		        	        
		Debug("ShowSuggestions Call")
		var k = ev.keyCode ? ev.keyCode : ev.rawEvent?ev.rawEvent.keyCode:null;
		if (k != Sys.UI.Key.esc && k != Sys.UI.Key.up && k != Sys.UI.Key.down && k != Sys.UI.Key.enter) {
			var textbox=$extend(this.inputFieldId);
			Debug("textbox:"+textbox);
			var text;		
			var additionalParams='&additionalParams=';
			if(textbox!=null){				
				text=textbox.value;			
				Debug('textbox.value:'+text);	
				if(text!=null && ""!=text){	
				    for(var i = 0;i<this.additionalFields.length;i++)
				    {
				        if ($extend(this.additionalFields[i]) != null)
				        {
				            additionalParams+='&additionalParams=';
						    additionalParams+=this.additionalFields[i];
						    additionalParams+='|';
						    additionalParams+=$F(this.additionalFields[i]);
						}
				    }
					Debug('doing service request:'+'tryValue='+ encodeURIComponent(text)+additionalParams);							
					new Ajax.Request(this.serviceUrl, 
						{   
							method: 'post',   
							parameters:'tryValue='+ encodeURIComponent(text)+additionalParams,					
							onSuccess: this.OnSuccess.bindAsEventListener(this),
							onError: this.OnError.bindAsEventListener(this)
						}
					);
				}else {	
					this.doHide=true;
					this.HideSuggestions();
				}
			}
		}		
	}
	
	this.OnError = function OnError(transport)
	{
	    alert(transport.get_message());
	}
	
	//creates a table from the results
	this.OnSuccess = function OnSuccess(transport){		
		Debug('Success!!! Raw Data:'+transport.responseText);
		this.suggestionsDiv.style.display='none';		
		//we remove all childs of an old container
		while (this.suggestionsDiv.firstChild) {
			this.suggestionsDiv.removeChild(this.suggestionsDiv.firstChild);
		}		
		var results = transport.responseText.stripTags().split('|');   								
		Debug('Real Data:'+results);
		var title, titleValue, description;	
		var resultedTable = document.createElement('table');
		var resultedTableTBody = document.createElement('tbody');
		this.suggestionsDiv.appendChild(resultedTable);				
		resultedTable.appendChild(resultedTableTBody);
		resultedTable.cellSpacing="0";
		resultedTable.cellPadding="0";
		Element.extend(resultedTable);
		resultedTable.addClassName(this.tableCss);
		var i;	
		Array.clear(this.suggestionsList);
		Array.clear(this.suggestionsIdList);
		Array.clear(this.suggestionsTrList);
		this.selectedIndex=-1; 							
		for(i=0;i<results.length;i++){			
			title=results[i].split(',')[0].replace('\r\n','');
			titleValue=results[i].split(',')[1].replace('\r\n','');
			description=results[i].split(',')[2];
			idValue=results[i].split(',')[3];
			tr=document.createElement('tr');
			td=document.createElement('td');
			Element.extend(tr);Element.extend(td);
			tr.addClassName(this.tableTrCss);
			td.addClassName(this.tableTdCss);			
			resultedTableTBody.appendChild(tr);tr.appendChild(td);
			Array.add(this.suggestionsList,this.FixText(new String(titleValue)));
			Array.add(this.suggestionsIdList,new String(idValue));				
			
					
			Event.observe(td,'click', this.ReplaceValue.bindAsEventListener(this,i));		
			Event.observe(td,'mouseover', this.DisableHide.bindAsEventListener(this,i));
			Event.observe(td,'mouseout', this.EnableHide.bindAsEventListener(this,i));
			
			//we create an inner row table where we store visible title and description
			rowTable = document.createElement('table');
			rowTableBody = document.createElement('tbody'); 
			Array.add(this.suggestionsTrList,rowTable);
			//title row
			rowTitleTr=document.createElement('tr'); 		
			rowTitleTd=document.createElement('td');
			Element.extend(rowTable);Element.extend(rowTableBody);Element.extend(rowTitleTr);Element.extend(rowTitleTd);
			rowTitleTr.addClassName(this.titleTr);
			rowTitleTd.addClassName(this.titleTd);			
			td.appendChild(rowTable);rowTable.appendChild(rowTableBody);
			rowTableBody.appendChild(rowTitleTr);rowTitleTr.appendChild(rowTitleTd);
			rowTitleTd.update(this.FixText(title).unescapeHTML());	//we set title		
			//description row
			if(description!=null && description!=''){
				rowCommentsTr=document.createElement('tr');
				rowCommentsTd=document.createElement('td');	
				Element.extend(rowCommentsTr);Element.extend(rowCommentsTd);			
				rowCommentsTr.addClassName(this.commentsTrCss);
				rowCommentsTd.addClassName(this.commentsTdCss);			
				rowTableBody.appendChild(rowCommentsTr);		
				rowCommentsTr.appendChild(rowCommentsTd);
				rowCommentsTd.update(this.FixText(description).unescapeHTML()); //we set description		
			}
		}			
		this.PositionBox(this.inputFieldId);
		this.doHide = true;
	}
	/*
	replces special chars
	*/
	this.FixText = function FixText(text){
		text=text.replace(/\+\+\+\+/g, ",");
		text=text.replace(/\-\-\-\-/g, "|");
		return text;
	}
	/*
	Positions the box under the control
	*/
	this.PositionBox = function PositionBox(parentId){		
		var parentbox=$extend(parentId);	
		var zIndex = 0;		
		if(this.suggestionsDiv.style.display=='none'){						
				var yPos=parentbox.offsetTop+parentbox.offsetHeight;
				var xPos=parentbox.offsetLeft;//+parentbox.offsetWidth;				
				while(parentbox.offsetParent!=null){				
					parentbox=parentbox.offsetParent;
					yPos+=parentbox.offsetTop;
					xPos+=parentbox.offsetLeft;
					if(parentbox.style.zIndex && parentbox.style.zIndex>zIndex){
						zIndex=parentbox.style.zIndex
					}
				}			
				this.suggestionsDiv.style.display='';	
				Debug("zIndex:"+zIndex);			
				this.suggestionsDiv.style.zIndex=zIndex+1;							
				this.suggestionsDiv.style.top=yPos+'px';
				this.suggestionsDiv.style.left=xPos+'px';							
				this.suggestionsDiv.style.width=$extend(parentId).offsetWidth+'px';
				Debug(Sys.Browser.name);
				Debug(Sys.Browser.version);
				//IE 6 fix to hide dropdowns
				if ((Sys.Browser.agent === Sys.Browser.InternetExplorer) && (Sys.Browser.version < 7)) {
					Debug("Doing IE6 FIX");
					var i;
					var tagElements;
					i = 0;
					for (var k = 0 ; k < this._saveDesableSelect.length; k++) {					
						this._saveDesableSelect[k].tag.disabled = this._saveDesableSelect[k].visib;					
					}
					this._saveDesableSelect.clear();
					tagElements = document.getElementsByTagName('SELECT');
					Debug("Found "+tagElements.length+" SELECT BOXES");
					for (var k = 0; k < tagElements.length; k++) {						
						this._saveDesableSelect[i] = {tag: tagElements[k], visib: tagElements[k].disabled};
						tagElements[k].disabled = true;						
						i++;						
					}					
					var childFrame = this._iframeElement;
					var elt = this.suggestionsDiv;
					// copied from  PreviewScript.js function Sys$Preview$UI$PopupBehavior$show
					childFrame.style.top = elt.style.top;
					childFrame.style.left = elt.style.left;
					childFrame.style.width = elt.offsetWidth + "px";
					childFrame.style.height = elt.offsetHeight + "px";
					childFrame.style.display = elt.style.display;
					Debug("_iframeElement.style.top:"+childFrame.style.top);
					Debug("_iframeElement.style.left:"+childFrame.style.left);
					Debug("_iframeElement.style.width:"+childFrame.style.width);
					Debug("_iframeElement.style.height:"+childFrame.style.height);
					Debug("_iframeElement.style.display:"+childFrame.style.display);					
					if (elt.currentStyle && elt.currentStyle.zIndex) {
						childFrame.style.zIndex = elt.currentStyle.zIndex;
					}else if (elt.style.zIndex) {
						childFrame.style.zIndex = elt.style.zIndex;
					}					
					Debug("_iframeElement.style.zIndex:"+childFrame.style.zIndex);
				}
				
		}		
	}
	this.OnKeyDown = function OnKeyDown(ev) {
        var k = ev.keyCode ? ev.keyCode : ev.rawEvent.keyCode;
        if (k === Sys.UI.Key.esc) {
            this.doHide=true;
			this.HideSuggestions();
			Event.stop(ev);
        }
        else if (k === Sys.UI.Key.up) {
            if (this.selectedIndex > 0) {
				this.RemoveHighLight(ev,-1);
                this.selectedIndex--;
                this.HighLight(ev,-1);
                this.doHide=true;
                Event.stop(ev);       
            }
        }
        else if (k === Sys.UI.Key.down) {
            if (this.selectedIndex < (this.suggestionsList.length - 1)) {
				this.RemoveHighLight(ev,-1);
                this.selectedIndex++;
                this.HighLight(ev,-1); 
                this.doHide=true;
                Event.stop(ev);
            }
        }
        else if (k === Sys.UI.Key.enter) {
            if (this.selectedIndex !== -1) {
                this.ReplaceValue(ev,this.selectedIndex);
                Event.stop(ev);               
            }
        }        
        if (k !== Sys.UI.Key.tab) {
           // this.doHide=false;
        }
    }
	//replaces a value in the textbox on click
	this.ReplaceValue = function ReplaceValue(ev, index){
		this.selectedIndex=index; 		
		$extend(this.inputFieldId).value=this.suggestionsList[this.selectedIndex];
		if(this.updateFieldId && $extend(this.updateFieldId)){
			$extend(this.updateFieldId).value=this.suggestionsIdList[this.selectedIndex];
		}
		if (this.OnReplaceValue)
		{
		    this.OnReplaceValue(this,this.get_element(),this.suggestionsIdList[this.selectedIndex]);
		}
		this.doHide=true;
		this.HideSuggestions();
	}
	
	//cleans updateFieldId text box
	this.CleanUpdateField = function CleanUpdateField(ev){
		var k = ev.keyCode ? ev.keyCode : ev.rawEvent?ev.rawEvent.keyCode:null;
        if (k != Sys.UI.Key.esc && k != Sys.UI.Key.up && k != Sys.UI.Key.down && k != Sys.UI.Key.enter) {
            if(this.updateFieldId && $extend(this.updateFieldId)){
				$extend(this.updateFieldId).value="";
			}
			if (this.OnCleanValue)
			{
			    this.OnCleanValue(this, this.get_element());
			}
        }	
	}
	
	//hides suggestions div
	this.HideSuggestions = function HideSuggestions(){					
		if(this.doHide){				
			 //IE6 Bug with SELECT element always showing up on top
			if ((Sys.Browser.agent == Sys.Browser.InternetExplorer) && (Sys.Browser.version < 7)) {
				for (var k = 0 ; k < this._saveDesableSelect.length; k++) {					
					this._saveDesableSelect[k].tag.disabled = this._saveDesableSelect[k].visib;					
				}
			}
        	this.suggestionsDiv.style.display='none';
        	if(this._iframeElement){
        		this._iframeElement.style.display='none';			
        	}
		}		
	}
	//function is to enable hide on onmouseout event of suggestions row
	this.EnableHide = function EnableHide(ev, index){
		this.RemoveHighLight(ev, index);
		this.doHide=true;
	}
	//function is to disable hide and highlight current row on mouseover event of suggestions row
	this.DisableHide = function DisableHide(ev,index){
		this.HighLight(ev,index);
		this.doHide=false;
	}
	this.RemoveHighLight =  function RemoveHighLight(ev,index){
		if (index==-1){index=this.selectedIndex}//else{this.selectedIndex=index}
		if(index!=-1){
			var element = this.suggestionsTrList[index];		
			Element.extend(element);
			element=element.ancestors().find(this.FindRow.bindAsEventListener(this))
			if(element!=null){
				element.removeClassName(this.hilightedTrCss);
			}			
		}
	}
	//highlights the row
	this.HighLight = function HighLight(ev,index){
		if(this.selectedIndex!=-1){
			this.RemoveHighLight(ev,-1);
		}
		if (index==-1){index=this.selectedIndex}else{this.selectedIndex=index}
			if(index!=-1){			
				var element = this.suggestionsTrList[index];
				Element.extend(element);
				element=element.ancestors().find(this.FindRow.bindAsEventListener(this))
				if(element!=null){
					element.addClassName(this.hilightedTrCss);			
				}			
		}
	}
	//a function to find a row from mouseover event to highlight it.	
	this.FindRow = function FindRow(el){
		Element.extend(el);		
		if(el && el.tagName && el.tagName.toLowerCase()=="td" && el.hasClassName(this.tableTdCss)){
			return el;
		}
	}
}

AdvancedAutoSuggestControlExtender.AdvancedAutoSuggestControlExtenderBehavior.prototype = {

    initialize : function() {
        AdvancedAutoSuggestControlExtender.AdvancedAutoSuggestControlExtenderBehavior.callBaseMethod(this, 'initialize');
        //#################################################################################################################
		//######### Constructor actions
		//#################################################################################################################	
		this.inputFieldId=this.get_element().id;
		Debug("Starting SuggestEngine inputFieldId:"+this.inputFieldId+" serviceUrl:"+this.serviceUrl+" additionalFields:"+this.additionalFields+" updateFieldId:"+this.updateFieldId);		
		//bind events to text box
		if(this.inputFieldId){	    
			new Form.Element.DelayedObserver(this.inputFieldId, this.delay, this.ShowSuggestions.bindAsEventListener(this));
			Event.observe(this.inputFieldId, 'keydown', this.OnKeyDown.bindAsEventListener(this));
			Event.observe(this.inputFieldId, 'keyup', this.CleanUpdateField.bindAsEventListener(this));
			Event.observe(this.inputFieldId, 'blur', this.HideSuggestions.bindAsEventListener(this));		
			//Event.observe(this.inputFieldId, 'focus', this.ShowSuggestions.bindAsEventListener(this));		
		}
		if ((Sys.Browser.agent === Sys.Browser.InternetExplorer) && (Sys.Browser.version < 7)) {
			//IE6 fix		
			var childFrame;
			var elt = this.suggestionsDiv;
			// copied from  PreviewScript.js function Sys$Preview$UI$PopupBehavior$show
			childFrame = document.createElement("iframe");
			childFrame.src = "about:blank";
			childFrame.style.position = "absolute";
			childFrame.style.display = "none";
			childFrame.scrolling = "no";
			childFrame.frameBorder = "0";
			childFrame.style.filter = "progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)";
			elt.parentNode.insertBefore(childFrame, elt);
			// end copied
			this._iframeElement = childFrame;
		}
			
    },

    dispose : function() {
        // TODO: add your cleanup code here
        AdvancedAutoSuggestControlExtender.AdvancedAutoSuggestControlExtenderBehavior.callBaseMethod(this, 'dispose');
    },    
    //-----------------
    get_UpdateField : function() {
        return this.updateFieldId;
    },

    set_UpdateField : function(value) {
        this.updateFieldId = value;
    },
    //-----------------
    get_Delay : function() {
        return this.delay;
    },

    set_Delay : function(value) {
		
        this.delay = value==0?100:value;
    },
    //-------------------
    get_ServiceUrl : function() {
        return this.serviceUrl;
    },

    set_ServiceUrl : function(value) {
        this.serviceUrl = value;
    },
    
    get_AdditionalFields : function() {
        return this.additionalFields;
    },

    set_AdditionalFields : function(value) {
		//split additional params and fills an array of additional fields
		if(value){value.split(',').each(this.UpdateAdditionalFields.bindAsEventListener(this))}
        this.additionalFields = value.split(',');
    },
    
    get_SuggestionsDivId : function() {
        return this.suggestionsDivId;
    },

    set_SuggestionsDivId : function(value) {
		if(value && value!="") this.suggestionsDivId = value;       
    },
    
    get_TableCss : function() {
        return this.tableCss;
    },

    set_TableCss : function(value) {
		if(value && value!="")this.tableCss = value;
    },
    get_TableTrCss : function() {    
        return this.tableTrCss;
    },

    set_TableTrCss : function(value) {
        if(value && value!="")this.tableTrCss = value;
    },
    get_TableTdCss : function() {
        return this.tableTdCss;
    },

    set_TableTdCss : function(value) {
       if(value && value!="") this.tableTdCss = value;
    },
    
    get_TitleTrCss : function() {
        return this.titleTrCss;
    },

    set_TitleTrCss : function(value) {
       if(value && value!="") this.titleTrCss = value;
    },
    
    get_TitleTdCss : function() {
        return this.titleTdCss;
    },

    set_TitleTdCss : function(value) {
       if(value && value!="") this.titleTdCss = value;
    },
    //---------
    get_CommentsTrCss : function() {
        return this.commentsTrCss;
    },

    set_CommentsTrCss : function(value) {
       if(value && value!="") this.commentsTrCss = value;
    },
    //---------
    get_CommentsTdCss : function() {
        return this.commentsTdCss;
    },

    set_CommentsTdCss : function(value) {
       if(value && value!="") this.commentsTdCss = value;
    },
    //---------
    get_HilightedTrCss : function() {
        return this.hilightedTrCss;
    },

    set_HilightedTrCss : function(value) {
       if(value && value!="") this.hilightedTrCss = value;
    },
    
    get_OnCleanValue : function() {
        return this.OnCleanValue;
    },
    set_OnCleanValue : function(value) {
        this.OnCleanValue = eval(value);
    },
    
    get_OnReplaceValue : function() {
        return this.OnReplaceValue;
    },
    set_OnReplaceValue : function(value) {
        this.OnReplaceValue = eval(value);
    }
}

AdvancedAutoSuggestControlExtender.AdvancedAutoSuggestControlExtenderBehavior.registerClass('AdvancedAutoSuggestControlExtender.AdvancedAutoSuggestControlExtenderBehavior', AjaxControlToolkit.BehaviorBase);

// Delayed observer, like Form.Element.Observer, 
// but waits for delay after last key input

Form.Element.DelayedObserver = Class.create();
Form.Element.DelayedObserver.prototype = {
  initialize: function(element, delay, callback) {
    this.delay     = delay || 500;
    this.element   = $extend(element);
    this.callback  = callback;
    this.timer     = null;
    this.lastValue = $F(this.element); 
    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
  },
  delayedListener: function(event) {
    if(this.lastValue == $F(this.element)) return;
    if(this.timer) clearTimeout(this.timer);
    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay);
    this.lastValue = $F(this.element);
  },
  onTimerEvent: function() {
    this.timer = null;
    this.callback(this.element, $F(this.element));
  } 
}
function Debug(info) {
	if($get('debugConsole')){
		$get('debugConsole').value+=info+"\n";
	}
 }

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();