/* 
GDAutoComplete: by randy bacon 06/16/09
	make a drop down for auto selection.  revision of previous version.
*/

//keep track OH your class here by item id
var g_GDACSOjbects;

function GDACSAddObj(itemId, oitemId)
{
	if (typeof(g_GDACSOjbects) == "undefined")
		g_GDACSOjbects = new Array();
			
	g_GDACSOjbects[itemId] = oitemId;
}

function GDACSGetObj(itemId)
{
	return g_GDACSOjbects[itemId];
}

function GDACSResetAll()
{
    for ( keyVar in g_GDACSOjbects ) 
    {
        GDACSGetObj(keyVar).ResetDDLInfo();
    }
} 

function GDAutoComplete(myId, textboxElementId, resultElementId, ajaxLocation)
{
	//class members (consider _ members private)
	this._MyId = myId;
    
	//public class members
    /* the approx height of the text box */
	this.TextboxHeight = 21;
	/* the roll over menu bg color */
	this.RolloverMenuColor = "red";
	/* the roll over menu a color color */
	this.RolloverAColor = "white";
	/* the roll off menu bg color */ 
	this.RolloffMenuColor = "white";
	/* the roll off menu a color color */
	this.RolloffAColor = "blue";
	/* the name of the opt pre - unique name it for your rollovers */
	this.OptionDivPre = "opt";
	/* hide the ddl time out */
	this.HideDDLIn = 1000;
	/* the min length to start your XML request */
	this.MinSendChars = 2;
	/* the MAX length chars to start your XML request */
	this.MaxSendChars = 100;
	/* the delay before showing the menu so you aren't firing off a ton of requests in MS */
	this.DelayBeforeRequest = 300;
	/* the max items to show in the ddl */
	this.MaxNumMenuItemsToShow = 15;
	/* the name of the text box to web service var */
	this.AjaxTextBoxVar = "uinput";
	
	//private members
	/* set this to true if you want to debug it */
	this._DebugIt = true;
	
	/* start elements this script will reference set by "constructor" */
	this._TextboxElementId = textboxElementId;
	this._ResultElementId = resultElementId;
	this._AjaxLocation = ajaxLocation;
	
	this._TextboxElement = null;
	this._ResultElement;
	
	this._FirstItemInList = "";
	/* xml request what not */
	this.oXmlReq;
	this._DelayHideTimer = null;
    this._DelayBeforeReqTimer = null;
	
	//set up a ref for me
	GDACSAddObj(this._MyId, this);
	
	//event stuff
	this._EventPointers = new Array();
}

//call me when obj set up is complete
GDAutoComplete.prototype.Launch = function()
{
	//finally attach events to our buttons
	this._AttachEvents();	
};

//attach event handlers
GDAutoComplete.prototype._AttachEvents = function()
{
	//text box set up
    this._TextboxElement = document.getElementById(this._TextboxElementId);
	if( !this._TextboxElement )
	{
		alert("The text box you have selected could not be found.  Please verify this item exists.");
		return;
	}
	//result text div set up
	this._ResultElement = document.getElementById(this._ResultElementId);
	if( !this._ResultElement )
	{
		alert("The result div you have selected could not be found.  Please verify this item exists.");
		return;
	}
	
	//made it here good to attach events
	
	//start input item events
	var INsdd = "GDACSGetObj('" + this._MyId + "').ShowDDLDiv()";
	GDEventHelper.Add(this._TextboxElement, "mouseover", function(){ eval(INsdd); });
	this._EventPointers.push(new Array(this._TextboxElement, "mouseover", function(){ eval(INsdd); }));
	
	var INdhd = "GDACSGetObj('" + this._MyId + "').DelayHideDDLDivWTime(200)";
	GDEventHelper.Add(this._TextboxElement, "mouseout", function(){ eval(INdhd); });
	this._EventPointers.push(new Array(this._TextboxElement, "mouseout", function(){ eval(INdhd); }));
	
	var INku = "GDACSGetObj('" + this._MyId + "').OnKeyUp()";
	GDEventHelper.Add(this._TextboxElement, "keyup", function(){ eval(INku); });
	this._EventPointers.push(new Array(this._TextboxElement, "keyup", function(){ eval(INku); }));
	
	var INkd = "GDACSGetObj('" + this._MyId + "').OnKeyDown()";
	GDEventHelper.Add(this._TextboxElement, "keydown", function(){ eval(INkd); });
	this._EventPointers.push(new Array(this._TextboxElement, "keydown", function(){ eval(INkd); }));
	
	/*onmouseover="webD.ShowDDLDiv();" onmouseout="webD.DelayHideDDLDivWTime(200)" 
	 onkeyup="webD.OnKeyUp(event)" onkeydown="webD.OnKeyDown(event)"*/
	
	//result box events
	var RBchd = "GDACSGetObj('" + this._MyId + "').ClearHideDelay()";
	GDEventHelper.Add(this._ResultElement, "mouseover", function(){ eval(RBchd); });
	this._EventPointers.push(new Array(this._ResultElement, "mouseover", function(){ eval(RBchd); }));
	
	var RBdhd= "GDACSGetObj('" + this._MyId + "').DelayHideDDLDiv()";
	GDEventHelper.Add(this._ResultElement, "mouseout", function(){ eval(RBdhd); });
	this._EventPointers.push(new Array(this._ResultElement, "mouseout", function(){ eval(RBdhd); }));
	
	//position the results box - note: expects the layout to have a real size on the text input
	var tbH = parseInt(gdAUCGetStyle(this._TextboxElementId, "height").replace("px", ""));
	var tbOff = gdAUCGetOffset(this._TextboxElementId);
	//var topOff = tbH + tbOff[1] + 5;
	var topOff = tbH + 5;
	var leftOff = tbOff[0];
	//only set left if not 0
	if( leftOff != 0 && leftOff > 0 )
	{
		this._ResultElement.style.left = leftOff + "px";
	}
	
	this._ResultElement.style.top = topOff + "px";
};

