
/**
 * An autosuggest textbox control.
 * @class
 * @scope public
 */
function AutoSuggestControl(oTextbox /*:HTMLInputElement*/, 
                            oProvider /*:SuggestionProvider*/) {
    
    /**
     * The currently selected suggestions.
     * @scope private
     */   
    this.cur /*:int*/ = -1;

    /**
     * The dropdown list layer.
     * @scope private
     */
    this.layer = null;
    
    /**
     * Suggestion provider for the autosuggest feature.
     * @scope private.
     */
    this.provider /*:SuggestionProvider*/ = oProvider;
    
    /**
     * The textbox to capture.
     * @scope private
     */
    this.textbox = document.getElementById("autoSuggestBox");
    //this.textbox /*:HTMLInputElement*/ = oTextbox;
    
    //initialize the control
    this.init();
    
}
var enableBlur=true;
var browser=navigator.appName;

/**
 * Autosuggests one or more suggestions for what the user has typed.
 * If no suggestions are passed in, then no autosuggest occurs.
 * @scope private
 * @param aSuggestions An array of suggestion strings.
 * @param bTypeAhead If the control should provide a type ahead suggestion.
 */
AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/,
                                                     bTypeAhead /*:boolean*/) {
    
    //make sure there's at least one suggestion
    if (aSuggestions.length > 0) {
        if (bTypeAhead) {
           //this.typeAhead(aSuggestions[0]);
        }
        
        this.showSuggestions(aSuggestions);
    } else {
        this.hideSuggestions();
    }
};

/**
 * Creates the dropdown layer to display multiple suggestions.
 * @scope private
 */
AutoSuggestControl.prototype.createDropDown = function () {

    var oThis = this;
		
    //create the layer and assign styles
    this.layer = document.createElement("div");
    this.layer.className="autosuggest";
    
    this.layer.style.visibility = "hidden";    
    
    //when the user clicks on the a suggestion, get the text (innerHTML)
    //and place it into a textbox
    this.layer.onmousedown = 
    this.layer.onmouseup = 
    this.layer.onmouseover = function (oEvent) {
        oEvent = oEvent || window.event;
        oTarget = oEvent.target || oEvent.srcElement;
        if (oEvent.type == "mousedown") {
            var selection=oTarget.firstChild.nodeValue;
            if (oTarget.selection!="" && selection!=null && selection!="null")
            {
                oThis.textbox.value = selection;
                oThis.hideSuggestions();
                DoAutoSuggestQuery(oThis.textbox.value);
                if(oEvent.cancelBubble)
                {
                oEvent.cancelBubble = true
                }
                else
                {
                    if (oEvent.stopPropagation){
                        oEvent.stopPropagation();
                    }
                }

                //scroll to box
                window.scrollTo(0,findPosY(oThis.textbox));
             }
             else{
                enableBlur=false;
             }
        } else if (oEvent.type == "mouseover") {
            oThis.highlightSuggestion(oTarget);
        } else {
            oThis.textbox.focus();
        }
    };
    
    this.layer.onblur=function(){
       if (browser=="Microsoft Internet Explorer"){
        if (enableBlur){
            oThis.hideSuggestions();
            }
            enableBlur=true;
        }
        else{
            oThis.hideSuggestions();
        }
    };
    
    this.textbox.parentNode.appendChild(this.layer);
};

/**
 * Handles three keydown events.
 * @scope private
 * @param oEvent The event object for the keydown event.
 */
AutoSuggestControl.prototype.handleKeyDown = function (oEvent /*:Event*/) {

    switch(oEvent.keyCode) {
        case 27: // escape
            this.hideSuggestions();
            break;
        case 38: //up arrow
            this.previousSuggestion();
            break;
        case 40: //down arrow 
            this.nextSuggestion();
            break;
        case 13: //enter
            this.hideSuggestions();
            break;
    }

};

/**
 * Handles keyup events.
 * @scope private
 * @param oEvent The event object for the keyup event.
 */
