// ==UserScript==
// @name           GoogleAutoPager
// @namespace      http://ma.la/
// @author         ma.la <timpo@ma.la>
// @include        http://www.google.*/search*
// @description    Add autoloading for next page to Google search result. Demo at http://la.ma.la/misc/demo/googleautopager.htm (Working in Trixie and captured by Wink)
// ==/UserScript==

// Released under the GPL license
//  http://www.gnu.org/copyleft/gpl.html

// ver 0.1 @ 2005-06-23
//  experimental release
// ver 0.2 @ 2005-06-23
//  double click to start.
// ver 0.3 @ 2005-12-02 - modified by beerboy <http://beerboy.org/>
//  convert XMLHttpRequest to GM_xmlhttpRequest.
// ver 0.4 @ 2006-01-17 - modified by Takayama Fumihiko <tekezo@tkym.org>
//  - Disable "Double Click enable/disable function".
//  - Change all-links-target to _blank.
//  - Add "New Loading" effect.
// ver 0.5 @ 2006-09-02 - modified by Takayama Fumihiko <tekezo@tkym.org>
//  - fixed unloading-bug when the google-result contains sponsor.
// ver 0.6 @ 2006-10-15 - modified by Takayama Fumihiko <tekezo@tkym.org>
//  - fixed method of search 'Next href'.
//  - add 'End' text when search result was terminated.
// ver 0.7 @ 2006-11-15 - modified by Takayama Fumihiko <tekezo@tkym.org>
//  - Apply new Google HTML Result.
// ver 0.8 @ 2006-12-05 - modified by Takayama Fumihiko <tekezo@tkym.org>
//  - Add Hatena Bookmark Count function by following script.
//       http://d.hatena.ne.jp/kusigahama/20051207#p1
//       http://ukgk.g.hatena.ne.jp/faerie/
// ver 0.9 @ 2007-04-05 - modified by Takayama Fumihiko <tekezo@tkym.org>
//  - change "Now Loading" css to use style.display instead of style.visibility
// ver 1.0 @ 2007-07-18 - modified by Takayama Fumihiko <tekezo@tkym.org>
//  - [bugfix] Fixed a collapse problem when Youtube was included in search results.
//  - Invalidated onmousedown of search results.
//  - Show the "End text" even if the search result is 1 page only.