//hide the drop down
GDAutoComplete.prototype.HideDDLDiv = function()
{
    this._ResultElement.style.display = "none";
    //clear timer
    this.ClearHideDelay();
};

//set a timer to hide the drop down
GDAutoComplete.prototype.DelayHideDDLDivWTime = function(timeOut)
{
	var funCall = "GDACSGetObj('" + this._MyId + "').HideDDLDiv()";
	this._DelayHideTimer = setTimeout(funCall, timeOut); //adjust time here to make pop up stay up longer
};

//hide the drop down at fixed time
GDAutoComplete.prototype.DelayHideDDLDiv = function()
{
	this.DelayHideDDLDivWTime(this.HideDDLIn);
};

//method to show our drop down div
GDAutoComplete.prototype.ShowDDLDiv = function()
{
	if( this._ResultElement.innerHTML != "" )
	{
		this._ResultElement.style.display = "inline-block";
		this._ResultElement.style.zIndex = "50000";
		this.ClearHideDelay();
	}
	//hide all others ddls if they exist
	for ( keyVar in g_GDACSOjbects ) 
	{
		if( keyVar != this._MyId )
			GDACSGetObj(keyVar).HideDDLDiv();
	}
};

//method to stop our hide delay timer
GDAutoComplete.prototype.ClearHideDelay = function()
{
    if( this._DelayHideTimer != null )
    {
        clearTimeout(this._DelayHideTimer);
        this._DelayHideTimer = null;
    }
};

//reset the text and ddl div text
GDAutoComplete.prototype.ResetDDLInfo = function()
{
    this.HideDDLDiv();
    this._ResultElement.innerHTML = "";
    this._TextboxElement.value = "";
    this._FirstItemInList = "";
};

//set the selected text in the text box
GDAutoComplete.prototype.SelectText = function(selectedText, theId)
{
    //hide the div
    this.HideDDLDiv();
    
    //fire selected event
    if( this.OnTextSelected != null )
    	this.OnTextSelected(selectedText, theId);
};

//hover text in the drop down
GDAutoComplete.prototype.HoverText = function(elementIdNum)
{
    var hovElem = document.getElementById(this.OptionDivPre + '' + elementIdNum);
    hovElem.style.background = this.RolloverMenuColor;
    hovElem.style.color = this.RolloverAColor;
};

//hover off text in the ddl
GDAutoComplete.prototype.HoverOffText = function(elementIdNum)
{
    var hovElem = document.getElementById(this.OptionDivPre + '' + elementIdNum);
    hovElem.style.background = this.RolloffMenuColor;
    hovElem.style.color = this.RolloffAColor;
};

