/*
 * Unicorn field validation with Prototype1.6
 * Peter
 * Version 1.0 (2008-01-02)
 * Copyright (c) 2008 Peter
 */
var Validator = Class.create();

Validator.messagesSourceI18n = [
    ['validation-failed' ,_validation.validationFailed],
    ['required' , _validation.required],
    ['number' ,    _validation.number],
    ['digits' ,   _validation.digits],
    ['alpha' ,   _validation.alpha],
    ['alphanum' ,  _validation.alphanum],
    ['date' ,       _validation.date],
    ['email' ,     _validation.email],
    ['url' ,      _validation.url],
    ['dateAu' ,   _validation.dateAu],
    ['dollar' ,   _validation.dollar],
    ['dateCn' ,   _validation.dateCn],
    ['integer' ,  _validation.integer],
    ['pattern' ,  _validation.pattern],
    ['chinese' ,  _validation.chinese],
    ['ip' ,      _validation.ip],
    ['phone' ,     _validation.phone],
    ['mobile' ,    _validation.mobile],
    ['minValue' ,  _validation.minValue],
    ['maxValue' ,  _validation.maxValue],
    ['minLength' ,  _validation.minLength],
    ['maxLength' ,  _validation.maxLength],
    ['integerRange' ,  _validation.integerRange],
    ['floatRange' ,  _validation.floatRange],
    ['lengthRange' ,  _validation.lengthRange],
    ['file' ,    _validation.file],
    ['equals' ,   _validation.equals],
    ['lessThan' ,  _validation.lessThan],
    ['greatThan' ,   _validation.greatThan],
    ['selection' ,  _validation.selection],
    ['oneRequired ' , _validation.oneRequired]
]

Validator.messagesSource = Validator.messagesSourceI18n;
Validator.messages = {};
//init Validator.messages
Validator.messagesSource.each(function(ms) {
    Validator.messages[ms[0]] = ms[1];
});

Object.extend(Validator, {

    isPassed : function(validType, elm) {
        try {
            var methodName = "validate" + validType.substring(0, 1).toUpperCase() + validType.substring(1, validType.length);
            var params = Validator.getArgumentsByValidType(validType, Validator.getValidConf(elm));
            return !(Validator.isVisible(elm) && !eval(methodName).call(this, $F(elm),params,elm))
        } catch(e) {
            throw(e)
        }
    },
    isVisible : function(elm) {
        while (elm.tagName != 'BODY') {
            if (!$(elm).visible()) return false;
            elm = elm.parentNode;
        }
        return true;
    },
    getElementAdvice : function(elm) {
        return $('advice-' + Validator.getElementId(elm));
    },
    getElementId : function(elm) {
        return elm.id ? elm.id : elm.name;
    },
    reset : function(elm) {
        elm = $(elm);

        var prop = '__advice' + Validator.getElementId(elm);
        if (elm[prop]) {
            var advice = Validator.getElementAdvice(elm);
            advice.hide();
            elm[prop] = '';
        }
        elm.removeClassName('validation-failed');
        elm.removeClassName('validation-passed');

    },
    getInputValue : function(elm) {
        var tempElm = $(elm);
        if (tempElm.type.toLowerCase() == 'file') {
            return tempElm.value;
        } else {
            return $F(tempElm);
        }
    },
    getErrorMsg : function(validType, elm, useTitle) {
        var value = Validator.getInputValue(elm)
        var validConf = Validator.getValidConf(elm);
        var args = Validator.getArgumentsByValidType(validType, validConf);
        var errorMsg = Validator.messages[validType] || 'Validation failed.';

        if (typeof errorMsg == 'string') {
            if (value) args.push(value.length);
            errorMsg = Validator.format(errorMsg, args);
        } else {
            alert('error must type of string or function');
        }
        //if (!useTitle) useTitle = elm.className.indexOf('useTitle') >= 0;
        if (!useTitle) useTitle = validConf.indexOf('useTitle') >= 0;
        return useTitle ? ((elm && elm.title) ? elm.title : errorMsg) : errorMsg;

    },
    format : function(str, args) {
        args = args || [];
        Validator.assert(args.constructor == Array, "Validator.format() arguement 'args' must is Array");
        var result = str
        for (var i = 0; i < args.length; i++) {
            result = result.replace(/%s/, args[i]);
        }
        return result;
    },
    assert : function(condition, message) {
        var errorMessage = message || ("assert failed error,condition=" + condition);
        if (!condition) {
            alert(errorMessage);
            throw new Error(errorMessage);
        } else {
            return condition;
        }
    },
    getValidConf :function(elm) {
        //validConf="required&minLength=12&lengthRange=4-8"
        return elm.readAttribute("validConf");
    },
    getValidTypes : function(elm) {
        var validConf = Validator.getValidConf(elm);
        if (!validConf)
            return [];
        var confParams = validConf.toQueryParams();
        var types = Object.keys(confParams);
        if (!types)
            return [];
        return types;
    },
    getArgumentsByValidType : function(validType, validConf) {
        if (!validConf)
            return [];
        var confParams = validConf.toQueryParams();
        var typeParams = confParams[validType];
        if (!typeParams)
            return [];
        return typeParams.split('-');
    }
})


