function fm_is_henkilotunnus(value) {
    var codes = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                 'A', 'B', 'C', 'D', 'E', 'F', 'H', 'J', 'K', 'L',
                 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y']; // 31

    result = value.match(/^([0-9]{6})([A+-])([0-9]{3})([0-9A-Z])$/)
    if (result == null)
        return false;

    var pv = result[1].substr(0, 2);
    var kk = result[1].substr(2, 2);
    var vv = result[1].substr(4, 2);

    if (result[2] == '+') {
        vv = "18" + vv;
    } else if (result[2] == '-') {
        vv = "19" + vv;
    } else {
        vv = "20" + vv;
    }

    pv = parseInt(pv, 10)
    kk = parseInt(kk, 10)
    vv = parseInt(vv, 10)

    var testdate = new Date(vv, kk-1, pv);
    if (! testdate
        || testdate.getDate()     != pv
        || testdate.getMonth()    != kk-1
        || testdate.getFullYear() != vv) {
        return false;
    }

    modtest = result[1] + result[3];
    var modulo = parseInt(modtest, 10) % 31;
    return codes[modulo] == result[4];
}

/* added numbering on 7.12.2006 (alankila) */
function fm_autotoc() {
    var toc = document.getElementById('toc');
    if (! toc)
        return;
    // get rid of any part after #
    var arr = window.location.href.split("#");
    var basehref = arr[0];
    var fragment = arr[1];

    /* copy is built because headings updates dynamically when I
     * add new a elements into the page. Yay for the observer pattern!
     * I opted to make a copy of the headings so that I'm immune to
     * changes I'm making myself. */
    var copy = [];
    var headings = document.getElementsByTagName("a");
    for (var i = 0; i < headings.length; i += 1)
        copy[i] = headings[i];
    headings = null; /* let browser off the hook for updating headings */

    var heading_numbered_factory = function() {
        var headingnum = 1;
        return function(text) {
            var str = "" + headingnum + ". " + text;
            headingnum += 1;
            return str;
        };
    };
    var heading_plain = function(text) {
        return text;
    };
    var headingfactory = toc.getAttribute('tva:numbering') == "numbers" ? heading_numbered_factory() : heading_plain;

    /* Go through the <a> tags, find those that were anchors, build a text
     * string like this: '&rdarr; <a href="#foo">anchor text</a><br>' except
     * it's done with DOM. */
    for (var i = 0; i < copy.length; i += 1) {
        var el = copy[i];
        if (! el.name) /* not an anchor */
            continue;

        /* generate the link list as one long stream of WTF */
        var text = el.firstChild.nodeValue;
        var headingtext = headingfactory(text);
        var link = document.createElement("a");
        link.href = basehref + "#" + el.name;
        link.appendChild(document.createTextNode(headingtext));

        /* &raquo; I think */
        toc.appendChild(document.createTextNode("\xbb "));
        toc.appendChild(link);
        toc.appendChild(document.createElement("br"));

        /* maybe prepend number to the heading */
        if (headingtext != text)
            el.replaceChild(document.createTextNode(headingtext), el.firstChild);
    }

    /* Now jump to original fragment on page if there was a fragment on url...
     * this should not cause a full refresh on any browser. */
    if (fragment)
        window.location.href = window.location.href;
}

function fm_init() {
    for (var i = 0; i < document.forms.length; i += 1) {
        var f = document.forms[i];
        fm_rig_form(f);
    }
}

function fm_rig_form(f) {
    /* if radio groups or checkbox groups were being validated by this
     * code, a shortcoming would be apparent. Accessing elements by
     * the form-as-array iterates through each element in group as if
     * the element was standalone. That has implications on the semantics
     * of a "required" test: you need to test whether any value in
     * the group was set, not whether each individual element was set. */
    for (var i = 0; i < f.length; i += 1) {
        /* unfortunately XHTML is the bastard child of XML and HTML, and has
         * the bad sides of both. What I mean is that the document will not
         * validate, but the good side is dynamic feedback, instantly and
         * separation of JS from HTML. */
        if (f[i].getAttribute && f[i].getAttribute('tva:subtype') == 'henkilotunnus') {
            f[i].checker = function() {
                var str = this.value;
                if (! str)
                    return true;
                newstr = str.toUpperCase();
                if (str != newstr)
                    this.value = newstr;
                return fm_is_henkilotunnus(newstr);
            }
            f[i].onchange = function() {
                if (! this.checker()) {
                    alert(this.getAttribute('tva:subtypefault'));
                    this.select();
                }
            };
        }
    }

    /* add a validating submit hook */
    f.onsubmit = function() {
        var i;
        /* same caveat on form element iteration applies, see above. */
        for (i = 0; i < this.length; i += 1) {
            var el = this[i];
            var str = el.getAttribute('tva:required');
            if (str) {
                if ((el.type == 'text'       && !el.value) ||
                    (el.type == 'textarea'   && !el.value) ||
                    (el.type == 'select-one' && !el[el.selectedIndex].value)) {
                    alert(str);
                    el.focus();
                    return false;
                }
            }
            if (el.checker && !el.checker()) {
                el.select();
                return false;
            }
        }
        return true;
    };
}
