lib.x({
	form:lib.x({
		getElements:function(form) {//retorna somente os campos validaveis
			return lib(form.elements).filter(function(v) {
				return v.tagName.toLowerCase() != 'fieldset' && !(/submit|image|reset|hidden|button/i.test(v.type));
			});
		},
		addSelectOptions:function(elm,options) {//[{text:'text',value:'value'},{text:'text',value:'value'}]
			var _options = elm.options;
			for(var i=0,len=options.length;i<len;i++) {
				_options.push(new Option(options[i].text,options[i].value));
			}
		},
		compactForms:function compactForms() {
			var blur = function(field) {
				$T("label", field.parentNode,true)[0].style.textIndent = lib.form.validators.fEmpty.test(field) ? "-5000px" : "0px";
			};
			$C('compactForm','fieldset').forEach(function(frm) {
				$T('div',frm).forEach(function(div) {
					var input = $T('input',div,true)[0],
						label = $T('label',div,true)[0];
					
					label.className = 'label';
					lib.addEvent(label,'click',function() {//Safari tem problemas com focus
						$(this.htmlFor).focus();
					});
					lib.addEvent(input,'blur',function(){blur(this);});
					lib.addEvent(input,'focus',function(){
						$T('label',this.parentNode,true)[0].style.textIndent = '-5000px';
					});
					blur(input);
				});
			});
		},
		validators:{//return true == valido
			'fEmpty':{
				test:function(f) {
					return !(/^\s*$/i.test(f.value));
				},
				msg:'O campo % deve ser preenchido.',
				fields:'text|textarea|password|file'
			},
			'fLet':{
				test:function(f) {
					return (/^[A-Za-záàãâäéèêëíìîïóòõôöúùûüçÁÀÃÂÄÉÈÊËÍÌÎÏÓÒÕÔÖÚÙÛÜÇ]+/i.test(f.value));
				},
				msg:'O campo % só deve conter letras.',
				fields:'text|textarea|password'
			},
			'fNum':{
				test:function(f) {
					return (/^[0-9]+/i.test(f.value));
				},
				msg:'O campo % só deve conter números.',
				fields:'text|textarea|password'
			},
			'fAlpha':{
				test:function(f) {
					return (/^[0-9A-Za-záàãâäéèêëíìîïóòõôöúùûüçÁÀÃÂÄÉÈÊËÍÌÎÏÓÒÕÔÖÚÙÛÜÇ]+/i.test(f.value));
				},
				msg:'O campo % só deve conter caracteres alfanuméricos',
				fields:'text|textarea|password'
			},
			'fEmail':{
				test:function(f) {
					return (/^[a-zA-Z0-9_.+-]{2,}@([a-zA-Z0-9-]{2,}.)+[a-zA-Z0-9]{2,4}$/i.test(f.value));
				},
				msg:'O campo % deve possuir um e-mail válido.',
				fields:'text|textarea'
			},
			'fCpf':{
				test:function(f) {
					var str = f.value;
					str = str.replace(/[\.-]/g,'');
					if(str.length != 11 || (str.charAt(10) == str.charAt(9) && str.charAt(8) == str.charAt(10)) || str == '12345678909')
						return false;
					str = str.split('');
					var m = 0;
					do {
						for(var i=10+m,d=0;i>1;i--)
							d += str[(10+m)-i] * i;
						if((d%11<2?0:11-(d%11)) != str[str.length-(2-m)])
							return false;
						m++;
					}while(m<2);
					return true;
				},
				msg:'O campo % deve possuir um CPF válido.',
				fields:'text|textarea'
			},
			'fCnpj':{
				test:function(f) {
					var str = f.value;
					str = str.replace(/[\.\/-]/g,'');
					if(cnpj.length != 14)
						return false;
					cnpj = cnpj.split('');
					var m=0;
					do {
						for(var i=0,j=5+m,d=0;i<cnpj.length-(2-m);i++,j--) {
							if(j<2)j=9;
							d += cnpj[i] * j;
						}
						if((d%11<2?0:11-(d%11)) != cnpj[cnpj.length-(2-m)])
							return false;
						m++;
					}while(m<2);
					return true;
				},
				msg:'O campo % deve possuir um CNPJ válido.',
				fields:'text|textarea'
			},
			'fEq':{
				test:function(f) {//Id == Id2
					if(f.value != $(f.id.substr(0,f.id.length-1)).value) {
						this.msg = 'O campo % deve ser igual ao campo ' + $(f.id.substr(0,f.id.length-1)).title;
						return false;
					}
					else {
						return true;
					}
				},
				msg:'O campo % deve ser igual ao campo %',
				fields:'text|password'
			},
			'fReq':{
				test:function(f) {
					switch(f.type) {
						case 'text':
						case 'textarea':
						case 'file':
						case 'password':
							return lib.form.validators.fEmpty.test(f);
							break;
						case 'checkbox':
							return f.checked;
							break;
						case 'select-one':
							return !(f.options.selectedIndex < 1);
							break;
						case 'select-multiple':
							return !(f.options.selectedIndex < 0);
							break;
						case 'radio':
							for(var i=0,t=$T('input',f.form,true);i<t.length;i++) {
								if(t[i].name === f.name && t[i].checked)
									return true;
							}
							return false;
							break;
					}
				},
				msg:'O campo % é obrigatório',
				fields:'.*'
			}
		}
	},function(form) {
		if(!form)
			throw 'Formulário não especificado.';
		var submit = function(evt) {
			var _return = lib.form.getElements(this)
			.map(function(field) {
				var classes = field.className;
				if(classes == '')
					return false;
				classes = classes.split(' ');
				var validators = lib.form.validators;
				for(var i=0,validator=false,len=classes.length;i<len;i++) {//passando pelas classes do campo
					if((validator = validators[classes[i]]) && validator.test && (new RegExp(validator.fields,'i').test(field.type)))//verifico se eh possivel validar
						return !validator.test(field) && (validator.msg?validator.msg.replace('%',field.title):('Campo ' + field.title + ' inválido'));//validando e retornando a frase
				}
				return false;
			})
			.filter(function(v){return v;})
			.toArr();
			if(_return.length) {
				alert(_return.join('\n'));
				lib.preventDefault(evt);
			}
		};
		lib.addEvent(form,'submit',submit);
	})
});