var Validation = Class.create();

Validation.prototype = {
    initialize : function(form, options) {
        this.options = Object.extend({
            onSubmit : true,
            stopOnFirst : false,
            immediate : false,
            focusOnError : true,
            useTitles : false,
            onFormValidate : function(result, form) {
            },
            onElementValidate : function(result, elm) {
            }
        }, options || {});
        this.form = $(form);
        if (this.options.onSubmit) Event.observe(this.form, 'submit', this.onSubmit.bind(this), false);
        if (this.options.immediate) {
            var useTitles = this.options.useTitles;
            var callback = this.options.onElementValidate;
            Form.getElements(this.form).each(function(input) { // Thanks Mike!
                Event.observe(input, 'blur', function(ev) {
                    Validation.validate(Event.element(ev), {useTitle : useTitles, onElementValidate : callback});
                });
            });
        }
    },
    onSubmit :  function(ev) {
        var result = false;
        var useTitles = this.options.useTitles;
        var callback = this.options.onElementValidate;
        if (this.options.stopOnFirst) {
            result = Form.getElements(this.form).all(function(elm) {
                return Validation.validate(elm, {useTitle : useTitles, onElementValidate : callback});
            });
        } else {
            result = Form.getElements(this.form).collect(function(elm) {
                return Validation.validate(elm, {useTitle : useTitles, onElementValidate : callback});
            }).all();
        }
        if (!result && this.options.focusOnError) {
            Form.getElements(this.form).findAll(function(elm) {
                return $(elm).hasClassName('validation-failed')
            }).first().focus()
        }
        this.options.onFormValidate(result, this.form);

        if (!result) Event.stop(ev);
    },
    reset : function() {
        Form.getElements(this.form).each(Validator.reset);
    }
}