(function(){
    var base = "http://"+location.host+"/search";
    var offset;
    var num;
    var query;
    var loadingElemID = 'ggap_loadingElem';
    var nextPageBlockElemID = 'ggap_nextPageBlock';

    var Remain = {
        valueOf : function() {
            var sc = document.body.scrollTop;
            var total = (document.body.scrollHeight - document.body.clientHeight);
            var remain = total - sc;
            return total - sc;
        }
    };

    var watch_scroll = function() {
        var self = arguments.callee;
        if (Remain < 500) {
            do_request();
        }
        setTimeout(self,100);
    };

    var appendSearchResult = function(googleResult) {
        var html = "<hr />" + offset + " to " + (offset + num) + '<br /><br />';

        var list = googleResult.getElementsByTagName('*');
        var isNextExist = false;
        for (var i = 0; i < list.length; ++i) {
            if (list[i].className == 'g') {
                setLinkTarget(list[i]);
                stripOnMouseDown(list[i]);
                html += list[i].innerHTML + '<br />';
            }
            if (list[i].id == 'nn') {
                isNextExist = true;
            }
        }

        var elem = document.createElement('div');
        elem.innerHTML = html;
        document.getElementById(nextPageBlockElemID).innerHTML += html;

        if (isNextExist) {
            offset += num;
        } else {
            insertEndText();
        }
    };

    var insertEndText = function() {
        var elem = document.createElement("div");
        elem.innerHTML = "End";
        with (elem.style) {
            padding = "0.3em";
            marginBottom = "5em";
            background = "#00E";
            color = "#FFF";
        };
        document.body.appendChild(elem);
    };

    var insertNextPageBlock = function() {
        var elem = document.createElement('div');
        elem.id = nextPageBlockElemID;
        document.body.appendChild(elem);
    };

    var insertLoadingText = function() {
        var elem = document.createElement("div");
        elem.id = loadingElemID;
        elem.innerHTML = "Now Loading";
        with(elem.style){
            position = "fixed";
            top = "4px";
            right = "4px";
            padding = "0.3em";
            background = "#E00";
            color = "#FFF";
            display = "none";
        };
        document.body.appendChild(elem);
    }

    var do_request = function(){
        if (this.requested == offset) {
            return;
        }

        this.requested = offset;

        document.getElementById(loadingElemID).style.display = 'inline';
        GM_xmlhttpRequest({
                method:"GET",
                    url:base + query.replace(/start=\d*/,"start=" + offset),
                    onload:function(details)
                    {
                        var googleResult = document.createElement('div');
                        googleResult.innerHTML += details.responseText;

                        appendSearchResult(googleResult);
                        hatenaBookmarkCount();

                        document.getElementById(loadingElemID).style.display = 'none';
                    }
            });
    };

    var setLinkTarget = function(elem) {
        // all-link-target set _blank
        var listLink = elem.getElementsByTagName('a');
        for (var i = 0; i < listLink.length; ++i) {
            listLink[i].setAttribute('target', '_blank');
        }
    };

    var stripOnMouseDown = function(elem) {
        var listLink = elem.getElementsByTagName('a');
        for (var i = 0; i < listLink.length; ++i) {
            listLink[i].setAttribute('onmousedown', '');
        }
    }

    var init_autopager = function(){
        var nextElem = document.getElementById('nn');
        if (nextElem == null) {
            insertEndText();
        } else {
            var next = document.getElementById('nn').parentNode;
            var href = next.href;
            query = href.substr(href.indexOf("?"));
            offset = (query.match(/start=(\d*)/))[1] - 0;
            var tmp = query.match(/num=(\d*)/);
            num = tmp ? (tmp[1] - 0) : 10;
        }
        setLinkTarget(document);
        stripOnMouseDown(document);
    };


    var hatenaBookmarkCount = function() {
        function setBookmarkCount(link, count) {
            var a = document.createElement("a");
            a.setAttribute("href", "http://b.hatena.ne.jp/entry/"+link.href);
            a.appendChild(document.createTextNode(""+count+" user"+(count>1?"s":"")));
            with (a.style) {
                fontSize = "0.9em";
                textDecoration = "none";
                if (count >= 5) {
                    fontWeight = "bold";
                    backgroundColor = "#fff0f0";
                    color = "#f66";
                }
                if (count >= 10) {
                    backgroundColor = "#ffcccc";
                    color = "red";
                }
            }
            link.parentNode.insertBefore(a, link.nextSibling);
            link.parentNode.insertBefore(document.createTextNode(" "), link.nextSibling);
        }
        function callXmlrpc(requestbody, url2link) {
            const endpoint = "http://b.hatena.ne.jp/xmlrpc";
            function onload(response) {
                var pattern = /<name>([^<]+)<\/name>\s*<value><int>(\d+)/g;
                var m;
                while (m = pattern.exec(response.responseText)) {
                    var link = url2link[m[1]];
                    if (link && m[2] > 0) setBookmarkCount(link, m[2]);
                }
            }
            GM_xmlhttpRequest({method: "POST", url: endpoint, data: requestbody, onload: onload});
        }

        var links = document.getElementsByTagName('a');
        var request = '<?xml version="1.0"?>\n<methodCall>\n<methodName>bookmark.getCount</methodName>\n<params>\n';
        var url2link = new Object;
        String.prototype.htmlescape = function() {
            return this.replace(/&/, "&amp;").replace(/</g, "&lt;");
        }
        for (var i = 0; i < links.length; ++i) {
            if (links[i].className == 'l' && links[i].getAttribute('hatenaBookmarkCount') == null) {
                links[i].setAttribute('hatenaBookmarkCount', 'true');
                request += "<param><value><string>"+links[i].href.htmlescape()+"</string></value></param>\n";
                url2link[links[i].href] = links[i];
            }
        }
        request += "</params>\n</methodCall>\n";
        callXmlrpc(request, url2link);
    };

    // init
    if (window.location.href.indexOf(base) != -1) {
        init_autopager();
        insertLoadingText();
        insertNextPageBlock();
        hatenaBookmarkCount();
        watch_scroll();
    }
})();