//handle a get key event
GDAutoComplete.prototype.GetKey = function(evt)
{
	evt = (evt) ? evt : (window.event) ? event : null;
	if (evt)
	{
		var cCode = (evt.charCode) ? evt.charCode :
				((evt.keyCode) ? evt.keyCode :
				((evt.which) ? evt.which : 0));
		return cCode; 
	}
};

//key down handler
GDAutoComplete.prototype.OnKeyDown = function(evt)
{
	//see if user is hitting enter
	if(this.GetKey(evt)==13) //Enter
	{
	    //grab the first item and make "AUTO complete" here
	    if( this._FirstItemInList != "" )
	    {
	        this._TextboxElement.value = this._FirstItemInList;
	        //hide ddl
	        this.HideDDLDiv();
	    }
	}				
	return true;
};

//get what is being typed ONKEYUP!
GDAutoComplete.prototype.OnKeyUp = function(evt)
{				
	var nKey = this.GetKey(evt);
	
	//Skip enter
	if (nKey!=13)
	{
	    if( this._TextboxElement.value.length >= this.MinSendChars && this._TextboxElement.value.length <= this.MaxSendChars )
	    {
	        var funCall = "GDACSGetObj('" + this._MyId + "').AutoComp()";
            this._DelayBeforeReqTimer = setTimeout(funCall, this.DelayBeforeRequest);
	    }
	    else if( this._TextboxElement.value.length == 0 )
	    {
	        this.ResetDDLInfo();
	    }
	}
};

//method to load up an xml doc
GDAutoComplete.prototype.LoadXMLDoc = function(postData) 
{
	//show loading?
	this._ResultElement.innerHTML =  "Loading...";     
    this.ShowDDLDiv();
	
    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) {
        this.oXmlReq = new XMLHttpRequest();
    } 
    else if (window.ActiveXObject) 
    {
        // branch for IE/Windows ActiveX version
        try {
            this.oXmlReq = new ActiveXObject("Msxml2.XMLHTTP");
        } 
        catch (e) 
        {
            try 
            {
                this.oXmlReq = new ActiveXObject("Microsoft.XMLHTTP");
            } 
            catch (E) 
            {
                this.oXmlReq = false;
            }
        }
    }
    if( this.oXmlReq )
    {
        var oThis = this; //reference to this obj to use in function
        this.oXmlReq.onreadystatechange = function(){ oThis.AutoCompDone(); };
        this.oXmlReq.open("POST", this._AjaxLocation, true);
        this.oXmlReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        this.oXmlReq.send(postData);
    }        
};

//check result XML response
GDAutoComplete.prototype.XmlResponseValid = function()
{
    if(this.oXmlReq)
    {
        if (this.oXmlReq.readyState == 4) 
        {
            if (this.oXmlReq.status == 200) 
            {
                //alert("Request return text status was:\n" + this.oXmlReq.responseText);
                return true;
            } 
            else 
            {
                 //unexpected response handle it here
                if(this._DebugIt)
                    alert("Request return text status was:\n" + this.oXmlReq.statusText + "\nText:" + this.oXmlReq.responseText);
            }
        }
    }
    return false;
};

//prepare our XML request
GDAutoComplete.prototype.AutoComp = function()
{
    //clear timers
    if( this._DelayBeforeReqTimer != null )
    {
        clearTimeout(this._DelayBeforeReqTimer);
        this._DelayBeforeReqTimer = null;
    }
    //then work with the value - since on timer make sure we still have chars to work with
    if( this._TextboxElement.value.length >= this.MinSendChars && this._TextboxElement.value.length <= this.MaxSendChars )
    {
    	var postData = this.AjaxTextBoxVar + "=" + escape(this._TextboxElement.value) + "&maxNumItemsToShow=" + this.MaxNumMenuItemsToShow;
    	//on xml request start event should be used to append any items to the post data
    	if(this.OnXMLRequestStart != null)
    		postData += this.OnXMLRequestStart();
        this.LoadXMLDoc(postData);
    }
    else if( this._TextboxElement.value.length == 0 )
    {
        this.ResetDDLInfo();
    }
};

//dispose and clean up
GDAutoComplete.prototype.Dispose = function()
{
    if( this._EventPointers != null && this._EventPointers.length > 0)
    {
        for(var i=0;i<this._EventPointers.length;i++)
        {
            GDEventHelper.Remove(this._EventPointers[i][0], this._EventPointers[i][1], this._EventPointers[i][2]);
        }
        this._EventPointers.length = 0;
    }
};

