
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),
        'onAfterAddValidateField': new YAHOO.util.CustomEvent('afterAddValidateField', _self, false, YAHOO.util.CustomEvent.LIST),
        'onAfterDelValidateField': new YAHOO.util.CustomEvent('afterDelValidateField', _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))
        },
        isTrimedEmpty: function(val, el, params){
            return YL.trim(val) == null || (YL.trim(val).length == 0)
        },
        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;
    };
    _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 = {};
    _self.allTipsAdvisor = {};
    _self.allErrorAdvisor = {};
    _self.configData = {};
    _self.formObj = {};
    _self.getAllFields = function(){
        for (var f in _self.configData.fields) {
            el = get(f);
            if (el) {
                _self.allFields[f] = el;
            }
        }
    };
    _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;
    };
    _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];
            }
    }
    _self.isSpecialField = function(el){
        return (el.type.toLowerCase() == 'radio' || el.type.toLowerCase() == 'checkbox' || el.type.toLowerCase() == 'file' || el.tagName == 'SELECT') ? true : false
    }
    _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);
    }
    _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;
    }
    _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);
        return returnMsg;
    }
    _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;
    }
    _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;
    }
    _self.getValidators = function(el){
        if (!_self.configData.fields[el.id]) {
            return false;
        }
        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 = _self.configReader(el, 'ifNeedValidate');
            displayFuncs = _self.configReader(el, 'displayFuncMap');
            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();
                    _self.displayFuncPool[displayFuncs['showStatus']](el, _self.configData.fields[el.id].statusResult);
                    advice = _self.displayFuncPool[displayFuncs['getErrorAdvice']](el);
                    msg = _self.configData.fields[el.id].statusMsg;
                    _self.displayFuncPool[displayFuncs['closeTipsMsg']](el);
                    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.validateAllFieldFlag = function(){
        var validateResult, el, ifNeedValidate, finalResult = true;
        var firstErrorField = null;
        var errFieldNum = 0;
        var elValidators = false;
        for (var f in _self.allFields) {
            el = _self.allFields[f];
            ifNeedValidate = _self.configReader(el, 'ifNeedValidate');
            elValidators = _self.getValidators(el);
            if ((f in _self.configData.errorFromServer) && firstErrorField == null) {
                firstErrorField = el;
                errFieldNum++;
                finalResult = false;
                _self.configData.fields[el.id].statusResult = false;
                _self.configData.fields[el.id].statusMsg = _self.configData.errorFromServer[f];
                _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();
                    if (!_self.configData.fields[el.id].statusResult) {
                        finalResult = false;
                        if (firstErrorField == null) 
                            firstErrorField = el;
                    }
                }
        }
        return finalResult;
    }
    _self.displayFuncPool = {
        getAdvice_getTips: function(el){
            var id = el.id;
            var advice;
            if (id in _self.allTipsAdvisor) {
                advice = _self.allTipsAdvisor[id];
            }
            else {
                var aid = (el.id) + '-advice-tips';
                advice = get(aid);
                if (!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 = document.createElement('div');
                        YUD.addClass(advice, tipsAdviceClass);
                        if (_self.configData.fields[el.id].tipsAdviceContainerClass) {
                            container.appendChild(advice);
                        }
                        else {
                            switch (el.type.toLowerCase()) {
                                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;
        },
        getAdvice_getError: function(el){
            var id = el.id;
            var advice;
            if (id in _self.allErrorAdvisor) {
                advice = _self.allErrorAdvisor[id];
            }
            else {
                var aid = (el.id) + '-advice-error';
                advice = get(aid);
                if (!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 = document.createElement('div');
                        YUD.addClass(advice, errorAdviceClass);
                        if (_self.configData.fields[el.id].errorAdviceContainerClass) {
                            container.appendChild(advice);
                        }
                        else {
                            switch (el.type.toLowerCase()) {
                                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;
        },
        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');
            }
        },
        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]]);
            }
        },
        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]]);
            }
        },
        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]]);
            }
        },
        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]]);
            }
        },
        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]]);
            }
        },
        closeTipsMsg_close: function(el){
            YUD.setStyle(_self.allTipsAdvisor[el.id], 'display', 'none')
        },
        closeErrorMsg_close: function(el){
            YUD.setStyle(_self.allErrorAdvisor[el.id], 'display', 'none')
        },
        scrollToField: function(el){
            var elOffsetHeight = el.offsetHeight;
            var elY = YUD.getY(el);
            var clientHeight = YUD.getClientHeight();
            var documentScrollTop = YUD.getDocumentScrollTop();
            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');
            elValidators = _self.getValidators(el);
            var isTrimedEmpty = (YL.trim(el.value) == null) || (YL.trim(el.value).length == 0);
            if (validateImmediate && ifNeedValidate && elValidators && (_self.configData.fields[el.id].isInValidateProcess || !isTrimedEmpty)) {
                var validateResult = _self.validateField(el, elValidators);
                _self.configData.fields[el.id].statusResult = !validateResult.isError();
                _self.configData.fields[el.id].statusMsg = validateResult.getContent();
                _self.displayFuncPool[displayFuncs['showStatus']](el, _self.configData.fields[el.id].statusResult);
                var msg = _self.configData.fields[el.id].statusMsg;
                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');
            var advice = _self.displayFuncPool[displayFuncs['getTipsAdvice']](el);
            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){
            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(){
        YUE.on(_self.formObj, 'submit', _self.eventFuncPool['default_submit']);
        YUE.on(_self.formObj, 'reset', _self.eventFuncPool['default_reset']);
    }
    _self.init = function(formId, userConfig){
        _self.initWithoutEvent(formId, userConfig);
        _self.fieldsEventHandle(_self.allFields, 'add');
        _self.formEventRegist();
    };
    _self.initWithoutEvent = function(formId, userConfig){
        _self.formObj = get(formId);
        _self.configData = YL.merge(defConfig, userConfig || {});
        if (_self.configData.fields === undefined) {
            _self.configData.fields = {};
        }
        _self.configData.errorSubmitTime = 0;
        _self.configData.errorFromServer = {};
        _self.configData.errorFromServerCount = 0;
        _self.getAllFields();
        YUE.on(window, 'resize', function(){
            setTimeout(_self.displayFuncPool['repositionAdvice'], 300);
        });
    };
    _self.addValidateField = function(fieldsConfig){
        _self.configData.fields = AE.tools.depthMerge(_self.configData.fields, fieldsConfig);
        var aFields = _self.addFields(fieldsConfig);
        _self.fieldsEventHandle(aFields, 'add');
        var elId = '';
        _self.customEvent['onAfterAddValidateField'].fire(fieldsConfig);
    }
    _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) {
            delete _self.configData.fields[fid];
        }
        if (_self.allFields[fid] !== undefined) {
            delete _self.allFields[fid];
        }
        if (_self.allErrorAdvisor[fid] !== undefined) {
            delete _self.allErrorAdvisor[fid];
        }
        YUD.setStyle(_self.allTipsAdvisor[fid], 'display', 'none');
        YUD.setStyle(_self.allErrorAdvisor[fid], 'display', 'none');
        _self.customEvent['onAfterDelValidateField'].fire(fid);
    }
    _self.fieldsEventHandle = function(els, mType){
        var eventFuncMap;
        var targetEl;
        for (var f in els) {
            eventFuncMap = _self.configReader(els[f], 'eventFuncMap');
            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]]);
                    }
                }
            }
        }
    }
};