Object.extend(Validation, {

    validate : function(elm, options) {
        options = Object.extend({
            useTitle : false,
            onElementValidate : function(result, elm) {
            }
        }, options || {});
        elm = $(elm);
        var validTypes = Validator.getValidTypes(elm);
        var errorMsg = "";
        var result = validTypes.all(function(validType) {
            var testResult = Validator.isPassed(validType, elm);
             if (!testResult){
                errorMsg = errorMsg + Validator.getErrorMsg(validType, elm, options.useTitle) + "<br/>";
                if (options.stopOnError)
                 elm.focus();
            }
            return testResult;
        });
        Validation.handleErrorMsg(result, errorMsg, elm);
        options.onElementValidate(result, elm);
        return result;
    },
    handleErrorMsg : function(isPassed, errorMsg, elm) {
        var prop = '__advice' + Validator.getElementId(elm);
        var advice = null;

        try {
            if (!isPassed) {
                if (!elm[prop]) {
                    advice = Validator.getElementAdvice(elm);
                    if (advice == null) {

                        advice = '<div class="validation-advice" id="advice-' + Validator.getElementId(elm) + '" style="display:none">' + errorMsg + '</div>'
                        switch (elm.type.toLowerCase()) {
                            case 'checkbox':
                            case 'radio':
                                var p = elm.parentNode;
                                if (p) {
                                    new Insertion.Bottom(p, advice);
                                } else {
                                    new Insertion.After(elm, advice);
                                }
                                break;
                            default:
                                new Insertion.After(elm, advice);
                        }
                        advice = Validator.getElementAdvice(elm);
                    }
                    if (typeof Effect == 'undefined') {
                        advice.style.display = 'block';
                    } else {
                        new Effect.Appear(advice, {duration : 1 });
                    }
                }
                advice = Validator.getElementAdvice(elm);
                advice.innerHTML = errorMsg;
                elm[prop] = true;
                elm.removeClassName('validation-passed');
                elm.addClassName('validation-failed');

            } else {
                advice = Validator.getElementAdvice(elm);
                if (advice != null) advice.hide();
                elm[prop] = '';
                elm.removeClassName('validation-failed');
                elm.addClassName('validation-passed');

            }
        } catch(e) {
            throw(e)
        }
    }
});
function validateUseTitle(value){
    return true;
}

//only one parameter function --begin
function validateIsEmpty(value) {
    return  ((value == null) || (value.length == 0));
}
function validateRequired(value) {
    return !validateIsEmpty(value);
}
function validateNumber(value) {
    return validateIsEmpty(value) || (!isNaN(value) && !/^\s+$/.test(value));
}
function validateDigits(value) {
    return validateIsEmpty(value) || !/[^\d]/.test(value);
}
function validateAlpha(value) {
    return validateIsEmpty(value) || /^[a-zA-Z]+$/.test(value);
}
function validateAlphanum(value) {
    return validateIsEmpty(value) || !/\W/.test(value);
}
function validateDate(value) {
    var test = new Date(value);
    return validateIsEmpty(value) || !isNaN(test);
}
function validateEmail(value) {
    return validateIsEmpty(value) || /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(value);
}
function validateUrl(value) {
    return validateIsEmpty(value) || /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i.test(value);
}
function validateDateAu(value) {
    if (validateIsEmpty(value)) return true;
    var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
    if (!regex.test(value)) return false;
    var d = new Date(value.replace(regex, '$2/$1/$3'));
    return ( parseInt(RegExp.$2, 10) == (1 + d.getMonth()) ) &&
           (parseInt(RegExp.$1, 10) == d.getDate()) &&
           (parseInt(RegExp.$3, 10) == d.getFullYear() );
}
function validateDollar(value) {
    return validateIsEmpty(value) || /^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/.test(value);
}
function validateDateCn(value) {
    if (validateIsEmpty(value)) return true;
    var regex = /^(\d{4})-(\d{2})-(\d{2})$/;
    if (!regex.test(value)) return false;
    var d = new Date(value.replace(regex, '$1/$2/$3'));
    return ( parseInt(RegExp.$2, 10) == (1 + d.getMonth()) ) &&
           (parseInt(RegExp.$3, 10) == d.getDate()) &&
           (parseInt(RegExp.$1, 10) == d.getFullYear() );
}
function validateInteger(value) {
    return validateIsEmpty(value) || (/^[-+]?[\d]+$/.test(value));
}
function validateMobile(value) {
    return validateIsEmpty(value) || (/(^0?[1][35][0-9]{9}$)/.test(value));
}
function validatePhone(value) {
//    return validateIsEmpty(value) || /^((0[1-9]{3})?(0[12][0-9])?[-])?\d{6,8}$/.test(value);
     return validateIsEmpty(value) || /^(([0\+]\d{2,3}-)?(0\d{2,3})-)?(\d{7,8})(-(\d{3,}))?$/.test(value);  
}
function validateIp(value) {
    return validateIsEmpty(value) || (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(value));
}
function validateChinese(value) {
    return validateIsEmpty(value) || (/^[\u4e00-\u9fa5]+$/.test(value));
}
//only one parameter function --end

