(function($) {
	$.tiny = $.tiny || {};
	$.tiny.validate = {
		messages : {
			required : "{0} is not empty",
			email : "{0}  email is valid",
			select : "{0}  is not select",
			username : "{0}  String only",
			digits : "{0}  is digits",
			maxlength : "{0}  maxlength {1}",
			minlength : "{0}  minlength {1}",
			check : "{0} check box",
			maxvalue : "{0} max value {1}",
			minvalue : "{0} min value {1}",
			equalto : "{0} not match {1}",
			format : "{0} is invalid",
			url : "{0} is invalid url",
			number : "{0} is number",
			date : "{0} is not date",
			rangelength : "{0} range length from {1} to {2}",
			rangevalue : "{0} range value from {1} to {2}",
			fileValid : "file invalid",
			radio:"{0} radio",
		}
	};

	$.fn.trimMoreSpace = function() {
		var val = jQuery.trim($(this).val())
		val = val.replace(/\s{2,}/, ' ');
		$(this).val(val);
	};

	$.fn.validate = function(messages) {
		var messages = $.extend( {}, $.tiny.validate.messages, messages);
		return new newValidate($(this), messages);
	};
	
	$.fn.removeValidate = function(o){
		try{
			var root = $(this);
			var key = 'valid';
			if(o == null){
				jQuery.each(root.data(key), function(i, o) {
					o.removeData(key);
				});
				root.removeData(key);
			}else{
				if(!o.jquery){
					o = $(o);
				}
				var id = o.data(key).id;
				var rootData = root.data(key);
				var newData = new Array();
				var k = 0;
				jQuery.each(datas, function(i, data) {
					if(id != data.data(key).id){
						newData[i] = data;
						k++;
					}
				});
				root.removeData(key);
				root.data(key, newData);
			}
		}catch(err){
			// safe
		}
	};
	
	$.fn.clearError = function(){
		try{
			clearError($(this).data('valid'));
		}catch(err){
			// safe
		}
	};
	
	$.fn.registerValidate = function(o){
		try{
			if(!o.jquery){
				o = $(o);
			}
			var datas = $(this).data('valid');
			datas[datas.length] = o;
			regInput(o, $(this));
		}catch(err){
			alert("Can't register validate - cause : " + err);
		}
	};
	
	$.fn.resetForm = function(){
		jQuery.each($(this).data('valid'), function(index, o) {
			o.clearError();
		});
	};
	
	$.fn.valid = function validator() {
		var isValid = true;
		var focus = false;
		jQuery.each($(this).data('valid'), function(index, o) {
			if (validateOption(o) == false) {
				if (focus == false) {
					o.focus();
					focus = true;
				}
				isValid = false;
			}
		});
		return isValid;
	};
	
	function newValidate(root, messages) {
		var message = messages;
		var $inputs = $('*[valid]', root);
		root.data('valid', new Array());

		function initialize() {
			setEvent();
			return root;
		};

		function setEvent() {
			$inputs.each(function(index) {
				o = $(this);
				root.data('valid')[index] = o;
				regInput(o, root);
				
				if (this.tagName == 'INPUT'
						&& o.attr('type') == 'text') {
					o.change(function() {
						$(this).trimMoreSpace();
						validateOption($(this));
					});
				} else if (this.tagName == 'TEXTAREA') {
					o.change(function() {
						$(this).trimMoreSpace();
						validateOption($(this));
					});
				}
				o.keyup(function() {
					validateOption($(this));
				});
				o.focusout(function() {
					validateOption($(this));
				});	
			});
		}
		
		return initialize();
	};
	
	function regInput(o, root){
		var id = o.attr('id');
		var errorObj = $('.error[for="' + id + '"]');
		var error = o.attr('error');
		if(error == null){
			error = root.attr('error');
		}
		if(o.attr('valid') != 'custom' && errorObj.attr('for') == undefined && error != 'title'){
			if (error == 'display' || error == 'image') {
				errorObj = $("<img class='error error_img' src='/images/icon-16/validate_error.png' for='" + id + "'></img");
			} else {
				errorObj = $("<div class='error' for='" + id + "'></div");
			}
			errorObj.insertAfter(o);
		}
		errorObj.css("display", "none");
		
		var name = o.attr('vname');
		if (typeof (name) == 'undefined' || name == null) {
			name = '';
		}
		
		o.data('valid', {
			o: o,
			id: id,
			errorObj: errorObj,
			title: name,
			error: error,
			valids: o.attr('valid').split(','),
			maxlength: o.attr('vmaxlength'),
			minlength: o.attr('vminlength'),
			maxvalue: o.attr('vmaxvalue'),
			minvalue: o.attr('vminvalue'),
			equalto: o.attr('equalto'),
			format: o.attr('vformat'),
			fromlength: o.attr('vfromlength'),
			tolength: o.attr('vtolength'),
			fromvalue: o.attr('vfromvalue'),
			tovalue: o.attr('vtovalue'),
			file: o.attr('vfile')
		});
	}
	
	function validateOption(o) {
		var data = o.data('valid');
		if(data == null){
			return true;
		}
		var isValid = true;
		for ( var i = 0; i < data.valids.length; i++) {
			if (data.valids[i] == 'required' && validateRequired(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'email' && validateEmail(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'select' && validateSelect(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'username'
					&& validateUsername(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'digits' && validateDigits(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'maxlength'
					&& validateMaxlength(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'minlength'
					&& validateMinlength(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'check' && validateCheck(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'maxvalue'
					&& validateMaxvalue(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'minvalue'
					&& validateMinvalue(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'equalto'
					&& validateEqualto(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'custom' && validateCustom(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'format'
					&& validateFormat(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'url' && validateUrl(data) == false) {
				isValid = false;
				break;
			}  else if (data.valids[i] == 'radio' && validateRadio(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'number' && validateNumber(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'date' && validateDate(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'rangelength'
					&& validateRangelength(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'rangevalue'
					&& validateRangevalue(data) == false) {
				isValid = false;
				break;
			} else if (data.valids[i] == 'file'
					&& validateFile(data) == false) {
				isValid = false;
				break;
			}
		}
		return isValid;
	}

	function validateCustom(data) {
		return window['v' + data.id]();
	}
	
	function getVal(o){
		if(o.attr('search')){
			return o.searchVal();
		}
		return o.val();
	}

	function validateFile(data) {
		var file = getVal(data.o);
		if (file.indexOf('/') > -1) {
			file = file.substring(file.lastIndexOf('/') + 1);
		} else if (file.indexOf('\\') > -1) {
			file = file.substring(file.lastIndexOf('\\') + 1);
		}

		var extensions = new RegExp(data.file + '$', 'i');
		if (file != '' && !extensions.test(file)) {
			insertError(id, message.fileValid, {
				1 : data.file
			});
			return false;
		}
		clearError(data);
		return true;
	}

	function validateRequired(data) {
		if (getVal(data.o) == '') {
			insertError(data, message.required);
			return false;
		}
		clearError(data);
		return true;
	}
	function validateRadio(data) {
		if ($('#' + data.id+' input[type=radio]:checked').size()<=0) {
			insertError(data, message.radio);
			return false;
		}
		clearError(data);
		return true;
	}

	function validateRangelength(data) {
		var value = getVal(data.o);
		if (value != '' && (value.length < data.fromlength || value.length > data.tolength)) {
			insertError(data, message.rangelength, {
				1 : data.fromlength,
				2 : data.tolength
			});
			return false;
		}
		clearError(data);
		return true;
	}

	function validateRangevalue(data) {
		var value = getVal(data.o);
		if (value != '' && (parseInt(value) < data.fromvalue || parseInt(value) > data.tovalue)) {
			insertError(data, message.rangevalue, {
				1 : data.fromvalue,
				2 : data.tovalue
			});
			return false;
		}
		clearError(data);
		return true;
	}

	function validateEmail(data) {
		var renmail = /[a-z0-9]+@\w+\.\w{2,4}(\.\w{2}){0,1}$/i;
		var value = getVal(data.o);
		if (value != ''
				&& renmail.test(value) == false) {
			insertError(data, message.email);
			return false;
		}
		clearError(data);
		return true;
	}
	;

	function validateSelect(data) {
		var val = getVal(data.o);
		if (val == null || val.replace(' ', '') == '') {
			insertError(data, message.select);
			return false;
		}
		clearError(data);
		return true;
	}
	;

	function validateUsername(data) {
		var ren = /^[a-zA-Z\d]+$/i;
		var value = getVal(data.o);
		if (value != '' && ren.test(value) == false) {
			insertError(data, message.username);
			return false;
		}
		clearError(data);
		return true;
	}
	;

	function validateDigits(data) {
		var value = getVal(data.o);
		var renphone = /^\d+$/;
		if (value != '' && !renphone.test(value) == true) {
			insertError(data, message.digits);
			return false;
		}
		clearError(data);
		return true;
	}
	;

	function validateFormat(data) {
		var value = getVal(data.o);
		var m = value.match(new RegExp(data.format));
		if (value != '' && m == null) {
			insertError(data, message.format);
			return false;
		}
		clearError(data);
		return true;
	}

	function validateDate(data) {
		var value = getVal(data.o);
		if (value != '' && /Invalid|NaN/.test(new Date(value))) {
			insertError(data, message.date);
			return false;
		}
		clearError(data);
		return true;
	}

	function validateUrl(data) {
		var value = getVal(data.o);
		var expUrl = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
		if (value != '' && !expUrl.test(value)) {
			insertError(data, message.url);
			return false;
		}
		clearError(data);
		return true;

	}

	function validateNumber(data) {
		var value = getVal(data.o);
		var expNumber = /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/;
		if (value != '' && !expNumber.test(value)) {
			insertError(data, message.number);
			return false;
		}
		clearError(data);
		return true;

	}

	function validateMaxlength(data) {
		var value = getVal(data.o);
		if (value != '' && value.length > data.maxlength) {
			insertError(data, message.maxlength, {
				1 : data.maxlength
			});
			return false;
		}
		clearError(data);
		return true;
	}

	function validateMinlength(data) {
		var value = getVal(data.o);
		if (value != '' && value.length < data.minlength) {
			insertError(data, message.minlength, {
				1 : data.minlength
			});
			return false;
		}
		clearError(data);
		return true;
	}

	function validateMinvalue(data) {
		var value = getVal(data.o);
		if (value != '' && parseInt(value) < data.minvalue) {
			insertError(data, message.minvalue, {
				1 : data.minvalue
			});
			return false;
		}
		clearError(data);
		return true;
	}

	function validateMaxvalue(data) {
		var value = getVal(data.o);
		if (value != '' && parseInt(value) > data.maxvalue) {
			insertError(value, message.maxvalue, {
				1 : data.maxvalue
			});
			return false;
		}
		clearError(value);
		return true;
	}

	function validateCheck(data) {
		if (!isChecked(data.o)) {
			insertError(data, message.check);
			return false;
		}
		clearError(data);
		return true;
	}

	function validateEqualto(data) {
		oto = $('#' + data.equalto);
		var from = getVal(data.o);
		var to = getVal($('#' + data.equalto));
		
		if (to != null && to != '' && from != to) {
			insertError(data, message.equalto, {
				1 : oto.attr('vname')
			});
			return false;
		}
		clearError(data);
		return true;
	}

	function clearError(data) {
		if (data.error == 'title') {
			data.o.attr('title', '');
		}
		data.errorObj.css('display', 'none');
	}
	
	function insertError(data, strError, params) {
		strError = strError.replace('{0}', data.title);
		if (params != null) {
			$.each(params, function(index, value) {
				strError = strError.replace('{' + index + '}', value);
			});
		}

		if (data.error == 'display' || data.error == 'image') {
			data.errorObj.attr('title', strError);
			data.errorObj.css('display', 'inline-block');
		} else {
			if (data.error == 'title') {
				data.o.attr('title', strError);
			}
			data.errorObj.html(strError);
			data.errorObj.css('display', 'block');
		}
	}
	
	function isChecked(o){
		return o.attr('checked') != undefined;
	}
})(jQuery);

function reset(id) {
	if(!id.jquery){
		id = $(id);
	}
	id.val('');
	id.clearError();
};
