/*****************************************************
 * 文件名：validator.js                               
 * 功  能：基于自定义属性的统一检测用Javascript函数库 
 ******************************************************/
if(!String.prototype.trim )
	String.prototype.trim=function() { 
    return this.replace(/(^\s*)|(\s*$)/g, ""); 
}

var Validator = {
	require    : /.+/,
	username   : /^[a-zA-Z]{1}([a-zA-Z0-9]){3,15}$/,
	barusername: /^[a-zA-Z0-9]{6,30}$/,
	password   : /^([a-zA-Z0-9\^-_\~!@#\$%\^&\*\.\(\)\[\]\{\}<>\?\\\/\'\"]){6,16}$/,
	nosign     : /^[^\s]{1}[^-_\~!@#\$%\^&\*\.\(\)\[\]\{\}<>\?\\\/\'\"]*$/,
	domain     : /^([a-zA-Z0-9]|[-]){4,}$/,
	verifycode : /^[a-zA-Z0-9]{4,6}$/,
	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     : /^((13\d{9})|(0\d{2,3}[1-9]\d{6,7}))$/,
	url        : /^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/,
	idcard15   : /^\d{8}(0[1-9]|10|11|12)([0-2][1-9]|10|20|30|31)(\d{3})$/,
	idcard18   : /^\d{10}(0[1-9]|10|11|12)([0-2][1-9]|10|20|30|31)(\d{3}[A-Za-z0-9])$/,
	price      : /^\d+(\.\d{2})?$/,
	currency   : /^\d+(\.\d+)?$/,
	number     : /^\d+$/,
	digital    : /^\d+$/,
	integer    : /^[-\+]?\d+$/,
	double     : /^[-\+]?\d+(\.\d+)?$/,
	english    : /^[A-Za-z]+$/,
	chinese    : /^[\u0391-\uFFE5]+$/,
	haschinese : /[\u0391-\uFFE5]*/,
	zip        : /^[1-9]\d{5}$/,
	qq         : /^[1-9]\d{4,8}$/,
	unsafestr  : /^(([A-Z]*|[a-z]*|\d*|[-_\~!@#\$%\^&\*\.\(\)\[\]\{\}<>\?\\\/\'\"]*)|.{0,5})$|\s/,
	unsafeurl  : /[#&.%\?\\/\'\"\s]+/,
	unsafehtml : /[#<>\?\\\/\'\"\s]+/,
	unsafechar : /[<>\\\/\'\"]+/,
	datetime   : /^\d{4}-(0[1-9]|10|11|12)-([0-2][1-9]|10|20|30|31) ([0-1][0-9]|20|21|22|23):[0-5][0-9]:[0-5][0-9]$/,
	photo      : /(.*)\.(jpeg|jpg|bmp|gif|png)$/,
	compress   : /(.*)\.(zip|rar)$/,
	notupload  : /(.*)\.(exe|cab|ocx|bat|dll|ini|html|htm|asp|php|jsp)$/,
	date       : "this.isDate(obj.value, obj.getAttribute('format'))",
	repeat     : "obj.value == document.getElementsByName(obj.getAttribute('to'))[0].value",
	range      : "obj.getAttribute('min') <= obj.value && obj.value <= obj.getAttribute('max')",
	numrange   : "obj.getAttribute('min') <= parseFloat(obj.value) && parseFloat(obj.value) <= obj.getAttribute('max')",
	compare    : "this.compareFunc(obj.value,obj.getAttribute('operator'),obj.getAttribute('to'))",
	custom     : "new RegExp(obj.getAttribute('regexp'),'g').test( obj.value )",
	group      : "this.mustChecked(obj.getAttribute('name'), obj.getAttribute('min'), obj.getAttribute('max'))",
	limit      : "this.limitFunc(obj.value.length, obj.getAttribute('min'),  obj.getAttribute('max'))",
	limitbyte  : "this.limitFunc(this.byteLength(obj.value), obj.getAttribute('min'), obj.getAttribute('max'))",
	safestring : "!this.unsafestr.test(obj.value)",
	safechar   : "!this.unsafechar.test(obj.value)",
	safeurl    : "!this.unsafeurl.test(obj.value)",
	safehtml   : "!this.unsafehtml.test(obj.value)",
	canupload  : "!this.notupload.test(obj.value.toLowerCase())",
	photofile  : "this.photo.test(obj.value.toLowerCase())",
	idcard     : "this.idcard15.test(obj.value)||this.idcard18.test(obj.value)",
	
	ErrItem    : [],
	ErrMessage : ["以下原因导致提交失败：\t\t\t\t\n"],
	OkItem     : [],
	OkMessage  : ["以下内容已通过验证：\t\t\t\t\n"],
  
	check : function( obj ){
		var ret = false;
		var theType = obj.getAttribute("datatype");
		if( ! theType ) return true;
		require = obj.getAttribute("require");
		if( require == "true" && obj.value.trim() == ""){
			this.addError(obj);
			return true;
		}
		if( (require == null ||require == "false" ) && obj.value.trim() == "") return true;
		var justOneValid = /[\|]/.test( theType );  //只需要满足其中一个类型就可以了
		var typeArray = theType.split( /[&,\|]/ );
		for( k in typeArray ){
			if( typeof( typeArray[k] ) == "object"  || typeof(this[typeArray[k]]) == "undefined")  continue;
			switch( typeArray[k].toLowerCase() ){
				case "date" :
				case "repeat" :
				case "numrange" :
				case "range" :
				case "compare" :
				case "custom" :
				case "group" : 
				case "limit" :
				case "limitbyte" :
				case "safestring" :
				case "safeurl" : 
				case "safehtml" : 
				case "safechar" : 
				case "canupload" : 
				case "photofile" : 
					ret = eval(this[typeArray[k].toLowerCase()]);
					break;
				default :
					ret = this[typeArray[k].toLowerCase()].test(obj.value.toLowerCase()) ;
					break;
			}
			if( ret && justOneValid ) break;
		}
		if( ret )
			this.addOk( obj );
		else
			this.addError(obj);
		return ret;
	},

	checkForm : function(theForm, mode){
		var obj = theForm || event.srcElement;
		var count = obj.elements.length;
		this.ErrMessage.length = 1;
		this.ErrItem.length = 1;
		this.ErrItem[0] = obj;
		this.OkMessage.length = 1;
		this.OkItem.length = 1;
		this.OkItem[0] = obj;
		for(var i=0;i<count;i++){
			this.check( obj.elements[i] );
			this.clearState( obj.elements[i],mode );
		}
		this.showOkMsg(mode);
		return(this.showErrorMsg(mode));
	},

	checkField : function(theElement, mode){
		var obj = theElement || event.srcElement;
		this.ErrMessage.length = 1;
		this.ErrItem.length = 1;
		this.ErrItem[0] = obj;
		this.OkMessage.length = 1;
		this.OkItem.length = 1;
		this.OkItem[0] = obj;
		this.check( obj );
		this.clearState( obj,mode );
		this.showOkMsg(mode);
		return( this.showErrorMsg(mode) );
	},

	getNoticeBox : function(obj) {
		var lastNode=null, span=null;
		try{
	    if (typeof obj == 'string')
  	  	obj = document.getElementById(obj);
			if( obj.nextSibling && obj.nextSibling.tagName == "SPAN" ){
				return obj.nextSibling;
			}
			if(obj.parentNode && obj.parentNode.childNodes[obj.parentNode.childNodes.length-1]){
				lastNode = obj.parentNode.childNodes[obj.parentNode.childNodes.length-1];
				if( lastNode && lastNode.tagName == "SPAN"){
					return lastNode;
				}
			}
			span = document.createElement("SPAN");
			obj.parentNode.appendChild(span);
			return span;
		}
		catch(e) {
			alert("getNoticeBox(" + obj + ") Error:" + e.name + "," +e.description);
		}
		return null;
	},

	showErrorMsg : function(mode){
		var errCount = this.ErrItem.length;
		if( errCount > 1){
			mode = mode || 1;
			switch(mode){
				case 2 :
		  			for(var i=1;i<errCount;i++){
				  		//this.ErrItem[i].className = "textError";
				  		this.ErrItem[i].style.color = "red";
				  		this.ErrItem[i].style.borderColor = "red";
				  	}
				  	break;
				case 3 :
				  	for(var i=1;i<errCount;i++){
						this.showNotice( this.ErrItem[i], this.ErrMessage[i].replace(/\d+:/,""),"noticeError" );
						//this.ErrorItem[1].focus();
					}
					break;
				case 1 :
				default :
					alert(this.ErrMessage.join("\n"));
					this.ErrItem[1].focus();
					break;
			}
			return false;
		}
		return true;
	},
	showOkMsg : function(mode){
		var okCount = this.OkItem.length;
		if( okCount > 1){
			mode = mode || 1;
			switch(mode){
				case 2 :
					for(var i=1;i<okCount;i++){
						this.OkItem[i].style.color = "green";
						this.OkItem[i].style.borderColor = "green";
						//this.OkItem[i].className = "textOk";
					}
					break;
				case 3 :
					for(var i=1;i<okCount;i++)
						this.showNotice( this.OkItem[i], this.OkMessage[i].replace(/\d+:/,""),"noticeOk" );
					break;
				case 1 :
				default :
					//alert(this.OkMessage.join("\n"));
					//this.OkItem[1].focus();
					break;
			}
		}
		return true;
	},
	showNotice: function( obj, msg, styleclass ){
		try{
			var span = this.getNoticeBox( obj );
			span.innerHTML = msg;
			span.className = styleclass;
			span.id = "_ErrorMessagePanel_";
 		}
 		catch(e){
 			alert("showNotice(" + obj.name+ ",msg:" + msg + ","+styleclass+") Error:" +e.description);
		}		
 	},
	clearState : function( obj,mode ){
		amode = mode || 1;
		switch(amode){
			case 2 :
				obj.style.color="#666666";
				obj.style.borderColor="#666666";
				break;
			case 3 :
				var span = this.getNoticeBox( obj );
				if( span && span.id == "_ErrorMessagePanel_"){
					span.className = "notice";
				}
				break;
			case 1 :
			default :
				break;
		}
	},
	addError : function( obj ){
		this.ErrItem[this.ErrItem.length] = obj;
		errmsg = obj.getAttribute("errmsg") || "〤";  //√╳
		this.ErrMessage[this.ErrMessage.length] = this.ErrMessage.length + ":" + errmsg;
	},
	addOk : function( obj ){
		this.OkItem[this.OkItem.length] = obj;
		okmsg = obj.getAttribute("okmsg") || "√";
		this.OkMessage[this.OkMessage.length] = this.OkMessage.length + ":" + okmsg;
		//alert(this.OkMessage);
	},
	limitFunc : function( num, min, max ){
		min = parseFloat(min) || 0;
		max = parseFloat(max) || Number.MAX_VALUE;
		return min <= num && num <= max;
	},
	byteLength : function(str){  //字符串的字节数,对于中文等多字节字符,str.length不等于字节数
		return str.replace(/[^\x00-\xff]/g,"**").length;
	},
	compareFunc : function(op1,operator,op2){
		switch (operator) {
			case "NE": //NotEqual
				return (op1 != op2);
			case "GT": //GreaterThan
				return (op1 > op2);
			case "GE": //GreaterThanEqual
				return (op1 >= op2);
			case "LT":  //LessThan
				return (op1 < op2);
			case "LE": //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;
	},
	initForm: function( formAttr ){
		f = document.forms[formAttr.name];
		if( !f ) return;
		for( i=0;i< formAttr.fields.length;i++ ){
			o = f.elements[formAttr.fields[i].name];
			if( !o ) continue;
			for( var j in formAttr.fields[i].attrs ){
				o.setAttribute( j, formAttr.fields[i].attrs[j] );
		  }
		}
	},
	isDate : function(op, formatString){
		formatString = formatString || "ymd";
		var m, year, month, day;
		switch(formatString){
			case "ymd" :
				ymdexp = /^\s*((\d{4})|(\d{2}))([-\.\/])(\d{1,2})\4(\d{1,2})\s*$/;
				m = op.match( ymdexp );
				if(m == null ) return false;
				day = m[6];
				month = m[5]--;
				syear = parseInt(m[3], 10);
				year =  (m[2].length == 4) ? m[2] : ((syear<30 ? "20" : "19") + syear) ;
				break;
			case "dmy" :
				dmyexp = /^\s*(\d{1,2})([-\.\/])(\d{1,2})\2((\d{4})|(\d{2}))\s*$/ ;
				m = op.match( dmyexp );
				if(m == null ) return false;
				day = m[1];
				month = m[3]--;
				syear = parseInt(m[3], 10);
				year = (m[5].length == 4) ? m[5] : ((syear<30 ? "20" : "19") + syear);
				break;
			default :
				break;
		}
		var date = new Date(year, month, day);
		return (typeof(date) == "object" && year == date.getFullYear() && month == date.getMonth() && day == date.getDate());
	}
};
with(document){
	write("<style>");
	write("input.text {color:black;padding:0px 2px 0px;background-color:white; border:1px solid #cecece;}\n");
	write("input.textOk {color:green;padding:0px 2px 0px;background-color:white;border:1px solid #cecece;}\n");
	write("input.textError {color:red;padding:0px 2px 0px;background-color:white;border:1px solid red;}\n");
	write("span.notice {color:black;padding:2px 2px 0px;}\n");
	write("span.noticeOk { background-color:#ffffe1;border:1px solid green;color:green;padding:2px 2px 0px;}\n");
	write("span.noticeError { background-color:#ffffe1;border:1px solid #ccc000;color:red;padding:2px 2px 0px;}\n");
	write("</style>\n");
}