//Search.js t.b.v. LG 6.0 publicatie
//De array moet zoekresultaten die wordt opgebouwd bevat geen shorttext en de url is en volledig pad naar een topic 
//    ../html/topic_[chapterguid]_[topicguid]_[position].htm
//    Er wordt geen geen targetframe meegegeven.



function initSearch() {
    // Deze functie bepaald welke zoekactie er moet worden uitgevoerd.
    //    Optie A: Zoeken in een hoofdstuk (als zowel het chapter als het search argument zijn ingevuld, en zoeken per boekje aan staat)
    //    Optie B: Zoeken in de volledige (als de vorige optie niet van toepassing is en er wel een zoekterm is ingevuld)
    //    Optie C: Tonen van een blanco zoekpagina t.b.v. zoeken per boekje (als er geen zoekterm is opgegeven maar wel een chapter)
    //    Optie D: Tonen van een blanco zoekpagina als alle voorgaande opties niet van toepassing zijn

    // bepaal of attributen zijn meegegeven in de URL    
    var s;
    s = new String(document.location);
    if (s.indexOf('?') > 0) { s = s.substr(s.indexOf('?') + 1); }
    else {
        try {
            if (parent.parent.isLearningGuideAssistent()) {
                Assistant = new ActiveXObject("LearningGuide.Assistant.COM.Assistant");
                if (Assistant.Parameters != '') att = Assistant.Parameters;
            }
            else {
                att = '-1';
            }
        }
        catch (err) {
            s = '-1';
        }
    }
    if (s != '-1') {
        // bouw een array van attributen in de URL
        var arguments = new Array();
        if (s.indexOf('&') == -1) {
            var pairs = location.search.substring(1).split('?');
        }
        else {
            var pairs = location.search.substring(1).split('&');
        }
        for (iPair = 0; iPair < pairs.length; iPair++) {
            var pair = pairs[iPair].split('=');
            var name = pair[0];
            var value = pair[1];
            arguments[name.toUpperCase()] = value;

        }
    }

    // main...
    if (typeof (arguments['_CHAPTER']) != 'undefined' && searchbychapter == 'true') {
        chapterGuid = ChapterGuidByName(decodeURI(arguments['_CHAPTER'].toUpperCase()));
        if (chapterGuid != -1) {
            parent.cd.activeMainChapterGuid = chapterGuid;
            setSelectedMainChapter();
            // chapter gevonden, controleer of een zoekterm is meegegeven
            if (typeof (arguments['_SEARCH']) != 'undefined') {
                searchChapterID = chapterGuid;
                search.search(decodeURI(arguments['_SEARCH']));
                parent.cd.searchTerm = decodeURI(arguments['_SEARCH']);
            }
            else {
                // chapter gevonden, geen zoekterm (toon zoeken per boekje)
                searchChapterID = chapterGuid;
            }
        }
        else {
            // opgegeven chapternaam bestaat niet, val terug op algemene search
            search.search(arguments['_SEARCH']);
            if (typeof (arguments['_SEARCH']) != 'undefined') {
                parent.cd.searchTerm = decodeURI(arguments['_SEARCH']);
            }
            else {
                parent.cd.searchTerm = parent.cd.searchTitle;
            }
            document.forms['nav_main_search_form'].Word.value = decodeURI(arguments['_SEARCH']);
        }
    }
    else {

        //Geen hoofdstuk opgegeven: optie B
        if (typeof (arguments['_SEARCH']) != 'undefined') {
            search.search(arguments['_SEARCH']);
            parent.cd.searchTerm = decodeURI(arguments['_SEARCH']);
            document.forms['nav_main_search_form'].Word.value = decodeURI(arguments['_SEARCH']);
        }
        else {
            //Zoekterm niet gevonden - optie D; toon blanco search pagina

        }
    }
    // Display default search title or seach by chapter title
    var menuTitle;
    var searchTerm;
    var emptySearchTerm;
    if (typeof (arguments['_SEARCH']) == 'undefined') {
        emptySearchTerm = true;
    }
    else {
        emptySearchTerm = false;
    }

    if (typeof (arguments['_CHAPTER']) != 'undefined' && searchbychapter == 'true') {
        if (typeof (arguments['_SEARCH']) != 'undefined') {
            searchTerm = arguments['_SEARCH'];
        } else {
            searchTerm = parent.cd.searchTitle;
        }
        menuTitle = '<div id="explorer_title"><p>' + decodeURI(arguments['_CHAPTER']) + '</p></div>';
        var chaptername = arguments['_CHAPTER'].replace('\'', '\\\'');
        menuTitle = menuTitle + '<div id="explorer_main" class="search"><div id="bychapter">';
        menuTitle = menuTitle + '<div id="explorer_main_search"><form id="explorer_main_search_form" action="javascript:searchChapter(\'' + chaptername + '\');"><input name="Word" type="text" value="' + decodeURI(searchTerm) + '"></form>';
        menuTitle = menuTitle + '<div id="explorer_main_search_button"><ul class="buttonlist"><li class="button"><a class="" id="searchchapter" title="' + parent.cd.searchTitle + '" href="javascript:searchChapter(\'' + chaptername + '\');"><span>' + parent.cd.searchTitle + '</span></a></li></ul>';
        menuTitle = menuTitle + '</div></div><div id="explorer_main_searchresults">'
    }
    else {
        menuTitle = '<div id="explorer_title"><p>' + decodeURI(arguments['_SEARCH']) + '</p></div><div id="explorer_main"  class="search"><div id="explorer_main_searchresults">'
    }

    var menuContent = menuTitle + search.paint(emptySearchTerm) + '</div></div></div>' + parent.cd.searchFooter;
    document.getElementById("content_explorer").innerHTML = menuContent;
    parent.cd.menuState = 'search';
    parent.cd.searchLastContent = menuContent;
    // show example files
	//    oMain = document.getElementById('content_main');
	oMain = document.getElementById('searchresultcontent');
    oMain.innerHTML = search.ShowExamples();

}




