﻿Validator = {
    Require: /.+/,
    Email: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
    Phone: /^((\(\d{3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}$/,
    Mobile: /^((\(\d{3}\))|(\d{3}\-))?(13|15|18)\d{9}$/,
    Url: /^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/,
    IdCard: /^\d{15}(\d{2}[A-Za-z0-9])?$/,
    Currency: /^\d+(\.\d+)?$/,
    Number: /^\d+$/,
    myCardId: /^\d+$/,
    Zip: /^[1-9]\d{5}$/,
    QQ: /^[1-9]\d{4,8}$/,
    Integer: /^[-\+]?\d+$/,
    Double: /^[-\+]?\d+(\.\d+)?$/,
    English: /^[A-Za-z]+$/,
    Chinese: /^[\u0391-\uFFE5]+$/,
    UnSafe: /^(([A-Z]*|[a-z]*|\d*|[-_\~!@#\$%\^&\*\.\(\)\[\]\{\}<>\?\\\/\'\"]*)|.{0,5})$|\s/,
    IsSafe: function(str) {
        return ! this.UnSafe.test(str);
    },
    SafeString: "this.IsSafe(value)",
    Limit: "this.limit(value.length,getAttribute('min'), getAttribute('max'))",
    LimitB: "this.limit(this.LenB(value), getAttribute('min'), getAttribute('max'))",
    Date: "this.IsDate(value, getAttribute('min'), getAttribute('format'))",
    Repeat: "value == document.getElementsByName(getAttribute('to'))[0].value",
    Range: "getAttribute('min') < value && value < getAttribute('max')",
    Compare: "this.compare(value,getAttribute('operator'),getAttribute('to'))",
    Custom: "this.Exec(value, getAttribute('regexp'))",
    Group: "this.MustChecked(getAttribute('name'), getAttribute('min'), getAttribute('max'))",
    MySFZH: "this.chkSFZH(value)",    
    MyYM: "this.IsYM(value)",
    ErrorItem: [document.forms[0]],
    ErrorMessage: ["以下原因导致提交失败(Possible problem)：\t\t\t\t"],

    Validate: function(theForm, mode) {
        var obj = theForm || event.srcElement;
        var count = obj.elements.length;
        this.ErrorMessage.length = 1;
        this.ErrorItem.length = 1;
        this.ErrorItem[0] = obj;
        for (var i = 0; i < count; i++) {
            with(obj.elements[i]) {
                var _dataType = getAttribute("dataType");
                if (typeof(_dataType) == "object" || typeof(this[_dataType]) == "undefined") continue;
                this.ClearState(obj.elements[i]);
                if (getAttribute("require") == "false" && value == "") continue;
                switch (_dataType) {
                case "Date":
                case "Repeat":
                case "Range":
                case "Compare":
                case "Custom":
                case "Group":
                case "Limit":
                case "LimitB":
                case "MySFZH":
                case "MyYM":
                case "SafeString":
                    if (!eval(this[_dataType])) {
                        this.AddError(i, getAttribute("msg"));
                    }
                    break;
                default:
                    if (!this[_dataType].test(value)) {
                        this.AddError(i, getAttribute("msg"));
                    }
                    break;
                }
            }
        }
        if (this.ErrorMessage.length > 1) {
            mode = mode || 1;
            var errCount = this.ErrorItem.length;
            switch (mode) {
            case 2:
                for (var i = 1; i < errCount; i++) this.ErrorItem[i].style.color = "";
            case 1:
                alert(this.ErrorMessage.join("\n"));
                this.ErrorItem[1].focus();
                break;
            case 3:
                for (var i = 1; i < errCount; i++) {
                    try {
                        var span = document.createElement("SPAN");
                        span.id = "__ErrorMessagePanel";
                        span.style.color = "black";
                        this.ErrorItem[i].parentNode.appendChild(span);
                        span.innerHTML = this.ErrorMessage[i].replace(/\d+:/, "*");
                    } catch(e) {
                        alert(e.description);
                    }
                }
                this.ErrorItem[1].focus();
                break;
            default:
                alert(this.ErrorMessage.join("\n"));
                break;
            }
            return false;
        }
        return true;
    },

    limit: function(len, min, max) {
        min = min || 0;
        max = max || Number.MAX_VALUE;
        return min <= len && len <= max;
    },
    LenB: function(str) {
        return str.replace(/[^\x00-\xff]/g, "**").length;
    },
    ClearState: function(elem) {
        with(elem) {
            if (style.color == "black") style.color = "";
            var lastNode = parentNode.childNodes[parentNode.childNodes.length - 1];
            if (lastNode.id == "__ErrorMessagePanel") parentNode.removeChild(lastNode);
        }
    },
    AddError: function(index, str) {
        this.ErrorItem[this.ErrorItem.length] = this.ErrorItem[0].elements[index];
        this.ErrorMessage[this.ErrorMessage.length] = this.ErrorMessage.length + ":" + str;
    },
    Exec: function(op, reg) {
        return new RegExp(reg, "g").test(op);
    },
    compare: function(op1, operator, op2) {
        switch (operator) {
        case "NotEqual":
            return (op1 != op2);
        case "GreaterThan":
            return (op1 > op2);
        case "GreaterThanEqual":
            return (op1 >= op2);
        case "LessThan":
            return (op1 < op2);
        case "LessThanEqual":
            return (op1 <= op2);
        default:
            return (op1 == op2);
        }
    },
    MustChecked: function(name, min, max) {
        var groups = document.getElementsByName(name);
        var hasChecked = 0;
        min = min || 1;
        max = max || groups.length;
        for (var i = groups.length - 1; i >= 0; i--) if (groups[i].checked) hasChecked++;
        return min <= hasChecked && hasChecked <= max;
    },
    IsDate: function(op, formatString) {
        formatString = formatString || "ymd";
        var m, year, month, day;
        switch (formatString) {
        case "ymd":
            m = op.match(new RegExp("^((\\d{4})|(\\d{2}))([-./])(\\d{1,2})\\4(\\d{1,2})$"));
            if (m == null) return false;
            day = m[6];
            month = m[5]--;
            year = (m[2].length == 4) ? m[2] : GetFullYear(parseInt(m[3], 10));
            break;
        case "dmy":
            m = op.match(new RegExp("^(\\d{1,2})([-./])(\\d{1,2})\\2((\\d{4})|(\\d{2}))$"));
            if (m == null) return false;
            day = m[1];
            month = m[3]--;
            year = (m[5].length == 4) ? m[5] : GetFullYear(parseInt(m[6], 10));
            break;
        default:
            break;
        }
        if (!parseInt(month)) return false;
        month = month == 12 ? 0 : month;
        var date = new Date(year, month, day);
        return (typeof(date) == "object" && year == date.getFullYear() && month == date.getMonth() && day == date.getDate());
        function GetFullYear(y) {
            return ((y < 30 ? "20": "19") + y) | 0;
        }
    },
    IsYM: function(strYM) {
        var formatString = "ymd";
        var m, year, month, day;
        switch (formatString) {
        case "ymd":
            m = strYM.match(new RegExp("^(\\d{4})(\\d{2})$"));
            if (m == null) return false;
            day = "01";
            month = m[2];
            year = m[1];
            break;
        default:
            break;
        }
        if (!parseInt(month,10)) return false;
        month = month == 12 ? 0 : month;
        var date = new Date(year, month, day);
        return (typeof(date) == "object" && year == date.getFullYear() && month == date.getMonth() && day == date.getDate());
        function GetFullYear(y) {
            return ((y < 30 ? "20": "19") + y) | 0;
        }
    },    
    chkSFZH: function (num) {
        num = num.toUpperCase();
        //身份证号码为15位或者18位，15位时全为数字，18位前17位为数字，最后一位是校验位，可能为数字或字符X。   
        if (! (/(^\d{15}$)|(^\d{17}([0-9]|X)$)/.test(num))) {
            return false;
        }
        //校验位按照ISO 7064:1983.MOD 11-2的规定生成，X可以认为是数字10。 
        //下面分别分析出生日期和校验位 
        var len, re;
        len = num.length;
        if (len == 15) {
            re = new RegExp(/^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/);
            var arrSplit = num.match(re);

            //检查生日日期是否正确 
            var dtmBirth = new Date('19' + arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4]);
            var bGoodDay;
            bGoodDay = (dtmBirth.getYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) && (dtmBirth.getDate() == Number(arrSplit[4]));
            if (!bGoodDay) {
//                alert('输入的身份证号里出生日期不对！');
                return false;
            } else {
                //将15位身份证转成18位 
                //校验位按照ISO 7064:1983.MOD 11-2的规定生成，X可以认为是数字10。 
                var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
                var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
                var nTemp = 0,
                i;
                num = num.substr(0, 6) + '19' + num.substr(6, num.length - 6);
                for (i = 0; i < 17; i++) {
                    nTemp += num.substr(i, 1) * arrInt[i];
                }
                num += arrCh[nTemp % 11];
                return num;
            }
        }
        if (len == 18) {
            re = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/);
            var arrSplit = num.match(re);

            //检查生日日期是否正确 
            var dtmBirth = new Date(arrSplit[2] + "/" + arrSplit[3] + "/" + arrSplit[4]);
            var bGoodDay;
            bGoodDay = (dtmBirth.getFullYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) && (dtmBirth.getDate() == Number(arrSplit[4]));
            if (!bGoodDay) {
//                alert(dtmBirth.getYear());
//                alert(arrSplit[2]);
//                alert('输入的身份证号里出生日期不对！');
                return false;
            } else {
                //检验18位身份证的校验码是否正确。 
                //校验位按照ISO 7064:1983.MOD 11-2的规定生成，X可以认为是数字10。 
                var valnum;
                var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
                var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
                var nTemp = 0,
                i;
                for (i = 0; i < 17; i++) {
                    nTemp += num.substr(i, 1) * arrInt[i];
                }
                valnum = arrCh[nTemp % 11];
                if (valnum != num.substr(17, 1)) {
//                    alert('18位身份证的校验码不正确！应该为：' + valnum);
                    return false;
                }
                return num;
            }
        }
        return false;
    }
}
