/*
 * Dynamically chain event functions in window.onload
 * http://simon.incutio.com/archive/2004/05/26/addLoadEvent
 */
function addLoadEvent(f) {
    var orig = window.onload;
    if (typeof window.onload != "function") {
        window.onload = function() {
            f();
        }
    } else {
        window.onload = function() {
            orig();
            f();
        }
    }
}

/* Note when onload scripts started executing */
startTime = new Date();
function onloadTimer() {
    onloadTime = new Date();
}
addLoadEvent(onloadTimer);

/*
 * Dynamically chain events to a specific element, with aborting.
 * http://simon.incutio.com/archive/2004/05/26/addLoadEvent
 * NOTE: addEvent(window, "onload", f) doesn't work!
 */
function addEvent(e, name, f) {
    var orig = e[name];
    if (typeof e[name] != "function") {
        e[name] = function(ev) {
            return f(ev);
        }
    } else {
        e[name] = function(ev) {
            var rc = orig(ev);
            if (rc) {
                rc = f(ev);
            }
            return rc;
        }
    }
}

/*
 * Get the target of an event
 * http://developer.apple.com/internet/webcontent/eventmodels.html
 */
function getEventTarget(ev) {
    if (!ev) {
        ev = window.event;
    }
    if (ev) {
        if (ev.target) {
            if (ev.target.nodeType == 3) {
                return ev.target.parentNode;
            }
            return ev.target;
        }
        if (ev.srcElement) {
            return ev.srcElement;
        }
    }
}

/* Check whether an element has a particular class */
function elementHasClass(e, c) {
    var re = new RegExp("(^" + c + "$|^" + c + " | " + c + "$| " + c + " )");
    return e.className.match(re);
}

/* Create a new option element */
function newOption(value, txt, sel) {
    var e = document.createElement("option");
    e.appendChild(document.createTextNode(txt));
    e.value = value;
    e.selected = sel;
    return e;
}

/* Give focus to the default element */
function setDefaultFocus() {
    var e = document.getElementById("js_focus");
    if (e) {
        e.focus();
    }
}
addLoadEvent(setDefaultFocus);

/* Connect enable/disable actions to checkboxes */
function setTogglingCheckboxes() {
    var toggler = function(e) {
        var i;
        var classes = e.className.split(" ");
        var rematch = new RegExp("js_(enable|disable)_([a-zA-Z0-9]+)");
        /* check each class separately */
        for (i = 0; i < classes.length; i++) {
            var typename = classes[i].match(rematch);
            if (typename) {
                var tgt = document.getElementById(typename[2]);
                if (tgt) {
                    if (typename[1] == "enable") {
                        tgt.disabled = !e.checked;
                    } else {
                        tgt.disabled = e.checked;
                    }
                }
            }
        }
    }
    var handler = function(ev) {
        toggler(getEventTarget(ev));
        return true;
    }
    /* add handler to all submit buttons */
    var inputs = document.getElementsByTagName("input");
    for (i = 0; i < inputs.length; i++) {
        if (inputs[i].type == "checkbox" &&
            elementHasClass(inputs[i], "js_addtoggle"))
        {
            toggler(inputs[i]);
            addEvent(inputs[i], "onclick", handler);
        }
    }
}
addLoadEvent(setTogglingCheckboxes);

/* Prevent accidental double-clicks on submit buttons */
function preventDoubleSubmit() {
    var i;
    var handler = function(ev) {
        var e = getEventTarget(ev);
        /* disable after a "delay" or form won't submit */
        var disabler = function() {
            e.disabled = true;
        }
        window.setTimeout(disabler, 0);
        /* re-enable after a delay */
        var reenabler = function() {
            e.disabled = false;
            addEvent(e, "onclick", handler);
        }
        window.setTimeout(reenabler, 1000);
        e.onclick = null;
        return true;
    }
    /* add handler to all submit buttons */
    var inputs = document.getElementsByTagName("input");
    for (i = 0; i < inputs.length; i++) {
        if (inputs[i].type == "submit") {
            addEvent(inputs[i], "onclick", handler);
        }
    }
}
addLoadEvent(preventDoubleSubmit);