function ChapterGuidByName(name) {
    var o;
    var i;
    for (i = 0; i < chaptersPairs.length; i++) {
        o = chaptersPairs[i].split('=');
        if (o[0] == name)
            return o[1];
    }
    return -1;
}

function searchChapter(chapter) {
    var aWord = decodeURI(document.forms['explorer_main_search_form'].Word.value);
    document.forms['explorer_main_search_form'].Word.value = aWord;
    document.location.href = '../html/search.htm?_chapter=' + chapter + '&_search=' + aWord;
}


// highlight
var highlighted;
function highlight(w) {
    if (highlighted) highlighted.className = '';
    w.className = 'selected';
    highlighted = w;
}


// Global variabels
var arrResults = new Array(0);




// Search object //
function search() {
    // methods
    this.initialize = search_initialize;
    this.paint = search_paint;
    this.search = search_search;
    this.ShowExamples = search_ShowExamples

    // initialize
    this.initialize();
}

function search_initialize() {
}

function search_paint(searchTerm) {
    var HTML = "";
    var _chapter = '';
    if (arrResults.length > 0) {
        quickSort();
        for (var i = 0; i < arrResults.length; i++) {
            if (i != 0) {
                if (arrResults[i].url != arrResults[i - 1].url) {
                    if (arrResults[i].chapter != _chapter) {
                        HTML += "<div class='searchresult_chapter_title'><p>" + arrResults[i].chapter + "</p></div>";
                        HTML += "<div class='searchresult_topic' id='top_" + arrResults[i].topicId + "'><p><a href='../html/" + arrResults[i].url + "'>" + arrResults[i].title + "</a></p></div>";
                        _chapter = arrResults[i].chapter;
                    }
                    else {
                        HTML += "<div class='searchresult_topic' id='top_" + arrResults[i].topicId + "'><p><a href='../html/" + arrResults[i].url + "'>" + arrResults[i].title + "</a></p></div>";
                    }
                }
            }
            else {
                HTML += "<div class='searchresult_chapter_title'><p>" + arrResults[i].chapter + "</p></div>";
                _chapter = arrResults[i].chapter;
                HTML += "<div class='searchresult_topic' id='top_" + arrResults[i].topicId + "'><p><a href='../html/" + arrResults[i].url + "'>" + arrResults[i].title + "</a></p></div>";
            }

        }
    }
    else {
        if (searchTerm == false) {
            HTML = "<p>" + parent.cd.searchNoResults + "</p>";
        }
    }
    return (HTML);
}


