// ==UserScript==
// @name            Link Manipulator
// @namespace       http://twitter.com/kosugi
// @description     manipulate links using plugin scripts
// @include         *
// ==/UserScript==
//
// version: 2008-06-22T17:17:40+09:00
// author:  KOSUGI Tomo (kosugi dot tomo at gmail dot com)
// license: GPL <http://www.gnu.org/copyleft/gpl.html>
//
//
// What's LinkManipulator:
//
//   LinkManipulator manipulates all links using plugin scripts (manipulator).
//   actual manipulator will be called by LinkManipulator
//   when the page loaded or paged by AutoPagerize.
//
//   for example, manipulator may expand various shorten URL,
//   set/remove 'target' attribute, etc.
//
//
// How to plug a manipulator into the LinkManipulator:
//
//   plugin script can add the manipulator function to LinkManipulator object.
//   |
//   | if (window.LinkManipulator)
//   |   window.LinkManipulator.addManipulator(f);
//   |
//   note that LinkManipulator should be loaded before other plugin scripts.
//   deferring (by setTimeout) method won't be work correctly.
//
//   when the page loaded or paged, manipulator function will be called like below:
//   |
//   | manipulator(anchor, chain);
//   |
//   'anchor' is a link node in current context, and
//   'chain' is a function to chain to the next manipulator (loaded after this script).
//
//   then, function should be defined like below:
//   |
//   | function manipulator(anchor, chain) {
//   |   anchor.textContent = anchor.href;
//   |   chain();
//   | }
//   |
//   if you don't call the function 'chain',
//   manipulation chain for this anchor will be stopped here.
//
//
// Experimental feature:
//   function 'chain' can receive one boolean argument (default: false).
//   if it receives the value 'true' once at least in the chain,
//   in the end of the chain, manipulation repeats again for this link node.
//   CAUTION: IT MAY CAUSE AN INFINITE LOOP.
//

new function() {

    var manipulators = [];

    var iterator = function(node, manipulators) {
        var n = 0, len = manipulators.length;
        var doRepeat = false;
        return function () {
            if (arguments[0])
                doRepeat = true;
            if (n < len)
                manipulators[n++](node, arguments.callee);
            else if (doRepeat)
                n = 0, doRepeat = false, arguments.callee();
        }
    }

    var doIt = function(node) {
        var num_manips = manipulators.length;
        if (0 == num_manips)
            return;

        var anchors = node.getElementsByTagName('a');
        for (var n = 0, len = anchors.length; n < len; ++n)
            iterator(anchors[n], manipulators)();
    }

    if (!window.LinkManipulator) {
        window.LinkManipulator = {
            addManipulator: function(manipulator) {
                manipulators.push(manipulator);
            }
        };
    }

    setTimeout(function() {
        if (window.AutoPagerize && window.AutoPagerize.addFilter) {
            window.AutoPagerize.addFilter(function(ctx) {
                ctx.forEach(function(node) { doIt(node); });
            });
        }
    }, 0);

    setTimeout(doIt, 300, document);
}
