/**
 * Keyword highlighter. 
 * Basic premise based on Search Engine Keyword Highlight available at:
 *  (http://fucoder.com/code/se-hilite/)
 * Original author: Scott Yang <http://scott.yang.id.au/>
 * Based on version 1.3
 *
 * Modifications provided by Appropriate Solutions, Inc. 
 * for @Web Site Publicity.
 *
 * Usage:
 *
 * This module can be imported by any HTML page. 
 * It requires keywords to be highlighted to appear in the URL as qw=a+b+c
 * Actual highlighting provided by an accompanying wsp_hilite.css file.
 * Keywords are highlighted by wrapping them around a 
 * <span class="wsp_hilite"> class. 
 * The "wsp_" is chosen to avoid name collisions with other possible scripts
 * and style sheets.
 * Style sheet provides access to the full range of display controls.
 *
 * Add the following (with suitable paths) in the header of each page: 
 *       <link href="wsp_hilite.css" rel="stylesheet" type="text/css" media="all" />
 *       <script type="text/javascript" src="wsp_hilite.js" />
 *
 * In CSS, define the following style:
 *
 * .wsp_hilite { background-color: #ff0; }
 *
 *
 * @author Ray Cote <http://AppropriateSolutions.com/>
 * @version 1.0
 
 MODIFICATIONS:
 20060420 rgac  Release initial modification of original fucoder script.
 
 */

// Configuration:
Wsp_Hilite = {
    /**
     * Element ID to be highlighted. If set, then only content inside this DOM
     * element will be highlighted, otherwise everything inside document.body
     * will be searched.
     */
    elementid: '',
    
    /**
     * Whether we are matching an exact word. For example, searching for
     * "highlight" will only match "highlight" but not "highlighting" if exact
     * is set to true.
     */
    exact: true,

    /**
     * Maximum number of DOM nodes to test, before handing the control back to
     * the GUI thread. This prevents locking up the UI when parsing and
     * replacing inside a large document.
     */
    max_nodes: 1000,

    /**
     * Whether to automatically hilite a section of the HTML document, by
     * binding the "Wsp_Hilite.hilite()" to window.onload() event. If this
     * attribute is set to false, you can still manually trigger the hilite by
     * calling Wsp_Hilite.hilite() in Javascript after document has been fully
     * loaded.
     */
    onload: true,

    /**
     * Name of the style to be used. Default to 'wsp_hilite'.
     */
    style_name: 'wsp_hilite',

    /**
     * Set it to override the document.URL string. Used for debugging
     * only.
     */
    debug_URL: ''
};


Wsp_Hilite.walkElements = function(node, depth, textproc) {
    var skipre = /^(script|style|textarea)/i;
    var count = 0;
    while (node && depth > 0) {
        count ++;
        if (count >= Wsp_Hilite.max_nodes) {
            var handler = function() {
                Wsp_Hilite.walkElements(node, depth, textproc);
            };
            setTimeout(handler, 50);
            return;
        }

        if (node.nodeType == 1) { // ELEMENT_NODE
            if (!skipre.test(node.tagName) && node.childNodes.length > 0) {
                node = node.childNodes[0];
                depth ++;
                continue;
            }
        } else if (node.nodeType == 3) { // TEXT_NODE
            node = textproc(node);
        }

        if (node.nextSibling) {
            node = node.nextSibling;
        } else {
            while (depth > 0) {
                node = node.parentNode;
                depth --;
                if (node.nextSibling) {
                    node = node.nextSibling;
                    break;
                }
            }
        }
    }
};


/**
 * Decode the URL string and return a list of search keywords.
 */
Wsp_Hilite.decodeURL = function(url) {
    var query_string = 'kw=';
    var query = null;
    var match = new RegExp('^.*'+'kw='+'(.*)&?.*$', 'i');
    query = url.replace(match, '$1');
    if (query) {
        query = decodeURIComponent(query);
        query = query.replace(/\'|"/, '');
        query = query.split(/[\s,\+\.]+/);
    }

    return query;
};


/**
 * Highlight an HTML document using keywords extracted from document.URL.
 * This is the main function to be called to perform search engine highlight
 * on a document.
 *
 * Currently it checks for DOM element 'content', element 'container' and
 * then document.body in that order, so it only highlights appropriate section
 * on WordPress and Movable Type pages.
 */
Wsp_Hilite.hilite = function() {
    // If 'debug_referrer' then we will use that as our referrer string
    // instead.
    var e = null;
    var url = Wsp_Hilite.debug_URL ? Wsp_Hilite.debug_URL : document.URL;
    
    // get list of keywords to highlight
    var q = Wsp_Hilite.decodeURL(url);

    if (q && ((Wsp_Hilite.elementid && 
               (e = document.getElementById(Wsp_Hilite.elementid))) || 
              (e = document.body)))
    {
	   Wsp_Hilite.hiliteElement(e, q);
    }
};


/**
 * Highlight a DOM element with a list of keywords.
 */
Wsp_Hilite.hiliteElement = function(elm, query) {
    if (!query || elm.childNodes.length == 0)
	return;

    var qre = new Array();
    for (var i = 0; i < query.length; i ++) {
        query[i] = query[i].toLowerCase();
        if (Wsp_Hilite.exact)
            qre.push('\\b'+query[i]+'\\b');
        else
            qre.push(query[i]);
    }

    qre = new RegExp(qre.join("|"), "i");
    var stylemapper = {};
    for (var i = 0; i < query.length; i ++)
        stylemapper[query[i]] = Wsp_Hilite.style_name+(i+1);

    var textproc_new = function(node) {
        var match=qre.exec(node.data);
        if(match) {
            var val = match[0];

            var node2 = node.splitText(match.index);
            var node3 = node2.splitText(val.length);
            var span = node.ownerDocument.createElement('SPAN');
            
            node.parentNode.replaceChild(span,node2);
            span.className = Wsp_Hilite.style_name;
            span.appendChild(node2);           
            return span;
        } else {
            return node;
        }
    };
    
    
    var textproc = function(node) {
        var match = qre.exec(node.data);
        if (match) {
            var val = match[0];
            var k = '';
            var node2 = node.splitText(match.index);
            var node3 = node2.splitText(val.length);
            var span = node.ownerDocument.createElement('SPAN');
            node.parentNode.replaceChild(span, node2);
            span.className = Wsp_Hilite.style_name;
            span.appendChild(node2);
            return span;
        } else {
            return node;
        }
    };
    Wsp_Hilite.walkElements(elm.childNodes[0], 1, textproc);
};


// Trigger the highlight using the onload handler.
if (Wsp_Hilite.onload) {
    if (window.attachEvent) {
        window.attachEvent('onload', Wsp_Hilite.hilite);
    } else if (window.addEventListener) {
        window.addEventListener('load', Wsp_Hilite.hilite, false);
    } else {
        var __onload = window.onload;
        window.onload = function() {
            Wsp_Hilite.hilite();
            __onload();
        };
    }
}
