<!-- REQUIRES PROTOTYPE.JS -->
// http://ideogramme.ca/rubytext/rubytext.html

// Compliments of Quirksmode.org
function findPosX(obj) {
    var curleft = 0;
    if (obj.offsetParent)
    {
        while (obj.offsetParent)
        {
            curleft += obj.offsetLeft
            obj = obj.offsetParent;
        }
    }
    else if (obj.x)
        curleft += obj.x;
    return curleft;
}

// Compliments of Quirksmode.org
function findPosY(obj) {
    var curtop = 0;
    if (obj.offsetParent)
    {
        while (obj.offsetParent)
        {
            curtop += obj.offsetTop
            obj = obj.offsetParent;
        }
    }
    return curtop;
}

function overlaps(a, b) {
    if (a && b) {
        /*
         * (aX1,          (aX2,
         *  aY1)           aY1)
         *     .----------.
         *     |          |
         *     |          |
         *     | (bX1,    |      (bX2,
         *     |  bY1)    |       bY1)
         *     |     .-----------.
         *     |     |    |      |
         *     |     |    |      |
         *     `-----|----'      |
         * (aX1,     |    (aX2,  |
         *  aY2)     |     aY2)  |
         *           |           |
         *           |           |
         *           `-----------'
         *       (bX1,           (bX2,
         *        bY2)            bY2)
         */
        var aDim = a.getDimensions();
        var aPos = a.positionedOffset();
        var aX1 = aPos["left"];
        var aY1 = aPos["top"];
        var aX2 = aDim["width"] + aX1;
        var aY2 = aDim["height"] + aY1;

        var bDim = b.getDimensions();
        var bPos = b.positionedOffset();
        var bX1 = bPos["left"];
        var bY1 = bPos["top"];
        var bX2 = bDim["width"] + bX1;
        var bY2 = bDim["height"] + bY1;

        /*
        LOGGER.log("A => (x1,y1): (" + aX1 + "," + aY1 + "); " +
                        "(x2,y2): (" + aX2 + "," + aY2 + ")");
        LOGGER.log("B => (x1,y1): (" + bX1 + "," + bY1 + "); " +
                        "(x2,y2): (" + bX2 + "," + bY2 + ")");
         */


                /* a is left of b */         /* but b overlaps a */
        return (bX2 >= aX2 && bY2 >= aY2 && (bX1 <= aX2 || bY1 <= aY2)) ||
                /* b is left of a */         /* but a overlaps b */
               (aX2 >= bX2 && aY2 >= bY2 && (aX1 <= bX2 || aY1 <= bY2));
    }

    // if either object is null, then they can't overlap
    return false;
}

function positionRubyText() {
    document.getElementsByTagName('BODY')[0].style.position = "relative";
    var rubys = $$("RUBY");
    var prevRuby;
    var SPACE = 5;

    for(i = 0; i < rubys.length; i++) {
        var relem = rubys[i];
            Element.cleanWhitespace(relem);
        var rbase = relem.getElementsByTagName('RB')[0];
            rbase.style.whiteSpace = "pre";
            // Setting white-space to "pre" prevents base text from wrapping.
        var rtext = relem.getElementsByTagName('RT')[0];
            rtext.style.display = "none";
        var newRuby = new Element("RT");
            newRuby.innerHTML = rtext.innerHTML;
            newRuby.className = rtext.className;
            newRuby.addClassName("rubytext");
            newRuby.setAttribute("style","display: inline-block; position: absolute;");
        var parentPara = relem.up();
        if (parentPara) {
            parentPara.addClassName("contains-ruby");
        }

        document.getElementsByTagName('BODY')[0].appendChild(newRuby);
        var left = findPosX(rbase, prevRuby, newRuby);
        newRuby.style.left = left + "px";

        if (!newRuby.hasClassName("below") && overlaps(prevRuby, newRuby)) {
            left += prevRuby.getDimensions()["width"] + SPACE;
            newRuby.style.left = left + "px";
        }

        // When we append newRuby to the body tag, dividing the height by 2 becomes
        // necessary. It's not clear why this is.
        newRuby.style.top = (findPosY(rbase) - (Element.getHeight(rbase)/2) - 1) + "px";

        prevRuby = newRuby;
    }
    return;
}