//  show example file
function search_ShowExamples() {
    var HTML = '<div class="titlebar" id="content_titlebar"><div class="titlebar_title" id="content_titlebar_title"><p></p></div></div>';
    HTML += '<div class="contentarea examplelist" id="contentarea">';
    HTML +=  parent.cd.searchExplantion;
    var previousURL;
    for (var i = 0; i < arrResults.length; i++) {
        if (arrResults[i].url != previousURL) {
            HTML += '<div id="example_' + arrResults[i].topicId + '">';
            // choose between LOB and RS topics 
            if (arrResults[i].examplefile) {
                HTML += '<div id="' + arrResults[i].topicId + '" class="example_LOB">';
            }
            else {
                HTML += '<div id="' + arrResults[i].topicId + '" class="example_RS">';
            }
            HTML += '<div class="example_title">';
            HTML += '<p>';
            HTML += '<a href="' + arrResults[i].url + '" >';
            HTML += arrResults[i].title;
            HTML += '</a>';
            HTML += '</p>';
            HTML += '</div>';
            // if the topic is an LOB then show the example file    
            if (arrResults[i].examplefile) {
                HTML += '<div class="example_main">';
                HTML += '<a href="' + arrResults[i].url + '" >';
                HTML += '<img id="image_' + arrResults[i].topicId + '" src="' + arrResults[i].examplefile + '"  alt="' + arrResults[i].examplefileAlt + '" />';
                HTML += '</a>';
                HTML += '</div>';
            }
            HTML += '</div>';
            HTML += '</div>';
            previousURL = arrResults[i].url;
        }
    }
    HTML += '</div>';
    return (HTML);
}



function search_search(sentence) {
    //    This loops all DIV objects that need to be indexed (children of the 'content_main' DIV)
    //    If the sentence that is searched for exist in the inner text the DIV's data is added to the searchresults array
    //    An additional check is done for the 'chapterGuid' when search by chapter is active    

    if (sentence != '') {
        sentence = decodeURI(sentence);
        sentence = replaceSpecialCharacters(sentence);
        var oDivMain = document.getElementById('content_main');

        var ExpressionTree = BuildSearchExpression(sentence);

        var oItem = oDivMain.childNodes;
        if (oItem != null) {
            for (i = 0; i < oItem.length; i++) {
                if (oItem.item(i).tagName == 'DIV') {
                    var aTopic = new Topic(oItem.item(i));
                    if ('{' + searchChapterID + '}' == aTopic.chapterGuid | searchChapterID == '') {
                        var score = ExpressionTree.score(aTopic);
                        if (score > 0) {
                            aTopic.score = score;
                            addHit(aTopic);
                        }
                    }
                }
            }
        }
    }
}

function Topic(item) {
    this.chapterGuid = item.getAttribute('chapterGuid');
    this.topicId = item.getAttribute('topicguid');
    this.title = item.title;
    this.keywords = item.getAttribute('keywords');
    this.body = item.innerHTML.toLowerCase();
    this.chapter = item.getAttribute('chapter');
    this.url = item.getAttribute('source');
    this.order = item.getAttribute('order');
    this.shorttext = item.getAttribute('shorttext');
    this.examplefile = item.getAttribute('examplefile');
    this.examplefileAlt = item.getAttribute('examplefile');
    this.score = 0;
    this.hits = 1;
    this.chapterPos = item.getAttribute('chapterPos');
}

function addHit(aTopic) {
    if (aTopic.topicId) {
        //' add a hit to the results, each hit is counted
        for (var i = 0; i < arrResults.length; i++) {
            if (arrResults[i].topicId == aTopic.topicId && arrResults[i].chapter == aTopic.chapter) {
                arrResults[i].hits++;
                return;
            }
        }
        //' the hit was not found yet in this document, so add it
        arrResults[arrResults.length] = aTopic;
    }
}

function addHitOld(topicId, title, chapter, url, order, chapterGuid, shorttext, examplefile, examplefileAlt) {
    //function addHit(topicId, title, chapter, url, order, chapterGuid, shorttext) {
    if (topicId) {
        //' add a hit to the results, each hit is counted

        for (var i = 0; i < arrResults.length; i++) {
            if (arrResults[i].topicId == topicId && arrResults[i].chapter == chapter) {
                arrResults[i].hits++;
                return;
            }
        }
        //' the hit was not found yet in this document, so add it
        //' the document number and title are stored to be displayed

        var obj = new Object();
        obj.hits = 1;
        obj.topicId = topicId;
        obj.title = title;
        if (!chapter) { chapter = ''; }
        obj.chapter = chapter;
        obj.url = url;
        obj.order = order;
        if (!chapterGuid) { chapterGuid = ''; }
        obj.chapterGuid = chapterGuid;
        obj.shorttext = shorttext;
        obj.examplefile = examplefile;
        obj.examplefileAlt = examplefileAlt;

        arrResults[arrResults.length] = obj;
    }
}

