/*

 David Cramer
 <david AT thingbag DOT net>

 Kasun Gajasinghe
 <kasunbg AT gmail DOT com>

 Copyright © 2008-2012 Kasun Gajasinghe, David Cramer

 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

 1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

 2. Except as contained in this notice, the names of individuals credited with contribution to this software shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the individuals in question.

 3. Any stylesheet derived from this Software that is publicly distributed will be identified with a different name and the version strings in any derived Software will be changed so that no possibility of confusion between the derived package and this Software will exist.

 Warranty: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL DAVID CRAMER, KASUN GAJASINGHE, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 */


/*
 List of modifications added by the Oxygen Webhelp plugin:

 1. Make sure the space-separated words from the search query are
 passed to the search function realSearch() in all cases (the
 total number of words can be less than or greater than 10 words).

 2. Accept as valid search words a sequence of two words separated
 by ':', '.' or '-'.

 3. Convert the search query to lowercase before executing the search.

 4. Do not omit words between angle brackets from the title of the
 search results.

 5. Normalize search results HREFs and add '#' for no-frames webhelp

 6. Keep custom footer in TOC after searching some text

 7. Accept as valid search words that contains only 2 characters

 */

/*
 HP Modifications
 Changed the search function to use HP's custom search including phrase, proximity, wildcard. All HP functions are prefaced with hp_
 searchRequest is the entry point
 */

// Return true if "word1" starts with "word2"
function startsWith(word1, word2) {
    var prefix = false;
    if (word1 !== null && word2 !== null) {
        if (word2.length <= word1.length) {
            prefix = true;
            for (var i = 0; i < word2.length; i++) {
                if (word1.charAt(i) !== word2.charAt(i)) {
                    prefix = false;
                    break;
                }
            }
        }
    } else {
        if (word1 !== null) {
            prefix = true;
        }
    }
    return prefix;
}


if (!("console" in window) || !("firebug" in console)) {
    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
    window.console = {};
    for (var i = 0, len = names.length; i < len; ++i) {
        window.console[names[i]] = function () {
        };
    }
}

function logLocal(msg){
  console.log(msg);
}

if (typeof debug !== 'function') {
    function debug(msg, obj) {
        if ( withFrames ){
          if (typeof parent.debug !== 'function') {
            logLocal(msg);
          }else{
            if (typeof msg!=="undefined"){
              if (typeof msg==="object"){
                parent.debug('['+src+']',msg);
              }else{
                parent.debug('['+src+']'+msg,obj);
              }
            }
          }
        }else{
          logLocal(msg);
        }
    }
}

var useCJKTokenizing = false;

var w = {};

var searchTextField = '';
var no = 0;
var noWords = [];
var partialSearch1 = "There is no page containing all the search terms.";
//var partialSearch2 = "Partial results:";
var partialSearch2 = "Excluded terms:";
var warningMsg = '<div style="padding: 5px;margin-right:5px;;background-color:#FFFF88;">';
warningMsg += '<b>Chrome does not highlight WebHelp search results.</b><br><br>';
warningMsg += 'This happens when the WebHelp files are loaded from the local file system.<br><br>';
warningMsg += 'You can try using another web browser or deploying the WebHelp files on a web server.';
warningMsg += '</div>';
var txt_filesfound = 'Results';

var txt_enter_at_least_2_char = "Search string must have at least two characters";
var txt_enter_more_than_10_words = "Only first 10 words will be processed.";
var txt_browser_not_supported = "Your browser is not supported. Use of Mozilla Firefox is recommended.";
var txt_please_wait = "Please wait. Search in progress...";
var txt_results_for = "Results for:";
//Verification errors
var searchType;






var result=new Pages([]);
var excluded=[];
var realSearchQuery;

var defaultOperator = "or";
var stackResults = [];


/**
 * @description This function verifies that the query is valid
 * CUSTOM CODE - NTT 20170429
 */

function hp_verify(){
    var languageType=hp_getLanguageType(indexerLanguage);
    var txt_entered_empty_phrase=getLocalization("txt_entered_empty_phrase");
    var txt_enter_at_least_1_char=getLocalization("txt_entered_empty_phrase");
    var txt_entered_only_wild_cards=getLocalization("txt_entered_only_wild_cards");
    var txt_entered_start_with_proximity=getLocalization("txt_entered_start_with_proximity");
    var txt_entered_contains_both_prox_oper=getLocalization("txt_entered_contains_both_prox_oper");
    var txt_entered_contains_multi_prox_oper=getLocalization("txt_entered_contains_multi_prox_oper");
    var txt_entered_only_boolean_oper=getLocalization("txt_entered_only_boolean_oper");
    var txt_entered_start_with_boolean=getLocalization("txt_entered_start_with_boolean");
    var txt_entered_wildcard_and_boolean=getLocalization("txt_entered_wildcard_and_boolean");
    var txt_entered_wildcard_with_asian=getLocalization("txt_entered_wildcard_with_asian");
    var errorMessage="",isInputValid=true;
    var expressionInput = strTrim(document.getElementById("textToSearch").value);	//trimmed user input
    // To Identify the type of search to execute
    searchType = hp_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 if(languageType==="asian" && (expressionInput.indexOf('*') != -1 || expressionInput.indexOf('?') != -1) && /^[a-zA-Z0-9- -*-?]*$/.test(expressionInput) == false ) { // wild cards and non English characters
            errorMessage = txt_entered_wildcard_with_asian;
            isInputValid = false;
        }
    }
    if (!isInputValid){
        $('#searchResults').html('<span id="loadingError">' + errorMessage + '</span>');
        return false;
    }

    return true;

}
function strTrim(txtToTrim){
    return txtToTrim.replace(/^\s+|\s+$/gm,'');
}
/**
 * @description This function make a search request. If all necessary resources are loaded search occurs
 *              otherwise search will be delayed until all resources are loaded.
 */
function searchRequest() {
    $('#search').trigger('click');
    if (!hp_verify()){
        return;
    }
    var expressionInput=strTrim(document.getElementById("textToSearch").value);
    var caseSensitive=document.getElementById("caseSensitiveChk").checked;
    hp_customSearch(expressionInput,hp_findSearchType(expressionInput),caseSensitive);
/*
    var ditaSearch_Form = document.getElementById('searchForm');
    var ready = setInterval(function () {
        if (searchLoaded) {
            $('#loadingError').remove();
            //SearchToc(ditaSearch_Form);
            alert(1);
            clearInterval(ready);
        } else {
            if ($('#loadingError').length < 1) {
                $('#searchResults').prepend('<span id="loadingError">' + getLocalization('Loading, please wait ...') + '</span>');
            }
        }
    }, 100);
    */
}

/**
 * List of all known operators
 * @type {string[]}
 */
var knownOperators = ["and", "or", "not"];

/**
 * @description Execute the search and display results after splitting a given query into different arrays that will contain search terms and
 * operators
 * @param searchQuery
 */
function searchAndDisplayResults(searchQuery) {
    var searchTerms = searchQuery.toLowerCase().split(" ");
    var toSearch = [];
    var operators = [];
    for (var i=0;i<searchTerms.length;i++) {
        if (!inArray(searchTerms[i], knownOperators)) {
            toSearch.push(searchTerms[i]);
        } else {
            operators.push(searchTerms[i]);
        }
    }

    searchQuery = normalizeQuery(searchQuery);

    computeResults(searchQuery);

    displayResults(stackResults[0]);
}

/**
 * @description Normalize query so that we have an operator between each two adjacent search terms. We'll add the defaultOperator if the
 * operator is missing.
 * e.g: If the defaultOperator is "and" the "iris flower" query will be "iris and flower"
 * @param query Search query
 * @return {string} Normalized query
 */
