// ==UserScript==
// @name           Atalib
// @namespace      http://cornelii.org/~michael/
// @description    Add WorldCat Search results to Amazon pages.
// @include        http://amazon.*
// @include        http://*.amazon.*
// @version        1.21
// ==/UserScript==

(function() {

    // Guess who's a python programmer.
    function zip(a, b) {
        var result = new Array();
        for(var i=0; i<a.length; i++)
            result.push([a[i], b[i]]);
        return result;
    }

    var atalib = {
        main:   function() {
            var isbn = atalib.getISBN(window.content.location.href);
            if(isbn) {
                atalib.lookup(isbn); 
            }
        }, 

        getISBN:    function(url) {
            var re = /\/(\d{7,9}[\dX])(\/|$)/;
            var isbn;
            try {
                isbn = url.match(re)[1];
            } catch(e) {
                isbn = 0;
            }

            return isbn;
        },

        lookup:   function(isbn) {
            GM_xmlhttpRequest({
                    method:     'GET',
                    url:        'http://www.worldcat.org/isbn/'+isbn,
                    onload:     atalib.handleResults
            });
        },

        scrape:    function(re, data) {
            //GM_log("scrape: re = " + re);
            return re.exec(data)[1];
        },

        scrapeAll:  function(searchRE, extractRE, data) {
            // searchRE should be global, to find all the instances.
            var matches = data.match(searchRE);
            var found = matches.map(function(e,i,a) {
                match = extractRE.exec(e);
                if(match)
                    return match[1];
                else
                    return '';
            });
            return found;
        },

        scrapeOCLC: function(wcPage) {
            var re = /<td\sclass="label">OCLC:<\/td><td>(\d*)/;
            return atalib.scrape(re, wcPage);
        },

        scrapeLink: function(wcPage) {
            var re = /Link to this Page:\s+<a\s+href[^>]+>(http:\/\/[^<]+)/;
            return atalib.scrape(re, wcPage);
        },

        scrapeLibraries:    function(wcPage) {
            // It was necessary to introduce a wrinkle here
            // (instead of just using "scrapeAll"), because
            // it's possible for a library in the list on WorldCat
            // to *not* have a link associated with it.
            var searchRE = /<td class="name">\s*<strong>\s*(<a href="\/wcpa\/oclc\/\d+\?page=frame&url=[^&]+&[^>]*>)?[^<]+/g;
            var linkRE = /url=([^&]+)/;
            var nameRE = /([^>]+)$/;
            var matches = wcPage.match(searchRE);
            var names = matches.map(function(e,i,a) {
                return nameRE.exec(e)[1];
            });
            var links = matches.map(function(e,i,a) {
                var match = linkRE.exec(e);
                if(match)
                    return match[1];
                else
                    return '';
            });

            return zip(names, links);
        },

        scrapeDistances:    function(wcPage) {
            var searchRE = /<td class="distance">\s*&nbsp;\s*(<strong>)?[^<]+/g;
            var extractRE = /<strong>([^<]+)/;
            return atalib.scrapeAll(searchRE, extractRE, wcPage);
        },

        scrapeTotal:  function(wcPage) {
            var re = /Displaying libraries <strong>[^>]*<\/strong> out of <strong>(\d+)/;
            return atalib.scrape(re, wcPage);
        },

        getOCLCNumber:  function(wcURL) {
            return /\d+$/.exec(wcURL);
        },

        updateDocument: function(data) {
            var count = data.libraries.length;
            if(count == 0) return;

            var frag = document.createDocumentFragment();

            var table = document.createElement('table');
            table.setAttribute('id', 'atalib');
            table.setAttribute('style', 'font-size: larger; margin: 20px 0;');
            table.setAttribute('cellpadding', 6);
            table.border = 1;
            table.frame = 'box';
            frag.appendChild(table);

            var tr, td, a;

            for(var i=0; i<count; i++) {

                tr = document.createElement('tr');
                table.appendChild(tr);

                td = document.createElement('td');
                tr.appendChild(td);
                if(data.links[i]) {
                    a = document.createElement('a');
                    a.setAttribute('href', data.links[i]);
                    td.appendChild(a);
                    a.appendChild(document.createTextNode(data.libraries[i]));
                } else {
                    td.appendChild(document.createTextNode(data.libraries[i]));
                }
                
                td = document.createElement('td');
                td.setAttribute('align', 'right');
                tr.appendChild(td);

                var span = document.createElement('span');
                span.setAttribute('class', 'price');
                td.appendChild(span);

                if(data.distances[i])
                    span.appendChild(document.createTextNode(data.distances[i]));
                else
                    span.innerHTML = "&nbsp;";
            }

            tr = document.createElement('tr');
            table.appendChild(tr);
            td = document.createElement('td');
            td.setAttribute('colspan', 2);
            td.appendChild(
                document.createTextNode(
                    'Displaying ' + count + ' of ' + data.total + 
                    ' listing' + ((data.total == 1) ? '' : 's') + ' from '
                )
            );

            a = document.createElement('a');
            var worldcatURL = "http://www.worldcat.org/oclc/" + data.oclc;
            a.setAttribute('href', worldcatURL);
            a.appendChild(document.createTextNode('WorldCat'));
            td.appendChild(a);

            tr.appendChild(td);

            var origTitle = document.evaluate(
                '//div[@id="promoGrid"]',
                document, null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null).singleNodeValue;

            if(origTitle) {
                origTitle.parentNode.insertBefore(frag, origTitle);
            } else {
                GM_log("Target not found.");
            }
        },

        wcData: function(wcPage) {
            this.oclc  = atalib.scrapeOCLC(wcPage);
            //GM_log(this.oclc);

            var tmp = atalib.scrapeLibraries(wcPage);
            this.libraries = new Array();
            this.links = new Array();
            for(var i=0; i<tmp.length; i++) {
                this.libraries.push(tmp[i][0]);
                this.links.push(unescape(tmp[i][1]));
            }

            this.distances = atalib.scrapeDistances(wcPage);
            this.total = atalib.scrapeTotal(wcPage);
        },

        handleResults:  function(searchResult) {
            if(searchResult.status != 200)
                alert("WorldCat error: " + searchResult.status);
            atalib.updateDocument(new atalib.wcData(searchResult.responseText));
        },
    };

    atalib.main();
})();
