// ==UserScript==
// @name            Shorten URL Expander (LM plugin)
// @namespace       http://twitter.com/kosugi
// @description     expands various shorten URLs
// @include         *
// ==/UserScript==
//
// version: 2008-09-07T18:54:14+09:00
// author:  KOSUGI Tomo (kosugi dot tomo at gmail dot com)
// license: GPL <http://www.gnu.org/copyleft/gpl.html>
//
// LM-priority: 100
//
// TODO: to clear/truncate cache automatically

new function() {

    var loading = [
        'data:image/gif;base64,',
        'R0lGODlhEAAQAPEAAP///6CY/7Ot/gAAACH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5',
        'BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAACLYSPacLtvkA7U64qGb2C6gtyXmeJ',
        'HIl+WYeuY7SSLozV6WvK9pfqWv8IKoaIAgAh+QQACgABACwAAAAAEAAQAAACLYSPacLtvhY7DYhY',
        '5bV62xl9XvZJFCiGaReS1Xa5ICyP2jnS+M7drPgIKoaIAgAh+QQACgACACwAAAAAEAAQAAACLISP',
        'acLtvk6TE4jF6L3WZsyFlcd1pEZhKBixYOie8FiJ39nS97f39gNUCBEFACH5BAAKAAMALAAAAAAQ',
        'ABAAAAIshI9pwu2+xGmTrSqjBZlqfnnc1onmh44RxoIp5JpWN2b1Vdvn/ZbPb1MIAQUAIfkEAAoA',
        'BAAsAAAAABAAEAAAAi2Ej2nC7b7YaVPEamPOgOqtYd3SSeFYmul0rlcpnpyXgu4K0t6mq/wD5CiG',
        'gAIAIfkEAAoABQAsAAAAABAAEAAAAiyEj2nC7b7akSuKyXDE11ZvdWLmiQB1kiOZdifYailHvzBk',
        'o5Kpq+HzUAgRBQA7AAAAAAAAAAAA'].join('');

    var scheme = /^https?:\/\//;
    var patterns = [
            /^ping\.fm\//,
            /^(www\.)?qurl\.com\//,
            /^xrl\.us\//,
            /^(preview\.)?tinyurl\.com\//];
    // 'http://urltea.com/',   // urltea (down)
    // 'http://z.la/',         // z.la (discon)

    var setObject = function(name, obj) {
        GM_setValue(name, obj.toSource());
    }

    var getObject = function(name, value) {
        return eval(GM_getValue(name, (value || {}).toSource()));
    }

    var REPLACE_ANCHOR_TEXT_TO_URL = GM_getValue('REPLACE_ANCHOR_TEXT_TO_URL', false);

    var CACHE_CAPACITY = 500;

    var urls = getObject('urls');

    var setUrlTreatmentFlag = function(value) {
        GM_setValue('REPLACE_ANCHOR_TEXT_TO_URL', REPLACE_ANCHOR_TEXT_TO_URL = value);
    }

    GM_registerMenuCommand('URL Expander - 展開後の URL を表示する',   function() { setUrlTreatmentFlag(true); });
    GM_registerMenuCommand('URL Expander - 展開後の URL を表示しない', function() { setUrlTreatmentFlag(false); });
    //GM_registerMenuCommand('URL キャッシュ (' + num_urls + ' 件) を削除する', function() { urls = {}; trySave(); });

    var stack_count = 0;

    var trySave = function() {
        ++stack_count;
        setTimeout(save, 2000);
    }

    var save = function() {
        if (--stack_count <= 0) {
            var num_urls = 0;
            for (var url in urls) ++num_urls;
            if (CACHE_CAPACITY < num_urls) {
                urls = {};
            }
            setObject('urls', urls);
        }
    }

    var replaceUrl = function(node, url) {
        node.href = node.title = url;
        if (REPLACE_ANCHOR_TEXT_TO_URL)
            node.textContent = url;
    }

    var manipulate = function(node, chain) {
        var url = node.href;
        if (urls[url]) {
            replaceUrl(node, urls[url]);
            chain();
            return;
        }

        var here = window.location.href.replace(scheme, '');
        var there = url.replace(scheme, '');
        for (var n = 0, len = patterns.length; n < len; ++n) {
            if (there.match(patterns[n]) && !here.match(patterns[n])) {
                var img = document.createElement('img');
                img.src = loading;
                node.appendChild(img);

                GM_xmlhttpRequest({
                    method: 'GET',
                    url: url,
                    onerror: function(r) {
                        node.title = r.statusText;
                        node.removeChild(img);
                        chain();
                    },
                    onload: function(r) {
                        var expanded = r['finalUrl'];
                        if (url != expanded) {
                            urls[url] = expanded;
                            trySave();
                        }
                        replaceUrl(node, expanded);
                        node.removeChild(img);
                        chain();
                    }
                });
                return;
            }
        }
        chain();
    }

    setTimeout(function() {
        if (window.LinkManipulator) {
            window.LinkManipulator.addManipulator(manipulate);
        }
    }, 100);
}