/* Get the lowercase basename of a file upload */
function getUploadBasename() {
    var tgt = document.getElementById("js_fullpath");
    if (tgt) {
        var handler = function(ev) {
            var e = getEventTarget(ev);
            var dst = document.getElementById("js_basename");
            if (e && dst) {
                /* pick OS-appropriate directory separation */
                if (e.value.indexOf("/") == -1) {
                    sep = "\\";
                } else {
                    sep = "/";
                }
                var parts = e.value.split(sep);
                dst.value = parts[parts.length - 1].toLowerCase();
            }
        }
        addEvent(tgt, "onchange", handler);
    }
}
addLoadEvent(getUploadBasename);

/* Hide ask box until a link is clicked */
function initAskBox() {
    var tgt = document.getElementById("js_askbox");
    if (tgt) {
        /* show ask box and remove self when clicked */
        var handler = function() {
            var dst = document.getElementById("js_askbox");
            if (dst) {
                dst.style.display = "block";
            }
            var src = document.getElementById("js_showaskbox");
            if (src) {
                src.parentNode.removeChild(src);
            }
            return false;
        }
        /* build js_showaskbox inside a div so IE aligns it right */
        var e = document.createElement("div");
        e.style.textAlign = "center";
        e.id = "js_showaskbox";
        e.className = "vpad";
        tgt.parentNode.insertBefore(e, tgt);
        var f = document.createElement("input");
        f.type = "submit";
        f.value = "Ready to ask?";
        f.className = "inbutton";
        addEvent(f, "onclick", handler);
        e.appendChild(f);
        tgt.style.display = "none";
    }
}
addLoadEvent(initAskBox);

/* minimal javascript strftime implementation */
function strftime(fmt, t) {
    var zeropad = function(n,c) { return n > 9 ? n : "0" + n; };
    var funcs = new Array(
        new Array("a", function(t) { return strftime("%A", t).substr(0,3); }),
        new Array("A", function(t) {
            return ["Sunday","Monday","Tuesday","Wednesday",
            "Thursday","Friday","Saturday"][t.getDay()]; }),
        new Array("b", function(t) { return strftime("%B", t).substr(0,3); }),
        new Array("B", function(t) {
            return ["January","February","March","April",
            "May","June","July","August","September",
            "October","November","December"][t.getMonth()]; }),
        new Array("d", function(t) { return zeropad(t.getDate()); }),
        new Array("e", function(t) { return t.getDate(); }),
        new Array("H", function(t) { return zeropad(t.getHours()); }),
        new Array("I", function(t) {
            var h = t.getHours() % 12; return zeropad(h == 0 ? 12 : h); }),
        new Array("M", function(t) { return zeropad(t.getMinutes()); }),
        new Array("p", function(t) { return t.getHours() < 12 ? "AM" : "PM"; }),
        new Array("S", function(t) { return zeropad(t.getSeconds()); }),
        new Array("Y", function(t) { return t.getFullYear(); })
    );
    var i;
    for (i = 0; i < funcs.length; i++) {
        if (fmt.indexOf("%" + funcs[i][0]) != -1) {
            fmt = fmt.replace("%" + funcs[i][0], funcs[i][1](t));
        }
    }
    return fmt;
};

/* adjust date and time fields for timezone offsets */
function adjustTimezone() {
    /* get timezone offset in milliseconds */
    var d = new Date();
    var tzoff = d.getTimezoneOffset() * 60000;

    /* update all displayed timestamps */
    var i;
    var elms = document.getElementsByTagName("span");
    for (i = 0; i < elms.length; i++) {
        var e = elms[i];
        /* update timestamps with full date */
        if (elementHasClass(e, "js_tslong")) {
            d.setTime(Date.parse(e.lastChild.data) - tzoff);
            var txt = strftime("%a %b %d %H:%M:%S %Y", d);
            e.replaceChild(document.createTextNode(txt), e.lastChild);
        /* update timestamps with only the time */
        } else if (elementHasClass(e, "js_tsshort")) {
            d.setTime(Date.parse("Jan 1 1970 " + e.lastChild.data) - tzoff);
            var txt = strftime("%I:%M %p", d);
            e.replaceChild(document.createTextNode(txt), e.lastChild);
        }
    }

    /* break timestamped rows up by day */
    var day = null;
    var rematch = new RegExp("ts([0-9]+)");
    elms = document.getElementsByTagName("tr");
    for (i = 0; i < elms.length; i++) {
        var e = elms[i];
        if (elementHasClass(e, "js_ts")) {
            var match = e.className.match(rematch);
            if (match) {
                d.setTime(match[1] * 1000 - tzoff);
                var today = Math.floor(d.getTime() / 86400000);

                /* add a date row if we hit the next day */
                if (!day || today != day) {
                    day = today;
                    var txt = strftime("%A, %B %e, %Y", d);
                    var td = document.createElement("td");
                    td.className = "day";
                    td.colSpan = "5";
                    td.appendChild(document.createTextNode(txt));
                    var tr = document.createElement("tr");
                    tr.appendChild(td);
                    e.parentNode.insertBefore(tr, e);
                }
            }
        }
    }
}
addLoadEvent(adjustTimezone);

