if (Navigator.IsRoot == false)
{
    if (window.opener != null && window.opener.Filter != null)
    {
        // use search from parent
        Search = window.opener.Search;
    } else if (window.parent != null && window.parent.Search != null)
    {
        // use search from parent
        Search = window.parent.Search;
    }
} else 
{
    // create new search
    var Search = new Object();

    Search.Init = function(htmlObject)
    {
        this.HtmlObject = htmlObject;
        this.Prefix = '<span style="background-color:pink">';
        this.Postfix = '</span>';
        
        this.Show();
        
        Navigator.OnDocumentLoad.Bind(this.Highlight, this);
        
        if (window.Filter != null && Filter.Active == true){
            Filter.OnChange.Bind(this.FilterChange, this);
        }
    }

    Search.Show = function(){
        var html = "";

        // close search button
        html += '<div id="search_header" class="menu_header">';
        html += '<a id="search_close" onclick="ToggleSearch(); return false;" class="close_button"></a>';
        html += '</div>';
        
        
        // search index
        html += '<iframe id="searchIndex" src="content/searchIndex.htm" style="display: none;" onload="Search.LoadHaystack(this);"></iframe>';
        html += '<iframe id="dmsSearchResults" style="display: none;" onload="Search.LoadDmsResults(this);"></iframe>';
        
        html += '<div id="search_input">';
        
        html += '<div id="search_string">';
        html += '<input type="text" id="search_text" onkeypress="if (event.keyCode==13) Search.Search();"/>';
        html += '<input id="search_button" type="button" value="' + Translation.btn_search + '" onclick="Search.Search();"/>';
        html += '</div>';
        
        html += '<div id="search_wholeWord" class="search_option">';
        html += '<input id="search_wholeWord_checkbox" class="search_checkbox" type="checkbox"/>';
        html += '<span id="search_wholeWord_caption" class="search_caption">' + Translation.lbl_wholeWord + '</span>';
        html += '</div>';
        
        html += '<div id="search_caseSensitive" class="search_option">';
        html += '<input id="search_caseSensitive_checkbox" class="search_checkbox" type="checkbox"/>';
        html += '<span id="search_caseSensitive_caption" class="search_caption">' + Translation.lbl_caseSensitive + '</span>';
        html += '</div>';
        
        html += '</div>';
        
        html += '<div id="search_results">' + Translation.msg_search_notFound + '</div>';
        html += '<div id="search_dms_results"></div>';
        
        this.HtmlObject.innerHTML = html;
    }

    Search.FilterChange = function()
    {
        // allow new search to occur with same parameters
        this.Params = null;
        
        // remove current results
        var searchResults = document.getElementById("search_results");
        searchResults.innerHTML = Translation.msg_search_notFound;
    }

    Search.LoadHaystack = function(haystackNode)
    {
        this.Haystack = haystackNode.contentWindow.document.body;
    }

    Search.GetParams = function()
    {
        return { 
            Text: document.getElementById("search_text").value,  
            WholeWord: document.getElementById("search_wholeWord_checkbox").checked,
            CaseSensitive: document.getElementById("search_caseSensitive_checkbox").checked
        };
    }

    Search.Search = function()
    {
        // get parameters
        var params = this.GetParams();
        if (this.Params != null && params.Text == this.Params.Text && params.CaseSensitive == this.Params.CaseSensitive && params.WholeWord == this.Params.WholeWord) return; // don't search for the same thing twice
        this.Params = params;

        // Generate Regular Expression
        this.GenerateExpression();
        
        // notify that search is in progress
        var fResultContainer = document.getElementById("search_results");
        fResultContainer.innerHTML = Translation.msg_search_inProgress;
        
        this.DmsSearch();
        
        // Excecute search
        window.setTimeout("Search.Finish();", 0);
    }

    Search.Finish = function()
    {
        // Execute search
        if (this.SearchExpression != null){ 
            var result = this.SubSearch(this.Haystack);
            if (result != null) var results = result.SubResults;
            else var results = new Array();
        } else {
            var results = new Array();
        }
        
        // write results
        var fResultContainer = document.getElementById("search_results");

        // Create Results
        if (results.length == 0)
        {
            fResultContainer.innerHTML = Translation.msg_search_notFound;
        } else
        {
            fResultContainer.innerHTML = this.CreateResultTable(results);
        }
    }

    Search.GenerateExpression = function ()
    {
        if (this.Params.Text == ""){
            this.SearchExpression = null;
            return;
        }
        
        var text = strip(this.Params.Text).replace(/([\\|^$()[\]{}.*+?])/g, '\\$1');

        // look for whole word
        if (this.Params.WholeWord == true) text = "\\b" + text + "\\b";

        // use casesensitive searching
        if (this.Params.CaseSensitive == true) this.SearchExpression  = new RegExp(text, "g");
        else this.SearchExpression = new RegExp(text, "gi");
    }
    
    Search.DmsSearch = function()
    {
        var iframe = document.getElementById("dmsSearchResults");
        //iframe.src = "content/dmsSearchResults.htm";
    }
    
    Search.LoadDmsResults = function(object)
    {
        var results = object.contentWindow.DmsSearchResults;
        
        if (results == null) return;
        
        var htmlObject = document.getElementById("search_dms_results");
        
        var html = '<table class="search_results_table" cellspacing="0">';
        html += this.CreateResultHeader();
        
        for (var i in results){
            var result = results[i];
            html += this.CreateDmsResultRows(result.Id, result.SubResults, 0);
        }
        
        html += "</table>";
        
        htmlObject.innerHTML = html;
        
        return html;
    }
    
    Search.CreateDmsResultRows = function(id, results, indent)
    {
        var html = '';

        // create result rows
        for (var i = 0; i < results.length; i++)
        {
            var result = results[i];
            
            html += this.CreateResultRow(id, result.Path, result.Count, false, indent);

            if (result.SubResults != null && result.SubResults.length > 0)
            {
                html += this.CreateDmsResultRows(id, result.SubResults, indent + 1);
            }
        }
        
        return html;
    }

    Search.SubSearch = function(documentNode)
    {
        var fCount = 0;
        var fSubResults = new Array();
        
        for (var i = 0; i < documentNode.childNodes.length; i++)
        {
            var fCurrentNode = documentNode.childNodes[i];
            var menuitem = window.Menuitems[fCurrentNode.id];
            
            if (fCurrentNode.tagName == "DIV" && menuitem.Filtered !== true)
            {
                // search childnodes
                var fResults = this.SubSearch(fCurrentNode);
                if (fResults != null) fSubResults.push(fResults);
            }
            else if (fCurrentNode.tagName == "P")
            {
                // find text of the node
                var fNodeText;
                if (fCurrentNode.innerText == null)
                {
                    // firefox
                    fNodeText = fCurrentNode.textContent;
                } else
                {
                    // Internet Explorer
                    fNodeText = fCurrentNode.innerText;
                }

                // find needles
                var fMatch = this.SearchExpression.exec(fNodeText);

                while (fMatch != null)
                {
                    fCount++;
                    fMatch = this.SearchExpression.exec(fNodeText);
                }
            }
        }

        // add result if needles have been found
        if (fCount > 0 || fSubResults.length > 0)
        {
            return { Node: documentNode, Count: fCount, SubResults: fSubResults };
        } else
        {
            return null;
        }
    }

    Search.Highlight = function(menuitem, opened, documentNode)
    {
        if (opened !== true) return;
        
        if (this.MenuitemIdToMark != menuitem.Id)
        {
            return;
        }
        else
        {
            this.MenuitemIdToMark = -1;
        }

        var fResult = "";
        var fPost = "", fInput = documentNode.innerHTML;
        var fMatch = this.SearchExpression.exec(fInput);
        var fIndex = 0, fLastIndex;

        while (fMatch != null)
        {
            // update regular expression info
            fLastIndex = fIndex;
            fIndex = this.SearchExpression.lastIndex;
            fPost = RegExp.rightContext;

            // make sure text is outside of html node
            var fHtmlMatch = fPost.match("<|>");
            if (fHtmlMatch == null || fHtmlMatch[0] != ">") // text is outside html
            {
                fResult += fInput.slice(fLastIndex, fIndex - fMatch[0].length);
                fResult += this.Prefix + fMatch[0] + this.Postfix;
            }
            else // text is inside a html node
            {
                fResult += fInput.slice(fLastIndex, fIndex);
            }

            // Find next
            fMatch = this.SearchExpression.exec(fInput);
        }

        // Add remaining text to the result
        fResult += fInput.slice(fIndex);

        // write result to document
        documentNode.innerHTML = fResult;
    }

    /*
    <table class="[style]_table" cellspacing="0">
    <!-- header -->
    <tr>
    <th align="left">[Translation.lbl_searchResult_title]</th>
    <th align="left">[Translation.lbl_searchResult_count]</th>
    </tr>
            
    <!-- no results/no link -->
    <tr>
    <td>
    <a class="[style]_node">
    [result.title]
    </a>
    </td>
    <td></td>
    </tr>
            
    <!-- result -->
    <tr>
    <td>
    <a class="[style]_node [style]_link" onclick="window.ContentNavigator.OpenId('[result.id]'\');">
    [result.title]
    </a>
    </td>
    <td class="[style]_count">[result.count]</td>
    </tr>
            
    <!-- nested result -->
    <tr>
    <td>
    <div class="[style]_indent">
    <a class="[style]_node [style]_link" onclick="window.ContentNavigator.OpenId('[result.id]'\');">
    [result.title]
    </a>
    </div>
    </td>
    <td class="[style]_count">[result.count]</td>
    </tr>
            
    </table>
    */
    Search.CreateResultTable = function(results)
    {
        var html = '<table class="search_results_table" cellspacing="0">';
        html += this.CreateResultHeader();

        // create result rows
        for (var i = 0; i < results.length; i++)
        {
            var result = results[i];
            
            html += this.CreateResultRow(result.Node.id, result.Node.title, result.Count, result.IsFiltered, 0);

            if (result.SubResults != null && result.SubResults.length > 0)
            {
                html += this.CreateNestedResultTable(result.SubResults, 1);
            }
        }

        html += "</table>";

        return html;
    }
    
    Search.CreateNestedResultTable = function(results, nesting)
    {
        var html = '';

        // create result rows
        for (var i = 0; i < results.length; i++)
        {
            var result = results[i];
            html += this.CreateResultRow(result.Node.id, result.Node.title, result.Count, result.IsFiltered, nesting);
            
            if (result.SubResults != null && result.SubResults.length > 0)
            {
                html += this.CreateNestedResultTable(result.SubResults, nesting + 1);
            }
        }

        return html;
    }    
    
    Search.CreateResultHeader = function()
    {
        // create header
        html = '<tr id="search_results_header_row">';
        html += '<th align="left" id="search_results_header_title" class="search_results_header_cell search_results_title_column">' + Translation.lbl_searchResult_title + '</th>';
        html += '<th align="left" id="search_results_header_count" class="search_results_header_cell search_results_count_column">' + Translation.lbl_searchResult_count + '</th>';
        html += '</tr>';
        
        return html;
    }
    
    Search.CreateResultRow = function(id, title, count, isFiltered, indent)
    {
        var result = "";
        var indentHtml = "";
        var outdentHtml = "";
        
        if (count == null) count = 0;
        if (isFiltered == null) isFiltered = false;
        if (indent == null) indent = 0;
        
        while (indent > 0)
        {
            indentHtml += '<div class="search_results_indent">';
            outdentHtml += '</div>';
            indent--;
        }
        
        var filterClass = "";
        if (isFiltered && Filter != null)
        {
            filterClass = "search_results_" + Filter.Type;
        }
        
        result += '<tr class="search_results_row ' + filterClass + '">';
        result += '<td class="search_results_title search_results_title_column">';
        result += indentHtml;
     
        
        if (count > 0)
        {
            result += '<a class="search_results_node search_results_link" onclick="window.Search.MenuitemIdToMark=\'' + id + '\';window.Navigator.OpenId(\'' + id + '\');">' + title + '</a>';
        }
        else
        {
            result += '<a class="search_results_node">' + title + '</a>';
        }
        
        result += outdentHtml;
        
        result += '</td>'
        result += '<td class="search_results_count search_results_count_column">' + count + '</td>';
        
        return result;
    }

}

/**
Returns:
The text without whitespace at the start or the end.
*/
function strip(text)
{
    return text.match(/^\s*([\w\W]*?)\s*$/)[1];
}