/*----------------------------------------------------------------------------
 * JavaScript for webhelp search
 *----------------------------------------------------------------------------
 This file is part of the webhelpsearch plugin for DocBook WebHelp
 Copyright (c) 2007-2008 NexWave Solutions All Rights Reserved.
 www.nexwave.biz Nadege Quaine
 http://kasunbg.blogspot.com/ Kasun Gajasinghe
 
 Lionbridge I18n: externalized search UI strings; l.158
 */

var startTimeInMillis = 0;
var endTimeInMillis = 0;

/* This function checks the validity of the search text entered by the user */
function Verifie(ditaSearch_Form) {

	var isInputValid 	= true; //stores is validation failed or not
    var errorMessage 	= '';   //stores validation error message  
	
	function chkForIE8Version(){	
		var ver = 999;	
		var isIENewVersion = true;
		if (navigator.appName == 'Microsoft Internet Explorer'){
			var ua = navigator.userAgent;
			var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
			if (re.exec(ua) != null){
				ver = parseFloat( RegExp.$1 );
			}
		}	
		if ( ver < 9.0 ){
		   isIENewVersion = false;
		}
		return isIENewVersion;	
	}
	
	if(chkForIE8Version()){
		// Check browser compatibility
		if (navigator.userAgent.indexOf("Konquerer") > -1) {
			alert(Encoder.htmlDecode(txt_browser_not_supported));
			return;
		}
		clearSearchResults();
	 
		var expressionInput = strTrim(document.ditaSearch_Form.textToSearch.value);	//trimmed user input
		var isCaseSensitive = document.ditaSearch_Form.caseSensitiveChk.checked == true ? true : false; // for case sensitive search
		var productToSearch	= document.ditaSearch_Form.productSelect.value;	 //product on which search has to be executed				
			
		// To Identify the type of search to execute
		var searchType = findSearchType(expressionInput);
		
		if (expressionInput.length < 1) { //if empty string   	
			errorMessage = txt_enter_at_least_1_char;
			isInputValid = false;
		}else if (searchType == 'phrase' && /[^ "]/.test(expressionInput) == false){ //empty phrase search
			errorMessage = txt_entered_empty_phrase;
			isInputValid = false;
		}else if(searchType != 'phrase'){
			if (/[^*?]/.test(expressionInput) == false){ // contains only wild cards
				errorMessage = txt_entered_only_wild_cards;     
				isInputValid = false;
			}else if (expressionInput.toLowerCase().indexOf('near ') == 0 || expressionInput.indexOf('fby ') == 0){ // starts with a proximity operator	
				errorMessage = txt_entered_start_with_proximity;
				isInputValid = false;
			}else if (expressionInput.toLowerCase().indexOf(' near ') != -1 && expressionInput.indexOf(' fby ') != -1){ // contains both proximity operators	
				errorMessage = txt_entered_contains_both_prox_oper;
				isInputValid = false;	
			}else if ((expressionInput.match(/ near /g)||[]).length > 1 || (expressionInput.match(/ fby /g)||[]).length > 1){ // contains multiple times the proximity operators	
				errorMessage = txt_entered_contains_multi_prox_oper;
				isInputValid = false;	
			}else if (/[^ \-]/.test(expressionInput) == false){ // contains only boolean operators		
				errorMessage = txt_entered_only_boolean_oper;     
				isInputValid = false;		
			}else if (expressionInput.toLowerCase().indexOf('or ') == 0 || expressionInput.indexOf('-') == 0){ // starts with a boolean operator		
				errorMessage = txt_entered_start_with_boolean;
				isInputValid = false;		
			}else if ((expressionInput.indexOf('*') != -1 || expressionInput.indexOf('?') != -1) && (expressionInput.indexOf('+') != -1 || expressionInput.indexOf('-') != -1 || expressionInput.indexOf(' ') != -1)){ // wild cards and boolean operator exists together		
				errorMessage = txt_entered_wildcard_and_boolean;
				isInputValid = false;   
			}
		}
	}else{
		errorMessage = txt_old_version_of_browser;
		isInputValid = false;
	}
    if(isInputValid){      	
    	if(!isCaseSensitive){
    		expressionInput = expressionInput.toLowerCase();
    	}
    	
    	//Set a cookie to store the searched keywords
    	$.cookie('textToSearch', expressionInput);		

    	// Execute the search
        Effectuer_recherche(expressionInput, productToSearch, searchType, isCaseSensitive);

        // set focus back to search text box
        document.ditaSearch_Form.textToSearch.focus();
    }else{
    	showSearchResults(Encoder.htmlDecode(errorMessage), 'error');    	     
        document.ditaSearch_Form.textToSearch.focus();
    }   		
}

/* This function parses the search expression, loads the indices and displays the results*/
function Effectuer_recherche(expressionInput, productToSearch, searchType, isCaseSensitive) {
	
	startTimeInMillis = new Date().getTime();
    var searchFor 			= ''; // to store the search string     
    var wordsList 			= new Array(); // Array of search key words to look for.    
    var fileIndexArray 		= new Object(); // hash table, key = file number, value = the content of the file as string.          
	var sortedResultsObj	= new Object(); // to store the results for all products.
	
	// get the index array based on search type (single product or multiple products)
	var searchIndexObj 	= new Object();
	var fileInfoObj 	= new Object();
	var fileIndexObj 	= new Object();
	
	if(productToSearch == 'All'){ //multiple products search
		searchIndexObj 	= globalIndexObj;
		fileInfoObj 	= globalFileInfoObj;
		fileIndexObj  	= globalFileIndexObj; 
	}else{ // product specific search
		searchIndexObj[productToSearch] = globalIndexObj[productToSearch];
		fileInfoObj[productToSearch] 	= globalFileInfoObj[productToSearch];
		fileIndexObj[productToSearch]  	= globalFileIndexObj[productToSearch];
	}
	
	// replacing the special characters in the search string  
	searchFor = replaceSpecialChar(expressionInput, true);
	
	// make an array of the search keywords	
	wordsList = searchFor.split(" ");			
	
    // code to execute the search on the index array    
    if(searchType == 'phrase'){ //phrase search      	
    	
    	// escape the special characters in the search string and remove "
    	var searchForPhrase = replaceSpecCharInPhrase(expressionInput, true);      	
    	
    	//Get the index array for each product
    	for(productId in searchIndexObj){    		
    		var resultObj 	= new Object();       		
    		fileIndexArray  = fileIndexObj[productId];	 
    		wordIndexArray 	= searchIndexObj[productId];
    		
    		//regular expression for search
    		var regExp = new RegExp(searchForPhrase, "gi");    	
    		if(isCaseSensitive){
    			regExp = new RegExp(searchForPhrase, "g"); 
    		}    			 		 		
    			
    		var isResultExists = false;
			//search for the occurrence of the phrase in each file content array
			for (var fileNo in fileIndexArray) {					
				//find the number of occurrence 				
				var count = (fileIndexArray[fileNo].match(regExp) || []).length;				
				if(count > 0){ //match exists					
					resultObj[fileNo] = count;	//count used for sorting results
					isResultExists = true;
				}									
			} 
			if(isResultExists){
				sortedResultsObj[productId] = sortObject(resultObj);				
			}
    	} 
    	
    	// get the search string without escape sequence
    	searchFor = replaceSpecCharInPhrase(expressionInput, false);
    	
    }else{ //all other word searches 
	
    	//the special characters in search text will be replaced with space
		// so re-access the search type once again
		if(searchType.indexOf(" ") != -1){
			searchType = 'boolean';    	
		}  	
   	
    	//check if stop word exist in the search text 
    	//if exists then exit search
    	if(searchType != 'wildcard'){
    		if(existsStopWords(wordsList)){
    			showSearchResults(Encoder.htmlDecode(txt_entered_stop_word), 'error'); 			
    			return; //exit search
    		}
    	}	
    	
    	if(searchType == 'wildcard'){
    		// get the matching search keywords based on wild cards
    		wordsList = getWildCardMatchingWords(wordsList, searchIndexObj, isCaseSensitive);
    		if(wordsList.length > 0){
    			expressionInput = wordsList.toString().replace(/,/g, " ");    
    		}
    	}
		
    	// Tokenize the search words 
    	//wordsList = tokenize(wordsList); 		
		
		if(searchType == 'proximity'){ //proximity search
			searchFor = replaceSpecialChar(expressionInput, false); //search string with proximity operators			
			var firstWord = '';
			var secondWord = '';
			var regExp;
			
			if(searchFor.indexOf('$') != -1){ //near 
				firstWord = searchFor.substring(0, searchFor.indexOf('$'));
				secondWord = searchFor.substring(searchFor.indexOf('$')+1, searchFor.length);
				
				//regular expression for search 
				regExp = new RegExp('(' + firstWord + '.{0,16}' + secondWord + '|' + secondWord + '.{0,16}' + firstWord + ')', "gi");   
				if(isCaseSensitive){
					regExp = new RegExp('(' + firstWord + '.{0,16}' + secondWord + '|' + secondWord + '.{0,16}' + firstWord + ')', "g");   
				}	
							
			}else{ //followed by				
				firstWord = searchFor.substring(0, searchFor.indexOf('%'));
				secondWord = searchFor.substring(searchFor.indexOf('%')+1, searchFor.length);
				
				//regular expression for search  			
				regExp = new RegExp(firstWord + '.{0,16}' + secondWord, "gi");   
				if(isCaseSensitive){
					regExp = new RegExp(firstWord + '.{0,16}' + secondWord, "g");   
				}							
			}			
			
			//Get the index array for each product
        	for(productId in searchIndexObj){    		
        		var resultObj 	= new Object();      
        		wordIndexArray 	= searchIndexObj[productId];	
        		fileIndexArray  = fileIndexObj[productId];	
    			var isResultExists = false;   		       		
				
				//search for the occurrence of the phrase in each file content array
				for (var fileNo in fileIndexArray) {					
					//find the number of occurrence 				
					var count = (fileIndexArray[fileNo].match(regExp) || []).length;				
					if(count > 0){ //match exists        					
						isResultExists = true;
						if (resultObj[fileNo] == undefined) {
							resultObj[fileNo] = count;
						} else {
							resultObj[fileNo] += count;
						}	           				
					}									
				} 	    						
    			if(isResultExists){
    				sortedResultsObj[productId] = sortObject(resultObj);    				
    			}								
        	}			
			searchFor = searchFor.replace(/\$/g, " near ");
        	searchFor = searchFor.replace(/\%/g, " fby ");
			
    }else if(searchType == 'boolean' || searchType == 'normal'){ //boolean or normal search
        	searchFor = replaceSpecialChar(expressionInput, false); //search string with boolean operators
        	
        	//build the word array for each operator
        	var andWordsArray 	= buildBooleanSearchArray(searchFor, 'AND');
        	var orWordsArray 	= buildBooleanSearchArray(searchFor, 'OR');
        	var notWordsArray 	= buildBooleanSearchArray(searchFor, 'NOT');          	
        	
        	//Get the index array for each product
        	for(productId in searchIndexObj){
        		
        		var isResultExists 	= false;
        		var resultObj 		= new Object();      
        		wordIndexArray 		= searchIndexObj[productId];	   			
        		fileIndexArray  	= fileIndexObj[productId];	
        		
    			var fileAndWordsBeforeFilter = new Object();
    			var fileAndWordsAfterFilter = new Object();	    			
    			var fileAndCount = new Object();	    
    			   			
    			//compare each search keyword in the current word array
    			for (var t in wordsList) {				
    				var currWord = wordsList[t].toString();	 		
            		
            		//regular expression for search            		
    				var regExp = new RegExp('' + currWord + '', "gi");   
            		if(isCaseSensitive){
            			regExp = new RegExp('' + currWord + '', "g");   
            		}          		
            		
            		//search for the occurrence of the phrase in each file content array
        			for (var fileNo in fileIndexArray) {					
        				//find the number of occurrence 				
        				var count = (fileIndexArray[fileNo].match(regExp) || []).length;				
        				if(count > 0){ //match exists        					   				
        					if (fileAndWordsBeforeFilter[fileNo] == undefined) {
        	    				fileAndWordsBeforeFilter[fileNo] = "" + wordsList[t];
        	    				fileAndCount[fileNo] = count;
        	    			} else {
        	    				fileAndWordsBeforeFilter[fileNo] += "," + wordsList[t];
        	    				fileAndCount[fileNo] += count;
        	    			}        					          				
            			}									
        			} 		
    			}	   			   			

    	    	//to apply the boolean conditions and filter out results
    	    	fileAndWordsAfterFilter = applyBooleanSearch(fileAndWordsBeforeFilter, andWordsArray, orWordsArray, notWordsArray);      	    	  	
    		    	
    	    	// to assign the hit count to the result
    	    	for (var fileNo in fileAndWordsAfterFilter) {       			
    				isResultExists = true;
    				resultObj[fileNo] = fileAndCount[fileNo];	       			
        		}        		
        		
            	if(isResultExists){
            		sortedResultsObj[productId] = sortObject(resultObj);
            	}
        	}
        	searchFor = searchFor.replace(/\|/g, " or ");
        	searchFor = searchFor.replace(/\^/g, " -");

        	//The NOT words are to be removed from word array
	    	for (var t in wordsList) { 
	    		for (var t1 in notWordsArray) { 
	    			if(wordsList[t] == notWordsArray[t1]){
	    				wordsList.splice(t, 1);
	    			}
	    		}
	    	}         	 
        	
        }else{ // all other word searches (wild card etc)
        	
        	//Get the index array for each product
        	for(productId in searchIndexObj){    		
        		var resultObj 	= new Object();      
        		wordIndexArray 	= searchIndexObj[productId];	
        		fileIndexArray  = fileIndexObj[productId];	
    			var isResultExists = false;    	    			
    			
    			//compare each search keyword in the current word array
    			for (var t in wordsList) {				
    				var currWord = wordsList[t].toString();	 		
            		
            		//regular expression for search
            		var regExp = new RegExp('' + currWord + '', "gi");   
            		if(isCaseSensitive){
            			regExp = new RegExp('' + currWord + '', "g");   
            		}          		
            		
            		//search for the occurrence of the phrase in each file content array
        			for (var fileNo in fileIndexArray) {					
        				//find the number of occurrence 				
        				var count = (fileIndexArray[fileNo].match(regExp) || []).length;				
        				if(count > 0){ //match exists        					
        					isResultExists = true;
            				if (resultObj[fileNo] == undefined) {
            					resultObj[fileNo] = count;
            				} else {
            					resultObj[fileNo] += count;
            				}	           				
            			}									
        			} 		
    			}			
    			if(isResultExists){
    				sortedResultsObj[productId] = sortObject(resultObj);    				
    			}				
        	}
        	searchFor = wordsList.toString().replace(/,/g, " or ");
        	//searchFor = wordsList.toString().replace(/,/g, " ");
        }        
    }     
	
    // To show the search result to User
    buildSearchResults(productToSearch, sortedResultsObj, searchFor, wordsList, fileInfoObj, searchType, isCaseSensitive);    
}

/* To apply the boolean filter on the search results*/
function applyBooleanSearch(fileAndWordsBeforeFilter, andWordsArray, orWordsArray, notWordsArray){
	
	var fileAndWordsAfterFilter = new Object();	
	
	//applying the NOT filter    		
	for (var k in fileAndWordsBeforeFilter) {
		//find all the entries that matches the NOT criteria		
		var isMatching = false;
		for (var i=0; i<notWordsArray.length; i++) {
			if (fileAndWordsBeforeFilter[k].indexOf(notWordsArray[i]) != -1) { 
				isMatching = true;
				break;					
			}
		}
		if (isMatching) {
            delete fileAndWordsBeforeFilter[k];				
        }			
	}	   	    	
	
	//applying the AND filter
	if(andWordsArray.length > 0){	    		
		for (var k in fileAndWordsBeforeFilter) {
			//find all the entries that matches the AND criteria	
			var isMatching = true;
			for (var i=0; i<andWordsArray.length; i++) {
				if (fileAndWordsBeforeFilter[k].indexOf(andWordsArray[i]) == -1) { 
					isMatching = false;
				}
			}			
			if (isMatching) {
				fileAndWordsAfterFilter[k]= fileAndWordsBeforeFilter[k];
            }
		}    	    		
		
		//applying the OR filter
		if(orWordsArray.length > 0){
    		for (var k in fileAndWordsBeforeFilter) {
    			//find all the entries that matches the OR criteria	
    			var isMatching = false;
    			for (var i=0; i<orWordsArray.length; i++) {
    				if (fileAndWordsBeforeFilter[k].indexOf(orWordsArray[i]) != -1) { 
    					isMatching = true;
    					break;	
    				}
    			}			
    			if (isMatching) {
    				fileAndWordsAfterFilter[k]= fileAndWordsBeforeFilter[k];
                }
    		}
		}
	}else{ 
		fileAndWordsAfterFilter = fileAndWordsBeforeFilter; 
	}	
	return fileAndWordsAfterFilter;
}

function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}