function normalizeQuery(query) {
    debug("normalizeQuery("+query+")");

    query = query.trim();
    query = query.replace(/\( /g, "(");
    query = query.replace(/ \)/g, ")");
    query = query.replace(/-/g, " and ");
    query = query.replace(/ and or /g, " or ");
    query = query.replace(/^not /g, "");
    query = query.replace(/ or and /g, " or ");
    var regex =  " " + defaultOperator + " " + defaultOperator + " ";
    query = query.replace(new RegExp(regex,"g"), " " + defaultOperator + " ");
    query = query.replace(/ not and /g, " not ");
    query = query.replace(/ and not /g, " not ");
    query = query.replace(/ or not /g, " not ");

		query = query.trim();
    query = query.indexOf("or ")==0 ? query.substring(3) : query;
    query = query.indexOf("and ")==0 ? query.substring(4) : query;
    query = query.indexOf("not ")==0 ? query.substring(4) : query;

    query = (query.lastIndexOf(" or")==query.length-3 && query.lastIndexOf(" or")!=-1) ? query.substring(0,query.lastIndexOf(" or")) : query;
    query = (query.lastIndexOf(" and")==query.length-4 && query.lastIndexOf(" and")!=-1) ? query.substring(0,query.lastIndexOf(" and")) : query;
    query = (query.lastIndexOf(" not")==query.length-4 && query.lastIndexOf(" not")!=-1) ? query.substring(0,query.lastIndexOf(" not")) : query;

    try {
        var result = query.toLowerCase().trim().replace(/ /g, " " + defaultOperator + " ");

        result = result.replace(/ or and or /g, " and ");
        result = result.replace(/ or not or /g, " not ");
        result = result.replace(/ or or or /g, " or ");
        result = result.replace(/ and and and /g, " and ");

        result = result.replace(/ and or /g, " or ");
        result = result.replace(/ not or /g, " not ");
        result = result.replace(/ or not /g, " not ");
        result = result.replace(/ or and /g, " or ");

        result = result.replace(/ not and /g, " not ");
        result = result.replace(/ and not /g, " not ");
    } catch (e) {
        debug(e);
    }

    return result;
}

/**
 * @description Convert search expression from infix notation to reverse polish notation (RPN): iris and flower => iris flower and
 * @param {string} search Search expression to be converted. e.g.: iris and flower or (gerbera not salvia)
 */
function computeResults(search) {
    debug("computeResults("+search+")");
    var stringToStore="";
    var stack=[];
    var item = "";
    var items = [];
    for (var i=0;i<search.length;i++) {
        if (search[i]!=" " && search[i]!="(" && search[i]!=")") {
            item+=search[i];
        }
        if (search[i]==" ") {
            if (item!="") {
                items.push(item);
                item = "";
            }
        }
        if (search[i]=="(") {
            if (item!="") {
                items.push(item);
                items.push("(");
                item = "";
            } else {
                items.push("(");
            }
        }
        if (search[i]==")") {
            if (item!="") {
                items.push(item);
                items.push(")");
                item = "";
            } else {
                items.push(")");
            }
        }
    }

    if (item!="") {
        items.push(item);
        item="";
    }

    for (i=0;i<items.length;i++) {
        if (isTerm(items[i])) {
            stringToStore+=items[i] + " ";
        }
        if (inArray(items[i], knownOperators)) {
            while (stack.length>0 && inArray(stack[stack.length-1],knownOperators)) {
                stringToStore+=stack.pop() + " ";
            }
            stack.push(items[i]);
        } else if (items[i]=="(") {
            stack.push(items[i]);
        } else if (items[i]==")") {
            var popped = stack.pop();
            while (popped!="(") {
                stringToStore+=popped + " ";
                popped = stack.pop();
            }
        }
    }

    while (stack.length > 0) {
        stringToStore+=stack.pop() + " ";
    }

    calculateRPN(stringToStore);
}

/**
 * @description Compute results from a RPN expression
 * @param {string} rpn Expression in Reverse Polish notation
 */
function calculateRPN(rpn) {
    debug("calculate("+rpn+")");
    var lastResult;
    var rpnTokens = trim(rpn);
    rpnTokens = rpnTokens.split(' ');
    var result;
    for(var i=0;i<rpnTokens.length;i++) {
        var token = rpnTokens[i];

        if (isTerm(token)) {
            result = realSearch(token);

            if (result.length > 0) {
                stackResults.push(new Pages(result[0]));
            } else {
                stackResults.push(new Pages([]));
            }
        } else {
            switch (token) {
                case "and":
                    lastResult = stackResults.pop();
                    if (lastResult.value !== undefined) {
                        stackResults.push(stackResults.pop().and(lastResult));
                    }
                    break;
                case "or":
                    lastResult = stackResults.pop();
                    if (lastResult.value !== undefined) {
                        stackResults.push(stackResults.pop().or(lastResult));
                    }
                    break;
                case "not":
                    lastResult = stackResults.pop();
                    if (lastResult.value !== undefined) {
                        stackResults.push(stackResults.pop().not(lastResult));
                    }
                    break;
                default:
                    debug("Error in calculateRPN(string) Method!");
                    break;
            }
        }
    }
}

/**
 * @description Tests if a given string is a valid search term or not
 * @param {string} string String to look for in the known operators list
 * @return {boolean} TRUE if the search string is a search term
 *                   FALSE if the search string is not a search term
 */
function isTerm(string) {
    return !inArray(string, knownOperators) && string.indexOf("(") == -1 && string.indexOf(")") == -1;
}

/**
 * @description Search for an element into an array
 * @param needle Searched element
 * @param haystack Array of elements
 * @return {boolean} TRUE if the searched element is part of the array
 *                   FALSE otherwise
 */
function inArray(needle, haystack) {
    var length = haystack.length;
    for(var i = 0; i < length; i++) {
        if(haystack[i] == needle) return true;
    }

    return false;
}

/**
 * @description This function find all matches using the search term
 * @param {HTMLObjectElement} ditaSearch_Form The search form from WebHelp page as HTML Object
 */
