jQuery.validator.addMethod(
    'dateUS',
    function (value, element, params) {
        var check, matches, m, mm, dd, year, testDate,
            reUS = /^(\d\d?)\/(\d\d?)\/((\d\d)?\d\d)$/;

        function makeIsoDate(s) {
            var isoDate,
                matches = reUS.exec(s);
            if (matches) {
                mm = parseInt(matches[1], 10);
                dd = parseInt(matches[2], 10);
                year = parseInt(matches[3], 10);
                if (year < 100) year += 2000;
                isoDate = sprintf('%04d-%02d-%02d', year, mm, dd);
            }
            else if (/^\d{4}-\d\d-\d\d$/.exec(s)) {
                isoDate = s;
            }
            return isoDate;
        }

        matches = reUS.exec(value);
        if (matches) {
            if (params === true) params = {};
            params.min = params.min ? makeIsoDate(params.min) : '0000-01-01';
            params.max = params.max ? makeIsoDate(params.max) : '9999-12-31';
            mm = parseInt(matches[1], 10);
            dd = parseInt(matches[2], 10);
            year = parseInt(matches[3], 10);
            if (year < 100) year += 2000;
            value = sprintf('%02d/%02d/%04d', mm, dd, year);
            $(element).val(value);
            isoValue = sprintf('%04d-%02d-%02d', year, mm, dd);
            testDate = new Date(year, mm - 1, dd);
            check = (testDate.getFullYear() == year) &&
                (testDate.getMonth() == mm - 1) &&
                (testDate.getDate() == dd) &&
                (isoValue >= params.min) &&
                (isoValue <= params.max);
        }
        else {
            check = false;
        }
        return this.optional(element) || check;
    },
    'Please enter a valid date (mm/dd/yyyy)'
);

jQuery.validator.addMethod(
    'integer',
    function (value, element, params) {
        var check = /^[+-]?\d+$/.test(value);
        if (check) {
            if (params === true) params = {};
            params = $.extend({min: 0, max: Math.pow(2, 32) - 1}, params);
            value = parseInt(value, 10);
            $(element).val(value);
            check = check && (value >= params.min) && (value <= params.max);
        }
        return this.optional(element) || check;
    },
    'Please enter a valid number'
);

jQuery.validator.addMethod(
    'decimal',
    function (value, element, params) {
        var re, check;
        params = $.extend({min: 0, max: Math.pow(2, 32) - 1}, params);
        re = new RegExp('^[+-]?\\d+(\\.\\d{0,' + params.decimals + '})?$');
        check = re.test(value);
        if (check) {
            value = sprintf('%.' + params.decimals + 'f',
                parseFloat(value, 10));
            $(element).val(value);
            check = check && (value >= params.min) && (value <= params.max);
        }
        return this.optional(element) || check;
    },
    'Please enter a valid number'
);

jQuery.validator.addMethod(
    'code',
    function (value, element, params) {
        var re;
        if (params === true) params = {sep: '-'};
        value = value.toLowerCase().replace(/[^a-z\d]+/g, params.sep);
        if (value.substring(0, 1) == params.sep) {
            value = value.substring(1);
        }
        if (value.substring(value.length - 1) == params.sep) {
            value = value.substring(0, value.length - 1);
        }
        $(element).val(value);
        re = new RegExp('^[a-z\\d]+(?:\\' + params.sep + '[a-z\\d]+)*$');
        check = re.test(value);
        return this.optional(element) || check;
    },
    'Please enter a lowercase code (no spaces)'
);