//only two parameter function --begin

function validatePattern(value, args) {
    return validateIsEmpty(value) || args.test(value);
}
function validateGreatThan(value, args) {
    if (validateNumber(value) && validateNumber($F(args[0])))
        return validateIsEmpty(value) || parseFloat(value) > parseFloat($F(args[0]));
    return validateIsEmpty(value) || value > $F(args[0]);
}
/**
 * Usage : lessThan=otherInputId
 * Example: lessThan=filed1
 */
function validateLessThan(value, args) {
    if (validateNumber(value) && validateNumber($F(args[0])))
        return validateIsEmpty(value) || parseFloat(value) < parseFloat($F(args[0]));
    return validateIsEmpty(value) || value < $F(args[0]);
}
function validateEquals(value, args) {
    return validateIsEmpty(value) || $F(args[0]) == value;
}

/*
 * Usage: "file=type1-type2-typeX"
 * Example: file=png-jpg-jpeg
 * notice you must useTitle to display the error message
 * example  file=png-jpg-jpeg&useTitle
 */
function validateFile(value, args) {
    return validateIsEmpty(value) || $A(args).any(function(extentionName) {
	   return new RegExp('\\.'+extentionName+'$','i').test(value);
	});
}
function validateLengthRange(value, args) {
    return validateIsEmpty(value) || (value.length >= parseInt(args[0]) && value.length <= parseInt(args[1]));
}
function validateFloatRange(value, args) {
    if(validateIsEmpty(value))return true;
    if(validateNumber(value))
     return (parseFloat(value) >= parseFloat(args[0]) && parseFloat(value) <= parseFloat(args[1]));
    return false;
}
function validateIntegerRange(value, args) {
    if(validateIsEmpty(value))return true;
    if(validateInteger(value))
      return (parseInt(value) >= parseInt(args[0]) && parseInt(value) <= parseInt(args[1]));
    return false;

}
function validateMinLength(value, args) {
    return validateIsEmpty(value) || value.length >= parseInt(args[0]);
}
function validateMaxLength(value, args) {
    return validateIsEmpty(value) || value.length <= parseInt(args[0]);
}
function validateMaxValue(value, args) {
    if(validateIsEmpty(value))return true;
    if(validateNumber(value))
      return parseFloat(value) <= parseFloat(args[0]);
    return false;


}
function validateMinValue(value, args) {
   if(validateIsEmpty(value))return true;
    if(validateNumber(value))
      return parseFloat(value) >= parseFloat(args[0]);
    return false;
}
//only two parameter function --end

//only three parameter function --begin
function validateSelection(value, args,elm) {
    return elm.options ? elm.selectedIndex > 0 : !validateIsEmpty(value);
}
function validateOneRequired(value, args,elm) {
    var p = elm.parentNode;
    var options = p.getElementsByTagName('INPUT');
    return $A(options).any(function(elm) {
        return $F(elm);
    });
}
function validateEqualTo(value, args,elm){
    return value == $F(args[0]);
}
function validateNotEqualTo(value, args,elm){
    return value != $F(args[0]);
}
//only three parameter function --end
// define the validation function must like this
// ex.   function validate****(value, args ,elm)

Validation.autoBind = function() {
	 var forms = document.getElementsByClassName('required-valid');
	 $A(forms).each(function(form){
		var validation = new Validation(form,{immediate:true});
		Event.observe(form,'reset',function() {validation.reset();},false);
	 });
};
Event.observe(window,'load',Validation.autoBind,false);