AutoSuggestControl.prototype.handleKeyUp = function (oEvent /*:Event*/) {

    var iKeyCode = oEvent.keyCode;

    //for backspace (8) and delete (46), shows suggestions without typeahead
    if (iKeyCode == 8 || iKeyCode == 46 ) {
        this.provider.requestSuggestions(this, false);
        this.cur = -1;
    //make sure not to interfere with non-character keys
    } else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode < 46) || (iKeyCode >= 112 && iKeyCode <= 123)) {
        //ignore
    } else {
        //request suggestions from the suggestion provider with typeahead
        this.provider.requestSuggestions(this, true);
    }
};

/**
 * Hides the suggestion dropdown.
 * @scope private
 */
AutoSuggestControl.prototype.hideSuggestions = function () {
    this.layer.style.visibility = "hidden";
    this.layer.innerHTML = "";
};

/**
 * Highlights the given node in the suggestions dropdown.
 * @scope private
 * @param oSuggestionNode The node representing a suggestion in the dropdown.
 */
AutoSuggestControl.prototype.highlightSuggestion = function (oSuggestionNode) {
    
    for (var i=0; i < this.layer.childNodes.length; i++) {
        var oNode = this.layer.childNodes[i];
        if (oNode == oSuggestionNode) {
            oNode.className = "current"
        } else if (oNode.className == "current") {
            oNode.className = "";
        }
    }
};

/**
 * Initializes the textbox with event handlers for
 * auto suggest functionality.
 * @scope private
 */
AutoSuggestControl.prototype.init = function () {

    //save a reference to this object
    var oThis = this;
    
    //assign the onkeyup event handler
		if ( this.textbox != null ) {
    this.textbox.onkeyup = function (oEvent) {
    
        //check for the proper location of the event object
        if (!oEvent) {
            oEvent = window.event;
        }    
        
        //call the handleKeyUp() method with the event object
        oThis.handleKeyUp(oEvent);
    };
    
    //assign onkeydown event handler
    this.textbox.onkeydown = function (oEvent) {
    
        //check for the proper location of the event object
        if (!oEvent) {
            oEvent = window.event;
        }    
        
        //call the handleKeyDown() method with the event object
        oThis.handleKeyDown(oEvent);
    };
    
    //assign onblur event handler (hides suggestions)    
    this.textbox.onblur = function () {
    if (browser=="Microsoft Internet Explorer"){
        if (enableBlur){
            oThis.hideSuggestions();
            }
            enableBlur=true;
        }
        else{
            oThis.hideSuggestions();
        }
    };
    
    //create the suggestions dropdown
    this.createDropDown();
        
	}
};

/**
 * Highlights the next suggestion in the dropdown and
 * places the suggestion into the textbox.
 * @scope private
 */
AutoSuggestControl.prototype.nextSuggestion = function () {
    var cSuggestionNodes = this.layer.childNodes;
    if (cSuggestionNodes.length > 0 && this.cur < cSuggestionNodes.length-1) {
        var oNode = cSuggestionNodes[++this.cur];
        this.highlightSuggestion(oNode);
        this.textbox.value = oNode.firstChild.nodeValue; 
        this.layer.scrollTop = oNode.offsetTop - 20;
    }
};

/**
 * Highlights the previous suggestion in the dropdown and
 * places the suggestion into the textbox.
 * @scope private
 */
AutoSuggestControl.prototype.previousSuggestion = function () {
    var cSuggestionNodes = this.layer.childNodes;

    if (cSuggestionNodes.length > 0 && this.cur > 0) {
        var oNode = cSuggestionNodes[--this.cur];
        this.highlightSuggestion(oNode);
        this.textbox.value = oNode.firstChild.nodeValue;   
        this.layer.scrollTop = oNode.offsetTop - 20;
    }
};

/**
 * Selects a range of text in the textbox.
 * @scope public
 * @param iStart The start index (base 0) of the selection.
 * @param iLength The number of characters to select.
 */
AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iLength /*:int*/) {

    //use text ranges for Internet Explorer
    if (this.textbox.createTextRange) {
        var oRange = this.textbox.createTextRange(); 
        oRange.moveStart("character", iStart); 
        oRange.moveEnd("character", iLength - this.textbox.value.length);      
        oRange.select();
        
    //use setSelectionRange() for Mozilla
    } else if (this.textbox.setSelectionRange) {
        this.textbox.setSelectionRange(iStart, iLength);
    }     

    //set focus back to the textbox
    this.textbox.focus();      
}; 