/*
 * Theme switcher: http://www.alistapart.com/articles/alternate/
 */

/* Find and activate the requested stylesheet */
function setTheme(title) {
    var i;
    var found = false;
    var links = document.getElementsByTagName("link");
    /* bail if the requested stylesheet doesn't exist */
    for (i = 0; i < links.length; i++) {
        var e = links[i];
        if (e.rel.indexOf("style") != -1 && e.title == title) {
            found = true;
            break;
        }
    }
    if (!found) {
        return false;
    }
    /* disable all titled (optional) stylesheets except the requested one */
    for (i=0; i < links.length; i++) {
        var e = links[i];
        if (e.rel.indexOf("style") != -1 && e.title) {
            e.disabled = true;
            if (e.title == title) {
                e.disabled = false;
            }
        }
    }
    return true;
}

/* Save a cookie with the provided theme title */
function saveThemeCookie(title) {
    var date = new Date();
    date.setFullYear(date.getFullYear() + 1);
    var expires = "; expires=" + date.toGMTString();
    document.cookie = "theme=" + title + expires + "; path=/";
}

/* Load the theme title from the cookie */
function loadThemeCookie() {
    var name = "theme=";
    var attrs = document.cookie.split(";");
    for (var i = 0; i < attrs.length; i++) {
        var a = attrs[i];
        while (a.charAt(0)==" ") {
            a = a.substr(1);
        }
        if (a.indexOf(name) == 0) {
            return a.substr(name.length);
        }
    }
    return null;
}

/* Apply a theme; save settings if successful */
function applyTheme(title) {
    if (setTheme(title)) {
        saveThemeCookie(title);
    }
}

/* Initialize theme switcher options */
function initThemes() {
    var tgt = document.getElementById("js_themes");
    if (tgt) {
        var i;
        var links = document.getElementsByTagName("link");
        for (i = 0; i < links.length; i++) {
            var e = links[i];
            /* add theme switchers for each titled stylesheet */
            if (e.rel.indexOf("style") != -1 && e.title.length != 0) {
                var a = document.createElement("a");
                a.href = "javascript:applyTheme(\"" + e.title + "\");";
                a.appendChild(document.createTextNode(e.title));
                var div = document.createElement("div");
                div.className = "opt";
                div.appendChild(a);
                tgt.appendChild(document.createTextNode(" "));
                tgt.appendChild(div);
                tgt.appendChild(document.createTextNode(" "));
            }
        }
    }
}
addLoadEvent(initThemes);

/* Load theme preference without waiting for window.onload */
function loadTheme() {
    var title = loadThemeCookie();
    if (title) {
        setTheme(title);
    }
}
loadTheme();

/* Display a confirmation message when an element is clicked */
function confirmOnClick(e) {
    var handler = function(ev) {
        /* get confirmation suffix */
        var tgt = getEventTarget(ev);
        var reclass = new RegExp("js_confirmname_([a-zA-Z0-9]+)");
        var name = tgt.className.match(reclass);
        if (name) {
            var src = document.getElementById("js_confirminfo_" + name[1]);
            if (src) {
                /* clean up space/tab noise in message */
                var respace = new RegExp("[ \t\n\r]+", "g");
                var msg = src.lastChild.data.replace(respace, " ");
                if (msg) {
                    return confirm(msg);
                }
            }
        }
        return true;
    }
    addEvent(e, "onclick", handler);
}

