AE.namespace('AE.form.validator');

AE.form.validator = function(){
	var _self = this;
	
	var defConfig = {
		focusOnError:true,
    
		validateImmediate:true,
		
		tipsAdviceContainerClass:'fieldTipsContainer',
		tipsAdviceClass:'fieldTips',
		tipsAdviceMsgClass:'fieldTipsMsg',
		
		errorAdviceContainerClass:'fieldErrorContainer',
		errorAdviceClass:'fieldError',
		errorAdviceMsgClass:'fieldErrorMsg',
		
		fieldSuccessClass: 'fieldSuccess',
		fieldFailClass: 'fieldFail',
		
		ifNeedValidate: true,
		
		eventFuncMap:{
			blur:'default_blur',
			focus:'default_focus',
			keydown:'default_keydown',
			click:'default_click'
		},
		displayFuncMap:{
			getTipsAdvice:'getAdvice_getTips',
			getErrorAdvice:'getAdvice_getError',
			showStatus:'showStatus_changeTitleClass',
			showTipsMsg:'showTipsMsg_showMsgFollowOtherObj',
			closeTipsMsg:'closeTipsMsg_close',
			showErrorMsg:'showErrorMsg_showMsgFollowOtherObj',
			closeErrorMsg:'closeErrorMsg_close'
		}
	};
	//å¤–éƒ¨è‡ªå®šä¹‰äº‹ä»¶
	
	_self.customEvent={
		'onFeildErrFire'        :new YAHOO.util.CustomEvent('feildErrFire',_self,false,YAHOO.util.CustomEvent.LIST),
		'afterValidateAll'      :new YAHOO.util.CustomEvent('afterValidateAll',_self,false,YAHOO.util.CustomEvent.LIST),
		'afterValidateOneField' :new YAHOO.util.CustomEvent('afterValidateOneField',_self,false,YAHOO.util.CustomEvent.LIST),
		'afterFieldBlurNotValidators' :new YAHOO.util.CustomEvent('afterFieldBlurNotValidatorsEvent',_self,false,YAHOO.util.CustomEvent.LIST)
	}
	
	//æ ¡éªŒæ–¹æ³•æ± 
	_self.validatorsPool = {
		//ä¸ºç©º
		isEmpty : function(val, el, params) {return ((val == null) || (val.length == 0))}, 
		//ä¸ä¸ºç©º
		notEmpty : function(val, el, params) {return !((val == null) || (val.length == 0))},
		//trimåŽä¸ºç©º
		isTrimedEmpty: function(val, el, params) {return YL.trim(val) == null || (YL.trim(val).length == 0)},
		//trimåŽä¸ä¸ºç©º
		notTrimedEmpty: function(val, el, params) {return !(YL.trim(val) == null || (YL.trim(val).length == 0))},
		//æ­£åˆ™è¡¨è¾¾å¼åŒ¹é…
		regexp : function(val, el, params) {return eval(params[0]).test(val)},
		//æ­£åˆ™è¡¨è¾¾å¼åŒ¹é…å–å
		notRegexp : function(val, el, params) {return !eval(params[0]).test(val)},
		//æœ€å°é•¿åº¦
		minLength : function(val, el, params) {return val.length >= parseInt(params[0])},
		//æœ€å¤§é•¿åº¦
		maxLength : function(val, el, params) {return val.length <= parseInt(params[0])},
		//æœ€å°å€¼
		minValue : function(val, el, params) {return val >= parseFloat(params[0])}, 
		//æœ€å¤§å€¼
		maxValue : function(val, el, params) {return val <= parseFloat(params[0])},
		//ä¸å±žäºŽå…¶ä¸­
		notOneOf : function(val, el, params) {return params.every(function(v) {return val != v;})},
		//å…¶ä¸­ä¹‹ä¸€
		oneOf : function(val, el, params) {return params.some(function(v) {return val == v;})},
		//ç­‰äºŽ
		equal : function(val, el, params) {return val == params[0]},
		//ä¸ç­‰äºŽ
		notEqual : function(val, el, params) {return val != params[0]},
		//ç­‰äºŽæŸä¸ªè¡¨å•åŸŸçš„å€¼
		equalToField : function(val, el, params) {return val == get(params[0]).value},
		//ä¸ç­‰äºŽæŸä¸ªè¡¨å•åŸŸçš„å€¼
		notEqualToField : function(val, el, params) {return val != get(params[0]).value}
	};
	
	//ç¤ºä¾‹æ–¹æ³•ä¾›æ·»åŠ 
	var methods = {
		'oneRequire': function(val, el, params){
			var elname = el.name;
			var els = el.form.elements[elname];
			if (els.length > 0) {
				return AE.common.toArray(els).some(function(o) {return o.checked;});
			} else {
				return els.checked;
			}
		},
		'selection': function(val, el, params){
			return el.options ? el.selectedIndex >= 0 && _self.validatorsPool.notEmpty(val) : true;
		}
	};
	
		
	//////////////////////////////å¼€æ”¾æ–¹æ³•//////////////////////////////
	
	//æ·»åŠ æ ¡éªŒæ–¹æ³•
	_self.addValidator = function(){
		switch(arguments.length){
			case 1:
				_self.validatorsPool = YL.merge(_self.validatorsPool, arguments[0]);
				break;
			case 2:
				var m = {};
				m[arguments[0]] = arguments[1];
				_self.validatorsPool = YL.merge(_self.validatorsPool, m);
				break;
			default:
				return;
		}
	};
	
	//æ·»åŠ æ˜¾ç¤ºå±‚æ–¹æ³•
	_self.addDisplayFunc = function(){

		switch(arguments.length){
			case 1:
				_self.displayFuncPool = YL.merge(_self.displayFuncPool, arguments[0]);
				break;
			case 2:
				var m = {};
				m[arguments[0]] = arguments[1];
				_self.displayFuncPool = YL.merge(_self.displayFuncPool, m);
				break;
			default:
				return;
		}
	};
	
	//æ·»åŠ è§¦å‘äº‹ä»¶æ–¹æ³•
	_self.addEventFunc = function(){
		switch(arguments.length){
			case 1:
				_self.eventFuncPool = YL.merge(_self.eventFuncPool, arguments[0]);
				break;
			case 2:
				var m = {};
				m[arguments[0]] = arguments[1];
				_self.eventFuncPool = YL.merge(_self.eventFuncPool, m);
				break;
			default:
				return;
		}
	};
	
	
	//æ‰§è¡Œæ·»åŠ æ ¡éªŒæ–¹æ³•
	_self.addValidator(methods);
	
	//ä»ŽæœåŠ¡å™¨ç«¯è¿”å›žçš„é”™è¯¯ä¿¡æ¯
	_self.errorFromServer = function(elid, errorMsg){
		_self.configData.errorFromServerCount++;
		var el = get(elid);
		if(el){
			var displayFuncs = _self.configReader(el, 'displayFuncMap');
			var advice = _self.displayFuncPool[displayFuncs['getErrorAdvice']](el);
			_self.displayFuncPool[displayFuncs['showErrorMsg']](el, advice, errorMsg);
			_self.displayFuncPool[displayFuncs['showStatus']](el, false);
			if(_self.configData.errorFromServerCount == 1 ){
				_self.displayFuncPool['scrollToField'](el);
			}
		}
		//è®°å½•æœåŠ¡å™¨è¿”å›žçš„é”™è¯¯ï¼Œå…¨éƒ¨æäº¤æ—¶å¦‚æžœè¿˜å­˜åœ¨æœåŠ¡å™¨è¿”å›žé”™è¯¯ï¼Œä¹Ÿä¸èƒ½æäº¤
		_self.configData.errorFromServer[elid] = errorMsg;
	};
	
	//ä»ŽæœåŠ¡å™¨ç«¯è¿”å›žçš„tipsä¿¡æ¯
	_self.tipsFromServer = function(elid, tipsMsg){
		var el = get(elid);
		if(el){
			var displayFuncs = _self.configReader(el, 'displayFuncMap');
			var advice = _self.displayFuncPool[displayFuncs['getTipsAdvice']](el);
			_self.displayFuncPool[displayFuncs['showTipsMsg']](el, advice, tipsMsg);
		}
	};
	
	//////////////////////////////å¼€æ”¾æ–¹æ³•//////////////////////////////
	
	//æ‰€æœ‰é…ç½®è¿‡çš„å­—æ®µçš„å¼•ç”¨
	_self.allFields = {};
	
	//æ‰€æœ‰ç”Ÿæˆçš„tipsAdvisoré›†åˆ
	_self.allTipsAdvisor = {};
	
	//æ‰€æœ‰ç”Ÿæˆçš„errorAdvisoré›†åˆ
	_self.allErrorAdvisor = {};
	
	//æ‰€æœ‰æ•°æ®æ± 
	_self.configData = {};
	
	//å½“å‰è¡¨å•å¯¹è±¡
	_self.formObj = {};
	
	//static å¾—åˆ°æœ€åˆæ‰€æœ‰çš„field
	_self.getAllFields = function(  ){
		for(var f in _self.configData.fields){
			el = get(f);
			if(el){			   
				_self.allFields[f] = el;
			}
		}
	};
	
	//æ·»åŠ fieldsåˆ°æ•°æ®é›†é‡Œ,å¹¶è¿”å›žæœ¬æ¬¡æ·»åŠ çš„è¿™æ®µé›†
	_self.addFields = function( fields ){
	    if( fields == null ){ return ; }
	    var aFields = {};
	    for(var f in fields){	        
			el = get(f);
			if(el){	   
				_self.allFields[f] = el;
				aFields[f] = el;
			}
		}
		return aFields;
	};
	
	//attributeè¯»å–å™¨
	_self.configReader = function(el, attribute){
		var d = attribute.split(".");
		var o = _self.configData.fields[el.id];
		var p = _self.configData;
		for(var i=0,j=d.length;i<j;i++){
			o = o[d[i]] || {};
		}
		for(var m=0,n=d.length;m<n;m++){
			p = p[d[m]];
		}
 		if(YL.isObject(p)){
			return YL.merge(p, o);
		} else if(_self.configData.fields[el.id][attribute] !== undefined) {
		    return _self.configData.fields[el.id][attribute];
		} else {
	        return _self.configData[attribute];
	    }
	}
	
	//æ˜¯å¦æ˜¯radio,checkbox,select,fileç±»åž‹çš„field
    _self.isSpecialField = function(el){
    	return (el.type.toLowerCase() == 'radio' || el.type.toLowerCase() == 'checkbox' || el.type.toLowerCase() == 'file' || el.tagName == 'SELECT') ? true : false
    }
    
    //æ˜¯å¦æ˜¯radio,checkbox
    _self.isCheckBoxOrRadio = function(el){
    	return (el.type.toLowerCase() == 'radio' || el.type.toLowerCase() == 'checkbox') ? true : false
    }
	
	//å¤„ç†å‰ç½®æ¡ä»¶å‡½æ•°
	_self.executeBeforeFunc = function(data_before){
		if(data_before === undefined) {return true}
		var elid = data_before.elid;
		var elv = data_before.elv;
		if(elid in _self.configData.fields){
			var vali = _self.configData.fields[elid].validators[elv];
		} else {
			return false;
		}
		var el = get(elid);
		return _self.executeValidator(el, vali);
	}
	
	//æ‰§è¡Œå­—æ®µé‡Œçš„å•ä¸ªvalidator

	_self.executeValidator = function(el, data_validator,o){
		if(_self.validatorsPool[data_validator.ruleName] && !_self.validatorsPool[data_validator.ruleName](el.value, el, data_validator.params,o))

			return false;
		else
			return true;
	}
	
	
	
		
	//æ ¡éªŒå•ä¸ªå­—æ®µ return true or false;
	//o è°ƒç”¨è€…ä¼ é€’å‚æ•°
	
	_self.validateField = function(el, validators, o, byAllRule){
		var result = true;
		var msg = null;
		var returnMsg = new AE.widget.message();
		returnMsg.init();
		var errorFieldId = el.id;
		var errorValidatorName = null;
		for(var v in validators){
			if(!_self.executeValidator(el, validators[v],o)){
				msg = validators[v].errorMsg || _self.configData.fields[el.id].errorMsg;
				errorValidatorName = v;
				returnMsg.pushMsg(msg,v,1);
				result = false;
				if(!byAllRule){break;}
				
			}
		}

		returnMsg['result'] = result;
		returnMsg['msg'] = msg;
		_self.customEvent['afterValidateOneField'].fire(errorFieldId,returnMsg);
		//_self.customEvent['afterValidateOneField'].fire(errorFieldId, errorValidatorName, result);
		return returnMsg;
	}
	
	//####################add by justin, æœ‰äº›ç–‘è™‘çš„ä»£ç  begin#########################################################################################
	//æ ¡éªŒæ‰€æœ‰è§„åˆ™ã€‚è¿™ä¸ªé€»è¾‘. ç›®å‰æ¥è¯´æœ‰ç³»ç»Ÿæ¼æ´žï¼Œå°±æ˜¯å¯èƒ½é€ æˆæ­»å¾ªçŽ¯ã€‚åº”ç”¨çš„æ—¶å€™æ…Žé‡ã€‚
	//æ‰“å¼€å¾ªçŽ¯ç»“çš„æ–¹æ¡ˆæ˜¯ï¼Œåœ¨è¿è¡Œæ—¶ï¼ŒæŠŠæ ¡éªŒå™¨çš„è·¯å¾„è®°å½•ä¸‹æ¥ï¼Œåšæ ‡è®°ï¼Œæ¯æ¬¡å¯¹æ¯”ã€‚è€ƒè™‘åˆ°æ•ˆçŽ‡é—®é¢˜ï¼Œæš‚æ—¶ä¸åŠ è¿™æ®µé€»è¾‘ï¼Œ
//    _self.validateFieldByAllRule = function(el, validators,o){
//    		//var result = true;
//    		var msg = null;
//    		var returnMsg = new AE.widget.message();
//    		returnMsg.init();
//    		var errorFieldId = el.id;
//    		var errorValidatorName = null;
//    		for(var v in validators){
//    			if(!executeValidator(el, validators[v],o)){
//    				msg = validators[v].errorMsg || _self.configData.fields[el.id].errorMsg;
//    				returnMsg.pushMsg(msg,v,1);
//    				//result = false;
//    				//break;
//    			}
//    		}
//    		//_self.customEvent['afterValidateOneField'].fire({'fieldId':errorFieldId, 'validatorName':errorValidatorName, 'result':result});
//    		return returnMsg;
//    	}
	//####################add by justin, æœ‰äº›ç–‘è™‘çš„ä»£ç  end#########################################################################################	
	
	//æŠŠdosé‡Œå¯¹åº”çš„validatorè£…æˆvalidators  return validators
	_self.dosToValidator = function(el, dos){
		var vs = {};
		for(var i=0,j=dos.length;i<j;i++){
			if(_self.configData.fields[el.id].validators[dos[i]]){
				vs[dos[i]] = _self.configData.fields[el.id].validators[dos[i]];
			}
		}
		return vs;
	}
	
	//conditionHandle return validators or false
	_self.conditionHandle = function(el){
		if(YL.isArray(_self.configData.fields[el.id].condition) && _self.configData.fields[el.id].condition.length > 0){
			for(var i=0,j=_self.configData.fields[el.id].condition.length; i<j; i++){
				if(_self.executeBeforeFunc(_self.configData.fields[el.id].condition[i].before)){
					return _self.dosToValidator(el, _self.configData.fields[el.id].condition[i].dos);
				}
			}
		}
		return false;
	}
	
	//åˆ¤æ–­æœ€ç»ˆä½¿ç”¨çš„validator
	_self.getValidators = function(el){
		if(_self.configData.fields[el.id].condition != undefined){
			return _self.conditionHandle(el)
		} else {
			return _self.configData.fields[el.id].validators || false;
		}
	}

	//æ ¡éªŒæ‰€æœ‰å­—æ®µ
	_self.validateAllField = function(){
		var validateResult, el, ifNeedValidate, advice, msg, displayFuncs, finalResult=true;
		var firstErrorField = null;
		var errFieldNum = 0;
		var elValidators = false;
		for(var f in _self.allFields){
			el = _self.allFields[f];
			//æ‰‹åŠ¨æ ‡å¿—ä½ã€‚å­—æ®µé‡Œé…ç½®ifNeedValidateä¸ºfalseæ—¶äººä¸ºä¸æ ¡éªŒ
			ifNeedValidate = _self.configReader(el, 'ifNeedValidate');
			displayFuncs = _self.configReader(el, 'displayFuncMap');
			//å–å¾—æœ€ç»ˆçš„validators
			elValidators = _self.getValidators(el);
			//å¤„ç†æœåŠ¡ç«¯è¿”å›žçš„é”™è¯¯ä¿¡æ¯
			if((f in _self.configData.errorFromServer) && firstErrorField == null){
				firstErrorField = el;
				errFieldNum++;
				_self.customEvent['onFeildErrFire'].fire(_self.configData.errorSubmitTime+1, errFieldNum, el);
				finalResult = false;
				_self.configData.fields[el.id].statusResult = false;
				_self.configData.fields[el.id].statusMsg = _self.configData.errorFromServer[f];
				_self.displayFuncPool[displayFuncs['showStatus']](el, _self.configData.fields[el.id].statusResult);
				_self.errorFromServer(f, _self.configData.fields[el.id].statusMsg);
			//å¤„ç†é¡µé¢é”™è¯¯ä¿¡æ¯
			} else if(ifNeedValidate && elValidators) {
				validateResult = _self.validateField(el, elValidators);
				_self.configData.fields[el.id].statusResult = !validateResult.isError();
				_self.configData.fields[el.id].statusMsg = validateResult.getContent();
				//è°ƒç”¨æ”¹å˜å­—æ®µclassæ–¹æ³•
				_self.displayFuncPool[displayFuncs['showStatus']](el, _self.configData.fields[el.id].statusResult);
				advice = _self.displayFuncPool[displayFuncs['getErrorAdvice']](el);
				//å¾—åˆ°éœ€è¦é”™è¯¯çš„msg
				msg = _self.configData.fields[el.id].statusMsg;
				//è°ƒç”¨å…³é—­tipsæ–¹æ³•
				_self.displayFuncPool[displayFuncs['closeTipsMsg']](el);
				//å¦‚æžœå½“å‰éªŒè¯ç»“æžœä¸ä¸ºtrueæ—¶å°±æ˜¾ç¤ºé”™è¯¯
				if(!_self.configData.fields[el.id].statusResult){
					//è°ƒç”¨æ˜¾ç¤ºé”™è¯¯çš„æ–¹æ³•
					errFieldNum++;
					_self.customEvent['onFeildErrFire'].fire(_self.configData.errorSubmitTime+1, errFieldNum, el);
		        	_self.displayFuncPool[displayFuncs['showErrorMsg']](el, advice, msg);
		        	finalResult = false;
		        	//å¾—åˆ°ç¬¬ä¸€ä¸ªå‡ºé”™çš„å­—æ®µ
		        	if(firstErrorField == null) firstErrorField = el;
		        }
			}
		}
		//æ»šåŠ¨åˆ°ç¬¬ä¸€ä¸ªå‡ºé”™çš„åœ°æ–¹
		if(_self.configData.focusOnError && firstErrorField != null){
			_self.displayFuncPool['scrollToField'](firstErrorField);
		}
		if(firstErrorField != null){
			//è®¾ç½®æäº¤æ—¶å‡ºé”™æ¬¡æ•°
			_self.configData.errorSubmitTime++; 
		}
		_self.customEvent['afterValidateAll'].fire(_self.configData.errorSubmitTime, errFieldNum, finalResult);
		return finalResult;
	}
	
	//è¡¨çŽ°å±‚æ–¹æ³•é›†åˆ
	_self.displayFuncPool = {
		//å–å¾—tipsAdviceå¹¶å­˜å…¥_self.allTipsAdvisor,
		getAdvice_getTips: function(el) {
			var id = el.id;
			var advice;
			if (id in _self.allTipsAdvisor){
				advice = _self.allTipsAdvisor[id];
			} else {
				//æ‹¼å‡ºtipsadviceçš„id
				var aid = (el.id) + '-advice-tips';
				//å¦‚æžœé¡µé¢ä¸­å­˜åœ¨è¯¥idçš„<div>ï¼Œä½¿ç”¨å…¶ä½œä¸ºadvice
				advice = get(aid);
				if (!advice) {
					//å¦‚æžœè®¾ç½®äº† tipsAdviceContainerClassï¼Œæ ¹æ®è¯¥classæ‰¾åˆ°çˆ¶å®¹å™¨ï¼Œå› ä¸ºè¡¨å•åŸŸå¯èƒ½å­˜åœ¨å¤šå±‚åµŒå¥—(åœ¨<table>æˆ–å¤šå±‚<div>ä¸‹)ï¼Œè€Œadviceå¯èƒ½è¦æ±‚æ˜¾ç¤ºåœ¨çˆ¶å®¹å™¨æŒ‡å®šå¤„
					var tipsAdviceContainerClass = _self.configReader(el, 'tipsAdviceContainerClass');
					var container = YUD.getAncestorByClassName(el, tipsAdviceContainerClass) || el.parentNode;
					var tipsAdviceClass = _self.configReader(el, 'tipsAdviceClass');
					advice = YUD.getElementsByClassName(tipsAdviceClass, 'div', container)[0];
					if (!advice) {
						//åˆ›å»ºadvice
						advice = document.createElement('div');
						YUD.addClass(advice, tipsAdviceClass);
						if (_self.configData.fields[el.id].tipsAdviceContainerClass) {
							container.appendChild(advice);
						} else {
							//å°†adviceæ˜¾ç¤ºåœ¨ç´§éšè¡¨å•åŸŸçš„åŽé¢
							switch (el.type.toLowerCase()) {
								//checkbox å’Œ radio æ˜¾ç¤ºåœ¨çˆ¶å…ƒç´ çš„æœ€åŽé¢
								case 'checkbox':
								case 'radio':
									el.parentNode.appendChild(advice, el);
									break;
								default:
									AE.dom.insertAfter(advice, el);
							}
						}
					}
					advice.id = aid;
				}
				_self.allTipsAdvisor[id] = advice;
			}
			YUD.setStyle(advice, 'display', 'none');
			YUE.on(advice, 'mouseover', function(){
				_self.configData.fields[el.id].tipsClose = false;
			})
			YUE.on(advice, 'mouseout', function(){
				_self.configData.fields[el.id].tipsClose = true;
			})
			return advice;				
		},
		//å–å¾—ErrorAdviceå¹¶å­˜å…¥_self.allErrorAdvisor,
		getAdvice_getError: function(el) {
			var id = el.id;
			var advice;
			if (id in _self.allErrorAdvisor){
				advice = _self.allErrorAdvisor[id];
			} else {
				//æ‹¼å‡ºerrorAdviceçš„id
				var aid = (el.id) + '-advice-error';
				//å¦‚æžœé¡µé¢ä¸­å­˜åœ¨è¯¥idçš„<div>ï¼Œä½¿ç”¨å…¶ä½œä¸ºadvice
				advice = get(aid);
				if (!advice) {
					//å¦‚æžœè®¾ç½®äº† errorAdviceContainerClassï¼Œæ ¹æ®è¯¥classæ‰¾åˆ°çˆ¶å®¹å™¨ï¼Œå› ä¸ºè¡¨å•åŸŸå¯èƒ½å­˜åœ¨å¤šå±‚åµŒå¥—(åœ¨<table>æˆ–å¤šå±‚<div>ä¸‹)ï¼Œè€Œadviceå¯èƒ½è¦æ±‚æ˜¾ç¤ºåœ¨çˆ¶å®¹å™¨æŒ‡å®šå¤„
					var errorAdviceContainerClass = _self.configReader(el, 'errorAdviceContainerClass');
					var container = YUD.getAncestorByClassName(el, errorAdviceContainerClass) || el.parentNode;
					var errorAdviceClass = _self.configReader(el, 'errorAdviceClass');
					advice = YUD.getElementsByClassName(errorAdviceClass, 'div', container)[0];
					if (!advice) {
						//åˆ›å»ºadvice
						advice = document.createElement('div');
						YUD.addClass(advice, errorAdviceClass);
						if (_self.configData.fields[el.id].errorAdviceContainerClass) {
							container.appendChild(advice);
						} else {
							//å°†adviceæ˜¾ç¤ºåœ¨ç´§éšè¡¨å•åŸŸçš„åŽé¢
							switch (el.type.toLowerCase()) {
								//checkbox å’Œ radio æ˜¾ç¤ºåœ¨çˆ¶å…ƒç´ çš„æœ€åŽé¢
								case 'checkbox':
								case 'radio':
									el.parentNode.appendChild(advice, el);
									break;
								default:
									AE.dom.insertAfter(advice, el);
							}
						}
					}
					advice.id = aid;
				}
				_self.allErrorAdvisor[id] = advice;
			}
			YUD.setStyle(advice, 'display', 'none');
			return advice;				
		},
		//æ ¹æ®ç»“æžœæ·»åŠ fieldçš„æˆåŠŸæˆ–å¤±è´¥class
		showStatus_changeFieldClass: function(el, result) {
            var fieldFailClass = _self.configReader(el, 'fieldFailClass');
			var fieldSuccessClass = _self.configReader(el, 'fieldSuccessClass');
            if (!result) {
                YUD.removeClass(el, fieldSuccessClass);
				YUD.addClass(el, fieldFailClass);
            } else {
                YUD.removeClass(el, fieldFailClass);
				YUD.addClass(el, fieldSuccessClass);
            }
        },
        //æ ¹æ®ç»“æžœæ”¹å˜å­—æ®µæ ‡é¢˜
        showStatus_changeTitleClass: function(el, result){
        	var titleEl;
        	var titleId = el.getAttribute( '_validatorTitleId' );
        	if( titleId != null ){
        		titleEl = get(titleId);
        	} else {
        		var tmp = YUD.getPreviousSibling(YUD.getAncestorByTagName(el, 'TD'));
        		titleEl = YUD.getFirstChild(tmp);
        	}
        	if(!result){
        		YUD.addClass(titleEl, 'alert');
        	} else {
        		YUD.removeClass(titleEl, 'alert');
        	}
        },
        //åªæ˜¾ç¤ºå®¹å™¨ï¼Œä¸ç»™å†…å®¹ï¼Œç”¨åœ¨TIPSå†™æˆHTMLï¼Œç›´æŽ¥æ”¾åœ¨å®¹å™¨ä¸­
        showTipsMsg_justShowContainer: function(el, advice, msg){
        	if(msg != null){
		        var elPos = YUD.getXY(el);
		        YUD.setStyle(advice, 'position', 'absolute');
		        var tipsAdviceMsgClass = _self.configReader(el, 'tipsAdviceMsgClass');
				var msgbox = YUD.getElementsByClassName(tipsAdviceMsgClass, '*', advice)[0] || advice;
	            YUD.setStyle(advice, 'display', 'block');
	            YUD.setXY(advice, [elPos[0]-4 + el.offsetWidth, elPos[1]]);
		        //YUE.on(advice, 'click', function() {this.style.display = 'none';});
        	}
        },
        //æ‰“å¼€Tipsæç¤º_å¼¹å‡ºæ³¡æ³¡
        showTipsMsg_bubbleMsg: function(el, advice, msg){
        	if(msg != null){
	        	var elPos = YUD.getXY(el);
	        	YUD.setStyle(advice, 'position', 'absolute');
	            var tipsAdviceMsgClass = _self.configReader(el, 'tipsAdviceMsgClass');
				var msgbox = YUD.getElementsByClassName(tipsAdviceMsgClass, '*', advice)[0] || advice;
            	msgbox.innerHTML = msg;
            	YUD.setStyle(advice, 'display', 'block');
            	YUD.setXY(advice, [elPos[0]-4 + el.offsetWidth, elPos[1]]);
	            //YUE.on(advice, 'click', function() {this.style.display = 'none';});
        	}
            
        },
        
        //ä¸ç›´æŽ¥è·ŸéšOBJæ˜¾ç¤ºTipsï¼Œåœ¨åŒæ¯èŠ‚ç‚¹ä¸‹ï¼Œæ‰¾ç¬¬ä¸€ä¸ªCLASSå¸¦followedObjçš„ã€‚
        showTipsMsg_showMsgFollowOtherObj: function(el, advice, msg){
        	var dFollowedObj = get(el.getAttribute('errMsgTo'));
			dFollowedObj = dFollowedObj ?  dFollowedObj :  YUD.getElementsByClassName('followedObj','*',el.parentNode)[0];
			dFollowedObj = dFollowedObj? dFollowedObj : el;
        	if(msg != null){
	        	var elPos = YUD.getXY(dFollowedObj);
	        	YUD.setStyle(advice, 'position', 'absolute');
	            var tipsAdviceMsgClass = _self.configReader(el, 'tipsAdviceMsgClass');
				var msgbox = YUD.getElementsByClassName(tipsAdviceMsgClass, '*', advice)[0] || advice;
            	msgbox.innerHTML = msg;
            	YUD.setStyle(advice, 'display', 'block');
            	YUD.setXY(advice, [elPos[0]-4 + dFollowedObj.offsetWidth, elPos[1]]);
	            //YUE.on(advice, 'click', function() {this.style.display = 'none';});
        	}
            
        },
        
        //åœ¨å³è¾¹å‡ºçŽ°é”™è¯¯ä¿¡æ¯
        showErrorMsg_bubbleMsg: function(el, advice, msg){
        	if(msg != null){
	        	var elPos = YUD.getXY(el);
	        	YUD.setStyle(advice, 'position', 'absolute');
	            var errorAdviceMsgClass = _self.configReader(el, 'errorAdviceMsgClass');
				var msgbox = YUD.getElementsByClassName(errorAdviceMsgClass, '*', advice)[0] || advice;
            	msgbox.innerHTML = msg;
            	YUD.setStyle(advice, 'display', 'block');
            	YUD.setXY(advice, [elPos[0]-4 + el.offsetWidth, elPos[1]]);
	            //YUE.on(advice, 'click', function() {this.style.display = 'none';});
        	}
        },
        //ä¸ç›´æŽ¥è·ŸéšOBJæ˜¾ç¤ºERRORï¼Œåœ¨åŒæ¯èŠ‚ç‚¹ä¸‹ï¼Œæ‰¾errMsgToæ‰€æŒ‡å®šçš„å…ƒç´ ï¼Œè‹¥ä¸å­˜åœ¨å†æ‰¾ç¬¬ä¸€ä¸ªçˆ¶èŠ‚ç‚¹ä¸‹ç¬¬ä¸€ä¸ªCLASSå¸¦followedObjçš„ã€‚
		showErrorMsg_showMsgFollowOtherObj: function (el, advice, msg) {
			var dFollowedObj = get(el.getAttribute('errMsgTo'));
			dFollowedObj = dFollowedObj ?  dFollowedObj :  YUD.getElementsByClassName('followedObj','*',el.parentNode)[0];
			dFollowedObj = dFollowedObj? dFollowedObj : el;
			if(msg != null){
				var elPos = YUD.getXY(dFollowedObj);
				YUD.setStyle(advice, 'position', 'absolute');
				var errorAdviceMsgClass = _self.configReader(el, 'errorAdviceMsgClass');
				var msgbox = YUD.getElementsByClassName(errorAdviceMsgClass, '*', advice)[0] || advice;
				msgbox.innerHTML = msg;
				YUD.setStyle(advice, 'display', 'block');
				YUD.setXY(advice, [elPos[0]-4 + dFollowedObj.offsetWidth, elPos[1]]);
			}
		},
        //å…³é—­Tipsæç¤º_ç›´æŽ¥å…³é—­
        closeTipsMsg_close: function(el){
        	YUD.setStyle(_self.allTipsAdvisor[el.id],'display','none')
        },
        //å…³é—­Erroræç¤º_ç›´æŽ¥å…³é—­
        closeErrorMsg_close: function(el){
        	YUD.setStyle(_self.allErrorAdvisor[el.id],'display','none')
        },
        //å±å¹•æ»šåŠ¨åˆ°åˆ¶å®šä½ç½®
        scrollToField: function(el){
        	//fieldçš„è‡ªèº«é«˜åº¦
        	var elOffsetHeight = el.offsetHeight;
        	//fieldçš„åæ ‡
        	var elY = YUD.getY(el);
        	//æµè§ˆå™¨çª—å£çš„é«˜åº¦
        	var clientHeight = YUD.getClientHeight(); 
        	//é¡µé¢æ»šåŠ¨TOPé«˜åº¦
        	var documentScrollTop = YUD.getDocumentScrollTop();
        	//ä¸åœ¨æ˜¾ç¤ºçš„èŒƒå›´å†…å°±scrollåˆ°è¯¥ä½ç½®
        	if(documentScrollTop < elY + elOffsetHeight - clientHeight || documentScrollTop > elY ){
        		window.scroll(0, elY - 15);
        	}
        },
        //é‡æ–°å®šä½å„æç¤ºçª—
        repositionAdvice: function(){
        	var el, elPos;
        	for(var f in _self.allErrorAdvisor){
        		el = get(_self.allErrorAdvisor[f].id.replace(/-advice-error/gi, ''));
        		var dFollowedObj = get(el.getAttribute('errMsgTo'));
				dFollowedObj = dFollowedObj ?  dFollowedObj :  YUD.getElementsByClassName('followedObj','*',el.parentNode)[0];
				dFollowedObj = dFollowedObj? dFollowedObj : el;
        		elPos = YUD.getXY(dFollowedObj);
        		YUD.setXY(_self.allErrorAdvisor[f], [elPos[0]-4 + dFollowedObj.offsetWidth, elPos[1]]);
        	}
        	for(var f in _self.allTipsAdvisor){
        		el = get(_self.allTipsAdvisor[f].id.replace(/-advice-tips/gi, ''));
        		var dFollowedObj = get(el.getAttribute('errMsgTo'));
				dFollowedObj = dFollowedObj ?  dFollowedObj :  YUD.getElementsByClassName('followedObj','*',el.parentNode)[0];
				dFollowedObj = dFollowedObj? dFollowedObj : el;
        		elPos = YUD.getXY(dFollowedObj);
        		YUD.setXY(_self.allErrorAdvisor[f], [elPos[0]-4 + dFollowedObj.offsetWidth, elPos[1]]);
        	}
        }
	}

	//äº‹ä»¶é©±åŠ¨æ–¹æ³•é›†åˆ
	_self.eventFuncPool = {
		default_blur: function(ev, el){
			var displayFuncs = _self.configReader(el, 'displayFuncMap');            
			//æ˜¯å¦éœ€è¦ç«‹å³æ ¡éªŒ
			var validateImmediate = _self.configReader(el, 'validateImmediate');
			//æ˜¯å¦éœ€è¦æ ¡éªŒ
			var ifNeedValidate = _self.configReader(el, 'ifNeedValidate');
			//å–å¾—æœ€ç»ˆçš„validators
			elValidators = _self.getValidators(el);
			//å¦‚æžœéœ€è¦ç«‹å³æ ¡éªŒ && ifNeedValidateå¼€å…³ä¸ºå¼€ && å…·æœ‰æ ¡éªŒå™¨ && ï¼ˆæ ¡éªŒå¯åŠ¨æ ‡å¿—ä½ä¸ºtrue || ä¸ºç‰¹æ®Šå­—æ®µï¼‰
			if(validateImmediate && ifNeedValidate && elValidators && _self.configData.fields[el.id].isInValidateProcess){
				//æ‰§è¡Œæ ¡éªŒå¹¶å–å¾—æ ¡éªŒç»“æžœ
				var validateResult = _self.validateField(el, elValidators);
				//æŠŠç»“æžœå’Œå‡ºé”™ä¿¡æ¯å­˜å…¥æ•°æ®ç»“æž„ä¸­
				_self.configData.fields[el.id].statusResult = !validateResult.isError();
				_self.configData.fields[el.id].statusMsg = validateResult.getContent();
				//è°ƒç”¨æ”¹å˜å­—æ®µclassæ–¹æ³•
				_self.displayFuncPool[displayFuncs['showStatus']](el, _self.configData.fields[el.id].statusResult);
				//å¾—åˆ°éœ€è¦å‡ºçŽ°çš„msg
				var msg = _self.configData.fields[el.id].statusMsg;
				//å¦‚æžœå½“å‰éªŒè¯ç»“æžœä¸ä¸ºtrueæ—¶å°±æ˜¾ç¤ºé”™è¯¯
				if(!_self.configData.fields[el.id].statusResult){
					//è°ƒç”¨æ˜¾ç¤ºé”™è¯¯çš„æ–¹æ³•
					var advice = _self.displayFuncPool[displayFuncs['getErrorAdvice']](el);					
		        	_self.displayFuncPool[displayFuncs['showErrorMsg']](el, advice, msg);
		        } else {
		        	_self.displayFuncPool[displayFuncs['closeErrorMsg']](el);
		        }		       
			}
			
			//è§¦å‘æ— æ ¡éªŒå™¨äº‹ä»¶
			if( validateImmediate && ifNeedValidate && !elValidators && _self.configData.fields[el.id].isInValidateProcess){
				var returnMsg = new AE.widget.message();
						returnMsg.init();						
						returnMsg['result'] = true;
						returnMsg['msg'] = '';
					_self.customEvent['afterFieldBlurNotValidators'].fire(el.id, returnMsg );
			}
			
			//è°ƒç”¨å…³é—­æ¶ˆæ¯æç¤ºæ–¹æ³•
			if(_self.configData.fields[el.id].tipsMsg && _self.configData.fields[el.id].tipsClose != false){
				_self.displayFuncPool[displayFuncs['closeTipsMsg']](el);
			}
			
	
		},
		default_focus: function(ev, el){
			var displayFuncs = _self.configReader(el, 'displayFuncMap');
			//èŽ·å–advice
			var advice = _self.displayFuncPool[displayFuncs['getTipsAdvice']](el);
			/*
			//èšç„¦æ—¶æ˜¾ç¤ºTIPS
			if(_self.configData.fields[el.id].tipsMsg && _self.configData.fields[el.id].statusResult == undefined){
				_self.displayFuncPool[displayFuncs['showTipsMsg']](el, advice, _self.configData.fields[el.id].tipsMsg);
			}
			*/
			for(var f in _self.allTipsAdvisor){
				YUD.setStyle(_self.allTipsAdvisor[f], 'display', 'none');
			}
			if(_self.configData.fields[el.id].tipsMsg){
				_self.displayFuncPool[displayFuncs['showTipsMsg']](el, advice, _self.configData.fields[el.id].tipsMsg);
				_self.displayFuncPool[displayFuncs['closeErrorMsg']](el);
			}
		},
		default_keydown: function(ev, el){
			//è®¾ç½®æ ¡éªŒå¯åŠ¨æ ‡å¿—ä½ä¸ºtrue
			if(ev.keyCode != 9){
				_self.configData.fields[el.id].isInValidateProcess = true;
			}
		},
		default_click: function(ev, el){
			if(_self.isSpecialField(el)){
				_self.configData.fields[el.id].isInValidateProcess = true;
			}
		},
		//è¡¨å•æäº¤æ—¶ï¼Œæ‰¹é‡éªŒè¯é™æ€æ–¹æ³•
		default_submit: function(ev){
			if (!_self.validateAllField()) YUE.stopEvent(ev);
		},
		//é‡ç½®è¡¨å•æ—¶å›žå¤åˆå§‹çŠ¶æ€
		default_reset: function(ev){
			for(var t in _self.allTipsAdvisor){
				YUD.setStyle(_self.allTipsAdvisor[t], 'display', 'none');
			}
			for(var e in _self.allErrorAdvisor){
				YUD.setStyle(_self.allErrorAdvisor[e], 'display', 'none');
			}
			var fieldSuccessClass,fieldFailClass,el;
			for(var f in _self.configData.fields){
				el = get(f);
				fieldSuccessClass = _self.configReader(el, 'fieldSuccessClass');
				fieldFailClass = _self.configReader(el, 'fieldFailClass');
				YUD.removeClass(el, fieldSuccessClass);
				YUD.removeClass(el, fieldFailClass);
			}
			_self.configData.errorFromServerCount = 0;
			_self.configData.errorFromServer = {};
		}
	}
	
	
	
	_self.formEventRegist = function(){
		//æ³¨å†Œonsubmitäº‹ä»¶
		YUE.on(_self.formObj, 'submit', _self.eventFuncPool['default_submit']);
		//æ³¨å†Œonsubmitäº‹ä»¶
		YUE.on(_self.formObj, 'reset', _self.eventFuncPool['default_reset']);
	}
	
	
	//åˆå§‹åŒ–form
	_self.init = function(formId, userConfig){
		//æŠŠformå¯¹è±¡ä¿å­˜åœ¨formObjä¸­
		//æŠŠé…ç½®è½¬åŒ–ä¸ºæ•°æ®
		//åˆå§‹åŒ–æäº¤å‡ºé”™æ¬¡æ•°
		//åˆå§‹åŒ–æœåŠ¡å™¨é”™è¯¯å®¹å™¨
		//åˆå§‹åŒ–æœåŠ¡å™¨é”™è¯¯æ¬¡æ•°ï¼Œå°†æ¥è¦æ”¹è¿›
		//æŠŠæ‰€æœ‰é…ç½®å¥½çš„fieldçš„å¼•ç”¨å­˜å…¥_self.allFields
		
		_self.initWithoutEvent(formId, userConfig);
		
		//æ‰§è¡Œæ³¨å†Œäº‹ä»¶
		_self.fieldsEventHandle(_self.allFields, 'add');
		_self.formEventRegist();
		
		/*
		////////////////////////////////////// åŠ¨æ€æ·»åŠ å­—æ®µ test /////////////
		_self.addValidateFields(addFieldsConfig);
		_self.addValidateFields(addFieldsConfig22);
		
		_self.delValidateFields('business_email')
		
		////////////////////////////////////// åŠ¨æ€æ·»åŠ å­—æ®µ test /////////////
		*/
		
	};
	
	
	_self.initWithoutEvent = function(formId, userConfig){
		//æŠŠformå¯¹è±¡ä¿å­˜åœ¨formObjä¸­
		_self.formObj = get(formId);
		
		//æŠŠé…ç½®è½¬åŒ–ä¸ºæ•°æ®
		_self.configData = YL.merge(defConfig, userConfig || {});
		
		//ä¿è¯fieldså­—æ®µé…ç½®è‡³å°‘ä¸ºç©º
		if(_self.configData.fields === undefined){
	        _self.configData.fields = {};
	    }
		
		//åˆå§‹åŒ–æäº¤å‡ºé”™æ¬¡æ•°
		_self.configData.errorSubmitTime = 0;
		
		//åˆå§‹åŒ–æœåŠ¡å™¨é”™è¯¯å®¹å™¨
		_self.configData.errorFromServer = {};
		
		//åˆå§‹åŒ–æœåŠ¡å™¨é”™è¯¯æ¬¡æ•°ï¼Œå°†æ¥è¦æ”¹è¿›
		_self.configData.errorFromServerCount = 0;
		
		
		//æŠŠæ‰€æœ‰é…ç½®å¥½çš„fieldçš„å¼•ç”¨å­˜å…¥_self.allFields
		_self.getAllFields();

		//çª—å£resizeæ—¶é‡å®šä½ä¿¡æ¯æ¡†
		window.onresize = function(){
		    setTimeout(_self.displayFuncPool['repositionAdvice'], 300);
		};
		
		/*
		////////////////////////////////////// åŠ¨æ€æ·»åŠ å­—æ®µ test /////////////
		_self.addValidateField(addFieldsConfig);
		_self.addValidateField(addFieldsConfig22);
		
		////////////////////////////////////// åŠ¨æ€æ·»åŠ å­—æ®µ test /////////////
		*/
		
	};
	
	
	
	/*
	//////////////////////////////////////// åŠ¨æ€æ·»åŠ å­—æ®µ test /////////////
	
	var addFieldsConfig = {
		'city':{
			tipsMsg:'cityçš„tips',
			validators:{
				v1:{
					ruleName:'notEmpty',
					params:[],
					errorMsg: 'cityèƒ½ä¸ºç©ºï¼'
				}
			}
		}
	}
	
	var addFieldsConfig22 = {
		'street_address':{
			tipsMsg:'street_addressæ‰‹åŠ¨é˜€æ’’æ—¦æ³•',
			validators:{
				v1:{
					ruleName:'notEmpty',
					params:[],
					errorMsg: 'street_addressèƒ½ä¸ºç©ºï¼'
				}
			}
		},
		'province':{
			tipsMsg:'provinceTIps',
			validators:{
				v1:{
					ruleName:'notEmpty',
					params:[],
					errorMsg: 'provinceèƒ½ä¸ºç©ºï¼'
				}
			}
		}
	}
	
	
	
	//////////////////////////////////////// åŠ¨æ€æ·»åŠ å­—æ®µ test /////////////
	*/
	
	
	//åŠ¨æ€æ·»åŠ fields
	_self.addValidateField = function(fieldsConfig){
	    _self.configData.fields = YL.merge(_self.configData.fields, fieldsConfig);

		//æŠŠæ‰€æœ‰é…ç½®å¥½çš„fieldçš„å¼•ç”¨å­˜å…¥_self.allFields
		var aFields = _self.addFields( fieldsConfig );

		_self.fieldsEventHandle( aFields, 'add');
	}

	//åŠ¨æ€åˆ é™¤fields
	_self.delValidateField = function(fid){
	    var field = get(fid);
		for(var func in _self.configData.eventFuncMap){
		    //å–æ¶ˆæ‰€æœ‰æ³¨å†Œäº‹ä»¶
			YUE.removeListener(field, func);
		}
		if(_self.configData.fields[fid] !== undefined){
		    //ä»Žfieldsçš„é…ç½®ä¸­é™¤åŽ»è¯¥å­—æ®µ
		    delete _self.configData.fields[fid];
		}

		if(_self.allFields[fid] !== undefined){
		    //ä»Žfieldsçš„å¼•ç”¨ä¸­é™¤åŽ»è¯¥å­—æ®µ
		    delete _self.allFields[fid];
		}
		
		if(_self.allErrorAdvisor[fid] !== undefined ){
		      //ä»Žfieldsçš„é”™è¯¯å®¹å™¨ä¸­é™¤åŽ»è¯¥å­—æ®µ
		    delete _self.allErrorAdvisor[fid];
		}

    	YUD.setStyle(_self.allTipsAdvisor[fid], 'display', 'none');
	    YUD.setStyle(_self.allErrorAdvisor[fid], 'display', 'none');
	}
	
	//å¯¹å­—æ®µçš„äº‹ä»¶æ³¨å†Œæˆ–å–æ¶ˆ
	_self.fieldsEventHandle = function(els, mType){
		var eventFuncMap;
		var targetEl;
		for(var f in els){
			
			eventFuncMap = _self.configReader(els[f], 'eventFuncMap');
			//å¦‚æžœè¯¥å­—æ®µæ˜¯checkboxæˆ–è€…radio,åšç‰¹æ®Šå¤„ç†
			//å½“checkboxæˆ–è€…radioå­—æ®µé…ç½®é‡Œæœ‰needLoop:falseæ—¶ï¼Œåˆ™ä¸ä¼šè¢«æ³¨å†Œäº‹ä»¶ï¼Œå¦åˆ™å°†å¾ªçŽ¯æ³¨å†Œç›¸åº”äº‹ä»¶ã€‚
			if(_self.isCheckBoxOrRadio(els[f])){
				targetEl = document.getElementsByName(els[f].name);
				var i=0,len=targetEl.length;
				while(i<len){
					if(!YL.isUndefined(_self.configData.fields[targetEl[i].id]) && _self.configData.fields[targetEl[i].id].needLoop == false){
						targetEl = AE.common.toArray(targetEl);
						targetEl.splice(i,1);
						len--;
						continue;
					}
					i++;
				}
			} else {
				targetEl = els[f];
			}
			for(var func in eventFuncMap){
				if(YL.isFunction(_self.eventFuncPool[eventFuncMap[func]])){
					if(mType == 'add'){
						YUE.on(targetEl, func, _self.eventFuncPool[eventFuncMap[func]], els[f]);
					}
					if(mType == 'remove'){
						YUE.removeListener(targetEl, func, _self.eventFuncPool[eventFuncMap[func]]);
					}
				}
			}
		}
	}	
}

