// ========================================================================
// Backward compatible form field validation functions
// Adapted by Touchtech Ltd (http://www.touchtech.co.uk)
// from Danny Goodman's JavaScript & DHTML Cookbook
//   section 8.2 p. 192
//   section 8.3 p. 199
//   section 8.4 p. 201
//   section 8.11 p. 211
//       author    : Danny Goodman
//       title     : JavaScript & DHTML Cookbook
//       publisher : O'Reilly
//       ISBN      : 0-596-00467-2
// ========================================================================
// $Id: formVal.js 224 2005-01-31 10:07:40Z tprice $
// ========================================================================

// use an object so as to be able to easily provide some defaults
function LabelColours(normColour, errColour) {
    this.normColour = normColour || "#000";
    this.errColour = errColour || "#BD0C21";
}

// auto-focus a field and select all text in it for quick replacement
// Usage note: "An unfortunate timing bug (primarily affecting IE for
// Windows) prevents these calls from occurring immediately in the
// validation function. An arbitrary time-out is needed to let the failed
// validation alert window disappear and the rest of the page to settle
// down before focusing and selecting the text box." (p. 200)
// e.g. setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
function focusFormElem(formName, elemName, selectElem) {
    if (selectElem == null) selectElem = true;
    //alert("formName=" + formName + ", elemName=" + elemName + ", selectElem=" + selectElem);
    var elem = document.forms[formName].elements[elemName];
    if (elem instanceof NodeList) elem = elem[0];
    if (elem.focus) {
        elem.focus();
        if (elem.select && selectElem) elem.select();
    }
}

function setErrColour(labelId, labelColours) {
    if (labelId != null && document.getElementById) {
        var label = document.getElementById(labelId);
        label.style.color = labelColours.errColour;
    }
}

function resetLabelColours(labelIdArray, labelColours) {
    if (document.getElementById) {
        for (var i = 0; i < labelIdArray.length; i++) {
            document.getElementById(labelIdArray[i]).style.color = labelColours.normColour;
        }
    }
}

// validate that one of the radio buttons is checked
function isValidRadio(radio, msg, labelId, labelColours) {
    if (msg == null || msg.length == 0) {
        msg = "Please make a choice from the radio buttons";
    }
    var valid = false;
    for (var i = 0; i < radio.length; i++) {
        if (radio[i].checked) {
            return true;
        }
    }
    alert(msg);
    setErrColour(labelId, labelColours);
    setTimeout("focusFormElem('" + radio[0].form.name + "', '" + radio[0].name + "')", 0);
    return false;
}

// validate that a selection has been made
function isChosen(select, minIndex, msg, labelId, labelColours) {
    if (minIndex == null || minIndex < 0) {
        minIndex = 0
    }
    if (msg == null || msg.length == 0) {
        msg = "Please make a choice from the list";
    }
    if (select.selectedIndex <= minIndex) {
        alert(msg);
        setErrColour(labelId, labelColours);
        setTimeout("focusFormElem('" + select.form.name + "', '" + select.name + "')", 0);
        return false;
    } else {
        return true;
    }
}

// validates that the field value string has one or more characters in it
function isNotEmpty(elem, msg, labelId, labelColours) {
    if (msg == null || msg.length == 0) {
        msg = "Please fill in the required field";
    }
    var str = elem.value;
    if (str == null || str.length == 0) {
        alert(msg);
        setErrColour(labelId, labelColours);
        setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
        return false;
    } else {
        return true;
    }
}

