
(function($) {

    $.validate = function(options) {
        // Set up some options
        options = options || {};
        options.fieldset = options.fieldset || "";
        options.messagecontainer = options.messagecontainer || ".validationmsg";
        options.errormsg = options.errormsg || ".errmsg";
        options.notvalidclass = options.notvalidclass || "redbrdr";
        options.messageheader = options.messageheader || "Validation errors were found with:";
        options.onerror = options.onerror || "";
        options.erroridprefix = options.erroridprefix || "validationerror_";
        options.selectboxdefault = options.selectboxdefault || [""];
        options.selectboxdefaultclass = options.selectboxdefaultclass || "defaultval";
        options.usedefault = options.usedefault || false;

        var errors = new Array();

        $("." + options.notvalidclass).each(function(i, item) {
            $(item).removeClass(options.notvalidclass);
        });

        function isEmail(str) {
            var regex = /^[a-zA-Z0-9._-]+@([a-zA-Z0-9.-]+\.)+[a-zA-Z0-9.-]{2,4}$/;
            return regex.test(str);
        }

        function isUrl(str) {
            var regex = /^((http|ftp|https):\/\/w{3}[\d]*.|(http|ftp|https):\/\/|w{3}[\d]*.)([\w\d\._\-#\(\)\[\]\\,;:]+@[\w\d\._\-#\(\)\[\]\\,;:])?([a-z0-9]+.)*[a-z\-0-9]+.([a-z]{2,3})?[a-z]{2,6}(:[0-9]+)?(\/[\/a-z0-9\._\-,]+)*[a-z0-9\-_\.\s\%]+(\?[a-z0-9=%&amp;\.\-,#]+)?$/;
            return regex.test(str);
        }

        function isDate(str) {
            var regex = /^((0?[13578]|10|12)(-|\/)((0[0-9])|([12])([0-9]?)|(3[01]?))(-|\/)((\d{4})|(\d{2}))|(0?[2469]|11)(-|\/)((0[0-9])|([12])([0-9]?)|(3[0]?))(-|\/)((\d{4}|\d{2})))$/;
            return regex.test(str);
        }

        function isSixDigitYear(str) {
            var regex = /^((0[1-9])|(1[0-2]))\/(\d{4})$/;
            return regex.test(str);
        }

        function isTime(str) {
            var regex = /^(([0-1]?[0-9])|([2][0-3])):([0-5]?[0-9])(:([0-5]?[0-9]))?$/;
            return regex.test(str);
        }

        function isNumber(str) {
            var regex = /^[0-9-]*$/;
            return regex.test(str);
        }

        function isDollar(str) {
            var regex = /^\-?\$?(((\d{1,3},)+\d{3})|\d+)(\.\d{1,2})?$/;
            return regex.test(str);
        }

        function isQuarter(str) {
            var regex = /^[1-4]{1}$/;
            return regex.test(str);
        }

        function isYear(str) {
            var regex = /^[0-9]{4}$/;
            return regex.test(str);
        }

        function isSSN(str) {
            var regex = /^\d{3}-\d{2}-\d{4}$/;
            return regex.test(str);
        }

        function isPhone(str) {
            var regex = /^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/;
            return regex.test(str);
        }

        function isCloseYear(item) {
            var diff;
            var rt;
            var msg;
            var val;
            var dt = new Date().getYear();

            if (item.value.length == 7 && isSixDigitYear(item.value)) {
                val = item.value.substr(3, 4);
            } else if (isDate(item.value)) {
                val = Date.parse(item.value, 'MM/dd/yyyy').getFullYear();
            }
            if (val != "") {
                diff = Math.abs(parseInt(dt) - parseInt(val));
                if (diff > 1) {
                    msg = getMsg(item);
                    msg = msg.replace(".", "");
                    if (confirm(msg + " is " + diff + " years from now.\nIs this correct?")) {
                        rt = true;
                    } else {
                        rt = false;
                    }
                }
            } else {
                rt = true;
            }
            return rt;
        }

        function isZip(str) {
            var rt;
            var regex = /^[0-9-]{5}$/;
            rt = regex.test(str);
            return rt;
        }

        function isZipExt(str) {
            var rt = false;
            var regex = /^[0-9-]{4}$/;
            if (str != "") {
                rt = regex.test(str);
            } else {
                rt = true;
            }
            return rt;
        }

        function isEmpty(item) {
            if (item.value == "")
                return true;
            if (options.usedefault && item.value == $(item).attr("title"))
                return true;

            return false;
        }

        function getMsg(item) {
            return $(item.parentNode).find(options.errormsg).html();
        }

        function validateTextBox(item) {
            if ($(item).hasClass("email") && isEmail(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("url") && isUrl(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("date") && isDate(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("time") && isTime(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("number") && isNumber(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "number" });
            }

            if ($(item).hasClass("zip") && isZip(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("zipext") && isZipExt(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("quarter") && isQuarter(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("year") && isYear(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("datesix") && isSixDigitYear(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("closeyear") && isCloseYear(item) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("dollar") && isDollar(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("ssn") && isSSN(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }

            if ($(item).hasClass("phone") && isPhone(item.value) == false) {
                errors.push({ id: item.id, msg: getMsg(item), type: "text" });
            }
        }

        function validateCheckbox(item) {
            if (item.checked != true)
                errors.push({ id: item.id, msg: getMsg(item), type: "checkbox" });
        }

        function validateSelect(item) {
            if ($.inArray(item.value, options.selectboxdefault) > -1 || item[item.selectedIndex].className == options.selectboxdefaultclass)
                errors.push({ id: item.id, msg: getMsg(item), type: "select-one" });
        }

        function validatePassword() {
            if ($(".pwmatch").length == 2) {
                if ($(".pwmatch").get(0).value + $(".pwmatch").get(1).value != "") {
                    if ($(".pwmatch").get(0).value != $(".pwmatch").get(1).value) {
                        errors.push({ id: $(".pwmatch").get(0).id, msg: "Passwords do not match.", type: "password" });
                        errors.push({ id: $(".pwmatch").get(1).id, msg: "", type: "password" });
                    }
                } else {
                    errors.push({ id: $(".pwmatch").get(0).id, msg: "Passwords can not be empty.", type: "password" });
                    errors.push({ id: $(".pwmatch").get(1).id, msg: "", type: "password" });
                }
            }
        }

        // Loop required
        $(options.fieldset + " .required").each(function(i, item) {
            if (isEmpty(item) == true) {
                errors.push({ id: item.id, msg: getMsg(item), type: item.type });
            } else {
                switch (item.type) {
                    case "checkbox":
                        validateCheckbox(item);
                        break;
                    case "text":
                    case "file":
                    case "hidden":
                    case "textarea":
                        validateTextBox(item);
                        break;
                    case "select-one":
                        validateSelect(item);
                        break;
                    case "password":
                        validatePassword();
                        break;
                }
            }
        });

        // Loop
        $(options.fieldset + " .notrequired").each(function(i, item) {
            if (isEmpty(item) == false) {
                switch (item.type) {
                    case "checkbox":
                        validateCheckbox(item);
                        break;
                    case "text":
                    case "file":
                    case "hidden":
                    case "textarea":
                        validateTextBox(item);
                        break;
                    case "select-one":
                        validateSelect(item);
                        break;
                    case "password":
                        validatePassword();
                        break;
                }
            }
        });

        $(options.fieldset + " .checkboxgroup," + options.fieldset + " .radiogroup").each(function(i, item) {
            var checked = 0;
            var msg = $(item).find(options.errormsg).text();

            $(item).find("input[type=checkbox], input[type=radio]").each(function(i, item) {
                if (item.checked)
                    checked++;
            });

            if (checked == 0)
                errors.push({ id: item.id, msg: msg, type: "group" });
        });

        if (errors.length > 0) {
            if (typeof (options.onerror) == "function") {
                options.onerror(errors);
                return false;
            }
            var msg = options.messageheader + '\n';

            $(errors).each(function(i, item) {
                $("#" + item.id).addClass(options.notvalidclass);
                if (item.msg != "") {
                    msg = msg + item.msg + '\n';
                }
            });

            alert("Errors were found with the highlighted items.");
            return false;
        }

        return true;
    }
})(jQuery);
