﻿// Reference Below Provides Intellisense in Visual Studio 2008
/// <reference path="RealAge.Utils.js"/>

/*** SEARCH AUTO COMPLETE CLASS ***
   
   Created by: Jay Baugh on 06/30/2008
   
   Parameters:
   
   strTextBoxId: The id of the textbox to attach auto complete funcionality

   strOverlayId: The id of the overlay div that will contain the autocomplete list

   strBaseUrl: The base URL of the webservice that will be called to obtain match list.

   intMaxResults: Maximum number of results to return.

   autoSubmitForm: If true, forces form submit when selection is made.
   
*/

// Declare RealAge.Controls Namespace
RealAge.Utils.declareNamespace("RealAge.Controls");

// Declare RealAge.Controls.SearchAutoComplete Class
RealAge.Controls.SearchAutoComplete = function(strTextBoxId, strBaseUrl, intMaxResults, boolAutoSubmit) 
{
    ///<summary>Search Auto Complete Class</summary>

    // PRIVATE VARIABLES:
    var eTextBox; 
    var eOverlay; 
    var eOverlayMask;
    
    var eTextBoxId        = strTextBoxId;
    var eOverlayId        = "autocomplete_" + strTextBoxId;
    var eOverlayMaskId    = eOverlayId + "_mask";
    
	var XmlHttp = RealAge.Utils.CreateXmlHttp();
	var termList = new Array();
    var selectedRow = -1;
    var autoSubmit = boolAutoSubmit;
    var maxResults = intMaxResults;
    var currentTimer;
    
    // Create local reference to "this" instance.
    // The "me" is used to restore the "this" instance when
    // we can't use createDelegate (as with some mouse events)
    var me = this; 

    // Public Properties and Methods
    this.WebServiceUrl = strBaseUrl + "App_Controls/Content/SearchAutoComplete.asmx/GetCompletionList";

    // Auto Complete is active
    this.enabled    = true;
    this.minWidth   = 208;

	this.load = function()
	{
        ///<summary>Initializes Search Auto Complete</summary>

        eTextBox = document.getElementById(eTextBoxId);
        
        // Verify That Textbox Exists
	    if(eTextBox)
	    {
            this.createOverlayElement();
            
   	        eOverlay        = document.getElementById(eOverlayId);
   	        eOverlayMask    = document.getElementById(eOverlayMaskId);

	        // Set Up Events
	        RealAge.Utils.addEvent(eTextBox, "keydown", RealAge.Utils.createDelegate(this, this.keyDownHandler) );
   	        RealAge.Utils.addEvent(eTextBox, "keyup", RealAge.Utils.createDelegate(this, this.keyUpHandler));
   	        RealAge.Utils.addEvent(eTextBox, "blur", RealAge.Utils.createDelegate(this, this.blurHandler));
        }   	    
	}
	
	this.createOverlayElement = function()
	{
        ///<summary>Adds DIV used for overlay to document.</summary>
	    var node = document.createElement("div");
	    node.id = eOverlayId;
	    node.className = "SearchAutoComplete";
	    node.setAttribute("class", "SearchAutoComplete");
	    document.body.appendChild(node);

        node = null;
	    
	    node = document.createElement("iframe");
	    node.id = eOverlayMaskId;
	    node.setAttribute("frameborder", 0);
	    node.className = "SearchAutoComplete_Mask";
	    node.setAttribute("class", "SearchAutoComplete_Mask");
	    document.body.appendChild(node);

	}

    this.keyDownHandler = function(event)
    {
        if(event.keyCode == 38) /* Arrow Up */ 
        { 
            var newIndex = selectedRow - 1;
            if(newIndex < -1) newIndex = termList.length-1;
            this.selectionChanged(newIndex);
        }
        else if(event.keyCode == 40) /* Arrow Down */ 
        { 
            var newIndex = selectedRow + 1;
            if(newIndex >= termList.length) newIndex = -1;
            this.selectionChanged(newIndex);
        }
        else if((event.keyCode == 8) || (event.keyCode == 46))
        {
            this.hideOverlay();
        }
        else if((event.keyCode == 9) || (event.keyCode == 13))
        { 
           /* tab or return pressed so click term */ 
           this.termClicked(selectedRow); 
        }
    }
    
    this.rowSelected = function(rowIndex)
    {
        selectedRow = rowIndex;
        this.drawTermList();
    }
	
    this.keyUpHandler = function(event)
    {
        // Don't make Ajax call if it's an arrow key
        if ((event.keyCode != 38) && 
            (event.keyCode != 40) && 
            (event.keyCode != 39) && 
            (event.keyCode != 37))   
        {
            // Clear previous timeout (if there is one)
            if(currentTimer) window.clearTimeout(currentTimer);
            
            // Using a timer dramatically reduces the load on the server by only making a call to
            // the server once the user stops typing. (Rather than calling for each keystoke.)
            currentTimer = window.setTimeout(RealAge.Utils.createDelegate(this, this.performAutoComplete), 375);
        }
    }

    // Hide Overlay onBlur
    this.blurHandler = function() { this.hideOverlay(); }

    this.performAutoComplete = function()
    {
        ///<summary>Uses Ajax to call webservice to retrieve matching word list.</summary>
        var entryText = eTextBox.value;
        
        if((this.enabled) && (entryText != ""))
        {
            try
            {
		        if (XmlHttp) 
		        {	
		            // Abort Existing XmlHttp Request
		            if((XmlHttp.readyState > 0) && (XmlHttp.readyState < 4)) XmlHttp.abort();
		            
			        XmlHttp.open('POST', this.WebServiceUrl , true);
			        XmlHttp.onreadystatechange = RealAge.Utils.createDelegate(this, this.AjaxResultSuccessful);			
    			    
			        // Request JSON Response Type
			        XmlHttp.setRequestHeader('Content-Type', 'application/json');
    			    
			        // Send Parameters in JSON Format
			        XmlHttp.send('{"matchText":"' + entryText +'","maxResults":' + maxResults + '}'); 
                }
             }
             catch(ex) 
             { /* Error Occured */ 
                this.XmlHttpError();
             }
             
         }
         else
         {
            this.hideOverlay();   
         }
    }
    
    this.AjaxResultSuccessful = function(strResult)
    {
        if (XmlHttp.readyState == 4) 
        {
            if (XmlHttp.status == 200)
            {
                eOverlay.innerHTML = "";

                // Set termList to empty string as default
                termList = "";
                
                try 
                {
                    termList = eval(XmlHttp.responseText);
                }
                catch(ex)
                {
                    // Error Occured in Response Eval
                }
                
                selectedRow = -1; // Set No Item Selected as default
                this.drawTermList();
                this.displayOverlay();
            }
        }
    }

    this.XmlHttpError = function()
    {   
        try
        { 
            this.hideOverlay();
        }
        catch(ex) { /* Error Occured Outputing Error */ }
    }
    
    this.selectionChanged = function(newIndex)
    {
        if(eOverlay.hasChildNodes())
        {
            if(selectedRow >= 0) eOverlay.childNodes[selectedRow].className    = "SearchAutoComplete_Row";
            if(newIndex >= 0)    eOverlay.childNodes[newIndex].className       = "SearchAutoComplete_RowSelected";
            
            // If there is an error parsing the int, set 0 as default
            try { selectedRow = parseInt(newIndex); }
            catch(ex) { /* Error Parsing Int */ };
        }
    }
    
    this.termClicked = function(termIndex)
    {
        ///<summary>Handles term clicked. Sets "M" tracking value and auto submits form, if desired.</summary>

        // Verify there is an actual term selected
        if((termIndex >= 0) && (typeof(termList[termIndex]) != "undefined"))
        {
            // Populate Textbox with term, and hide overlay
            eTextBox.value = termList[termIndex];
            this.hideOverlay();
            
            // Set Tracking Value to 6 = Autocomplete Used
            var topForm = document.getElementById("SearchForm");
            var lowForm = document.getElementById("LowerSearchForm");
            if(topForm) RealAge.Utils.getElementByIdWithin("m", topForm).value = 6;
            if(lowForm) RealAge.Utils.getElementByIdWithin("m", lowForm).value = 6;
            
            // Automatically Submit Form When Term Selected (if desired)
            if (autoSubmit) 
            {
                // Disable Auto Complete While Posting
                this.enabled = false; 

                eTextBox.form.submit();
            }
        }
        else
        {
            // Set Tracking M Value to 1 = Autocomplete not used
            var topForm = document.getElementById("SearchForm");
            var lowForm = document.getElementById("LowerSearchForm");
            if(topForm) RealAge.Utils.getElementByIdWithin("m", topForm).value = 1;
            if(lowForm) RealAge.Utils.getElementByIdWithin("m", lowForm).value = 1;
        }
    }

    // Called as Static (Instance is lost, me restores instance.)
    this.termMouseOver = function() 
    { 
        var termIndex = this.id.substring(5, this.id.length);
        me.selectionChanged.call(me, termIndex); // Restores "this"
    }
    
    // Called as Static
    this.termMouseDown = function()
    {
        var termIndex = this.id.substring(5, this.id.length);
        me.termClicked.call(me, termIndex); // Restores "this"
    }
    
    this.drawTermList = function()
    {
        var i; // Number or Terms
        
        if((this.enabled) && (typeof(termList) != "undefined"))
        {
            // Clear Child Nodes (if any)
            if(eOverlay.hasChildNodes()) eOverlay.closeNode(false);
			
			var divNode;
			
			// Create Node
            for(i=0;i<termList.length;i++)
            {
                divNode = document.createElement("div");
                var test = RealAge.Utils.createDelegate(this, this.selectionChanged, 3);

                // Add Static Events to Node
                divNode.onmouseover = this.termMouseOver;          
                divNode.onmousedown = this.termMouseDown;
                
			    if(i == selectedRow) divNode.className = "SearchAutoComplete_RowSelected";
			    else                 divNode.className = "SearchAutoComplete_Row";

                // Put term text in node
			    divNode.innerHTML = termList[i];
                
                // Give ID to node
                divNode.id = "term_" + i;
                
                // Add Node to DOM
                eOverlay.appendChild(divNode);
            }
            
        }
        
        // Show Term List if there are terms, hide otherwise
        if(i > 0) this.showOverlay();
        else this.hideOverlay();

    }

    this.showOverlay = function()
    {
        RealAge.Utils.showElement(eOverlay);
        RealAge.Utils.showElement(eOverlayMask);
    }

    this.hideOverlay = function() 
    { 
        RealAge.Utils.hideElement(eOverlay); 
        RealAge.Utils.hideElement(eOverlayMask); 
    }

    this.displayOverlay = function()
    {
        // Set Position of Overlay
        var textBoxBounds = RealAge.Utils.getBounds(eTextBox);
        
        // Reset Width to Auto (for auto sizing)
        eOverlay.style.width = "auto";
        
        RealAge.Utils.setPosition(eOverlay, textBoxBounds.x, textBoxBounds.y + textBoxBounds.height);
        
        // Don't allow size to be smaller than minWidth
        var overlayWidth = RealAge.Utils.getWidth(eOverlay);
        if(overlayWidth < this.minWidth) RealAge.Utils.setWidth(eOverlay, this.minWidth);

        // Set Position of Overlay Mask
        var overlayBounds = RealAge.Utils.getBounds(eOverlay);
        RealAge.Utils.setBounds(eOverlayMask, overlayBounds.x, overlayBounds.y, overlayBounds.width, overlayBounds.height);
    }
    
	// Register Class
    RealAge.Utils.registerClass(this, arguments);

}