function repositionRubyText() {
    var rts = $$("RT");
    var j = 0;
    for(i=0; i < rts.length; i++) {
        var currentRuby = rts[i];
        if (currentRuby.hasClassName("rubytext")) {
            var rbase = document.getElementsByTagName('RB')[j];
            j++;
            currentRuby.style.left = findPosX(rbase) + "px";
            currentRuby.style.top = (findPosY(rbase) - (Element.getHeight(rbase)/2) - 1) + "px";
        }
    }
    // $("message").innerHTML = "font size is " + monitorFontSize();
    return;
}

function monitorFontSize() {
    var f = document.defaultView.getComputedStyle($("div1"),null).getPropertyValue("font-size");
    return f;
}

function positionRuby() {
    var agt=navigator.userAgent.toLowerCase();
    if ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1)) {
        return;
    }

    positionRubyText();
    Element.observe(window, 'resize', repositionRubyText);
}


function prepForCopyEdit() {
    // <replace with="new">old</replace>
    // <ruby><rb>old</rb><rt>new</rt></ruby>
    convertToRubyText("replace, del[with]", {
        rtextContentAttr: "with"
    });

    // <insert>new</insert>
    // <ruby><rb class="insert">^</rb><rt>new</rt></ruby>
    convertToRubyText("insert, ins", {
        rbaseClass: "insert",
        rbaseContent: function() { return "^" }
    });

    // <insert-below>new</insert>
    // <ruby><rb class="insert">&darr;</rb><rt class="below">new</rt></ruby>
    convertToRubyText("insert-below, ins[class=below]", {
        rbaseClass: "insert",
        rbaseContent: function() { return "&darr;" },
        rtextClass: "below"
    });

    // <move dir="left|right">old</move>
    // <ruby><rb>old</rb><rt class="fullsize">&larr;|&rarr;</rt></ruby>
    convertToRubyText("move, del[dir]", {
        rtextClass: "fullsize",
        rtextContent: function(elem) {
            return (elem.readAttribute("dir") == "left") ? "&larr;" : "&rarr;"
        }
    });
}

function convertToRubyText(replaceTagSelector, options) {

    function defaultContent(elem, attr) {
        return (attr) ? elem.readAttribute(attr) : elem.innerHTML;
    }

    defaultOptions = {
        rbaseContent: defaultContent,
        rtextContent: defaultContent,
        rbaseContentAttr: null,
        rtextContentAttr: null
    };
    options = Object.extend(defaultOptions, options || {});

    // "class" instead of :class, otherwise IE fails
    var rbaseAttrs = (options.rbaseClass) ? { "class": options.rbaseClass } : {};
    var rtextAttrs = (options.rtextClass) ? { "class": options.rtextClass } : {};

    var replaceElems = $$(replaceTagSelector);
    var replaceElem, ruby, rbase, rtext;

    for (var i = 0; i < replaceElems.length; i++) {
        replaceElem = replaceElems[i];

        ruby = new Element("ruby");
        rbase = new Element("rb", rbaseAttrs);
        rtext = new Element("rt", rtextAttrs);

        // add elements to DOM before adding content, or IE doesn't diplay them
        replaceElem.replace(ruby);
        ruby.insert(rbase);
        ruby.insert(rtext);

        rbase.insert(options.rbaseContent(replaceElem, options.rbaseContentAttr));
        rtext.insert(options.rtextContent(replaceElem, options.rtextContentAttr));
    }
}

function init() {
    prepForCopyEdit();
    positionRuby();
}

Event.observe(window, "load", init);