function SearchToc(ditaSearch_Form) {
    debug('SearchToc(..)');

    result = new Pages([]);
    noWords = [];
    excluded = [];
    stackResults = [];

    //START - EXM-30790
    var $searchResults = $("#searchResults");
    var footer = $searchResults.find(".footer");
    //END - EXM-30790
    // Check browser compatibility
    if (navigator.userAgent.indexOf("Konquerer") > -1) {
        alert(getLocalization(txt_browser_not_supported));
        return;
    }

    searchTextField = trim(ditaSearch_Form.textToSearch.value);
    // Eliminate the cross site scripting possibility.
    searchTextField = searchTextField.replace(/</g, " ")
        .replace(/>/g, " ")
        .replace(/"/g, " ")
        .replace(/'/g, " ")
        .replace(/=/g, " ")
        .replace(/0\\/g, " ")
        .replace(/\\/g, " ")
        .replace(/\//g, " ")
        .replace(/  +/g, " ");

    var expressionInput = searchTextField;
    debug('Search for: ' + expressionInput);

    var wordsArray = [];
    var splittedExpression = expressionInput.split(" ");
    for (var t in splittedExpression) {
        if (!contains(stopWords, splittedExpression[t]) || contains(knownOperators, splittedExpression[t])) {
            wordsArray.push(splittedExpression[t]);
        } else {
            excluded.push(splittedExpression[t]);
        }
    }
    expressionInput = wordsArray.join(" ");

    realSearchQuery = expressionInput;

    if (expressionInput.trim().length > 0 || excluded.length > 0) {
        searchAndDisplayResults(expressionInput);

        //START - EXM-30790
        $searchResults.append(footer);
        $searchResults.scrollTop(0);
        //END - EXM-30790
    }
    
    clearHighlights();
    ditaSearch_Form.textToSearch.focus();
}

var stemQueryMap = [];  // A hashtable which maps stems to query words

var scriptLetterTab = null;

/**
 * @description This function parses the search expression and loads the indices.
 * @param {String} expressionInput A single search term to search for.
 * @return {Array} Array with the resulted pages and indices.
 */
function realSearch(expressionInput) {
    expressionInput = trim(expressionInput);
    debug('realSearch("' + expressionInput + '")');
    /**
     *data initialisation
     */
    scriptLetterTab = new Scriptfirstchar(); // Array containing the first letter of each word to look for
    var finalWordsList = []; // Array with the words to look for after removing spaces
    var fileAndWordList = [];
    var txt_wordsnotfound = "";

    /* EXM-26412 */
    expressionInput = expressionInput.toLowerCase();
    /*  START - EXM-20414 */
    var searchFor = expressionInput.replace(/<\//g, "_st_").replace(/\$_/g, "_di_").replace(/%2C|%3B|%21|%3A|@|\/|\*/g, " ").replace(/(%20)+/g, " ").replace(/_st_/g, "</").replace(/_di_/g, "%24_");
    /*  END - EXM-20414 */

    searchFor = searchFor.replace(/  +/g, " ");
    searchFor = searchFor.replace(/ $/, "").replace(/^ /, "");

    var wordsList = [searchFor];
    debug('words from search:', wordsList);
    // set the tokenizing method
    useCJKTokenizing = !!(typeof indexerLanguage != "undefined" && (indexerLanguage == "zh" || indexerLanguage == "ko"));
    //If Lucene CJKTokenizer was used as the indexer, then useCJKTokenizing will be true. Else, do normal tokenizing.
    // 2-gram tokenizing happens in CJKTokenizing,
    // If doStem then make tokenize with Stemmer
    //var finalArray;
    if (doStem) {
        if (useCJKTokenizing) {
            // Array of words
            finalWordsList = cjkTokenize(wordsList);
        } else {
            // Array of words
            finalWordsList = tokenize(wordsList);
        }
    } else if (useCJKTokenizing) {
        // Array of words
        finalWordsList = cjkTokenize(wordsList);
        debug('CJKTokenizing, finalWordsList: ' + finalWordsList);
    } else {
        finalWordsList = [searchFor];
    }
    if (!useCJKTokenizing) {
        /**
         * Compare with the indexed words (in the w[] array), and push words that are in it to tempTab.
         */
        var tempTab = [];

        var wordsArray = '';
        for (var t in finalWordsList) {
            if (!contains(stopWords, finalWordsList[t])) {
                if (doStem || finalWordsList[t].toString().length == 2) {
                    if (w[finalWordsList[t].toString()] == undefined) {
                        txt_wordsnotfound += finalWordsList[t] + " ";
                    } else {
                        tempTab.push(finalWordsList[t]);
                    }
                } else {
                    var searchedValue = finalWordsList[t].toString();
                    var listOfWordsStartWith = wordsStartsWith(searchedValue);
                    if (listOfWordsStartWith != undefined) {
                        listOfWordsStartWith = listOfWordsStartWith.substr(0, listOfWordsStartWith.length - 1);
                        wordsArray = listOfWordsStartWith.split(",");
                        for (var i in wordsArray) {
                            tempTab.push(wordsArray[i]);
                        }
                    }
                }
            }
        }
        finalWordsList = tempTab;
        finalWordsList = removeDuplicate(finalWordsList);
    }

    for (var word in txt_wordsnotfound.split(" ")) {
        if (!inArray(word, noWords) && word.length>1) {
            noWords.push(word);
        }
    }

    if (finalWordsList.length) {
        fileAndWordList = SortResults(finalWordsList, expressionInput);
    } else {
        noWords.push(expressionInput);
    }

    return fileAndWordList;
}

/**
 * @description Display results in HTML format
 * @param {Array} fileAndWordList Array with pages and indices that will be displayed
 */
function displayResults(fileAndWordList) {
    var linkTab = [];

    var results = "";

    var txt_wordsnotfound = "";

    for (var i = 0; i < excluded.length; i++) {
        txt_wordsnotfound += excluded[i] + " ";
    }

    if (fileAndWordList && fileAndWordList.value !== undefined) {
        var allPages = fileAndWordList.sort().value;

        if (excluded.length > 0) {
            var tempString = "<p>" + partialSearch1;
            tempString += "<br />" + partialSearch2 + " " + txt_wordsnotfound + "</p>";
            linkTab.push(tempString);
        }

        if (realSearchQuery.length > 0) {

            var rsq = document.createElement("p");
            var rsqMessage = document.createTextNode(getLocalization(txt_results_for) + " ");
            rsq.appendChild(rsqMessage);

            var rsqSpan = document.createElement("span");
            rsqSpan.className="searchExpression";
            rsqSpan.appendChild(document.createTextNode(realSearchQuery));
            rsq.appendChild(rsqSpan);

            linkTab.push(hp_decodeFormatting(rsq.outerHTML));
        }
        linkTab.push("<ul class='searchresult'>");
        var ttScore_first = 1;
        if (allPages.length > 0) {
            ttScore_first = allPages[0].scoring;
        }
        for (var page = 0; page < allPages.length; page++) {
            debug("Page number: " + page);

            var hundredPercent = allPages[page].scoring + 100 * allPages[page].motsnb;
            var numberOfWords = allPages[page].motsnb;
            debug("hundredPercent: " + hundredPercent + "; ttScore_first: " + ttScore_first + "; numberOfWords: " + numberOfWords);

            var ttInfo = allPages[page].filenb;
            // Get scoring
            var ttScore = allPages[page].scoring;

            debug('score for' + allPages[page].motslisteDisplay + ' = ' + ttScore);

            var tempInfo = fil[ttInfo];
            var pos1 = tempInfo.indexOf("@@@");
            var pos2 = tempInfo.lastIndexOf("@@@");
            var tempPath = tempInfo.substring(0, pos1);
            // EXM-27709 START
            // Display words between '<' and '>' in title of search results.
            var tempTitle = tempInfo.substring(pos1 + 3, pos2)
                .replace(/</g, "&lt;").replace(/>/g, "&gt;");
            // EXM-27709 END
            var tempShortDesc = tempInfo.substring(pos2 + 3, tempInfo.length);

            if (tempPath == 'toc.html') {
                continue;
            }
            //var split = allPages[page].motsliste.split(",");
            var wordlist = allPages[page].motsliste.replace(/\sfby\s/i,", ").replace(/\snear\s/i,", ");

            var finalArray = [];
            wordlist.split(", ").forEach(function(word){
				//word = word.replace("'", "&amp;" + "apos;");
				word = Encoder.htmlEncode(word);
                finalArray=finalArray.concat(word.split(/\s+/));
            });

            debug(finalArray);
            var arrayString = 'Array(';

            if (searchType=="phrase"){
                arrayString += "'" + finalArray.join(" ") + "')";
            } else {

                for (var x in finalArray) {
                    if (x > 0 && finalArray[x].toLowerCase() == "or") {
                        continue;
                    }
                    if (finalArray[x].length >= 2 || useCJKTokenizing || (indexerLanguage == "ja" && finalArray[x].length >= 1)) {
                        arrayString += "'" + finalArray[x] + "',";
                    }
                }
                arrayString = arrayString.substring(0, arrayString.length - 1) + ")";
            }

            var idLink = 'foundLink' + page;
            var link = 'return openAndHighlight(\'' + tempPath + '\', ' + arrayString + '\)';
            var linkString = '<li><a id="' + idLink + '" href="' + tempPath + '" class="foundResult" onclick="' + link + '">' + tempTitle + '</a>';
            // Fake value
            var maxNumberOfWords = allPages[page].motsnb;
            var starWidth = (ttScore * 100 / hundredPercent) / (ttScore_first / hundredPercent) * (numberOfWords / maxNumberOfWords);
            starWidth = starWidth < 10 ? (starWidth + 5) : starWidth;
            // Keep the 5 stars format
            if (starWidth > 85) {
                starWidth = 85;
            }
            // Also check if we have a valid description
            if ((tempShortDesc != "null" && tempShortDesc != '...')) {
                linkString += "\n<div class=\"shortdesclink\">" + tempShortDesc + "</div>";
            }

            try {
                if (webhelpSearchRanking) {
                    // Add rating values for scoring at the list of matches
                    linkString += "<div id=\"rightDiv\">";
                    linkString += "<div id=\"star\">";
                    linkString += "<div id=\"star0\" class=\"star\">";
                    linkString += "<div id=\"starCur0\" class=\"curr\" style=\"width: " + starWidth + "px;\">&nbsp;</div>";
                    linkString += "</div>";
                    linkString += "<br style=\"clear: both;\">";
                    linkString += "</div>";
                    linkString += "</div>";
                }
            } catch (e) {
                debug(e);
            }

            linkString += "</li>";
            linkTab.push(linkString);
        }


        linkTab.push("</ul>");

        if (linkTab.length > 2) {
            results = "<p>";
            for (var t in linkTab) {
                results += linkTab[t].toString();
            }
            results += "</p>";
        } else {
            results = "<p>" + getLocalization("Search no results") + " " + "<span class=\"searchExpression\">" + txt_wordsnotfound + "</span>" + "</p>";
        }
    } else {
        results = "<p>" + getLocalization("Search no results") + " " + "<span class=\"searchExpression\">" + txt_wordsnotfound + "</span>" + "</p>";
    }

    // Verify if the browser is Google Chrome and the WebHelp is used on a local machine
    // If browser is Google Chrome and WebHelp is used on a local machine a warning message will appear
    // Highlighting will not work in this conditions. There is 2 workarounds
	//start mTS 1238 - Mobile search issue for ja output 
    if (isChrome = !!window.chrome && !!window.chrome.webstore) {
        document.getElementById('searchResults').innerHTML = warningMsg + results;
    } else {
        document.getElementById('searchResults').innerHTML = results;
    }
	//end mTS 1238 - Mobile search issue for ja output 
    $("#search").trigger('click');
}

// Return true if "word" value is an element of "arrayOfWords"  
function contains(arrayOfWords, word) {
    var found = true;
    if (word.length >= 2 || (indexerLanguage == "ja" && word.length >= 1)) {
        found = false;
        for (var w in arrayOfWords) {
            if (arrayOfWords[w] === word) {
                found = true;
                break;
            }
        }
    }
    return found;
}

// Look for elements that start with searchedValue.
function wordsStartsWith(searchedValue) {
    var toReturn = '';
    for (var sv in w) {
        if (sv.toLowerCase().indexOf(searchedValue.toLowerCase()) == 0) {
            toReturn += sv + ",";
        }
    }
    return toReturn.length > 0 ? toReturn : undefined;
}

function tokenize(wordsList) {
    debug('tokenize(' + wordsList + ')');
    var stemmedWordsList = []; // Array with the words to look for after removing spaces
    var cleanwordsList = []; // Array with the words to look for
    for (var j in wordsList) {
        var word = wordsList[j];
        if (typeof stemmer != "undefined" && doStem) {
            stemQueryMap[stemmer(word)] = word;
        } else {
            stemQueryMap[word] = word;
        }
    }
    debug('scriptLetterTab in tokenize: ', scriptLetterTab);
    scriptLetterTab.add('s');
    //stemmedWordsList is the stemmed list of words separated by spaces.
    for (var t in wordsList) {
        if (wordsList.hasOwnProperty(t)) {
            wordsList[t] = wordsList[t].replace(/(%22)|^-/g, "");
            if (wordsList[t] != "%20") {
                var firstChar = wordsList[t].charAt(0);
                scriptLetterTab.add(firstChar);
                cleanwordsList.push(wordsList[t]);
            }
        }
    }

    if (typeof stemmer != "undefined" && doStem) {
        //Do the stemming using Porter's stemming algorithm
        for (var i = 0; i < cleanwordsList.length; i++) {
            var stemWord = stemmer(cleanwordsList[i]);
            stemmedWordsList.push(stemWord);
        }
    } else {
        stemmedWordsList = cleanwordsList;
    }
    return stemmedWordsList;
}

//Invoker of CJKTokenizer class methods.
function cjkTokenize(wordsList) {
    var allTokens = [];
    var notCJKTokens = [];
    debug('in cjkTokenize(), wordsList: ', wordsList);
    for (var j = 0; j < wordsList.length; j++) {
        var word = wordsList[j];
        debug('in cjkTokenize(), next word: ', word);
        if (getAvgAsciiValue(word) < 127) {
            notCJKTokens.push(word);
        } else {
            debug('in cjkTokenize(), use CJKTokenizer');
            var tokenizer = new CJKTokenizer(word);
            var tokensTmp = tokenizer.getAllTokens();
            allTokens = allTokens.concat(tokensTmp);
            debug('in cjkTokenize(), found new tokens: ', allTokens);
        }
    }
    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;
}

//CJKTokenizer
function CJKTokenizer(input) {
    this.input = input;
    this.offset = -1;
    this.tokens = [];
    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() {
        while (this.incrementToken()) {
            var tmp = this.tokenize();
            this.tokens.push(tmp);
        }
        return this.unique(this.tokens);
    }

    function unique(a) {
        var r = [];
        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;
    }
}


/* Scriptfirstchar: to gather the first letter of index js files to upload */
function Scriptfirstchar() {
    this.strLetters = "";
}

Scriptfirstchar.prototype.add = function (caract) {
    if (typeof this.strLetters == 'undefined') {
        this.strLetters = caract;
    } else if (this.strLetters.indexOf(caract) < 0) {
        this.strLetters += caract;
    }

    return 0;
};

/* end of scriptfirstchar */


// Array.unique( strict ) - Remove duplicate values
function unique(tab) {
    debug("unique(",tab,")");
    var a = [];
    var i;
    var l = tab.length;

    if (tab[0] != undefined) {
        a[0] = tab[0];
    }
    else {
        return -1;
    }

    for (i = 1; i < l; i++) {
        if (indexof(a, tab[i], 0) < 0) {
            a.push(tab[i]);
        }
    }

    return a;
}
function indexof(tab, element, begin) {
    for (var i = begin; i < tab.length; i++) {
        if (tab[i] == element) {
            return i;
        }
    }
    return -1;

}
/* end of Array functions */


/**
 * This function creates an hashtable:
 *  - The key is the index of an HTML file which contains a word to look for.
 *  - The value is the list of all words contained in the HTML file.
 *
 * @param {Array} words - list of words to look for.
 * @param {String} searchedWord - search term typed by user
 * @return {Array} - the hashtable fileAndWordList
 */
function SortResults(words, searchedWord) {

    var fileAndWordList = {};
    if (words.length == 0 || words[0].length == 0) {
        return null;
    }

    // In generated js file we add scoring at the end of the word
    // Example word1*scoringForWord1,word2*scoringForWord2 and so on
    // Split after * to obtain the right values
    var scoringArr = [];
    for (var t in words) {
        // get the list of the indices of the files.
        var listNumerosDesFicStr = w[words[t].toString()];
        var tab = listNumerosDesFicStr.split(",");
        //for each file (file's index):
        for (var t2 in tab) {
            var tmp = '';
            var idx;
            var temp = tab[t2].toString();
            if (temp.indexOf('*') != -1) {
                idx = temp.indexOf('*');
                tmp = temp.substring(idx + 3, temp.length);
                temp = temp.substring(0, idx);
            }
            scoringArr.push(tmp);
            if (fileAndWordList[temp] == undefined) {
                fileAndWordList[temp] = "" + words[t];
            } else {
                fileAndWordList[temp] += "," + words[t];
            }
        }
    }

    var fileAndWordListValuesOnly = [];
    // sort results according to values
    var temptab = [];
    var finalObj = [];
    for (t in fileAndWordList) {
        finalObj.push(new newObj(t, fileAndWordList[t]));
    }
    finalObj = removeDerivates(finalObj, searchedWord);

    for (t in finalObj) {
        tab = finalObj[t].wordList.split(',');
        var tempDisplay = [];
        for (var x in tab) {
            if (stemQueryMap[tab[x]] != undefined && doStem) {
                tempDisplay.push(stemQueryMap[tab[x]]); //get the original word from the stem word.
            } else {
                tempDisplay.push(tab[x]); //no stem is available. (probably a CJK language)
            }
        }
        var tempDispString = tempDisplay.join(", ");
        var index;
        for (x in fileAndWordList) {
            if (x === finalObj[t].filesNo) {
                index = x;
                break;
            }
        }
        var scoring = findRating(fileAndWordList[index], index);
        temptab.push(new resultPerFile(finalObj[t].filesNo, finalObj[t].wordList, tab.length, tempDispString, scoring));
        fileAndWordListValuesOnly.push(finalObj[t].wordList);

    }
    debug("fileAndWordListValuesOnly: ", fileAndWordListValuesOnly);
    fileAndWordListValuesOnly = unique(fileAndWordListValuesOnly);
    fileAndWordListValuesOnly = fileAndWordListValuesOnly.sort(compareWords);

    var listToOutput = [];
    for (var j in fileAndWordListValuesOnly) {
        for (t in temptab) {
            if (temptab[t].motsliste == fileAndWordListValuesOnly[j]) {
                if (listToOutput[j] == undefined) {
                    listToOutput[j] = new Array(temptab[t]);
                } else {
                    listToOutput[j].push(temptab[t]);
                }
            }
        }
    }
    // Sort results by scoring, descending on the same group
    for (var i in listToOutput) {
        listToOutput[i].sort(function (a, b) {
            return b.scoring - a.scoring;
        });
    }
    // If we have groups with same number of words,
    // will sort groups by higher scoring of each group
    for (i = 0; i < listToOutput.length - 1; i++) {
        for (j = i + 1; j < listToOutput.length; j++) {
            if (listToOutput[i][0].motsnb < listToOutput[j][0].motsnb
                || (listToOutput[i][0].motsnb == listToOutput[j][0].motsnb
                && listToOutput[i][0].scoring < listToOutput[j][0].scoring)
            ) {
                var x = listToOutput[i];
                listToOutput[i] = listToOutput[j];
                listToOutput[j] = x;
            }
        }
    }

    return listToOutput;
}

/**
 * @description Remove derivatives words from the list of words
 * @param {Array} obj Array that contains results for searched words
 * @param {String} searchedWord search term typed by user
 * @return {Array} Clean array results without duplicated and derivatives words
 */
function removeDerivates(obj, searchedWord) {
    debug("removeDerivatives(",obj,")");
    var toResultObject = [];
    for (var i in obj) {
        var filesNo = obj[i].filesNo;
        var wordList = obj[i].wordList;
        var wList = wordList.split(",");

        for (var j = 0; j < wList.length; j++) {
            if (startsWith(wList[j], searchedWord)) {
                wList[j] = searchedWord;
            }
        }

        wList = removeDuplicate(wList);
        var recreateList = '';
        for (var x in wList) {
            recreateList += wList[x] + ",";
        }
        recreateList = recreateList.substr(0, recreateList.length - 1);
        toResultObject.push(new newObj(filesNo, recreateList));
    }

    return toResultObject;
}

function newObj(filesNo, wordList) {
    this.filesNo = filesNo;
    this.wordList = wordList;
}


// Object.
// Add a new parameter - scoring.
function resultPerFile(filenb, motsliste, motsnb, motslisteDisplay, scoring, group) {
    //10 - spring,time - 2 - spring, time - 55 - 3
    this.filenb = filenb;
    this.motsliste = motsliste;
    this.motsnb = motsnb;
    this.motslisteDisplay = motslisteDisplay;
    this.scoring = scoring;
}

function findRating(words, nr) {
    var sum = 0;
    var xx = words.split(',');
    for (var jj = 0; jj < xx.length; jj++) {
        var wrd = w[xx[jj]].split(',');
        for (var ii = 0; ii < wrd.length; ii++) {
            var wrdno = wrd[ii].split('*');
            if (wrdno[0] == nr) {
                sum += parseInt(wrdno[1]);
            }
        }
    }
    return sum;
}

function compareWords(s1, s2) {
    var t1 = s1.split(',');
    var t2 = s2.split(',');
    if (t1.length == t2.length) {
        return 0;
    } else if (t1.length > t2.length) {
        return 1;
    } else {
        return -1;
    }
}
// return false if browser is Google Chrome and WebHelp is used on a local machine, not a web server 
function verifyBrowser() {
    var returnedValue = true;
    BrowserDetect.init();
    var browser = BrowserDetect.browser;
    var addressBar = window.location.href;
    if (browser == 'Chrome' && addressBar.indexOf('file://') === 0) {
        returnedValue = false;
    }

    return returnedValue;
}

// Remove duplicate values from an array
function removeDuplicate(arr) {
    var r = [];
    o:for (var i = 0, n = arr.length; i < n; i++) {
        for (var x = 0, y = r.length; x < y; x++) {
            if (r[x] == arr[i]) continue o;
        }
        r[r.length] = arr[i];
    }
    return r;
}

function trim(str, chars) {
    return ltrim(rtrim(str, chars), chars);
}

function ltrim(str, chars) {
    chars = chars || "\\s";
    return str.replace(new RegExp("^[" + chars + "]+", "g"), "");
}

function rtrim(str, chars) {
    chars = chars || "\\s";
    return str.replace(new RegExp("[" + chars + "]+$", "g"), "");
}

/**
 * PATCH FOR BOOLEAN SEARCH
 */

/**
 * @description Object with resulted pages as array
 * @param array Array that contains partial results
 * @constructor
 */
function Pages(array) {
    this.value = array;

    this.toString = function() {
        var stringResult = "";

        stringResult += "INDEX\t|\tfilenb\t|\tscoring\n";
        for (var i=0;i<this.value.length;i++) {
            stringResult += i + ".\t\t|\t" + this.value[i].filenb + "\t\t|\t" + this.value[i].scoring + "\n";
        }

        return stringResult;
    };

    this.writeIDs = function() {
        var stringResult = "";

        for (var i=0;i<this.value.length;i++) {
            stringResult += this.value[i].filenb + " | ";
        }

        return stringResult;
    };

    this.and = function and(newArray) {
        var result = [];

        for (var x=0; x<this.value.length; x++) {
            var found = false;
            for (var y=0; y<newArray.value.length; y++) {
                if (this.value[x].filenb == newArray.value[y].filenb) {
                    this.value[x].motsliste += ", " + newArray.value[y].motsliste;
                    this.value[x].scoring += newArray.value[y].scoring;
                    found = true;
                    break;
                }
            }
            if (found) {
                result.push(this.value[x]);
            }
        }

        this.value = result;

        return this;
    };

    this.or = function or(newArray) {
        this.value = this.value.concat(newArray.value);
        var result = [];

        for (var i=0;i<this.value.length;i++) {
            var unique = true;
            for (var j=0;j<result.length;j++) {
                if (this.value[i].filenb == result[j].filenb) {
                    result[j].motsliste += ", " + this.value[i].motsliste;
                    var numberOfWords = result[j].motsliste.split(", ").length;
                    result[j].scoring = numberOfWords*(this.value[i].scoring + result[j].scoring);
                    unique = false;
                    break;
                }
            }
            if (unique) {
                result.push(this.value[i]);
            }
        }

        this.value = result;

        return this;
    };

    this.not = function not(newArray) {
        var result = [];

        for (var x=0; x<this.value.length; x++) {
            var found = false;
            for (var y=0; y<newArray.value.length; y++) {
                if (this.value[x].filenb == newArray.value[y].filenb) {
                    found = true;
                }
            }
            if (!found) {
                result.push(this.value[x]);
            }
        }

        this.value = result;

        return this;
    };

    this.sort = function() {
        for (var i = 0; i < this.value.length; i++) {
            for (var j = i; j > 0; j--) {
                if ((this.value[j].scoring - this.value[j - 1].scoring) > 0) {
                    var aux = this.value[j];
                    this.value[j] = this.value[j-1];
                    this.value[j-1] = aux;
                }
            }
        }

        return this;
    };
}

if(typeof String.prototype.trim !== 'function') {
    String.prototype.trim = function() {
        return $.trim(this);
    }
}



// LEGACY encoder.js
Encoder = {

    // When encoding do we convert characters into html or numerical entities
    EncodeType : "entity",  // entity OR numerical

    isEmpty : function(val){
        if(val){
            return ((val===null) || val.length==0 || /^\s+$/.test(val));
        }else{
            return true;
        }
    },
    arr1: new Array('&nbsp;','&iexcl;','&cent;','&pound;','&curren;','&yen;','&brvbar;','&sect;','&uml;','&copy;','&ordf;','&laquo;','&not;','&shy;','&reg;','&macr;','&deg;','&plusmn;','&sup2;','&sup3;','&acute;','&micro;','&para;','&middot;','&cedil;','&sup1;','&ordm;','&raquo;','&frac14;','&frac12;','&frac34;','&iquest;','&Agrave;','&Aacute;','&Acirc;','&Atilde;','&Auml;','&Aring;','&Aelig;','&Ccedil;','&Egrave;','&Eacute;','&Ecirc;','&Euml;','&Igrave;','&Iacute;','&Icirc;','&Iuml;','&ETH;','&Ntilde;','&Ograve;','&Oacute;','&Ocirc;','&Otilde;','&Ouml;','&times;','&Oslash;','&Ugrave;','&Uacute;','&Ucirc;','&Uuml;','&Yacute;','&THORN;','&szlig;','&agrave;','&aacute;','&acirc;','&atilde;','&auml;','&aring;','&aelig;','&ccedil;','&egrave;','&eacute;','&ecirc;','&euml;','&igrave;','&iacute;','&icirc;','&iuml;','&eth;','&ntilde;','&ograve;','&oacute;','&ocirc;','&otilde;','&ouml;','&divide;','&Oslash;','&ugrave;','&uacute;','&ucirc;','&uuml;','&yacute;','&thorn;','&yuml;','&quot;','&amp;','&lt;','&gt;','&oelig;','&oelig;','&scaron;','&scaron;','&yuml;','&circ;','&tilde;','&ensp;','&emsp;','&thinsp;','&zwnj;','&zwj;','&lrm;','&rlm;','&ndash;','&mdash;','&lsquo;','&rsquo;','&sbquo;','&ldquo;','&rdquo;','&bdquo;','&dagger;','&dagger;','&permil;','&lsaquo;','&rsaquo;','&euro;','&fnof;','&alpha;','&beta;','&gamma;','&delta;','&epsilon;','&zeta;','&eta;','&theta;','&iota;','&kappa;','&lambda;','&mu;','&nu;','&xi;','&omicron;','&pi;','&rho;','&sigma;','&tau;','&upsilon;','&phi;','&chi;','&psi;','&omega;','&alpha;','&beta;','&gamma;','&delta;','&epsilon;','&zeta;','&eta;','&theta;','&iota;','&kappa;','&lambda;','&mu;','&nu;','&xi;','&omicron;','&pi;','&rho;','&sigmaf;','&sigma;','&tau;','&upsilon;','&phi;','&chi;','&psi;','&omega;','&thetasym;','&upsih;','&piv;','&bull;','&hellip;','&prime;','&prime;','&oline;','&frasl;','&weierp;','&image;','&real;','&trade;','&alefsym;','&larr;','&uarr;','&rarr;','&darr;','&harr;','&crarr;','&larr;','&uarr;','&rarr;','&darr;','&harr;','&forall;','&part;','&exist;','&empty;','&nabla;','&isin;','&notin;','&ni;','&prod;','&sum;','&minus;','&lowast;','&radic;','&prop;','&infin;','&ang;','&and;','&or;','&cap;','&cup;','&int;','&there4;','&sim;','&cong;','&asymp;','&ne;','&equiv;','&le;','&ge;','&sub;','&sup;','&nsub;','&sube;','&supe;','&oplus;','&otimes;','&perp;','&sdot;','&lceil;','&rceil;','&lfloor;','&rfloor;','&lang;','&rang;','&loz;','&spades;','&clubs;','&hearts;','&diams;'),
    arr2: new Array('&#160;','&#161;','&#162;','&#163;','&#164;','&#165;','&#166;','&#167;','&#168;','&#169;','&#170;','&#171;','&#172;','&#173;','&#174;','&#175;','&#176;','&#177;','&#178;','&#179;','&#180;','&#181;','&#182;','&#183;','&#184;','&#185;','&#186;','&#187;','&#188;','&#189;','&#190;','&#191;','&#192;','&#193;','&#194;','&#195;','&#196;','&#197;','&#198;','&#199;','&#200;','&#201;','&#202;','&#203;','&#204;','&#205;','&#206;','&#207;','&#208;','&#209;','&#210;','&#211;','&#212;','&#213;','&#214;','&#215;','&#216;','&#217;','&#218;','&#219;','&#220;','&#221;','&#222;','&#223;','&#224;','&#225;','&#226;','&#227;','&#228;','&#229;','&#230;','&#231;','&#232;','&#233;','&#234;','&#235;','&#236;','&#237;','&#238;','&#239;','&#240;','&#241;','&#242;','&#243;','&#244;','&#245;','&#246;','&#247;','&#248;','&#249;','&#250;','&#251;','&#252;','&#253;','&#254;','&#255;','&#34;','&#38;','&#60;','&#62;','&#338;','&#339;','&#352;','&#353;','&#376;','&#710;','&#732;','&#8194;','&#8195;','&#8201;','&#8204;','&#8205;','&#8206;','&#8207;','&#8211;','&#8212;','&#8216;','&#8217;','&#8218;','&#8220;','&#8221;','&#8222;','&#8224;','&#8225;','&#8240;','&#8249;','&#8250;','&#8364;','&#402;','&#913;','&#914;','&#915;','&#916;','&#917;','&#918;','&#919;','&#920;','&#921;','&#922;','&#923;','&#924;','&#925;','&#926;','&#927;','&#928;','&#929;','&#931;','&#932;','&#933;','&#934;','&#935;','&#936;','&#937;','&#945;','&#946;','&#947;','&#948;','&#949;','&#950;','&#951;','&#952;','&#953;','&#954;','&#955;','&#956;','&#957;','&#958;','&#959;','&#960;','&#961;','&#962;','&#963;','&#964;','&#965;','&#966;','&#967;','&#968;','&#969;','&#977;','&#978;','&#982;','&#8226;','&#8230;','&#8242;','&#8243;','&#8254;','&#8260;','&#8472;','&#8465;','&#8476;','&#8482;','&#8501;','&#8592;','&#8593;','&#8594;','&#8595;','&#8596;','&#8629;','&#8656;','&#8657;','&#8658;','&#8659;','&#8660;','&#8704;','&#8706;','&#8707;','&#8709;','&#8711;','&#8712;','&#8713;','&#8715;','&#8719;','&#8721;','&#8722;','&#8727;','&#8730;','&#8733;','&#8734;','&#8736;','&#8743;','&#8744;','&#8745;','&#8746;','&#8747;','&#8756;','&#8764;','&#8773;','&#8776;','&#8800;','&#8801;','&#8804;','&#8805;','&#8834;','&#8835;','&#8836;','&#8838;','&#8839;','&#8853;','&#8855;','&#8869;','&#8901;','&#8968;','&#8969;','&#8970;','&#8971;','&#9001;','&#9002;','&#9674;','&#9824;','&#9827;','&#9829;','&#9830;'),

    // Convert HTML entities into numerical entities
    HTML2Numerical : function(s){
        return this.swapArrayVals(s,this.arr1,this.arr2);
    },

    // Convert Numerical entities into HTML entities
    NumericalToHTML : function(s){
        return this.swapArrayVals(s,this.arr2,this.arr1);
    },


    // Numerically encodes all unicode characters
    numEncode : function(s){

        if(this.isEmpty(s)) return "";

        var e = "";
        for (var i = 0; i < s.length; i++)
        {
            var c = s.charAt(i);
            if (c < " " || c > "~")
            {
                c = "&#" + c.charCodeAt() + ";";
            }
            e += c;
        }
        return e;
    },

    // HTML Decode numerical and HTML entities back to original values
    htmlDecode : function(s){

        var c,m,d = s;

        if(this.isEmpty(d)) return "";

        // convert HTML entites back to numerical entites first
        d = this.HTML2Numerical(d);

        // look for numerical entities &#34;
        arr=d.match(/&#[0-9]{1,5};/g);

        // if no matches found in string then skip
        if(arr!=null){
            for(var x=0;x<arr.length;x++){
                m = arr[x];
                c = m.substring(2,m.length-1); //get numeric part which is refernce to unicode character
                // if its a valid number we can decode
                if(c >= -32768 && c <= 65535){
                    // decode every single match within string
                    d = d.replace(m, String.fromCharCode(c));
                }else{
                    d = d.replace(m, ""); //invalid so replace with nada
                }
            }
        }

        return d;
    },

    // encode an input string into either numerical or HTML entities
    htmlEncode : function(s,dbl){

        if(this.isEmpty(s)) return "";

        // do we allow double encoding? E.g will &amp; be turned into &amp;amp;
        dbl = dbl || false; //default to prevent double encoding

        // if allowing double encoding we do ampersands first
        if(dbl){
            if(this.EncodeType=="numerical"){
                s = s.replace(/&/g, "&#38;");
            }else{
                s = s.replace(/&/g, "&amp;");
            }
        }

        // convert the xss chars to numerical entities ' " < >
        s = this.XSSEncode(s,false);

        if(this.EncodeType=="numerical" || !dbl){
            // Now call function that will convert any HTML entities to numerical codes
            s = this.HTML2Numerical(s);
        }

        // Now encode all chars above 127 e.g unicode
        s = this.numEncode(s);

        // now we know anything that needs to be encoded has been converted to numerical entities we
        // can encode any ampersands & that are not part of encoded entities
        // to handle the fact that I need to do a negative check and handle multiple ampersands &&&
        // I am going to use a placeholder

        // if we don't want double encoded entities we ignore the & in existing entities
        if(!dbl){
            s = s.replace(/&#/g,"##AMPHASH##");

            if(this.EncodeType=="numerical"){
                s = s.replace(/&/g, "&#38;");
            }else{
                s = s.replace(/&/g, "&amp;");
            }

            s = s.replace(/##AMPHASH##/g,"&#");
        }

        // replace any malformed entities
        s = s.replace(/&#\d*([^\d;]|$)/g, "$1");

        if(!dbl){
            // safety check to correct any double encoded &amp;
            s = this.correctEncoding(s);
        }

        // now do we need to convert our numerical encoded string into entities
        if(this.EncodeType=="entity"){
            s = this.NumericalToHTML(s);
        }

        return s;
    },

    // Encodes the basic 4 characters used to malform HTML in XSS hacks
    XSSEncode : function(s,en){
        if(!this.isEmpty(s)){
            en = en || true;
            // do we convert to numerical or html entity?
            if(en){
                s = s.replace(/\'/g,"&#39;"); //no HTML equivalent as &apos is not cross browser supported
                s = s.replace(/\"/g,"&quot;");
                s = s.replace(/</g,"&lt;");
                s = s.replace(/>/g,"&gt;");
            }else{
                s = s.replace(/\'/g,"&#39;"); //no HTML equivalent as &apos is not cross browser supported
                s = s.replace(/\"/g,"&#34;");
                s = s.replace(/</g,"&#60;");
                s = s.replace(/>/g,"&#62;");
            }
            return s;
        }else{
            return "";
        }
    },

    // returns true if a string contains html or numerical encoded entities
    hasEncoded : function(s){
        if(/&#[0-9]{1,5};/g.test(s)){
            return true;
        }else if(/&[A-Z]{2,6};/gi.test(s)){
            return true;
        }else{
            return false;
        }
    },

    // will remove any unicode characters
    stripUnicode : function(s){
        return s.replace(/[^\x20-\x7E]/g,"");

    },

    // corrects any double encoded &amp; entities e.g &amp;amp;
    correctEncoding : function(s){
        return s.replace(/(&amp;)(amp;)+/,"$1");
    },


    // Function to loop through an array swaping each item with the value from another array e.g swap HTML entities with Numericals
    swapArrayVals : function(s,arr1,arr2){
        if(this.isEmpty(s)) return "";
        var re;
        if(arr1 && arr2){
            //ShowDebug("in swapArrayVals arr1.length = " + arr1.length + " arr2.length = " + arr2.length)
            // array lengths must match
            if(arr1.length == arr2.length){
                for(var x=0,i=arr1.length;x<i;x++){
                    re = new RegExp(arr1[x], 'g');
                    s = s.replace(re,arr2[x]); //swap arr1 item with matching item from arr2
                }
            }
        }
        return s;
    },

    inArray : function( item, arr ) {
        for ( var i = 0, x = arr.length; i < x; i++ ){
            if ( arr[i] === item ){
                return i;
            }
        }
        return -1;
    }

}

//EOF LEGACY encoder.js

/* To Identify the type of search to execute (phrase, wild card, boolean etc) */
function hp_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;
}
/**
 *
 * @param expressionInput
 * @param searchType
 * @param isCaseSensitive
 *
 * Expect fileIndexArray to exist Array[file_id]=file_contents;
 */

function hp_customSearch(expressionInput, searchType, isCaseSensitive){
    var languageType=hp_getLanguageType(indexerLanguage);
    var resultObj 	= new Object();
    var sortedResultsObj	= new Object();
    var searchForPhrase,regExp,fileNo,andWordsArray,orWordsArray,notWordsArray, t,t1, i,result;
    var o2results=[];
    var resultsForDisplay;
    var isResultExists = false;
    var count=0;
    var firstWord = '';
    var secondWord = '';
    var fileAndWordsBeforeFilter = new Object();
    var fileAndWordsAfterFilter;
    var fileAndCount = new Object();

    if (expressionInput){
        expressionInput=expressionInput.replace("-","^").replace(/\s*\|\s*/,"|");
    }

    //Strip punctuation from search files
    if (fileIndexArray){
        Object.keys(fileIndexArray).forEach(function(index){
            if (fileIndexArray[index]) {
                fileIndexArray[index] = fileIndexArray[index].replace(/\.,;:"/g, " ");
            }
        })
    }

    // replacing the special characters in the search string
    var searchFor = hp_replaceSpecialChar(expressionInput, true);

    // make an array of the search keywords
    var 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 "
        searchForPhrase = hp_replaceSpecCharInPhrase(expressionInput, true);
        //regular expression for search
        regExp = new RegExp(searchForPhrase, "gi");
        if(isCaseSensitive){
            regExp = new RegExp(searchForPhrase, "g");
        }

        //Search the files
        sortedResultsObj=hp_matchAndSort(regExp);
        // get the search string without escape sequence
        searchFor = hp_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';
        }


        if(searchType == 'wildcard'){
            // get the matching search keywords based on wild cards
            wordsList = hp_getWildCardMatchingWords(wordsList, isCaseSensitive);
            if(wordsList.length > 0){
                expressionInput = wordsList.toString().replace(/,/g, " ");
            }
        }

        if(searchType == 'proximity'){ //proximity search
            searchFor = hp_replaceSpecialChar(expressionInput, false); //search string with proximity operators

            if(searchFor.indexOf('$') != -1){ //near
                firstWord = searchFor.substring(0, searchFor.indexOf('$'));
                secondWord = searchFor.substring(searchFor.indexOf('$')+1, searchFor.length);

                //regular expression for search
                if (languageType==="asian"){
                    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 if (languageType==="others"){
                    regExp = new RegExp('\\s(?:' + firstWord + '\\W+(?:\\w+\\W+){0,10}?' + secondWord + '|' + secondWord + '\\W+(?:\\w+\\W+){0,10}?' + firstWord + ')\\s', "gi");
                    if (isCaseSensitive) {
                        regExp = new RegExp('\\s(?:' + firstWord + '\\W+(?:\\w+\\W+){0,10}?' + secondWord + '|' + secondWord + '\\W+(?:\\w+\\W+){0,10}?' + firstWord + ')\\s', "g");
                    }
                } else {
                    regExp = new RegExp('\\b(?:' + firstWord + '\\W+(?:\\w+\\W+){0,10}?' + secondWord + '|' + secondWord + '\\W+(?:\\w+\\W+){0,10}?' + firstWord + ')\\b', "gi");
                    if (isCaseSensitive) {
                        regExp = new RegExp('\\b(?:' + firstWord + '\\W+(?:\\w+\\W+){0,10}?' + secondWord + '|' + secondWord + '\\W+(?:\\w+\\W+){0,10}?' + firstWord + ')\\b', "g");
                    }
                }
            }else{ //followed by
                firstWord = searchFor.substring(0, searchFor.indexOf('%'));
                secondWord = searchFor.substring(searchFor.indexOf('%')+1, searchFor.length);

                //regular expression for search
                if (languageType==="asian"){
                    regExp = new RegExp(firstWord + '.{0,16}' + secondWord, "gi");
                    if(isCaseSensitive){
                        regExp = new RegExp(firstWord + '.{0,16}' + secondWord, "g");
                    }
                }else if (languageType==="others"){
                    regExp = new RegExp('\\s' + firstWord + '\\W+(?:\\w+\\W+){0,10}?' + secondWord + '\\s', "gi");
                    if (isCaseSensitive) {
                        regExp = new RegExp('\\s' + firstWord + '\\W+(?:\\w+\\W+){0,10}?' + secondWord + '\\s', "g");
                    }
                } else {
                    regExp = new RegExp('\\b' + firstWord + '\\W+(?:\\w+\\W+){0,10}?' + secondWord + '\\b', "gi");
                    if (isCaseSensitive) {
                        regExp = new RegExp('\\b' + firstWord + '\\W+(?:\\w+\\W+){0,10}?' + secondWord + '\\b', "g");
                    }
                }
            }

            //search for the occurrence of the phrase in each file content array
            sortedResultsObj=hp_matchAndSort(regExp);

            //Revert the search phrase for display
            searchFor = searchFor.replace(/\$/g, " near ");
            searchFor = searchFor.replace(/\%/g, " fby ");

        }else if(searchType == 'boolean' || searchType == 'normal'){ //boolean or normal search
            searchFor = expressionInput; //search string with boolean operators

            //build the word array for each operator
            andWordsArray 	= hp_buildBooleanSearchArray(searchFor, 'AND');
            orWordsArray 	= hp_buildBooleanSearchArray(searchFor, 'OR');
            notWordsArray 	= hp_buildBooleanSearchArray(searchFor, 'NOT');

            //compare each search keyword in the current word array
            for (var t in wordsList) {
                var currWord = wordsList[t].toString();
                if (currWord==""){
                    continue;
                }
                //regular expression for search
                if (languageType==="asian"){
                    var regExp = new RegExp('' + currWord + '', "gi");
                    if(isCaseSensitive){
                        regExp = new RegExp('' + currWord + '', "g");
                    }
                } else if (languageType==="others"){
                    regExp = new RegExp('\\s' + currWord + '\\s', "gi");
                    if (isCaseSensitive) {
                        regExp = new RegExp('\\s' + currWord + '\\s', "g");
                    }
                } else{
                    regExp = new RegExp('\\b' + currWord + '\\b', "gi");
                    if (isCaseSensitive) {
                        regExp = new RegExp('\\b' + currWord + '\\b', "g");
                    }
                }

                //search for the occurrence of the phrase in each file content array
                if (fileIndexArray) {
                    for (fileNo in fileIndexArray) {
                        //find the number of occurrence
                        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 = hp_applyBooleanSearch(fileAndWordsBeforeFilter, andWordsArray, orWordsArray, notWordsArray);

            // to assign the hit count to the result
            for (fileNo in fileAndWordsAfterFilter) {
                isResultExists = true;
                resultObj[fileNo] = fileAndCount[fileNo];
            }

            if(isResultExists){
                sortedResultsObj = hp_sortObject(resultObj);
            }

            searchFor = searchFor.replace(/\|/g, " or ");
            searchFor = searchFor.replace(/\^/g, " -");

            //The NOT words are to be removed from word array
            for (t in wordsList) {
                for (t1 in notWordsArray) {
                    if(wordsList[t] == notWordsArray[t1]){
                        wordsList.splice(t, 1);
                    }
                }
            }

        }else{ // all other word searches (wild card etc)
            //compare each search keyword in the current word array
            for (t in wordsList) {
                currWord = wordsList[t].toString();

                //regular expression for search
                if (languageType==="asian"){
                    var regExp = new RegExp('' + currWord + '', "gi");
                    if(isCaseSensitive){
                        regExp = new RegExp('' + currWord + '', "g");
                    }
                } else if (languageType==="others"){
                    regExp = new RegExp('\\s' + currWord + '\\s', "gi");
                    if (isCaseSensitive) {
                        regExp = new RegExp('\\s' + currWord + '\\s', "g");
                    }
                } else {
                    regExp = new RegExp('\\b' + currWord + '\\b', "gi");
                    if (isCaseSensitive) {
                        regExp = new RegExp('\\b' + currWord + '\\b', "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 = hp_sortObject(resultObj);
            }

            searchFor = wordsList.toString().replace(/,/g, " or ");
        }
    }

    //Convert the results to what Oxygen expects for display
    if (sortedResultsObj && sortedResultsObj.length>0){
        for (i=0;i<sortedResultsObj.length;i++){
            result=sortedResultsObj[i];
            //filenb, motsliste, motsnb, motslisteDisplay, scoring, group
            var rpf= new resultPerFile(result.key,searchFor,wordsList,wordsList.toString().split(",").length,wordsList,result.value)
            o2results.push(
                rpf
            );
        }
        resultsForDisplay=new Pages(o2results);
    }

    if (!resultsForDisplay){
        var results = document.createElement("p");
        var noResultMessage = document.createTextNode(getLocalization("Search no results"));
        results.appendChild(noResultMessage);

        var resultSpan = document.createElement("span");
        resultSpan.className="searchExpression";
        resultSpan.appendChild(document.createTextNode((searchFor?searchFor:expressionInput)));
        results.appendChild(resultSpan);
        //var results = "<p>" + getLocalization("Search no results") + " " + "<span class=\"searchExpression\">" + (searchFor?searchFor:expressionInput) + "</span>" + "</p>";
		/* start mTS 1296 - Advanced search options not working in mobile output */
	   if (isChrome = !!window.chrome && !!window.chrome.webstore) {
            document.getElementById('searchResults').innerHTML = warningMsg;
        } else {
            document.getElementById('searchResults').innerHTML = "";
        }
		/* end mTS 1296 - Advanced search options not working in mobile output */
        document.getElementById('searchResults').appendChild(results);
        return;
    }


    realSearchQuery=hp_highlightSearchQuery(searchFor);
    //Use the o2 display results
    displayResults(resultsForDisplay);
}
/**
 *
 * @param regExp
 * @return [{key:fileId,value:count}]
 * Search the indexed file for matches and return sorted results
 */
function hp_matchAndSort(regExp){
    var fileNo,count,isResultExists=false,resultObj={},sortedResultsObj;
    for (fileNo in fileIndexArray) {
        //find the number of occurrence
        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 = hp_sortObject(resultObj);
    }

    return sortedResultsObj || [];
}

/* To find all matching words based on the wild card from the index array */
function hp_getWildCardMatchingWords(wordsList, isCaseSensitive){
    var languageType=hp_getLanguageType(indexerLanguage);
    var tempWordsList = new Array();
    var regExpSearchString;
    var myRegexp, t, k,matchingWordArr,j;

    //get all the key word as a string separated by commas
    var keys = [];
    for(k in w){
        keys.push(k);
    }
    var keysStr = keys.toString();
    var aword;
    var cleanWord;
    //iterate each search key word //
    for (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
            regExpSearchString = '^' + wordsList[t].toString().replace(/\?/g, ".*");
            regExpSearchString = regExpSearchString.replace(/\*/g, ".*");
            regExpSearchString+="$";


            //regular expression for search
            myRegexp = new RegExp(regExpSearchString, "gi");
            /*
            if(isCaseSensitive){
                myRegexp = new RegExp(regExpSearchString, "g");
            }
            */
            //find matching words
            var matchingWordArr = keys.filter(function(word){
                return (word && word.trim().match(myRegexp));
            })
            for(j in matchingWordArr){
                if(!isCaseSensitive){
                    tempWordsList.push(matchingWordArr[j].toLowerCase());
                }else{
                    cleanWord=wordsList[t].toString().replace("*","").replace("?","");
                    aword=matchingWordArr[j].replace(cleanWord.toLowerCase(),cleanWord);
                    tempWordsList.push(aword);
                }
            }
        }
    }
    if (tempWordsList.length>0) {
        tempWordsList = unique(tempWordsList);
    }
    return tempWordsList;
}
/* To replacing the special characters in the search string. */
function hp_replaceSpecialChar(expressionInput, replaceAll) {
    var searchFor;
    var languageType=hp_getLanguageType(indexerLanguage);
    //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(/ - /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, "");



    if (languageType==="asian"){
        //boolean operators
        searchFor = searchFor.replace(/ or/gi, "|");
        //proximity operators
        searchFor = searchFor.replace(/ near /gi, "$");
        searchFor = searchFor.replace(/ near/gi, "");
        searchFor = searchFor.replace(/ fby /gi, "%");
        searchFor = searchFor.replace(/ fby/gi, "");
    } else if (languageType==="others"){
        //boolean operators
        searchFor = searchFor.replace(/\s or\s/gi, "|");
        //for proximity operators
        searchFor = searchFor.replace(/\s near \s/gi, "$");
        searchFor = searchFor.replace(/\s near\s/gi, "");
        searchFor = searchFor.replace(/\s fby \s/gi, "%");
        searchFor = searchFor.replace(/\s fby\s/gi, "");
    } else{
        //boolean operators
        searchFor = searchFor.replace(/\b or\b/gi, "|");
        //for proximity operators
        searchFor = searchFor.replace(/\b near \b/gi, "$");
        searchFor = searchFor.replace(/\b near\b/gi, "");
        searchFor = searchFor.replace(/\b fby \b/gi, "%");
        searchFor = searchFor.replace(/\b fby\b/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 sort the result based on the hit count */
function hp_sortObject(obj) {
    //create an array from object
    var arr = [],prop;
    for (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;
}

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

/* to extract the AND, OR and NOT words from the search string */
function hp_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){
                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 apply the boolean filter on the search results*/
function hp_applyBooleanSearch(fileAndWordsBeforeFilter, andWordsArray, orWordsArray, notWordsArray){

    var i,k,isMatching,fileAndWordsAfterFilter = {};

    //applying the NOT filter
    for (k in fileAndWordsBeforeFilter) {
        //find all the entries that matches the NOT criteria
        isMatching=false;
        for (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 (k in fileAndWordsBeforeFilter) {
            //find all the entries that matches the AND criteria
            isMatching = true;
            for (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 (k in fileAndWordsBeforeFilter) {
                //find all the entries that matches the OR criteria
                isMatching = false;
                for (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 hp_highlightSearchQuery(searchFor){
    var 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>');
    return searchForDisplay;
}

function hp_decodeFormatting(word){
    //Change HTML encoded formatting statements back to HTML
    if (!word){
        return null;
    }
    return word.replace(/&lt;b&gt; OR &lt;\/b&gt;/g, '<b> OR </b>')
        .replace(/&lt;b&gt; FBY &lt;\/b&gt;/g, '<b> FBY </b>')
        .replace(/&lt;b&gt; NEAR &lt;\/b&gt;/g, '<b> NEAR </b>')
        .replace(/&lt;b&gt; -&lt;\/b&gt;/g, '<b> -</b>');
}

function hp_getLanguageType(language){
    var  languageType = "english";
    if(typeof language != "undefined"){
        if(language=="zh" || language=="zh_cn" || language=="zh_tw" ||  language=="zh-cn" || language=="zh-tw" || language=="ja" || language=="ko" || language=="th"){
            languageType = "asian";
        }else if(language=="en"){
            languageType = "english";
        }else{
            languageType = "others";
        }
    }
    return languageType;
}

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

if (!Object.keys) {
    Object.keys = (function() {
        'use strict';
        var hasOwnProperty = Object.prototype.hasOwnProperty,
            hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
            dontEnums = [
                'toString',
                'toLocaleString',
                'valueOf',
                'hasOwnProperty',
                'isPrototypeOf',
                'propertyIsEnumerable',
                'constructor'
            ],
            dontEnumsLength = dontEnums.length;

        return function(obj) {
            if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) {
                throw new TypeError('Object.keys called on non-object');
            }

            var result = [], prop, i;

            for (prop in obj) {
                if (hasOwnProperty.call(obj, prop)) {
                    result.push(prop);
                }
            }

            if (hasDontEnumBug) {
                for (i = 0; i < dontEnumsLength; i++) {
                    if (hasOwnProperty.call(obj, dontEnums[i])) {
                        result.push(dontEnums[i]);
                    }
                }
            }
            return result;
        };
    }());
}