/*
	(0) Nome do campo ou grupo / habiliata validação
		=====>  ['String', (true/false)]
	(1) Tipo de validação
		=====> [(free/text/numeric/option/cpf/cnpj/email/file), 'Mensagem de erro']
	(2) Campo obrigatório
		=====> [(true/false), 'Mensagem de erro']
	(3) Mínimo e Máximo de elementos preenchidos do grupo (text, checkbox, select-one, select-multiple, file)
		=====> [[min, max], 'Mensagem de erro']
	(4) Mínimo e Máximo de caracteres
		=====> [[min, max], 'Mensagem de erro']
	(5) Mínimo e Máximo de letras  
		=====> [[min, max], 'Mensagem de erro']
	(6) Mínimo e Máximo de números
		=====> [[min, max], 'Mensagem de erro']
	(7) Número maior ou menos que (Caso (1) for numeric)
		=====> [[men, maio], 'Mensagem de erro']
	(8) Compara o campo com outro campo
		=====> ['campo', 'Mensagem de erro']
	(9) Tipo de arquivos aceitaveis
		=====> ['jpg, gif, png, doc, pdf, txt', 'Mensagem de erro']
	(10) Retorna 'Mensagem de erro' de uma função
		 $mapField[10] = array('teste(123)', 'javascript', false, false);
		 =====> ["função", "this.value"]
*/