function quickSort() {
    // sort by chapter according to position in toc
    arrResults.sort(SortByChapter);
    // sort by score descending     
    var o;
    for (var i = 0; i < arrResults.length; i++) {
        for (var j = i + 1; j < arrResults.length; j++) {
            if (arrResults[i].chapterPos == arrResults[j].chapterPos) {
                if (arrResults[i].score < arrResults[j].score) {
                    o = arrResults[i];
                    arrResults[i] = arrResults[j];
                    arrResults[j] = o;
                }
            }
        }
    }
}

function SortByChapter(a, b) {
    a = a.chapterPos;
    b = b.chapterPos;
    return a == b ? 0 : (a < b ? -1 : 1)
}




// Search object //

// BuildSearchExpression Parse sentence and build expression tree //
var LITERALBYDOUBLEQUOTE = new RegExp('^"([^"]*)".*$'); //returns first dubblequoted section in a string
var LITERALBYSINGLEQUOTE = new RegExp('^\'([^\']*)\'.*$'); //returns first singlequoted section in a string

// BuildSearchExpression builds an Expression object for the sentence 
// params:
//  sentence: string
// return value
//  Expression object (AndExpression|OrExpression|LitteralExpression|EmptyExpression)
function BuildSearchExpression(sentence) {
    if (sentence === undefined) sentence = '';
    sentence = sentence.ltrim();
    if (sentence == '') {
        return new EmptyExpression();
    }

    // Split the sentence in a left hand side token and string remainder
    var tokens = GetToken(sentence);
    var firstToken = tokens[0];
    var remainder = tokens[1];

    // set expression LeftHandSide 
    // current token is either a string literal or a set of expressions enclosed by brackets
    var lhs; // expression
    if (firstToken.toString().charAt(0) == '(') {
        lhs = BuildSearchExpression(firstToken.substr(1, firstToken.length - 2));
    }
    else {
        lhs = new LitteralExpression(firstToken);
    }

    var ExpressionContainer = GetOperator(remainder);
    var expression = ExpressionContainer[0];
    remainder = ExpressionContainer[1];
    if (null == expression) {
        expression = lhs;
    }
    else {
        expression.lhs = lhs;
        expression.rhs = BuildSearchExpression(remainder);
    }
    return expression;
}

// GetOperator determines the operator type of the current expression
// params:
//  sentence: string
// return value:
//  Array(expression object (AndExpression | OrExpression | null), remainder)
function GetOperator(sentence) {
    sentence = sentence.ltrim();
    if ('' == sentence) {
        return new Array(null, sentence); //remainder is empty
    }
    else if (sentence.substr(0, 3).toLowerCase() == 'and') {
        return new Array(new AndExpression(), sentence.substr(3));
    }
    else if (sentence.substr(0, 3).toLowerCase() == '+') {
        return new Array(new AndExpression(), sentence.substr(1));
    }
    else if (sentence.substr(0, 2).toLowerCase() == 'or') {
        return new Array(new OrExpression(), sentence.substr(2));
    }
    else {
        return new Array(new OrExpression(), sentence);
    }
}

// GetToken gets first token (word, literal or bracketedExpression) from sentence
// params:
//  sentence: string
// return value
//  array [token, remainder]
function GetToken(sentence) {
    var token;
    var remainder;
    sentence = sentence.trim();
    if (sentence.charAt(0) == '(') {
        var bracketedExpression = GetBracketedExpression(sentence);
        token = bracketedExpression[0];
        remainder = bracketedExpression[1];
    }
    else if (sentence.charAt(0) == '"') {
        token = LITERALBYDOUBLEQUOTE.exec(sentence)[1];
        remainder = sentence.substr(token.length + 2);
        return new Array(token, remainder);
    }
    else if (sentence.charAt(0) == '\'') {
        token = LITERALBYSINGLEQUOTE.exec(sentence)[1];
        remainder = sentence.substr(token.length + 2);
    }
    else {
        if (sentence.indexOf(' ') != -1) {
            token = sentence.substr(0, sentence.indexOf(' '));
            remainder = sentence.substr(token.length);
        }
        else {
            token = sentence;
            remainder = '';
        }
    }
    return new Array(token, remainder);
}