//handle the auto complete done
GDAutoComplete.prototype.AutoCompDone = function()
{
    //regardless kill our last hide timer
    this.ClearHideDelay();
    //process our request
    if (this.XmlResponseValid()) 
    {
    	//alert(this.oXmlReq.responseText); //debug here
        var xmlResponse = this.oXmlReq.responseXML.documentElement;
        
        //set up some temp vars for processing returned values
        var returnedItems = xmlResponse.getElementsByTagName("item");
        var debugDump = "";
        
        
		
        //if we have items to work with
        if( returnedItems )
        {
            var countStr = "";
            var tempOutItem = "";
            var tempOutText = "";
            this._ResultElement.innerHTML = "";
            var itemIdCount = 0;
		
            for(var i=0;i<returnedItems.length;i++)
            {
                if( returnedItems[i].firstChild )
                {
                    //wrap each item with wrapper
                    countStr = "";
                    countStr = itemIdCount.toString();
                    tempOutItem = "";
                    tempOutItem = new String(tempOutItem = returnedItems[i].getElementsByTagName("name")[0].firstChild.nodeValue);
					tempOutId = returnedItems[i].getElementsByTagName("id")[0].firstChild.nodeValue;
                    tempOutItem.replace("'", "\'");
                    //hook up our first item in the list
                    if( i == 0 )
                        this.firstItemInList = tempOutItem;
                    tempOutText += "<a href=\"javaScript:GDACSGetObj('" + this._MyId + "').SelectText('" + tempOutItem.replace("'", "\\'") + "'," + tempOutId + ");\"><div class=\"innerResult\" id=\"" + this.OptionDivPre + "" + countStr + "\" onmouseover=\"GDACSGetObj('" + this._MyId + "').HoverText(" + countStr + ");\" onmouseout=\"GDACSGetObj('" + this._MyId + "').HoverOffText(" + countStr + ");\">" + tempOutItem + "</div></a>";

                    //counter
                    itemIdCount++;
                    //debugging help here
                    /*if(this._DebugIt)
                        debugDump += returnedItems[i].getElementsByTagName("name")[0].data + "\n";*/
                }
				
				/*alert(returnedItems[i].getElementsByTagName("name")[0].firstChild.nodeValue + " " + returnedItems[i].getElementsByTagName("id")[0].firstChild.nodeValue);*/
									
				//hiddenIdElement
            }

            if( itemIdCount == 0 )
            {
                tempOutText = "No results found.";
            }

            this._ResultElement.innerHTML =  tempOutText;     
                            
            //show the divs
            this.ShowDDLDiv();
        }
		
        /*if(this.debugIt)
            alert("debug dump: " + debugDump);*/
    }
};

//events
GDAutoComplete.prototype.OnRequestComplete = null;
GDAutoComplete.prototype.OnTextSelected = null;
GDAutoComplete.prototype.OnXMLRequestStart = null;

/* end GDAutoComplete */

/* GDEventHelper
   by: randy bacon
   11/12/07
   help attach even handling to elems - static only
*/
function GDEventHelper(){}

GDEventHelper.Add = function(obj,type,fn)
{
	if (obj.attachEvent) 
	{
		obj['e'+type+fn] = fn;
		obj[type+fn] = function() { obj['e'+type+fn](window.event); };
		obj.attachEvent('on'+type,obj[type+fn]);
	} 
	else
	{
	    obj.addEventListener(type,fn,false);
    }
};

GDEventHelper.Remove = function(obj,type,fn)
{
	if (obj.detachEvent) 
	{
		obj.detachEvent('on'+type,obj[type+fn]);
		obj[type+fn] = null;
	} 
	else
	{
	    obj.removeEventListener(type,fn,false);
	}
};	
//end event helper

//globals
function gdAUCGetStyle(el,styleProp)
{
	var x = document.getElementById(el);
	if (x.currentStyle)
	var y = x.currentStyle[styleProp];
	else if (window.getComputedStyle)
	var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
	return y;
}

function gdAUCGetOffset(el)
{
	var tmpElem = document.getElementById(el);
	var leftBox = tmpElem.offsetLeft;
    var topBox = tmpElem.offsetTop;
	var obj = tmpElem.offsetParent;

	if (obj)
	{
		do {
			leftBox += obj.offsetLeft;
			topBox += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	
	var results = new Array();
	results[0] = leftBox;
	results[1] = topBox;
	
	return results;
}