function replaceSpecCharInPhrase(expressionInput, escape) {
	var searchFor = expressionInput;
	if(escape){
		searchFor = escapeRegExp(searchFor);		 
	}
	searchFor = searchFor.replace(/["]/g, "");
	return searchFor;
}

/* To replacing the special characters in the search string. */
function replaceSpecialChar(expressionInput, replaceAll) {
	var searchFor = '';
	//searchFor = expressionInput.toLowerCase();
	searchFor = expressionInput;
  searchFor = searchFor.replace(/<\//g, "_st_").replace(/\$_/g, "_di_").replace(/%2C|%3B|%21|%3A|@|\//g, " ").replace(/(%20)+/g, " ").replace(/_st_/g, "</").replace(/_di_/g, "%24_");
    searchFor = searchFor.replace(/ $/, "").replace(/^ /, ""); 	    
    searchFor = searchFor.replace(/[!"#$%&()+\/;<=>@\[\\\]\^_`{|}~´„“]/g, " ");
    searchFor = searchFor.replace(/  +/g, " ");
    searchFor = searchFor.replace(/ +/g, " "); //remove multiple spaces with single space
    
    //for boolean operators
	searchFor = searchFor.replace(/ or /gi, "|"); 	
	searchFor = searchFor.replace(/ or/gi, "|"); 
	searchFor = searchFor.replace(/ - /g, "^"); 
	searchFor = searchFor.replace(/ -/g, "^"); 
	searchFor = searchFor.replace(/- /g, "-");
	//
	searchFor = searchFor.replace(/ '/g, " "); 
	searchFor = searchFor.replace(/' /g, " ");
	searchFor = searchFor.replace(/\, /g, " ");
	searchFor = searchFor.replace(/\,$/g, "");
	searchFor = searchFor.replace(/\. /g, " ");
	searchFor = searchFor.replace(/\.$/g, "");
	searchFor = searchFor.replace(/\: /g, " ");
	searchFor = searchFor.replace(/\:$/g, "");
	//searchFor = searchFor.replace(/-$/g, "");
	//searchFor = searchFor.replace(/|$/g, "");
	
	//for proximity operators 
	searchFor = searchFor.replace(/ near /gi, "$"); 
	searchFor = searchFor.replace(/ near/gi, ""); 
	searchFor = searchFor.replace(/ fby /gi, "%"); 
	searchFor = searchFor.replace(/ fby/gi, ""); 
	
    if(replaceAll){
    	searchFor = searchFor.replace(/\|/g, " "); 
    	//searchFor = searchFor.replace(/\-/g, " "); 
    	searchFor = searchFor.replace(/\^/g, " ");   
		searchFor = searchFor.replace(/\$/g, " "); 
		searchFor = searchFor.replace(/\%/g, " "); 
    }
    searchFor = strTrim(searchFor);
	return searchFor;
}

/* To Identify the type of search to execute (phrase, wild card, boolean etc) */
function findSearchType(searchFor) {
	var searchType = 'normal';	
	
    if(searchFor.length > 1 && searchFor.indexOf("\"") == 0 && searchFor.lastIndexOf("\"") == (searchFor.length-1)){ //phrase search
		searchType = 'phrase';
	}else if(searchFor.toLowerCase().indexOf("near") != -1 || searchFor.toLowerCase().indexOf("fby") != -1){ //proximity search
		searchType = 'proximity';
	}else if(searchFor.indexOf(" ") != -1){ //boolean search
		searchType = 'boolean';				
	}else if(searchFor.indexOf("?") != -1 || searchFor.indexOf("*") != -1){ // wild card search		
		searchType = 'wildcard';		
	}	
	return searchType;	
}

/* To build the search result links*/
function buildSearchResults(productToSearch, sortedResultsObj, searchFor, wordsList, fileInfoObj, searchType, isCaseSensitive) {
	
	// build the result output
    var resultLink 	= new Array();
    var isFirstTime = true;
    
    // the text to be highlighted is passed as a parameter to the calling result page
    // so replace all the spaces if any in the search text, else it will not be passed correctly
    var textToHighlight = searchType != 'phrase' ? wordsList.toString() : searchFor.replace(/ /g, "##");
    textToHighlight = encodeURIComponent(textToHighlight);
    textToHighlight = textToHighlight.replace(/'/g, "%27");
    
	for(productId in sortedResultsObj){		
		var resultArr 		= sortedResultsObj[productId]; //resultArr -> key is fileNo and value is hit count			
		var fileInfoArray	= fileInfoObj[productId]; // hash table, key = file number, value = the file info. 		
		
		if(productToSearch == 'All'){
			if(isFirstTime){
				resultLink.push("<p>&nbsp;</p>");
				isFirstTime = false;
			}
			resultLink.push("<p>" + productsObj[productId] + "</p>"); //to show the product Name			
		}
		resultLink.push("<ul class='searchresult' type='disc'>");		
		for(var fileNo=0;  fileNo<resultArr.length; fileNo++){				
			var tempInfo = fileInfoArray[resultArr[fileNo].key];
			var pos1 = tempInfo.indexOf("@@@");
			var pos2 = tempInfo.lastIndexOf("@@@");
			var tempPath = relativePath + productId + webhelpPath + tempInfo.substring(0, pos1);
			var tempTitle = tempInfo.substring(pos1 + 3, pos2);	
			resultLink.push("<li><a target='mainhelp_pane' href='" + tempPath + "?searchType=" + searchType + "&isCaseSensitive=" + isCaseSensitive + "&languageType=" + languageType + "&textToHighlight=" + textToHighlight +"'>" + tempTitle + "</a></li>");				
		}
		resultLink.push("</ul>");
	}	
	
	// (synonym search) get matching words if any to suggest to the user //
	//  works only for single word searches	
	var matchingWords = new Array();	
	var suggestedSearchLink = '';
	if(searchType == 'normal' && wordsList.length == 1){		
		matchingWords = getMatchingSynonyms(wordsList[0]); 			
	}
	
	//if matching words exists build the link
	if(matchingWords.length > 0){		
		//build the matching/corrected words links //
		suggestedSearchLink = "<p>" + txt_synonym_search_suggest + " ";		
		for(var i=0; i < matchingWords.length; i++){		
			if(i==0){
				suggestedSearchLink += '<a href="javascript:triggerSearch(\''+ matchingWords[i] +'\')">' + matchingWords[i] + '</a>';
			}else{
				suggestedSearchLink += ', <a href="javascript:triggerSearch(\''+ matchingWords[i] +'\')">' + matchingWords[i] + '</a>';
			}
		}
		suggestedSearchLink += "</p>";			
	}
	
	// apply fuzzy search to correct any spelling mistakes in the search text.		
	var newSearchText = '';
	if(matchingWords.length == 0 && searchType != 'wildcard'){			
		newSearchText = exceuteFuzzySearch(searchFor, isCaseSensitive); 
		
		//if the search text is auto corrected//
		if(newSearchText != searchFor){				
			//build the link for the corrected search text//
			suggestedSearchLink = "<p>" + txt_fuzzy_search_suggest + " ";	
			if(searchType == 'phrase'){
				suggestedSearchLink += '<a href="javascript:triggerSearch(\'' + newSearchText + '\', \'' + searchType +  '\')">"' + newSearchText + '"</a>';
			}else{
				suggestedSearchLink += '<a href="javascript:triggerSearch(\'' + newSearchText + '\', \'' + searchType +  '\')">' + newSearchText + '</a>';
			}					
			suggestedSearchLink += "</p>";			
		}
	}	
	
	//group all the results together
    var resultHtml = "";
    if (resultLink.length > 0) {    	    	
		searchForDisplay = searchFor.replace(/ or /g, '<b> OR </b>');
		searchForDisplay = searchForDisplay.replace(/ fby /g, '<b> FBY </b>');
		searchForDisplay = searchForDisplay.replace(/ near /g, '<b> NEAR </b>');
		searchForDisplay = searchForDisplay.replace(/ -/g, '<b> -</b>');
    	if(searchType == 'phrase'){
			resultHtml += "<p style='font-size:14px;'>" + txt_results_for + " <span class=\"searchExpression\">\"" + searchFor + "\"</span></p>";
		}else{
			resultHtml += "<p style='font-size:14px;'>" + txt_results_for + " <span class=\"searchExpression\">" + searchForDisplay + "</span></p>";
		} 			
    	resultHtml += suggestedSearchLink;
    	for (var t in resultLink) {
            resultHtml += resultLink[t].toString();
        }  
    	//show results in the search page
        showSearchResults(resultHtml, 'info');		
    } else {	    		
    	resultHtml = "<p style='font-size:14px;'>" +  txt_Your_Search_Returned_No_Results + "</p>";
        resultHtml += suggestedSearchLink;
        //show results in the search page
        showSearchResults(resultHtml, 'info');	
    }
    
    endTimeInMillis = new Date().getTime();
    //console.log(searchType + ": Search time in miilisecond is : " + (endTimeInMillis - startTimeInMillis));
}

/* To show the results to user */
function showSearchResults(resultHtml, messageType) {
	if(messageType == "error"){
		resultHtml = "<p style='font-size:14px; color : #FF0000;'>" + resultHtml + "</p>";
	}else{
		resultHtml = "<p>" + resultHtml + "</p>";
	}	
	document.getElementById('searchResults').innerHTML = resultHtml; 		
}

/* To clear the result list */
function clearSearchResults() {	
	document.getElementById('searchResults').innerHTML = ''; 		
}

//Invoker of CJKTokenizer class methods.
function cjkTokenize(wordsList){
    var allTokens= new Array();
    var notCJKTokens= new Array();
    var j=0;
    for(j=0;j<wordsList.length;j++){
        var word = wordsList[j];
        if(getAvgAsciiValue(word) < 127){
            notCJKTokens.push(word);
        } else { 
            var tokenizer = new CJKTokenizer(word);
            var tokensTmp = tokenizer.getAllTokens();
            allTokens = allTokens.concat(tokensTmp);
        }
    }
    allTokens = allTokens.concat(tokenize(notCJKTokens));
    return allTokens;
}

//A simple way to determine whether the query is in English or not.
function getAvgAsciiValue(word){
    var tmp = 0;
    var num = word.length < 5 ? word.length:5;
    for(var i=0;i<num;i++){
        if(i==5) break;
        tmp += word.charCodeAt(i);
    }
    return tmp/num;
}

function tokenize(wordsList){    
    var cleanwordsList = new Array(); // Array with the words to look for
    
    for (var t in wordsList) {
        wordsList[t] = wordsList[t].replace(/(%22)|^-/g, "");
        if (wordsList[t] != "%20") {           
            cleanwordsList.push(wordsList[t]);
        }
    }     
    
    return cleanwordsList;
}

//CJKTokenizer
function CJKTokenizer(input){
    this.input = input;
    this.offset=-1;
    this.tokens = new Array(); 
    this.incrementToken = incrementToken;
    this.tokenize = tokenize;
    this.getAllTokens = getAllTokens;
    this.unique = unique;

    function incrementToken(){
		if(this.input.length - 2 <= this.offset){		
			return false;
		}else {
			this.offset+=1;
			return true;
		}
	}

	function tokenize(){		
		return this.input.substring(this.offset,this.offset+2);
	}

	function getAllTokens(){
		// Liox i18n - this covers special singleton case per Lucene CJK Analyzer
 	    if (this.input.length == 1) return this.input;
		while(this.incrementToken()){
			var tmp = this.tokenize();
			this.tokens.push(tmp);
		}
        return this.unique(this.tokens);
	}

	function unique(a){
		var r = new Array();
		o:for(var i = 0, n = a.length; i < n; i++){
			for(var x = 0, y = r.length; x < y; x++){
				if(r[x]==a[i]) continue o;
			}
			r[r.length] = a[i];
		}
		return r;
	} 
}

/* This function is used to find synonyms to the keyword searched*/
function getMatchingSynonyms(word){	
	var tempSynonymArr = new Array();	
	
	for(var t in synonymsArray){		
		var synonymWordArr = synonymsArray[t].split(",");
		for(var t1 in synonymWordArr){
			if(synonymWordArr[t1] == word.toLowerCase()){ //match exists				
				tempSynonymArr = synonymsArray[t].split(",");
				break;
			}	
		}
	}
	//to remove the currently searched word from the synonym array
	for(var i=0; i<tempSynonymArr.length; i++){
		if(tempSynonymArr[i] == word.toLowerCase()){ //matching				
			tempSynonymArr.splice(i, 1);
			break;
		}		
	}		
	
	return tempSynonymArr; 
}

/* To execute search when clicked on any synonym link*/
function triggerSearch(selectedWord, searchType){	
	//set the selected synonym into the search text box
	if(searchType == 'phrase'){
		document.ditaSearch_Form.textToSearch.value = '"' + selectedWord + '"';
	}else{
		document.ditaSearch_Form.textToSearch.value = selectedWord;
	}
	var ditaSearch_Form = document.getElementById('ditaSearch_Form');	
	Verifie(ditaSearch_Form);
}

/* To check if the search string contains any stop words*/
function existsStopWords(wordsList){		
	for(var i=0; i<wordsList.length; i++){
		for(var j=0; j<stopWordsArray.length; j++){		
			if(wordsList[i].toLowerCase() == stopWordsArray[j]){ //match exists				
				if(wordsList[i].toLowerCase() != "or" || (wordsList[i].toLowerCase() == "or" && wordsList.length == 1)){
					return true;
				}				
			}
		}			
	}
	return false;
}

/* To check if the search string contains any stop words*/
function removeStopWords(wordsList){		
	var wordArray = new Array();
	var isStopWord = false;
	for(var i=0; i<wordsList.length; i++){
		isStopWord = false;
		for(var j=0; j<stopWordsArray.length; j++){		
			if(wordsList[i].toLowerCase() == stopWordsArray[j]){ //match exists				
				isStopWord = true;	
				break;
			}
		}
		if(!isStopWord){
			wordArray.push(wordsList[i]);
		}
	}
	return wordArray;
}


/* To find all matching words based on the wild card from the index array */
function getWildCardMatchingWords(wordsList, searchIndexObj, isCaseSensitive){
	var tempWordsList = new Array();
	var indexArray;
	for(productId in searchIndexObj){	
		indexArray 	= searchIndexObj[productId];
		
		//get all the key word as a string separated by commas
		var keys = [];
		for(var k in indexArray){
			keys.push(k);
		}
		var keysStr = keys.toString(); 
		
		//iterate each search key word //
		for (var t in wordsList) {	
			//if the search word contains wild card characters//
			if(wordsList[t].toString().indexOf("?") != -1 || wordsList[t].toString().indexOf("*") != -1){ 					
				//construct the regular exp for matching	
				var regExpSearchString = '' + wordsList[t].toString().replace(/\?/g, "[^,-]"); 
				regExpSearchString = regExpSearchString.replace(/\*/g, "[^,]*"); 				
				regExpSearchString += '';
				
				//regular expression for search
	    		var myRegexp = new RegExp(regExpSearchString, "gi");  	    										
				if(isCaseSensitive){
					myRegexp = new RegExp(regExpSearchString, "g");
				}
				
				//find matching words
				var matchingWordArr = keysStr.match(myRegexp);
				for(var j in matchingWordArr){
					if(!isCaseSensitive){	
						tempWordsList.push(matchingWordArr[j].toLowerCase());
					}else{
						tempWordsList.push(matchingWordArr[j]);
					}
				}				
			}
		}
	}	
	tempWordsList = unique(tempWordsList);
	return tempWordsList;
}

/* Execute fuzzy search 
(auto correct the search text in case of spelling errors) */
function exceuteFuzzySearch(searchFor, isCaseSensitive){		
	
	//replace special characters and convert the search text to lower case	
	var searchForTemp = searchFor;
	searchForTemp = replaceSpecialChar(searchForTemp, true);		
	wordsList = searchForTemp.split(" ");
	wordsList = removeStopWords(wordsList);	

	//to find the mis-spelled words //
	var nonMatchingWords = new Array();
	var wordExists = false;
	var currentWord = '';
	for(var i=0; i<wordsList.length; i++){
		wordExists = false;
		currentWord = wordsList[i].toLowerCase();
		if(currentWord != 'or' && currentWord != 'near' && currentWord != 'fby'){
			for(var t in keyWordArray){
				if(keyWordArray[t].toLowerCase() == currentWord){
					wordExists = true;
					break;
				}
			}
			if(!wordExists){
				nonMatchingWords.push(wordsList[i]);
			}
		}
	}
	
	//if non matching word exists//
	if(nonMatchingWords.length > 0){
		var fuzzyResultIndex;			
		var suggestedWord 	= '';	
		
		//find a correction word for each non matching word
		for(var i=0; i<nonMatchingWords.length; i++){	
			if(nonMatchingWords[i].length > 1){
				//return the index of the suggested words
				fuzzyResultIndex = fuzzySearch.search(nonMatchingWords[i]);				
				
				//find the most matching word from the suggested words
				suggestedWord = findTheBestMatchingWord(fuzzyResultIndex, nonMatchingWords[i]);
				if(suggestedWord != undefined && suggestedWord != ''){
					suggestedWord = matchWordCase(nonMatchingWords[i],suggestedWord);
					searchFor = searchFor.replace(nonMatchingWords[i], suggestedWord); 	
				}
			}				
		}		
	}
	return searchFor; 	
}

/* to convert the suggested words case to match the original word */
function matchWordCase(nonMatchingWord, suggestedWord){		
	var wordCase = 'lower';
	var upperChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';	
	if(upperChars.indexOf(nonMatchingWord.charAt(0)) != -1){ //check if first char is in Upper case
		wordCase = 'firstUpper';
	}
	if (upperChars.indexOf(nonMatchingWord.charAt(nonMatchingWord.length-1)) != -1){ //check if last char is in Upper case
		wordCase = 'upper';
	}
	
	var suggestedWordWithCase = ''; 
	if(wordCase == 'upper'){
		suggestedWordWithCase = suggestedWord.toUpperCase();
	}else if (wordCase == 'firstUpper'){
		suggestedWordWithCase =  suggestedWord.charAt(0).toUpperCase() + suggestedWord.slice(1);		
	}else{
		suggestedWordWithCase = suggestedWord.toLowerCase();
	}	
	return suggestedWordWithCase;
}


/* to find the most appropriate match from the suggested words */
function findTheBestMatchingWord(fuzzyResultIndex, nonMatchingWord){	
	
	var suggestedWord = '';
	
	//if correction words exists
	if(fuzzyResultIndex.length > 0){				
		/*
		// check if the length and first character(case sensitive) matches
		for(var j in fuzzyResultIndex){	
			suggestedWord = keyWordArray[fuzzyResultIndex[j]];			
			if(nonMatchingWord.charAt(0) == suggestedWord.charAt(0) && nonMatchingWord.length == suggestedWord.length){
				return suggestedWord;										
			}
		}
		
		// check if the first character(case sensitive) matches and length difference is 1
		for(var j in fuzzyResultIndex){	
			suggestedWord = keyWordArray[fuzzyResultIndex[j]];						
			if(nonMatchingWord.charAt(0) == suggestedWord.charAt(0) && Math.abs(nonMatchingWord.length - suggestedWord.length) == 1){
				return suggestedWord;
			}
		}
		
		// check if the first character(case sensitive) matches and length difference is 2
		for(var j in fuzzyResultIndex){	
			suggestedWord = keyWordArray[fuzzyResultIndex[j]];							
			if(nonMatchingWord.charAt(0) == suggestedWord.charAt(0) && Math.abs(nonMatchingWord.length - suggestedWord.length) == 2){
				return suggestedWord;
			}
		}
		
		// check if the length and first character(case insensitive) matches
		for(var j in fuzzyResultIndex){	
			suggestedWord = keyWordArray[fuzzyResultIndex[j]];								
			if(nonMatchingWord.charAt(0).toLowerCase() == suggestedWord.charAt(0).toLowerCase() && nonMatchingWord.length == suggestedWord.length){
				return suggestedWord;
			}
		}
		
		// check if the first character(case insensitive) matches and length difference is 1
		for(var j in fuzzyResultIndex){	
			suggestedWord = keyWordArray[fuzzyResultIndex[j]];									
			if(nonMatchingWord.charAt(0).toLowerCase() == suggestedWord.charAt(0).toLowerCase() && Math.abs(nonMatchingWord.length - suggestedWord.length) == 1){
				return suggestedWord;
			}
		}
		
		// check if the first character(case insensitive) matches and length difference is 2
		for(var j in fuzzyResultIndex){	
			suggestedWord = keyWordArray[fuzzyResultIndex[j]];										
			if(nonMatchingWord.charAt(0).toLowerCase() == suggestedWord.charAt(0).toLowerCase() && Math.abs(nonMatchingWord.length - suggestedWord.length) == 2){
				return suggestedWord;
			}
		}
		
		// check if length difference is 1
		for(var j in fuzzyResultIndex){	
			suggestedWord = keyWordArray[fuzzyResultIndex[j]];											
			if(Math.abs(nonMatchingWord.length - suggestedWord.length) == 1){
				return suggestedWord;
			}
		}
		
		// check if length difference is 2
		for(var j in fuzzyResultIndex){	
			suggestedWord = keyWordArray[fuzzyResultIndex[j]];												
			if(Math.abs(nonMatchingWord.length - suggestedWord.length) == 2){
				return suggestedWord;
			}
		}*/
		
		// return the first suggested word
		suggestedWord = keyWordArray[fuzzyResultIndex[0]];
		return suggestedWord;
	}	
}

/* to extract the AND, OR and NOT words from the search string */
function buildBooleanSearchArray(searchStr, operator){	
	
	var currentIndex = 0;
	var prevOperator;
	var firstOperator;
	var wordArray = new Array();	
	
	var andIndex = searchStr.indexOf(" ");
	var orIndex = searchStr.indexOf("|");
	var notIndex = searchStr.indexOf("^");	
	
	if(andIndex == -1){ andIndex = 9999; }
	if(orIndex == -1){ orIndex = 9999; }
	if(notIndex == -1){ notIndex = 9999; }	
	
	// find the first occurring boolean operator in the search string
	if(andIndex < orIndex && andIndex < notIndex){ //AND
		firstOperator = 'AND';	
		currentIndex = andIndex;
	}else if(orIndex < andIndex && orIndex < notIndex){ //OR			
		firstOperator = 'OR';		
		currentIndex = orIndex;
	}else{ //NOT			
		firstOperator = 'NOT';		
		currentIndex = notIndex;
	}
	
	//Eg if search string is "system-using" here system should go to OR array and using should go to NOT array
	var tempWord = searchStr.substring(0, currentIndex);
	if(strTrim(tempWord) != ''){
		if((firstOperator == 'NOT' && operator == "OR") || (firstOperator != 'NOT' && firstOperator == operator)){ 
			wordArray.push(tempWord);
		}
	}		
	searchStr = searchStr.substring((currentIndex +1), searchStr.length);
	prevOperator =	firstOperator;
	
	// iterate through the search string
	while(searchStr.length > 0){
		andIndex = searchStr.indexOf(" ");
		orIndex = searchStr.indexOf("|");
		notIndex = searchStr.indexOf("^");	
		
		if(andIndex == -1){ andIndex = 9999; }
		if(orIndex == -1){ orIndex = 9999; }
		if(notIndex == -1){ notIndex = 9999; }
		
		if(andIndex != 9999 || orIndex != 9999 || notIndex != 9999){
			
			// find the first occurring boolean operator in the search string
			if(andIndex < orIndex && andIndex < notIndex){ //AND
				firstOperator = 'AND';	
				currentIndex = andIndex;
			}else if(orIndex < andIndex && orIndex < notIndex){ //OR			
				firstOperator = 'OR';		
				currentIndex = orIndex;
			}else{ //NOT			
				firstOperator = 'NOT';		
				currentIndex = notIndex;
			}			
			
			if(operator == prevOperator){
				var tempWord = searchStr.substring(0, currentIndex);
				if(strTrim(tempWord) != ''){
					wordArray.push(tempWord);
				}
			}							
			searchStr = searchStr.substring((currentIndex + 1), searchStr.length);	
			prevOperator =	firstOperator;	
		}else{
			if(strTrim(searchStr) != "" && operator == prevOperator){
				wordArray.push(searchStr);
			}
			searchStr = "";
		}
	}	
	return wordArray;
	
}

/* To sort the result based on the hit count */
function sortObject(obj) {
    //create an array from object	
	var arr = [];
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {            
			arr.push({
                'key': prop,
                'value': obj[prop]
            });
        }
    }
	
	//sort the array based on the value (hit count) in descending corder
    arr.sort(function(a, b) { return b.value - a.value; });   
	
	// returns the sorted array
	return arr;
}

/* To the spaces before and after the text */
function strTrim(txtToTrim){
	return txtToTrim.replace(/^\s+|\s+$/gm,'');
}
