// IMPORTANT NOTE: This file is "logically shared" between the WebSite and WebValidator modules.
// Any changes must be manually made in both places.

function validate(form) {
    clearErrors();
    var requiredGroups = new Array();
    var passwordFields = new Array();
    var message = new String();
    var totalLength = 0;
    var maximumAttributesLength = 0;

    for(i=0; i < form.elements.length; i++){
        // verify regular inputs
        var element = form.elements[i];
        if (element.getAttribute("required") == 'true' && trim(element.value) == '') {
            message += setError(element);
        }
        var validateType = element.getAttribute("vtype");
        if (validateType) {
            if ("email" == validateType) {
                message += checkEmail(element);
            }
            else if ("phone" == validateType) {
                message += checkPhone(element);
            }
            else if ("range" == validateType) {
                message += checkRange(element);
            }
        }
        var decimalPrecision = element.getAttribute("decimalprecision");
        if (decimalPrecision) {
            message += checkPrecision(element);
        }
        if (element.nodeName == "TEXTAREA" && element.getAttribute("maxlength")) {
            message += checkTextAreaLength(element);
        }

        // collect checkbox groups
        if (element.getAttribute("requiredGroup")) {
            var index = element.getAttribute("requiredGroup");
            var group = requiredGroups[index];
            if (!group)
                group = new Array();
            group.push(element.id);
            requiredGroups[index] = group;
        }
        // collect password fields
        if (element.nodeName == "INPUT" && element.type == "password") {
            passwordFields.push(element);
        }
    }
    // verify checkbox groups
    for (var i = 0; i < requiredGroups.length; i++) {
        var anyChecked = false;
        // allow any indexes
        if (!requiredGroups[i])
            continue;
        for (var j = 0; j < requiredGroups[i].length; j++) {
            var id = requiredGroups[i][j];
            if (document.getElementById(id).checked) {
                anyChecked = true;
                break;
            }
        }
        if (!anyChecked) {
            var label = document.getElementById('requiredGroupLabel' + i);
            message += setErrorForLabel(label);
        }
    }
    // verify password
    if (passwordFields.length > 0) {
        message += checkPassword(passwordFields);
    }

    if (message.length > 0) {
        alert(message);
        return false;
    }
    return true;
}

function setError(element, errorText) {
    var label = getLabel(element);
    return setErrorForLabel(label, errorText);
}

function getLabel(element) {
    var labels = document.getElementsByTagName('label');
    for (var i = 0; i < labels.length; i++) {
        var label = labels[i];
        if(label.htmlFor == element.id) {
            return label;
        }
    }
    return null;
}

function getLabelText(element) {
    var text = "";
    if (element != null) {
        if (element.innerText != undefined) {
            text = element.innerText;
        }
        else {
            text = element.textContent;
        }
    }

    if (text == "") {
        // shouldn't happen, but...
        text = "Field";
    }
    return text
}

function setErrorForLabel(label, errorText) {
    var message;
    var labelText = getLabelText(label);
    var pattern = new RegExp(substitutionToken);
    if (errorText) {
        message = errorText.replace(pattern, "'" + labelText + "'") + "\n";
    }
    else if (label.id.indexOf('requiredGroupLabel') == 0) {
        message = "Please select at least one of the '" + labelText + "'\n";
    }
    else {
        message = msgRequiredField.replace(pattern, "'" + labelText + "'") + "\n";
    }
    label.style.color = "#FF0000";
    return message;
}

function clearErrors() {
    var labels = document.getElementsByTagName("LABEL");
    for (var i = 0; i < labels.length; i++) {
        // assumes too much?
        labels[i].style.color = "#000000";
    }
}

function trim(str) {
    return str.replace(/^\s*|\s*$/g, "");
}

// from http://developer.apple.com/internet/webcontent/validation.html
function checkEmail(element) {
    var message = '';
    var email = element.value;
    // blank OR some chars, '@', more chars, '.', 2 or 3 trailing chars
    var emailFilter=/^$|^.+@.+\..{2,3}$/;
    if (!emailFilter.test(email)) {
        message = setError(element, msgInvalidEmail);
    }
    var illegalChars= /[\(\)\<\>\,\;\:\\\/\"\[\]]/;
    if (email.match(illegalChars)) {
        message = setError(element, msgIllegalChars);
    }
    return message;
}

function checkPhone(element) {
    var message = '';
    var phone = element.value;
    var legalChars = /^[A-Za-z0-9\(\)\.\-\ \+\/]*$/;
    if (!phone.match(legalChars)) {
        message = setError(element, msgIllegalChars);
    }
    return message;
}

function checkRange(element) {
    var message = '';
    var number = element.value;
    if (number.length > 0) {
        var low = Number(element.getAttribute("low"));
        var high = Number(element.getAttribute("high"));
        if (isNaN(number) || Number(number) < low || Number(number) > high) {
            message = setError(element, substitutionToken + " must be a valid number in the range " + low + " to " + high);
        }
    }
    return message;
}

function checkPrecision(element) {
    var message = '';
    var number = element.value;
    if (!isNaN(number) && number.length > 0) {
        var digits = Number(element.getAttribute("decimalprecision"));
        var string = number.toString();
        var strings = string.split(".");
        if (strings.length == 2 && strings[1].length > digits) {
            message = setError(element, substitutionToken + " cannot exceed " + digits + " digits after the decimal");
        }
    }
    return message;
}

function checkPassword(passwordFields) {
    var message = '';

    if (passwordFields.length != 2) {
        // reinforce password confirmation convention setup
        alert("There must be a password field and a confirm password field on the form, both of type password");
    }
    else {
        var pswd = passwordFields[0].value;
        var confirmPswd = passwordFields[1].value;

        if (pswd.length > 0) {
            var noWhitespace = /^\S+$/;   // passwords cannot contain whitespace
            var minPswdLength = 6;
            if (pswd.length < minPswdLength) {
                message += setError(passwordFields[0], substitutionToken + " must be at least " +  minPswdLength + " characters\n");
            }
            else if (!pswd.match(noWhitespace)) {
                message += setError(passwordFields[0], substitutionToken + " cannot contain spaces\n");
            }
            else if (pswd != confirmPswd) {
                message += setError(passwordFields[0], substitutionToken + " was not accurately confirmed\n");
            }
       }
    }
    return message;
}

function checkTextAreaLength(element) {
    var message = '';
    // make sure we use /r/n for newlines; FF uses \n but sends \r\n - we need to count what is sent
    // not handling the /r only case (Mac - pre OSX?)
    var text = element.value.replace(/\n/g, "\r\n").replace(/\r\r/g, "\r");
    var maxLength = Number(element.getAttribute("maxlength"));
    if (text.length > maxLength) {
        // cap at max and remove possibly orphaned \r from \r\n pair at end
        element.value = text.substring(0, maxLength).replace(/\r$/, "");
        var pattern = new RegExp(maxLengthToken);
        var maxMsg = msgTruncatedToMax.replace(pattern, maxLength);
        message = setError(element, maxMsg);
    }
    return message;
}