// GetBracketedExpression gets first bracketedExpression from sentence
// params:
//  sentence: string
// return value
//  array [brackedtedExpression, remainder]
function GetBracketedExpression(sentence) {
    var openBracketCounter = 0;
    var closeBracketCounter = 0;
    var token;
    var remainder;
    var i = 0;
    for (var i; i < sentence.length; i++) {
        var currentChar = sentence.charAt(i);
        if (currentChar == '(') {
            openBracketCounter++;
        }
        else if (currentChar == ')') {
            closeBracketCounter++;
        }
        if (openBracketCounter == closeBracketCounter) {
            break;
        }
    }
    // Make sure the number of open and close brackets is balanced, otherwise it's not a valid search expression
    while (closeBracketCounter < openBracketCounter) {
        sentence += ')';
        closeBracketCounter++;
        i++;
    }
    token = sentence.substr(0, i + 1);
    remainder = sentence.substr(i + 1);
    return new Array(token, remainder);
}

//  Expression Object  //

// AndExpression
function AndExpression() {
    this.score = AndExpression_Score;
    this.lhs = new EmptyExpression();
    this.rhs = new EmptyExpression();
    this.toString = AndExpression_toString;
}

// Returns the lowest score of all subExpressions 
function AndExpression_Score(topic) {
    var result = 1;
    var subExpressions = new Array(this.lhs, this.rhs);
    for (var i = 0; i < subExpressions.length; i++) {
        var aScore = subExpressions[i].score(topic);
        if (aScore == 0) {
            // optimization only. result would be identical when we would allow the loop to finish.
            return 0;
        }
        else {
            if (aScore < result) {
                result = aScore;
            }
        }
    }
    return result;
}
function AndExpression_toString() {
    return '(' + this.lhs.toString() + ' AND ' + this.rhs.toString() + ')';
}

// OrExpression
function OrExpression() {
    this.score = OrExpression_Score;
    this.lhs = new EmptyExpression();
    this.rhs = new EmptyExpression();
    this.toString = OrExpression_toString;
}
// Returns sum of the scores of all subExpressions 
function OrExpression_Score(topic) {
    var result = 0;
    var subExpressions = new Array(this.lhs, this.rhs);
    for (var i = 0; i < subExpressions.length; i++) {
        result += subExpressions[i].score(topic);
    }
    return result;
}
function OrExpression_toString() {
    return '(' + this.lhs.toString() + ' OR ' + this.rhs.toString() + ')';
}


// LitteralExpression
//    param: string;
function LitteralExpression(sentence) {
    this.score = LitteralExpression_Score;
    this.sentence = sentence.replace(')', '');
    this.toString = LitteralExpression_toString;
}

// Returns 0 if text is not matched
// 1 if sentence is in title
// 0.5 if sentence is in body
function LitteralExpression_Score(topic) {
    var score = 0;    
    if (topic.title.indexOf(this.sentence) != -1) {
        var instance = countInstances(topic.title.toString(), this.sentence);
        score += instance * 1;
    }
    if ((null != topic.keywords) && (topic.keywords.indexOf(this.sentence) != -1)) {
        var instance = countInstances(topic.keywords.toString(), this.sentence);
        score += instance * 1;
    }
    if (topic.body.indexOf(this.sentence) != -1) {
        var instance = countInstances(topic.body.toString(), this.sentence);
        score += 0.5 + ((instance-1) * 0.3);
    }
    return score;
}

function LitteralExpression_toString() {
    return '"' + this.sentence + '"';
}

function countInstances(string, word) {
    var substrings = string.split(word);
    return substrings.length - 1;
}

// EmptyExpression
function EmptyExpression() {
    this.score = 1;
    this.toString = EmptyExpression_toString;
}

function EmptyExpression_toString() {
    return ' [empty expression]';
}

// Javascript trim function //
String.prototype.trim = function () {
    return this.replace(/^\s*|\s*$/g, "")
}
String.prototype.ltrim = function () {
    return this.replace(/^\s*/g, "")
}
String.prototype.rtrim = function () {
    return this.replace(/\s*$/g, "")
}
