/**
 * Validate.js: unobtrusive HTML form validation.
 *
 * On document load, this module scans the document for HTML forms and
 * textfield form elements.  If it finds elements that have a "required" or 
 * "pattern" attribute, it adds appropriate event handlers for client-side 
 * form validation.
 *
 * If a form element has a "pattern" attribute, the value of that attribute
 * is used as a JavaScript regular expression, and the element is given an
 * onchange event handler that tests the user's input against the pattern.
 * If the input does not match the pattern, the background color of the
 * input element is changed to bring the error to the user's attention.
 * By default, the textfield value must contain some substring that matches
 * the pattern. If you want to require the complete value to match precisely,
 * use the ^ and $ anchors at the beginning and end of the pattern.
 *
 * A form element with a "required" attribute must have a value provided.
 * The presence of "required" is shorthand for pattern="\S".  That is, it 
 * simply requires that the value contain a single non-whitespace character
 *
 * If a form element passes validation, its "class" attribute is set to 
 * "valid".  And if it fails validation, its class is set to "invalid".
 * In order for this module to be useful, you must use it in conjunction with
 * a CSS stylesheet that defines styles for "invalid" class.  For example:
 *
 *    <!-- attention grabbing orange background for invalid form elements -->
 *    <style>input.invalid { background: #fa0; }</style>
 *
 * When a form is submitted the textfield elements subject to validation are
 * revalidated.  If any fail, the submission is blocked and a dialog box
 * is displayed to the user letting him know that the form is incomplete
 * or incorrect.
 *
 * You may not use this module to validate any form fields or forms on which
 * you define your own onchange or onsubmit event handlers, or any fields
 * for which you define a class attribute.
 *
 * This module places all its code within an anonymous function and does
 * not define any symbols in the global namespace.
 */
(function() { // Do everything in this one anonymous function
    // When the document finishes loading, call init()
    if (window.addEventListener) window.addEventListener("load", init, false);
    else if (window.attachEvent) window.attachEvent("onload", init);

    // Define event handlers for any forms and form elements that need them.
    function init() {
        // Loop through all forms in the document
        for(var i = 0; i < document.forms.length; i++) {
            var f = document.forms[i];  // the form we're working on now

            // Assume, for now, that this form does not need any validation
            var needsValidation = false;

            // Now loop through the elements in our form
            for(j = 0; j < f.elements.length; j++) {
                var e = f.elements[j];  // the element we're working on

                // We're only interested in <input type="text"> textfields
                if (e.type != "text") continue;

                // See if it has attributes that require validation
                var pattern = e.getAttribute("pattern");
                // We could use e.hasAttribute() but IE doesn't support it
                var required = e.getAttribute("required") != null;

                // Required is just a shortcut for a simple pattern
                if (required && !pattern) {
                    pattern = "\\S";
                    e.setAttribute("pattern", pattern);
                }

                // If this element requires validation,
                if (pattern) {
                    // validate the element each time it changes
                    e.onchange = validateOnChange;
                    // Remember to add an onsubmit handler to this form
                    needsValidation = true;
                }
            }

            // If at least one of the form elements needed validation,
            // we also need an onsubmit event handler for the form
            if (needsValidation) f.onsubmit = validateOnSubmit;
        }
    }
          
    // This function is the onchange event handler for textfields that 
    // require validation.  Remember that we converted the required attribute
    // to a pattern attribute in init().
    function validateOnChange() {
        var textfield = this;                            // the textfield
        var pattern = textfield.getAttribute("pattern"); // the pattern
        var value = this.value;                          // the user's input

        // If the value does not match the pattern set the class to "invalid".
        if (value.search(pattern) == -1) textfield.className = "invalid";
        else textfield.className = "valid";
    }

    // This function is the onsubmit event handler for any form that 
    // requires validation.
    function validateOnSubmit() {
        // When the form is submitted, we revalidate all the fields in the
        // form and then check their classNames to see if they are invalid.
        // If any of those fields are invalid, display an alert and prevent
        // form submission.
        var invalid = false;  // Start by assuming everything is valid
        // Loop through all form elements
        for(var i = 0; i < this.elements.length; i++) {
            var e = this.elements[i];
            // If the element is a text field and has our onchange handler
            if (e.type == "text" && e.onchange == validateOnChange) {
                e.onchange(); // Invoke the handler to re-validate
                // If validation fails for the element, it fails for the form
                if (e.className == "invalid") invalid = true;
            }
        }

        // If the form is invalid, alert user and block submission
        if (invalid) {
            alert("The form is incompletely or incorrectly filled out.\n" +
                  "Please correct the  highlighted fields and try again.");
            return false;
        }
        return (processForm(this));
        
    }
})();