// validates that the entry is a positive or negative number
function isNumber(elem, msg, labelId, labelColours) {
    if (msg == null || msg.length == 0) {
        msg = "Please enter a valid number";
    }
    var oneDecimal = false;
    var str = elem.value;
    var oneChar = 0;
    // make sure value hasn't cast to a number data type
    str = str.toString();
    for (var i = 0; i < str.length; i++) {
        oneChar = str.charAt(i).charCodeAt(0);
        // ok for minus sign as first character
        if (oneChar == 45) {
            if (i == 0) {
                continue;
            } else {
                // a number may hava a minus sign only in the first
                // character
                alert(msg);
                setErrColour(labelId, labelColours);
                setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
                return false;
            }
        }
        // ok for one decimal point
        if (oneChar == 46) {
            if (!oneDecimal) {
                oneDecimal = true;
                continue;
            } else {
                // a number should contain only one decimal point
                alert(msg);
                setErrColour(labelId, labelColours);
                setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
                return false;
            }
        }
        // characters outside of 0 through 9 not ok
        if (oneChar < 48 || oneChar > 57) {
            alert(msg);
            setErrColour(labelId, labelColours);
            setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
            return false;
        }
    }
    return true;
}

// validates that the number is non-zero
function isNonZero(elem, msg, labelId, labelColours) {
    if (msg == null || msg.length == 0) {
        msg = "Please enter a non-zero number";
    }
    if (!isNumber(elem)) return false;
    var str = elem.value;
    // make sure value hasn't cast to a number data type
    str = str.toString();
    var floatValue = parseFloat(str);
    var tol = 1.0e-10;
    if (floatValue < tol) {
        alert(msg);
        setErrColour(labelId, labelColours);
        setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
        return false;
    } else {
        return true;
    }
}

// validates the entry length
function checkLen(elem, type, len, msg, labelId, labelColours) {
    if (msg == null || msg.length == 0) {
        if (type == "min") msg = "The text must be at least " + len + " characters";
        else if (type == "max") msg = "The text cannot be more than " + len + " characters";
        else if (type == "equal") msg = "The text must be exactly " + len + " characters";
        else return false;
    }
    var str = elem.value;
    if (type == "min") {
        if (str.length < len) {
            alert(msg);
            return false;
        }
    } else if (type == "max") {
        if (str.length > len) {
            alert(msg);
            return false;
        }
    } else if (type == "equal") {
        if (str.length != len) {
            alert(msg);
            return false;
        }
    }
    return true;
}

// validates that the entry is less than or equal to a maximum length
function isMaxLen(elem, maxLen, msg, labelId, labelColours) {
    if (!checkLen(elem, "max", maxLen, msg, labelId, labelColours)) {
        setErrColour(labelId, labelColours);
        setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "', false)", 0);
        //setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
        return false;
    } else {
        return true;
    }
}

// validates that the entry is less than or equal to a maximum length
function isMinLen(elem, minLen, msg, labelId, labelColours) {
    if (!checkLen(elem, "min", minLen, msg, labelId, labelColours)) {
        setErrColour(labelId, labelColours);
        setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
        return false;
    } else {
        return true;
    }
}

// validates that the entry is a particular length
function isLen(elem, len, msg, labelId, labelColours) {
    if (!checkLen(elem, "equal", len, msg, labelId, labelColours)) {
        setErrColour(labelId, labelColours);
        setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
        return false;
    } else {
        return true;
    }
}