/**
 * Builds the suggestion layer contents, moves it into position,
 * and displays the layer.
 * @scope private
 * @param aSuggestions An array of suggestions for the control.
 */
AutoSuggestControl.prototype.showSuggestions = function (aSuggestions /*:Array*/) {
    
    var oDiv = null;
    this.layer.innerHTML = "";  //clear contents of the layer
    this.layer.className = "autosuggest";
    if (browser != "Microsoft Internet Explorer"){
        this.layer.className+=" autosuggestMarginTop";
    }
    if (aSuggestions.length > 10){
        this.layer.className += " autosuggestFixedSize";
        if (browser != "Microsoft Internet Explorer"){
            this.layer.className += " autosuggestFixedSizeMozilla";
        }
    }
    for (var i=0; i < aSuggestions.length; i++) {
        oDiv = document.createElement("div");
        if (aSuggestions.length <= 10) 
			oDiv.style.width = "150px";
        oDiv.appendChild(document.createTextNode(aSuggestions[i]));
        this.layer.appendChild(oDiv);
    }
    this.layer.style.visibility = "visible";
    //this.layer.style.height = (aSuggestions.length * 12 > 100) ? "100px" : aSuggestions.length * 12 + "px";
};

/**
 * Inserts a suggestion into the textbox, highlighting the 
 * suggested part of the text.
 * @scope private
 * @param sSuggestion The suggestion for the textbox.
 */
AutoSuggestControl.prototype.typeAhead = function (sSuggestion /*:String*/) {

    //check for support of typeahead functionality
    if (this.textbox.createTextRange || this.textbox.setSelectionRange){
        var iLen = this.textbox.value.length; 
        this.textbox.value = sSuggestion; 
        this.selectRange(iLen, sSuggestion.length);
    }
};


function WordSuggestions() {
	/*
		The 'AutoSuggestOptions' array is context dependent and is dynamically generated 
		in the "options_xxx.js" file.
		*/
	this.MyAutoSuggestOptions = AutoSuggestOptions;
	this.specialCharactersArray=AutoSuggestNormalize;
 
}

/**
 * Request suggestions for the given autosuggest control.
 * @scope protected
 * @param oAutoSuggestControl The autosuggest control to provide suggestions for.
 */
WordSuggestions.prototype.requestSuggestions = function (oAutoSuggestControl /*:AutoSuggestControl*/,
                                                          bTypeAhead /*:boolean*/) {
    var aSuggestions = [];
    var sTextboxValue = oAutoSuggestControl.textbox.value;

    if (sTextboxValue.length > 0){

        //search for matching words
        for (var i=0; i < this.MyAutoSuggestOptions.length; i++) {
            if ((this.specialCharactersArray[i].toLowerCase().indexOf(sTextboxValue.toLowerCase()) == 0)||(this.MyAutoSuggestOptions[i].toLowerCase().indexOf(sTextboxValue.toLowerCase()) == 0)) {
                aSuggestions.push(this.MyAutoSuggestOptions[i]);
            }
        }
    }

    //provide suggestions to the control
    oAutoSuggestControl.autosuggest(aSuggestions, bTypeAhead);
};


/*
	Initializes the autosuggest textbox.
*/
function InitAutoSuggest()
{	
	var oTextbox = new AutoSuggestControl(document.getElementById("autoSuggestBox"), new WordSuggestions());	
}

function OnAutoSuggestSubmit()
{
	var SearchParam;
		
	SearchParam = document.getElementById("autoSuggestBox").value;
	if (SearchParam)
	{
	    DoAutoSuggestQuery(SearchParam);
	}
}

/*
	Call this function to extend the current navigation query with a search.
*/
function OnAutoSuggestKeyPress(e)
{  
  var OriginalQueryString;
  var NewQueryString;
  var SearchParam;
        
  if ( window.event && window.event.keyCode == 13 )
  {
    var autoSuggestBox = document.getElementById("autoSuggestBox")
    SearchParam = autoSuggestBox.value;
    autoSuggestBox.focus()
  }
  else if ( e && e.which == 13)
  {
    var autoSuggestBox = document.getElementById("autoSuggestBox")
    SearchParam = autoSuggestBox.value;
    autoSuggestBox.focus()
   }
  else
    return true;
  if (SearchParam!=null)
  {
    DoAutoSuggestQuery(SearchParam);
  }
  
  return false;
}

