// search - pick up  requests made from search engines by referrer (including built-in site search)
// and highlight the target phrases on the page

// Add some ECMA262-5 methods if not supported natively
//
if (!('trim' in String.prototype)) {
    String.prototype.trim= function() {
        return this.replace(/^\s+/, '').replace(/\s+$/, '');
    };
}

if (!('indexOf' in Array.prototype)) {
    Array.prototype.indexOf= function(find, from /*opt*/) {
        for (var i= from || 0, n= this.length; i<n; i++)
            if (i in this && this[i]===find)
                return i;
        return -1;
    };
}

if (!('map' in Array.prototype)) {
    Array.prototype.map= function(mapper, that /*opt*/) {
        var other= new Array(this.length);
        for (var i= 0, n= this.length; i<n; i++)
            if (i in this)
                other[i]= mapper.call(that, this[i], i, this);
        return other;
    };
}

if (!('filter' in Array.prototype)) {
    Array.prototype.filter= function(filter, that /*opt*/) {
        var other= [];
        for (var i=0, n= this.length; i<n; i++)
            if (i in this && filter.call(that, this[i], i, this))
                other.push(this[i]);
        return other
    };
}

// Padded limited split
//
String.prototype.nsplit= function(sep, n) {
    var seq= this.split(sep);
    while (seq.length<n+1)
        seq.push('');
    if (seq.length>n+1) {
        seq[n]= seq.slice(n).join(sep);
        seq.length= n+1;
    }
    return seq;
}

// Backslash-escape string for literal use in a RegExp
//
function reliteral(s) {
    return s.replace(/([/\\^$*+?.()|[\]{}])/g, '\\$1')
}

// URL-decode with unknown charset. Try UTF-8 first, fall back to ISO-8859-1
//
urldecode= function(s) {
    s= s.replace(/\+/g, ' ');
    try {
        return decodeURIComponent(s);
    } catch(e) {
        return unescape(s);
    }
}

function getPageCoordinates(element) {
    var x= 0, y= 0;
    do {
        x+= element.offsetLeft;
        y+= element.offsetTop;
        element= element.offsetParent;
    } while (element && element.nodeType==1)
    return [x, y];
}

// Find regex matches in document text nodes. Reverse-walk matches,
// calling function back
//
function findTextInElement(node, pattern, callback) {
    var ignore= ['script', 'textarea', 'option', 'iframe', 'map'];
    var elements= node.getElementsByTagName('*');
    for (var elementi= elements.length; elementi-->0;) {
        var element= elements[elementi];
        if (ignore.indexOf(element.tagName.toLowerCase())===-1) {
            for (var childi= element.childNodes.length; childi-->0;) {
                var child= element.childNodes[childi];
                if (child.nodeType===3) { // TEXT_NODE
                    var matches= [];
                    var match;
                    while (match= pattern.exec(child.data))
                        matches.push(match);
                    for (var i= matches.length; i-->0;)
                        callback.call(window, child, matches[i]);
                }
            }
        }
    }
}


// main

(function() {
    // Parse query string (and hashstring for Google) of referrer page
    //
    var qs= document.referrer.nsplit('//', 1)[1].nsplit('/', 1)[1].nsplit('?', 1)[1]+'&'+document.referrer.split('#', 1)[1];
    var queries= qs.split('&');
    var lookup= {};
    for (var i= queries.length; i-->0;) {
        var components= queries[i].nsplit('=', 1);
        lookup[urldecode(components[0])]= urldecode(components[1]);
    }

    // Find search terms if present
    //
    var q= '';
    var parnames= ['q', 'query', 'p', 'encquery', 'terms', 'qs', 'qt', 'search_word', 'rdata', 'wd', 'words'];
    for (var i= 0; i<parnames.length; i++) {
        if (parnames[i] in lookup) {
            q= lookup[parnames[i]].toLowerCase();
            break;
        }
    }

    // Get words to search for in a single regex
    //
    var words= q.split(/[\s.,;:!?()<>\[\]{}]+/g).filter(function(v) {
        return v!=='';
    }).slice(0, 6);
    if (words.length===0)
        return;
    var r= new RegExp('\\b('+words.map(reliteral).join('|')+')\\b', 'gi');

    // Find in page and replace with spans
    //
    var span= null;
    findTextInElement(document.getElementById('content'), r, function(node, match) {
        var ix= words.indexOf(match[0].toLowerCase());
        if (ix!==-1) {
            node.splitText(match.index+match[0].length);
            span= document.createElement('span');
            span.className= 'highlight highlight-'+ix;
            span.appendChild(node.splitText(match.index));
            node.parentNode.insertBefore(span, node.nextSibling);
        }
    });

    // Scroll page to last replaced span (ie. first in page)
    //
    if (span!==null && 'scrollTo' in window)
        scrollTo(0, getPageCoordinates(span)[1]);
})();