// validates that the entry is formatted as an email address
function isEmailAddr(elem, labelId, labelColours) {
    var str = elem.value;
    var oneChar = 0;
    // make sure value hasn't cast to a number data type & convert to lower case
    str = str.toString().toLowerCase();
    if (str.indexOf("@") > 1) {
        var addr = str.substring(0, str.indexOf("@"));
        var domain = str.substring(str.indexOf("@") + 1, str.length);
        // at least one top level domain required
        if (domain.indexOf(".") == -1) {
            alert("Please verify the domain portion of the email address");
            setErrColour(labelId, labelColours);
            setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
            return false;
        }
        // parse address portion first, character by character
        for (var i = 0; i < addr.length; i++) {
            oneChar = addr.charAt(i).charCodeAt(0);
            // dot or hyphen not allowed in first position; dot in last
            if ((i == 0 && (oneChar == 45 || oneChar == 46)) ||
                (i == addr.length - 1 && oneChar == 46)) {
                alert("Please verify the username portion of the email address");
                setErrColour(labelId, labelColours);
                setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
                return false;
            }
            // acceptable characters (- . _ 0-9 a-z)
            if (oneChar == 45 || oneChar == 46 || oneChar == 95 ||
                (oneChar > 47 && oneChar < 58) || (oneChar > 96 && oneChar < 123)) {
                continue;
            } else {
                alert("Please verify the username portion of the email address");
                setErrColour(labelId, labelColours);
                setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
                return false;
            }
        }

        for (i = 0; i < domain.length; i++) {
            oneChar = domain.charAt(i).charCodeAt(0);
            if ((i == 0 && (oneChar == 45 || oneChar == 46)) ||
                ((i == domain.length - 1 || i == domain.length - 2) && oneChar == 46)) {
                alert("Please verify the domain portion of the email address");
                setErrColour(labelId, labelColours);
                setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
                return false;
            }
            if (oneChar == 45 || oneChar == 46 || oneChar == 95 ||
                (oneChar > 47 && oneChar < 58) || (oneChar > 96 && oneChar < 123)) {
                continue;
            } else {
                alert("Please verify the domain portion of the email address");
                setErrColour(labelId, labelColours);
                setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
                return false;
            }
        }

        return true;
    }
    alert("The email address does not appear to be formatted correctly - please verify");
    setErrColour(labelId, labelColours);
    setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
    return false;
}

// validates that the entry appears to be a phone number (valid
// chars are considered to be +, digits, spaces and dashes)
function isPhoneNum(elem, minDigits, msg, labelId, labelColours) {
    // set some reasonable default
    if (minDigits == null) minDigits = 8;
    if (msg == null || msg.length == 0) {
        msg = "Please enter at least " + minDigits + " digits for the phone number."
                + "\n\nYou may also enter spaces and dashes if you wish,"
                + "\nand a plus sign at the start (but no other characters).";
    }
    var digitCount = 0;
    var allZero = true;
    var valid = true;
    var str = elem.value;
    var oneChar = 0;
    // make sure value hasn't cast to a number data type & convert to lower case
    str = str.toString().toLowerCase();
    if (str.length >= minDigits) {
        for (var i = 0; i < str.length; i++) {
            oneChar = str.charAt(i).charCodeAt(0);
            // plus sign allowed in first position only
            if (oneChar == 43) {
                if (i == 0) {
                    continue;
                } else {
                    valid = false;
                    break;
                }
            } else if (oneChar == 32 || oneChar == 45 || (oneChar > 47 && oneChar < 58)) {
                if (oneChar > 47 && oneChar < 58) {
                    if (oneChar != 48) allZero = false;
                    digitCount += 1;
                }
                // acceptable characters (<spc> - 0-9)
                continue;
            } else {
                valid = false;
                break;
            }
        }
        if (digitCount < minDigits || allZero) valid = false;
        if (valid) return true;
    }
    alert(msg);
    setErrColour(labelId, labelColours);
    setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
    return false;
}

// displays the length of a text field
function showTextLen(elemId) {
    if (document.getElementById) {
        var elem = document.getElementById(elemId);
        var str = elem.value;
        alert("The text is " + str.length + " characters long");
    } else {
        alert("Unable to establish text length (this may be due to your browser type or version)")
    }
}

// allow only numbers (no decimals or minus signs) in a text box
function numeralsOnly(evt, elemId, msg) {
    if (msg == null || msg.length == 0) {
        msg = "Please enter only numerals in this field"
    }
    // 'equalise' IE and W3C event models
    evt = (evt) ? evt : ((window.event) ? window.event : null);
    evt.cancelBubble = true;
	if (evt.stopPropagation) evt.stopPropagation();

    if (evt) {
        var charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ?
            evt.keyCode : ((evt.which) ? evt.which : 0));
        if (charCode > 31 && (charCode < 48 || charCode > 57)) {
            alert(msg);
            if (document.getElementById) {
                var elem = document.getElementById(elemId);
                setTimeout("focusFormElem('" + elem.form.name + "', '" + elem.name + "')", 0);
            }
            return false;
        }
        return true;
    }
}