//*******************************FUNÇÕES GENÉRICAS***********************************//

	function addWindowOnload(newFunc){
		if(!window.funcs) window.funcs = [];
		window.funcs.push(newFunc);
		window.onload = function(){
			for(var i=0; i<this.funcs.length; i++){var func = this.funcs[i]; if(func) func(); }
		}
	}

	/////////// REMOVE ESPAÇOS DO INICIO E DO FIM DE UMA STRING
	function trim(str){return str.replace(/^\s+|\s+$/g,"");}

	/////////// PROCURA EM ARRAYS, KEYS INCOMPATIVEIS
	function searchInArray(array, value){
		for(var i=0; i<array.length; i++){
			if (array[i] == value) return true;
		}
		return false;
	}
	
	/////////// LIMPA UMA STRING
	function cleanStr(str){
		return str.replace(/(['-.,:\/])/g, "");
	}

	/////////// NUMERO DE LETRAS NA STRING
	function nLetters(str, nMin, nMax){
		var nStr = str.replace(/([^'áàãäâéèëêíìïîóòõöôúùüûabcçdefghijklmnopqrstuvwxyzÁÀÃÄÂÉÈËÊÍÌÏÎÓÒÕÖÔÚÙÜÛABCÇDEFGHIJKLMNOPQRSTUVWXYZ '])/g, "").length;
		if(nMin && (nStr < nMin)) return false;
		if(nMax && (nStr > nMax)) return false;
		return true;
	}

	/////////// NUMERO DE NUMEROS NA STRING
	function nNumbers(str, nMin, nMax){
		var nStr = str.replace(/([^'0-9'])/g, "").length;
		if(nMin && (nStr < nMin)) return false;
		if(nMax && (nStr > nMax)) return false;
		return true;
	}

//*******************************FUNÇÕES INSERIDAS NO HTML***********************************//

	/////////// FORMATA O CAMPO
	function formatField(e, field, format){
		var keyCode = e.charCode? e.charCode : e.keyCode;
		var keyChar = String.fromCharCode(keyCode);
		var noKey = [8, 9, 13, 37, 38, 39, 40, 46, 116];

		var string 	= field.value + keyChar;
		var char	= format.substring(string.length-1, string.length);
		var simb 	= format.substring(string.length, string.length+1);

		if( char && !searchInArray(noKey, keyCode) ){
			if(char == "n" && nNumbers(keyChar, 1, 0)) field.value += keyChar;
			if(char == "t" && nLetters(keyChar, 1, 0)) field.value += keyChar;
			if(char == "f") field.value += keyChar;
			
			if(field.value==string && simb != "n" && simb != "t" && simb != "f"){
				field.value += simb;
			}
		}

		if(!searchInArray(noKey, keyCode)) return false;
	}
	//onkeypress="return formatField(event, this, 'nnn.ttt.fff')"

	/////////// PULA PARA O CAMPO ESPECIFICADO
	function inputJump(e, atualField, totalLength, nextField){
		var keyCode=e.charCode? e.charCode : e.keyCode
		noKey = [8, 38, 40, 37, 46, 39];
		if(keyCode!=9  && atualField.value.length >= totalLength && !searchInArray(noKey, keyCode) ){
			document.getElementById(nextField).focus();
		}
	}

	/////////// PERMITE INSERIR APENAS NUMEROS
	function inputNumber(e){
		noKey = [8, 38, 40, 37, 46, 39];
		var keyCode=e.charCode? e.charCode : e.keyCode;
		if (keyCode!=8 && keyCode!=9 && keyCode!=13){
			if ((keyCode<48||keyCode>57) && !searchInArray(noKey, keyCode)){ 
				return false //disable key press
			}
		}
		return true;
	}
	//onkeypress="return inputNumber(event);"
	
	/////////// FORMATA MOEDA
	function formatMoeda(e, obj){
		if(!obj.value){obj.value = "0,0"; return true;}
		
		var noKey = [8, 38, 40, 37, 39];
		var keyCode=e.charCode? e.charCode : e.keyCode;
		if (keyCode!=8 && keyCode!=9 && keyCode!=13){
			if ((keyCode<48||keyCode>57) && !searchInArray(noKey, keyCode)){ 
				return false; //disable key press
			}
		}
		
		var value = obj.value.replace(/^0|(['-.:\/])/g, "");
		var chars = value.length;
		
		if(chars>=2){
			var milhar 	 = value.substring(0,chars-1);
			var m_milhar = Math.ceil(milhar.length/3);
				var array = [];
				for(var i=1; i<=m_milhar; i++){
					var posSlice = (3*i);
					array.push(value.substring((milhar.length-posSlice),(milhar.length-(posSlice-3))));
				}
				array.reverse();
				milhar = array.join(".");
				
			var decimal = value.substring(chars-1,chars);
		}else{
			var milhar 	= "0";
			var decimal = value;
		}
		
		obj.value = milhar + "," + decimal;
	}
	//onkeypress="return formatMoeda(event, this);"

	/////////// HABILITA E DESABILITA VALIDAÇÃO DE CADA CAMPO
	function enableDisableVal(form, array, value){
		if(typeof(form) != 'string') alert("Informe o nome do formulário em formato 'string'");
		var mapElements = this["FORMAP_" + form];
		if(!mapElements) {alert('O mapa de validação (Array) não foi encontrado'); return false;}
		
		if(typeof(array) == 'string'){
			var array = array.split(',');
			for(var i=0; i<array.length; i++){array[i] = trim(array[i]);}
		}
		
		for(var i=0; i<mapElements.length; i++){
			if(searchInArray(array, mapElements[i][0][0])){
				mapElements[i][0][1] = value;
			}
		}
	}
	function enableVal(form, array){
		enableDisableVal(form, array, true);
	}
	function disableVal(form, array){
		enableDisableVal(form, array, false);
	}

//***********************************VALIDAÇÕES ADICIONAIS***********************************//

	/////////// VALIDA CNPJ
	function valCNPJ(value) {
		value = cleanStr(value);
		
		if(value.length < 14) return false;

		var a = value.split('');
		var b = new Number;
		var c = [6,5,4,3,2,9,8,7,6,5,4,3,2];
		
		for (var i=0; i<12; i++){ b += a[i] * c[i+1]; }
		if ((x = b%11) < 2) { a[12] = 0; } else { a[12] = 11-x; }
		
		b = 0;
		for (var i=0; i<13; i++){ b += (a[i] * c[i]); }
		if ((x = b%11) < 2) { a[13] = 0; } else { a[13] = 11-x; }
		
		if ((value.charAt(12) != a[12]) || (value.charAt(13) != a[13])){
			return false;
		}
		return true;
	}

	/////////// VALIDA CPF
	function valCPF(value) {
		value = cleanStr(value);

		if (value.length != 11 || value == "00000000000" || value == "11111111111" ||	value == "22222222222" ||
		value == "33333333333" || value == "44444444444" ||	value == "55555555555" || value == "66666666666" ||
		value == "77777777777" || value == "88888888888" || value == "99999999999"){
			return false;
		}
		
		var soma = 0;
		for (var i=0; i<9; i++) soma += parseInt(value.charAt(i)) * (10 - i);
		var resto = 11 - (soma % 11);
		if (resto == 10 || resto == 11) resto = 0;
		if (resto != parseInt(value.charAt(9))) return false;
		
		var soma = 0;
		for (var i=0; i<10; i++) soma += parseInt(value.charAt(i)) * (11 - i);
		var resto = 11 - (soma % 11);
		if (resto == 10 || resto == 11) resto = 0;
		if (resto != parseInt(value.charAt(10))) return false;
			
		return true;
	}
	
	/////////// VALIDA E-MAIL
	function valEMAIL(value){
		var reg = RegExp(/^[A-Za-z0-9_\-\.]+@[A-Za-z0-9_\-\.]{2,}\.[A-Za-z0-9]{2,}(\.[A-Za-z0-9])?/);
		if(reg.test(value)) return true;
		else return false;
	}
	
	/////////// VALIDA ARQUIVO
	function valFile(value, tipo_arquivo){
		tipo_arquivo = tipo_arquivo.split(',');
		var ext 	= value.split('.');
			ext		= ext[ext.length-1];
			ext		= ext.toLowerCase();
		for(var i=0; i<tipo_arquivo.length; i++){
			var tipo = trim(tipo_arquivo[i]);
				tipo = tipo.toLowerCase();
			if(tipo == ext) return true;
		}
		return false;
	}
	
	/////////// VERIFICA SE UM CAMPO É IGUAL A OUTRO
	function valSame(field, field2){
		if(field.value != field2.value) return false;
		else return true;
	}

//***********************************VALIDAÇÕES BÁSICAS***********************************//

	/////////// VALIDA SE UM CAMPO FOI PREENCHIDO (SELECT)
	function valSelectMultiple(field, nMin, nMax){
		var itens = 0;
		for (var i=0; i<field.length; i++){
			if (field[i].selected) itens++;
		}
		if(nMin && itens<nMin) return false;
		if(nMax && itens>nMax) return false;
		return true;
	}
	function valSelectOne(field){
		var value =	field.value;
		if(!field.value) return false;
		else return true;
	}

	/////////// VALIDA SE UM CAMPO FOI PREENCHIDO (CHECKBOX)
	function valCheck(field, nMin, nMax){
		var itens = 0;
		for (var i=0; i<field.length; i++){
			if (field[i].checked) itens++;
		}
		if(nMin && itens<nMin) return false;
		if(nMax && itens>nMax) return false;
		return true;
	}
	
	/////////// VALIDA SE UM CAMPO FOI PREENCHIDO (RADIO)
	function valRadio(field){
		for (var i=0; i<field.length; i++){
			if (field[i].checked) return true;
		}
		return false;
	}

	/////////// VALIDA SE UM GRUPO DE CAMPOS FOI PREENCHIDO (TEXT GROUP)
	function valTextGroup(field, nMin, nMax){
		var itens = 0;
		for (var i=0; i<field.length; i++){
			if (field[i].value) itens++;
		}
		if(nMin=='all' && field.length!=itens) return false;
		if(nMin && itens<nMin) return false;
		if(nMax && itens>nMax) return false;
		return true;
	}

	/////////// VERIFICA SE UM CAMPO SÓ COMTEM NÚMEROS
	function valNumber(value) {
		var value = cleanStr(value);
		if(isNaN(value)) return false;
		return true;
	}

	/////////// VALIDA SE UM CAMPO FOI PREENCHIDO (TEXT)
	function valText(field, nMin, nMax){
		var nChars = field.value.length;
		if(nMin && nChars<nMin) return false;
		if(nMax && nChars>nMax) return false;
		return true;
	}
	
	///////////////////// RETORNA CONSULTA DE UMA PÁGINA
	function retornPage(page, func, param){
		
		var xmlhttp;
		//----------------------------------------------------
		try{
			xmlhttp = new XMLHttpRequest();
		}catch(ee){
			try{
				xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
			}catch(e){
				try{
					xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
				}catch(E){
					xmlhttp = false;
				}
			}
		}
		
		param = param.split(',');
		for(var i=0; i<param.length; i++){
			param[i] = 'pajax_values[]='+param[i];	
		}
		param = param.join('&');
		
		var dados = 'pajax_func=' + func + '&' + param;
		
		try{
			//INICIAL PROCESSO
			xmlhttp.open("GET", page+'?'+dados, false);
			xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			xmlhttp.send(null);
			return xmlhttp.responseText
		}catch(ex){throw ex;}

	}

//***********************************VALIDAÇÃO***********************************//

	/////////// MOSTRA MENSAGEM///////////////////
	function showMsg(campo, msg){
		var dadosDoCampo = dadosCampo(campo);
		var campo_nome 	 = dadosDoCampo.nome;
		var tipo_campo	 = dadosDoCampo.tipo;
		var isGroup 	 = dadosDoCampo.isGroup;
		
		if(isGroup){
			for(var i=0; i<campo.length;i++){
				if(!campo[i].value){
					campo[i].focus();
					
						var campo = campo[i];
						var isGroup = false;
						var id = i;
						
					break;
				}
			}
		}else{
			if(tipo_campo == 'select-one' || tipo_campo == 'select-multiple') campo.focus();
			else if(campo.length >= 1) campo[0].focus();
			else campo.focus();
		}
		if(id == undefined) id = "";
		//mostra mensagem
		var statusBox = document.getElementById("STATUS_" + campo_nome + id);
		if (!statusBox){
			var newElement = document.createElement('div');
				newElement.id = "STATUS_" + campo_nome + id;
				newElement.className = 'status';
			if(tipo_campo == 'select-one' || tipo_campo == 'select-multiple') campo[0].parentNode.parentNode.appendChild(newElement);
			else if(campo.length >= 1) campo[0].parentNode.appendChild(newElement);
			else campo.parentNode.appendChild(newElement);
			
			statusBox = newElement;
		}
		statusBox.style.display = "block";
		statusBox.innerHTML 	= msg;
		
		if(isGroup || tipo_campo=='radio' || tipo_campo=='checkbox'){
			for(var i=0; i<campo.length; i++){
				addOnBlur(campo[i], id);
			}
		}else{				
			addOnBlur(campo, id);
		}
	}////////////////////////

	function addOnBlur(campo, id){
		clearInterval(campo.intervalRemoveMsg);
		if(!campo.funcActive){
			campo._onblur = campo.onblur;
				if(campo.type=='radio' || campo.type=='checkbox') campo._checked = campo.checked;
				else campo._value = campo.value;
			campo.onblur = function(e){	
				var _name = this.name;
					if(campo.type=='radio' || campo.type=='checkbox'){
						if(campo._checked == this.checked) return;
					}else{
						if(campo._value == this.value) return;
					}
					
				campo.intervalRemoveMsg = setTimeout(function(){ removeMsg("STATUS_" + _name + id ); }, 100);
				
				if(campo._onblur != campo.onblur){
					this.onblur=this._onblur;
					if(this._onblur) this._onblur();
				}else  this.onblur = null;
				
				this._onblur	= null;
				this.funcActive = false;
			}
			campo.funcActive = true;
		}
	}

	/////////// REMOVE MWNSAGEM///////////////////
	intervalRemoveMsg = false;
	function removeMsg(target){
		if(typeof(target) == 'string') target = document.getElementById(target);
		if(target){ target.style.display = "none"; target.innerHTML = "";}
		//intervalRemoveMsg = setTimeout(function(){ target.style.display = "none"; target.innerHTML = ""; }, 100);
	}
	
	/////////// RETORNA CARACTERISTICAS DO CAMPO///////////////////
	function dadosCampo(campo){
		var campo_nome = campo.name || campo[0].name;
		var tipo_campo = campo.type || campo[0].type;
		//verifica se é um grupo de elementos (diferentes de radio e checkbox)
		type_groups = ['text','textarea','file','select-one'];
		if(campo.length && searchInArray(type_groups, campo[0].type)) var isGroup = true;
		else var isGroup = false;
		

		return {nome:campo_nome, tipo:tipo_campo, isGroup:isGroup};
	}

	/////////// VALIDA O FORMULARIO
	function validaForm(form){
		
		//encontra formulário
		if(typeof(form) == 'string') var form = document.getElementById(form);
		if(!form) {alert('O formulário não foi encontrado. Especifique corretamente o id do formulário'); return false;}
		
		//busca elementos de validação
		var mapElements = this["FORMAP_" + form.name];
		if(!mapElements) {alert('O mapa de validação (Array) não foi encontrado'); return false;}
		//inicia validação
		
		for(var i=0; i<mapElements.length; i++){
			//dados do campo
			var campo_nome 	 = mapElements[i][0][0];
			var campo 		 = form[campo_nome];   if(!campo) {alert('O campo "' + campo_nome + '" não foi encontrado'); return false;}
			
			var dadosDoCampo = dadosCampo(campo);
			var tipo_campo 	 = dadosDoCampo.tipo;
			var isGroup 	 = dadosDoCampo.isGroup;
			
			//dados da validacao
			var habilita_val 		= mapElements[i][0][1];		
		
			if(!habilita_val) continue;
			var tipo_val 			= mapElements[i][1][0];
			var tipo_val_msg 		= mapElements[i][1][1];
			var obrigatorio 		= mapElements[i][2][0];
			var obrigatorio_msg 	= mapElements[i][2][1];
			var num_preenchidos 	= mapElements[i][3][0];
			var num_preenchidos_msg = mapElements[i][3][1];
			var num_caracter 		= mapElements[i][4][0];
			var num_caracter_msg 	= mapElements[i][4][1];
			var num_letras 			= mapElements[i][5][0];
			var num_letras_msg 		= mapElements[i][5][1];
			var num_numeros 		= mapElements[i][6][0];
			var num_numeros_msg 	= mapElements[i][6][1];
			var limite_numero 		= mapElements[i][7][0];
			var limite_numero_msg 	= mapElements[i][7][1];
			var compara_campo 		= mapElements[i][8][0];
			var compara_campo_msg 	= mapElements[i][8][1];
			var tipo_arquivo 		= mapElements[i][9][0];
			var tipo_arquivo_msg 	= mapElements[i][9][1];
			var retorna_page 		= mapElements[i][10][0];
			var retorna_func 		= mapElements[i][10][1];
			var retorna_param 		= mapElements[i][10][2];

			//(2) Campo obrigatório
			if(obrigatorio){
				if(isGroup) 								var valid = valTextGroup(campo,1,0);
				else if	(tipo_campo == "checkbox") 			var valid = valCheck(campo,1,0);
				else if (tipo_campo == "radio") 			var valid = valRadio(campo);
				else if (tipo_campo == "select-multiple")	var valid = valSelectMultiple(campo,1,0);
				else if (tipo_campo == "select-one")		var valid = valSelectOne(campo);
				else 										var valid = valText(campo,1,0);
				if (!valid) {showMsg(campo, obrigatorio_msg); return false;}
			}

			//(3) Mínimo e Máximo de elementos preenchidos do grupo (text, checkbox, select-one, select-multiple, file)
			if (num_preenchidos[0] || num_preenchidos[1]){
				if(isGroup)							var valid = valTextGroup(campo, num_preenchidos[0], num_preenchidos[1]);
				else if	(tipo_campo == "checkbox")  		var valid = valCheck(campo, num_preenchidos[0], num_preenchidos[1]);
				else if	(tipo_campo == "select-multiple")  	var valid = valSelectMultiple(campo, num_preenchidos[0], num_preenchidos[1]);
				if (!valid) {showMsg(campo, num_preenchidos_msg); return false;}
			}
			
			//valida individualmente cada campo
			function validaCampo(campo){
				//(4) Mínimo e Máximo de caracteres
				if (num_caracter[0] || num_caracter[1]){
					var valid = valText(campo,num_caracter[0],num_caracter[1]);
					if (!valid) {showMsg(campo, num_caracter_msg); return false;}
				}
				
				//valida o tipo do campo
				if(tipo_val == 'text'){
					var valid = nLetters(campo.value, campo.value.length, 0);
					if (!valid) {showMsg(campo, tipo_val_msg); return false;}
				}
				if(tipo_val == 'numeric'){
					var _val = cleanStr(campo.value);
					var valid = nNumbers(_val, _val.length, 0);
					if (!valid) {showMsg(campo, tipo_val_msg); return false;}
				}
				if(tipo_val == 'option'){
					/**/
				}
				if(tipo_val == 'cpf'){
					var valid = valCPF(campo.value);
					if (!valid) {showMsg(campo, tipo_val_msg); return false;}
				}
				if(tipo_val == 'cnpj'){
					var valid = valCNPJ(campo.value);
					if (!valid) {showMsg(campo, tipo_val_msg); return false;}
				}
				if(tipo_val == 'email'){
					var valid = valEMAIL(campo.value);
					if (!valid) {showMsg(campo, tipo_val_msg); return false;}
				}

				//(5) Mínimo e Máximo de letras
				if(num_letras[0] || num_letras[1]){
					var valid = nLetters(campo.value, num_letras[0], num_letras[1]);
					if (!valid) {showMsg(campo, num_letras_msg); return false;}
				}
				
				//(6) Mínimo e Máximo de números
				if(num_numeros[0] || num_numeros[1]){
					var _val = cleanStr(campo.value);
					var valid = nNumbers(_val, num_numeros[0], num_numeros[1]);
					if (!valid) {showMsg(campo, num_numeros_msg); return false;}
				}
				
				//(7) Número maior ou menos que (Caso (1) for numeric)
				if (limite_numero[0] || limite_numero[1]){
					if (limite_numero[0]) if ( Number(campo.value) < Number(limite_numero[0]) ) {showMsg(campo, limite_numero_msg); return false;}
					if (limite_numero[1]) if ( Number(campo.value) > Number(limite_numero[1]) ) {showMsg(campo, limite_numero_msg); return false;}
				}
				
				//(9) Compara o campo com outro campo
				if (tipo_arquivo){
					var valid = valFile(campo.value, tipo_arquivo);
					if (!valid) {showMsg(campo, tipo_arquivo_msg); return false;}
				}
				
				return true;
			}
			
			if(isGroup){ //caso seja um grupo de campos valida os campos individualmente
				for(var z=0; z<campo.length; z++){
					if(campo[z].value && !validaCampo(campo[z])) return false;
				}
			}else{
				if(campo.value && !validaCampo(campo)) return false;
			}
			
			//(8) Compara o campo com outro campo
			if (compara_campo){
				if(typeof(compara_campo)=='string') compara_campo = form[compara_campo];
				var valid = valSame(campo, compara_campo);
				if (!valid) {showMsg(campo, compara_campo_msg); return false;}
			}
			
			//(10) Retorna 'Mensagem de erro' de uma função
			if(retorna_func){
				if(typeof(retorna_func)=='string'){
					var retorna_param=retorna_param.replace(/this.value/g, campo.value);
					var valid = retornPage(retorna_page, retorna_func, retorna_param);
				}
				if(valid && typeof(valid) == 'string'){
					var retorna_func_msg = valid;
					showMsg(campo, retorna_func_msg); return false;
				}
			}
		}
		return true;
	}