/*
  This method trims the input string. The spaces at the beginning and end are removed
*/
function trim(str)
{
   return str.replace(/^\s*|\s*$/g,"");
}

/*
	This function extends the current Endeca navigation query with the term provided
	in the searchParam argument.
*/
function DoAutoSuggestQuery(searchParam)
{
		var SearchParam;
		var ResetLink;
		
		// Take the exact name that came from endeca
		for (i=0; i<AutoSuggestOptions.length; i++)
			if (AutoSuggestOptions[i] == searchParam)
			{
				searchParam = AutoSuggestOptionsRaw[i];
				break;
			}
									
		// Add a wildcard to the end
		SearchParam = escape(searchParam) + "*";
		
		// Get the original query string
		OriginalQueryString = GetOriginalENEQueryString(); // GetOriginalENEQueryString() is defined in Atlas_Endeca.js
	    
	    if (searchParam=="")
	    {
	        EntityQuery(OriginalQueryString);
	    }
	    else
	    {
	        // Check if the auto suggest settings are registered on the page, otherwise do nothing	    
	        if (typeof(AutoSuggestSettings) == 'undefined' || AutoSuggestSettings == null) return;
	    	    
		    // Is there already a search in the query string?
	        if (OriginalQueryString.indexOf("&Ntk=" + AutoSuggestSettings.SearchKey) > 0)
		    {
			    // Replace the active search term with the new one (the regex 'Ntt=[^&]*' matches any character except "&".)
			    NewQueryString = OriginalQueryString.replace(/Ntt=[^&]*/, "Ntt=" + SearchParam);				
		    }		
		    else 
		    {
    			// Add the search term
		    	NewQueryString = OriginalQueryString + "&Ntk=EntityName" + "&Ntt=" + SearchParam + "&Ntx=mode+matchall";
	    		// Add the first letter dim key
	    		NewQueryString =  SetFirstLetterDimensionKey(SearchParam, NewQueryString);
		    }		
		
		    // Set the sort key (SetSortKey is defined in Atlas_Endeca.js)
		    NewQueryString = SetSortKey(NewQueryString, AutoSuggestSettings.SortKey, true);
		
		    // Perform the query
		    EntityQuery(NewQueryString);
		}
}

/*
	This function includes in a given endeca querystring the dimension key of the first letter in search param
*/
function SetFirstLetterDimensionKey(searchParam, queryString)
{
	// get the first letter
	var firstSearchParamLetter = searchParam.substring(0, 1);
	// this array contains the endeca first letter key for each of the alfabet letters
	var letterArray = AutoSuggestSettings.FirstLetterArray;
	var letterItem;
	var firstLetterDimKey = '';
	
	// identify endeca key for the given letter
	for (i=1; i<letterArray.length; i++)
	{
		// letterArray[i] = '<endecaDim>, <letter>'
		letterItem = letterArray[i].split(',');
		if (letterItem[1].toLowerCase() == firstSearchParamLetter.toLowerCase())
		{
			firstLetterDimKey = letterItem[0];
			break;
		}
	}
	
	// include the new dimension to the endeca query
	if (firstLetterDimKey != '') 
		queryString = queryString.replace(/N=/, "N=" + firstLetterDimKey + "+");
	
	return queryString;
}

/*
	Removes the current autosuggest term from the navigation query and clears
	the text box.
*/
function ClearAutoSuggest()
{	
	// Clear the text box
	document.getElementById("autoSuggestBox").value = "";
	
	ResetLink = document.getElementById("clearAutoSuggest");
	// don't show the resetLink
	ResetLink.style.visibility = "";
	
	// And reset the query
	ResetEntityQuery();		
}

function findPosY(obj)
{
	var curtop = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	else if (obj.y)
		curtop += obj.y;
	return curtop;
}

/*
	Attach the InitAutoSuggest() function to the body onload event.
	'addLoadEvent' can be found in "General_it31.js".
*/
addLoadEvent(InitAutoSuggest);