/* Initialize all confirmation message events */
function initConfirm() {
    /* hide confirmation message list */
    var e = document.getElementById("js_confirminfo");
    if (e) {
        e.style.display = "none";
    }
    /* add confirmation to submit buttons */
    var inputs = document.getElementsByTagName("input");
    for (i = 0; i < inputs.length; i++) {
        if (inputs[i].type == "submit" &&
            elementHasClass(inputs[i], "js_addconfirm"))
        {
            confirmOnClick(inputs[i]);
        }
    }
}
addLoadEvent(initConfirm);

/* Toggle visibility of an ignored entry */
function toggleIgnored(eid) {
    var e = document.getElementById(eid);
    if (e) {
        var txt = "hide";
        /* initial display style is empty, or "none" when rehidden */
        if (e.style.display.length == 0 || e.style.display == "none") {
            e.style.display = "block";
        } else {
            e.style.display = "none";
            txt = "show";
        }
        /* update c## visibility control */
        var c = document.getElementById("c" + eid.substr(1));
        if (c)
        {
            c.replaceChild(document.createTextNode(txt), c.lastChild);
        }
    }
}

/* Add visibility toggles to ignored entries */
function initIgnored() {
    var i;
    var spans = document.getElementsByTagName("span");
    for (i = 0; i < spans.length; i++) {
        /* controls are spans with w## id and js_ignore class */
        var e = spans[i];
        if (elementHasClass(e, "js_ignore")) {
            /* replace with visibility toggle having id c## */
            var x = e.id.substr(1);
            var tgt = document.createElement("a");
            tgt.id = "c" + x;
            tgt.href = "javascript:toggleIgnored(\"p" + x + "\");"
            tgt.appendChild(document.createTextNode("show"));
            e.replaceChild(tgt, e.lastChild);
        }
    }
}
addLoadEvent(initIgnored);

/* Rewrite icon dropdown when a new character is selected */
function selectNewChar() {
    var csel = document.getElementById("js_charsel");
    var isel = document.getElementById("js_iconsel");
    if (csel && isel) {
        var icons = iconList[csel.value];
        if (!icons) {
            alert("Character has no icons; try reloading the page.");
            return false;
        }
        /* remove all icons from select box */
        while (isel.length != 0) {
            isel.remove(isel.length - 1);
        }
        /* readd icons */
        var i;
        var nonesel = true;
        for (i = 0; i < icons.length; i++) {
            if (icons[i][2]) {
                nonesel = false;
            }
            isel.appendChild(newOption(icons[i][0], icons[i][1], icons[i][2]));
        }
        /* add the custom option if url textbox is available */
        var itext = document.getElementById("js_icontext");
        if (itext) {
            isel.appendChild(newOption("y", "Custom", nonesel));
        }
    }
    return true;
}

/* Initialize dynamic icon selection */
function initIconSelect() {
    var csel = document.getElementById("js_charsel");
    var isel = document.getElementById("js_iconsel");
    if (csel && isel) {
        var i;
        var icons = new Array();
        /* collect current non-custom icon options */
        for (i = 0; i < isel.options.length; i++) {
            var value = isel.options[i].value;
            var txt = isel.options[i].text;
            var sel = (isel.selectedIndex == i);
            if (value != "y") {
                icons[icons.length] = new Array(value, txt, sel);
            }
        }
        /* get the current character selection */
        var cur = null;
        for (i = 0; i < csel.options.length; i++) {
            if (csel.options[i].defaultSelected) {
                cur = csel.options[i].value;
                break;
            }
        }
        /* replace/add selection in the master icon list */
        if (cur) {
            iconList[cur] = icons;
        }
        /* if not present, add entry author to master icon list */
        if (cur != "x") {
            iconList["x"] = new Array(new Array("x", "default", true));
        }
        addEvent(csel, "onchange", selectNewChar);
        /* handle cached selections from back/forward/reload */
        selectNewChar();
    }
}
addLoadEvent(initIconSelect);

/* Display how long onload scripts have been running */
function showOnloadTime() {
    var e = document.getElementById("js_elapsed");
    if (e) {
        var load = (onloadTime.getTime() - startTime.getTime()) / 1000;
        var dynamic = (new Date().getTime() - onloadTime.getTime()) / 1000;
        var msg = " || Load: " + load + "s || Dynamic: " + dynamic + "s";
        e.replaceChild(document.createTextNode(msg), e.lastChild);
    }
}
addLoadEvent(showOnloadTime);
