/*
	w3FormValidation (2.3) - 02/02/2007
	Por Leandro Vieira Pinho - http://leandro.w3invent.com.br
	
	Para informações de uso deste add-on visite:
	http://leandro.w3invent.com.br/addons/w3FormValidation/

	Parâmetros que podem ser utilizados para ATIVAR ou DESATIVAR recursos deste add-on
	var valida = new w3FormValidation(param1,param2,param3,param4,param5);
	param1 {Array}    = Campos a serem validados.
	param2 {string}   = Título do box das mensagens de erro. Padrão: Observações!
	param3 {integer}  = Distância que o box terá em relação ao topo da página. Padrão: 0
	param4 {boolean}  = Coloque false para não utilizar o "overlay" sobre o body. Padrão: true
	param5 {boolean}  = Coloque false para o box não acompanhar a rolagem da página. Padrão: true

	O código HTML gerado para exibir o box com as mensagens é o seguinte:
	
	<div id="w3ShowMsgToUser">
		<h3>Observações!</h3>
		<ol>
			<li>Mensagem</li>
			<li>...</li>
		</ol>
		<input id="w3ShowMsgToUserBtnOk" value="Ok" type="button">
	</div>
	
	Você pode estilizá-lo através das CSS e deixá-lo como desejar.
	
	Funções de terceiros utlizadas neste add-on
	
	Função: getPageSize Autor: PPK
	Função: getScrollingPosition Autor: James Edwards/Cameron Adams
	
	Tipos de validação inspirado no JS Validation de Beenjamin Keen (.com)

*/

/**
 *
 * @param {array} arrInfoVal informações sobre os campos a serem validados; tipo de validação
 * @param {string} strTitleMsgToUser título que será utilizado no box da mensagem
 * @param {int} intPageTopDistance valor que será concedido a propriedade top do box da mensagem
 * @param {boolean} boolEncobrirBody se usará um overlay sobre o body (TRUE) ou não
 * @param {boolean} boolFixMsgToUserInViewPort se o box irá acompanhar (TRUE) ou não o scrolling da página
 *
 */
function w3FormValidation(arrInfoVal,strTitleMsgToUser,intPageTopDistance,boolEncobrirBody,boolFixMsgToUserInViewPort) {
	// arrInfoVal informações sobre os campos a serem validados; tipo de validação
	this.arrInfoVal = arrInfoVal;
	
	// Mensagem que será utilizada com o título da box da mensagem - H3
	if ( typeof strTitleMsgToUser == "undefined" ) {
		this.strTitleMsgToUser = 'Observações!';
	} else {
		this.strTitleMsgToUser = strTitleMsgToUser;
	}
	
	// Se nenhum valor for informado para o parâmetro pageTopDistance, definimos-o como 0
	if ( typeof intPageTopDistance == "undefined" ) {
		intPageTopDistance = 0;
	}
	this.top = intPageTopDistance;
	
	// Se nada for definido para o parâmetro boolEncobrirBody o valor padrão será TRUE
	if ( typeof boolEncobrirBody == "undefined" ) {
		this.boolEncobrirBody = true;
	}
	
	// Pegamos um Array com a localização do usuário na página, assim exibiremos o box da Mensagem no mesmo local em que ele está :)
	var arrAtualScrollingPosition = this.getScrollingPosition();
	// Pegamos apenas a localização do eixo Y, ou seja, a distância do local até o topo da página
	this.atualScrollingPositionY = arrAtualScrollingPosition[1];
	
	// Se nada for definido para o parâmetro boolFixMsgToUserInViewPort o valor padrão será TRUE
	if ( typeof boolFixMsgToUserInViewPort == "undefined" ) {
		boolFixMsgToUserInViewPort = true;	
	}
	if ( boolFixMsgToUserInViewPort ) {
		// Adicionamos a função fixMsgToUserInViewPort para o box da mensagem acompanhar o scrolling do usuário pela página
		addEvent(window, 'scroll', this.fixMsgToUserInViewPort, false, [this.top]);
	}
};

/**
 * Função que fixa o box da mensagem no viewport do browser
 *
 * @param {array} paraTopDistance valor que será concedido ao style.top
 */
w3FormValidation.prototype.fixMsgToUserInViewPort = function(paramTopDistance) {
	// Pegamos um Array com a localização do usuário na página, assim exibiremos o box da Mensagem no mesmo local em que ele está :)
	var arrCorrenteScrollingPosition = w3FormValidation.prototype.getScrollingPosition();
	// Pegamos apenas a localização do eixo Y, ou seja, a distância do local até o topo da página
	var correnteScrollingPositionY = arrCorrenteScrollingPosition[1];
	// Somente se o objeto - o box da mensagem - estiver na página
	if ( $('w3ShowMsgToUser') ) {
		$('w3ShowMsgToUser').style.top = correnteScrollingPositionY + parseInt(paramTopDistance,'') + 'px';
	}
};

/**
 * Chama a função que validará os dados informados. Retorna TRUE se os dados forem válidos ou FALSE caso contrário.
 */
w3FormValidation.prototype.start = function() {
	// Atribui à varíavel VALIDA o resultado da validação TRUE/FALSE
	var valida = this.validation(this.arrInfoVal);
	// valor de retorno - TRUE/FALSE
	return valida;
};

w3FormValidation.prototype.validation = function(arrParams) {
	// Array que conterá as mensagens a serem exibidas ao usuário
	var arrMsgToUser = [];
	// Array que conterá o atributo ID dos campos informados
	var arrFields = [];
	// Booleano sobre o resultado da validação
	var boolResultVal = true;

	// Loop entre o Array - arrParams - passado como param da função
	for ( i = 0; i < arrParams.length; i++ ) {
	
		// O parâmetro é recebido da seguinte forma: tipo-de-validação,id-do-campo,mensagem
		var arrFieldVal = arrParams[i].split(',');
		var if_typeVal = true;
		// Variáveis utilizados pelo tipo de validação condicional
		var strCondition, arrCondition, strFieldToCheck, strValueToCheck, strFieldToCheckValue;
		// Verificamos se o primeiro item do Array contém a condição if, mais precisamente: if:
		while ( arrFieldVal[0].match("^if:") ) {
			// Pegamos a condição informada e Retiramos a partícula if:
			strCondition = arrFieldVal[0].replace("if:",""); 
			// Verificamos se o tipo de campo será um radio button
			// Para os radion buttons não é informado o ID do campo como os outros, mas sim o atributo NAME
			// Precisamos também do ID do formulário em que o radio group se encontra
			// Então, esta regra será informada assim: 'if:frmID:radioButtonName=valor,req,id do campo requerido,mensagem'
			if ( strCondition.match(":") ) {
				var arrFieldInfo = strCondition.split(":");
				var strFormID = arrFieldInfo[0];
				arrCondition = arrFieldInfo[1].split("=");
				strFieldToCheck = arrCondition[0];
				strValueToCheck = arrCondition[1];
				for ( var r = 0; r < $(strFormID)[strFieldToCheck].length; r++) {
					if ( $(strFormID)[strFieldToCheck][r].checked ) {
						strFieldToCheckValue = $(strFormID)[strFieldToCheck][r].value;
					}
				}
			} else {
				// Separamos o campo e o valor
				arrCondition = strCondition.split("=");
				strFieldToCheck = arrCondition[0];
				strValueToCheck = arrCondition[1];
				// pegamos o valor do campo informado (para compará-lo ao valor informado)
				strFieldToCheckValue = $(strFieldToCheck).value;
			}
			if ( strFieldToCheckValue != strValueToCheck ) {
				if_typeVal = false;
				break;
			} else {
				arrFieldVal.shift();
			}
		} // Fim do while match:^if
		
		if ( !if_typeVal ) {
			continue;
		}

		// tipo de validação para o campo
		var typeVal   = arrFieldVal[0]; 
		// id do campo a ser validado
		var field     = arrFieldVal[1]; 
		// mensagem a ser exibida ao usuário
		var msgToUser = '';
		// Se for uma validação do tipo: igual (dois campos com o mesmo valor)
		// igual,campo-1,campo-2,mensagem
		if ( arrFieldVal.length == 4 ) { 
			// id do segundo campo a ser validado
			var field2 = arrFieldVal[2];
			// mensagem a ser exibida ao usuário
			// Neste caso - tipo: igual - a mensagem é o 4º índice do Array
			msgToUser = arrFieldVal[3];
		} else {
			// mensagem a ser exibida ao usuário
			// Neste caso - para todos - a mensagem é o 2º índice do Array
			msgToUser = arrFieldVal[2]; 
		}

		// Verificamos se há algum tipo de validação especial
		// Validações especiais: length,range,...
		if ( typeVal.match("^length=") ) {
			var strLength_typeVal = typeVal;
			typeVal = "length";
		}
		if ( typeVal.match("^range=") ) {
			var strRange_typeVal = typeVal;
			typeVal = "range";
		}

		// Verifica o tipo de validação e a realiza
		switch(typeVal) {
			// Valida os campos requeridos
			case 'req' :
				// Validação específica para os radion button
				// Por que as coisas às vezes é tão chata?
				// Para os radion buttons não é informado o ID do campo como os outros mas sim o atributo NAME
				// Precisamos também do ID do formulário em que o radio group se encontra
				// Então, esta regra será informada assim: 'req,formID:radioName,mensagem'
				// Foi a melhor solução até o momento
				if ( field.match(":") ) {
					var arrFieldInfo = field.split(":");
					var strFormID = arrFieldInfo[0];
					var strRadioName = arrFieldInfo[1];
					if ( typeof($(strFormID)[strRadioName].type) == "undefined" ) {
						var boolRadioChecked = false;
						for ( var r = 0; r < $(strFormID)[strRadioName].length; r++) {
							if ( $(strFormID)[strRadioName][r].checked ) {
								boolRadioChecked = true;
							}
						}
						if ( !boolRadioChecked ) {
							arrMsgToUser.push(msgToUser);
							boolResultVal = false;
						}
					}
				// Validação para os demais campos
				} else {
					// Remove a classe de erro. Se o campo tiver errado depois ela é inserida de novo.
					removeClass($(field),'w3FieldError');
					if ( !$(field).value ) {
						arrMsgToUser.push(msgToUser);
						arrFields.push($(field));
						boolResultVal = false;
					}
				}
			break;
			// Valida os campos de e-mail
			case 'email' :
				// Remove a classe de erro. Se o carro tiver errado depois ela é inserida de novo.
				removeClass($(field),'w3FieldError');
				if ( !this.isEmail($(field).value) ) {
					arrMsgToUser.push(msgToUser);
					arrFields.push($(field));
					boolResultVal = false;
				}
			break;
			// Valida os campos de URL
			case 'url' :
				// Remove a classe de erro. Se o carro tiver errado depois ela é inserida de novo.
				removeClass($(field),'w3FieldError');
				if ( !this.isURL($(field).value) ) {
					arrMsgToUser.push(msgToUser);
					arrFields.push($(field));
					boolResultVal = false;
				}
			break;
			// O valor de dois campos devem ser iguais
			case 'same' :
				// Remove a classe de erro. Se o carro tiver errado depois ela é inserida de novo.
				removeClass($(field),'w3FieldError');
				if ( $(field).value != $(field2).value ) {
					arrMsgToUser.push(msgToUser);
					arrFields.push($(field));
					boolResultVal = false;
				}
			break;
			// O campo não pode ficar vazio e aceitará somente digítos [0-9]
			// Não pode ficar vazio por que vazio não é um dígito :)
			case 'digits' :
				removeClass($(field),'w3FieldError');
				if ( !$(field).value || $(field).value.match(/\D/) ) {
					arrMsgToUser.push(msgToUser);
					arrFields.push($(field));
					boolResultVal = false;
				}
			break;
			// O valor total de caracteres contidos no campo precisará ser igual ao valor informado
			// ou poderá estar entre dois valores (x-y)
			case 'length' :
				removeClass($(field),'w3FieldError');
				var strLength = strLength_typeVal.replace("length=","");
				var arrLengthOrRange = strLength.match(/[^_]+/);
				var arrLength = arrLengthOrRange[0].split("-");
				// Se for especificado dois valores, verificamos se o total de caracteres está ente esses dois valors informados.
				if ( arrLength.length == 2 ) {
					if ( ( $(field).value.length < arrLength[0] ) || ( $(field).value.length > arrLength[1] ) ) {
						arrMsgToUser.push(msgToUser);
						arrFields.push($(field));
						boolResultVal = false;
					}
				// Se for especificado um valor, verificamos se o total de caracteres é igual ao valor informado
				} else {
					if ( $(field).value.length != arrLength ) {
						arrMsgToUser.push(msgToUser);
						arrFields.push($(field));
						boolResultVal = false;
					}
				}
			break;
			case 'range' :
				// O campo precisa conter apenas dígitos [0-9]. Uma vez que será um range entre um número X e Y
				// O valor do campo não poderá ser menor que primeiro número (X) e nem maior do que o segundo (Y)
				removeClass($(field),'w3FieldError');
				var strRange = strRange_typeVal.replace("range=","");
				var arrRange = strRange.split("-");
				if ( ( $(field).value.match(/\D/) ) || ( $(field).value <  Number(arrRange[0]) ) || ( $(field).value > Number(arrRange[1]) ) ) {
					arrMsgToUser.push(msgToUser);
					arrFields.push($(field));
					boolResultVal = false;		
				}
			break;
			default :
				alert('O tipo de validação desejado não é suportado ou desconhecido pelo w3FormValidation.\n\n-------------------------\nTipo de validação: ' + typeVal + '\n-------------------------\n\nConsulte a documentação do programa para maiores detalhes em:\n\nhttp://leandro.w3invent.com.br.');
				return false;
		} // fim do switch(typeVal);

	} // fim do loop for

	// Retorna TRUE se a validação foi bem sucedida
	if ( boolResultVal ) {
		return true;
	} else {
		
		// Os campos que não foram validados receberão a classe w3FieldError
		for ( var x = 0; x < arrFields.length; x++ ) {
			addClass(arrFields[x],'w3FieldError');
		}
		
		// Exibimos as mensagens sobre os erros de cada validação
		this.showMsgToUser(arrMsgToUser);
		
		// Retorna FALSE false para o bloquear o formulário
		return false;
	}

}; // Validation

/**
 * -------------------------------------------------------------------------------------------------------------------------- 
 * Funções de validação 
 * -------------------------------------------------------------------------------------------------------------------------- 
 */

/**
 * Verifica se o e-mail é valido
 * @param {string} strEmail
 */
w3FormValidation.prototype.isEmail = function(strEmail) {
	return strEmail.search(/(\w[\w\.\+]+)@(.+)\.(\w+)$/) == 0;	
};

/**
 * Verifica se a URL é valida
 * @param {string} strURL
 */
w3FormValidation.prototype.isURL = function(strURL) {
	return strURL.search(/http(s)?:\/\/(www.)?([\w.]+)(\.\w{2,4})+$/) == 0;
};

/**
 * -------------------------------------------------------------------------------------------------------------------------- 
 * Fim das Funções de validação 
 * -------------------------------------------------------------------------------------------------------------------------- 
 */

/**
 * Exibe todas as mensagens que deverão ser exibidas, gerando o seguinte código HTML
 * <div id="w3ShowMsgToUser">
 *	<h3>Observações!</h3>
 *	<ol>
 *		<li>Mensagem</li>
 *	</ol>
 *	<input id="w3ShowMsgToUserBtnOk" value="Ok" type="button">
 * </div>
 * @param {Array} arrMsgToUserParam
 */
w3FormValidation.prototype.showMsgToUser = function(arrMsgToUserParam) {

	// Caso já tenha o "box" com as mensagens, removemos.
	this.closeMsgToUser('noFade');

	// Correção do bug que exibe as tags select sobre o overlay no body
	var arrTagSelect = $tags("select");
	for ( var i = 0; i < arrTagSelect.length; i++ ) {
		arrTagSelect[i].style.visibility = "hidden";
	}
	
	if ( this.boolEncobrirBody ) {
		this.encobrirBody();	
	}
	
	// Array de tags LI com a mensagem de erro como seu conteúdo
	var arrTagsLi = [];
	for ( i = 0; i < arrMsgToUserParam.length; i++ ) {
		arrTagsLi.push($new('li',arrMsgToUserParam[i]));
	}
	// Inserimos o HTML desejado na página
	$append($new('div','id=w3ShowMsgToUser',[$new('h3',this.strTitleMsgToUser),$new('ol',arrTagsLi),$new('form',$new('input',["type=button","value=Ok","id=w3ShowMsgToUserBtnOk"],""))]));
	// Inicia o w3FadingOpacity para o box da mensagem
	var fadeBox = new w3FadingOpacity('w3ShowMsgToUser',0,100,100);
	fadeBox.start();
	// Fixa o box da mensagem exatamente onde o usuário estiver na página
	// Uma vez que o valor foi pego quando ele clicou no botão (chamou esta classe)
	$('w3ShowMsgToUser').style.top = this.atualScrollingPositionY + this.top + 'px';
	// Ao clicar no botão de Ok chama a função this.closeMsgToUser para remover o "box"
	addEvent($('w3ShowMsgToUserBtnOk'),'click',this.closeMsgToUser, false);
	// Focus no botão de OK	
	$('w3ShowMsgToUserBtnOk').focus();
};

w3FormValidation.prototype.encobrirBody = function() {
	var sizesPage = getPageSize();
	$append($new("div","id=w3BodyOverlay",''));
	//$('w3BodyOverlay').style.width = arrayPageSize[0] + 'px';
	$('w3BodyOverlay').style.height = arrayPageSize[1] + 'px';
	var fadeOverlay = new w3FadingOpacity('w3BodyOverlay',0,80,100);
	fadeOverlay.start();

};

/**
 * Remove as mensagens exibidas ao usuário e o código HTML gerado
 * @param {}
 */
w3FormValidation.prototype.closeMsgToUser = function(strFade) {

	if ( strFade != 'noFade' ) {
		var fadeBox = new w3FadingOpacity('w3ShowMsgToUser',100,0,100,removerBoxes);
		fadeBox.start();
	}
	function removerBoxes() {
		$remove($('w3ShowMsgToUser'));
		$remove($('w3BodyOverlay'));

		// Correção do bug que exibe as tags select sobre o overlay no body
		var arrTagSelect = $tags("select");
		for ( var i = 0; i < arrTagSelect.length; i++ ) {
			arrTagSelect[i].style.visibility = "visible";
		}

	}
};
/**
 * Retorna a localização do formulário na página
 * @return {array} scrollLeft,scrollTop
 * @author The JavaScript Anthology 101 Essential Tips, Tricks & Hacks
 */
w3FormValidation.prototype.getScrollingPosition = function() {
	// Variável que será retornada com os valores
	var position = [0, 0];
	// pageYOffset is used by Firefox and other Mozilla browsers, Safari, Konqueror, and Opera
	if (typeof window.pageYOffset != 'undefined') {
		position = [window.pageXOffset, window.pageYOffset];
	}
	// documentElement.scrollTop is used by IE 6 in standards-compliant mode
	else if (typeof document.documentElement.scrollTop != 'undefined' && document.documentElement.scrollTop > 0) {
		position = [document.documentElement.scrollLeft, document.documentElement.scrollTop];
	}
	// body.scrollTop is used by IE 5, and IE 6 in “Quirks” mode.
	else if (typeof document.body.scrollTop != 'undefined') {
		position = [document.body.scrollLeft, document.body.scrollTop];
	}
	return position;
	/**
	 * Notes
	 * More recent Mozilla browsers (such as Firefox) also support documentElement.scrollTop and body.scrollTop, 
	 * by the same render-ing mode rules as IE 6. Safari and Konqueror support body.scrollTop in either mode. 
	 * Opera supports all three properties in any mode!
	 */
};

//
// getPageSize()
// Returns array with page width, height and window width, height
// Core code from - quirksmode.org
// Edit for Firefox by pHaez
//
function getPageSize(){
	
	var xScroll, yScroll;
	
	if (window.innerHeight && window.scrollMaxY) {	
		xScroll = document.body.scrollWidth;
		yScroll = window.innerHeight + window.scrollMaxY;
	} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
		xScroll = document.body.scrollWidth;
		yScroll = document.body.scrollHeight;
	} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
		xScroll = document.body.offsetWidth;
		yScroll = document.body.offsetHeight;
	}
	
	var windowWidth, windowHeight;
	if (self.innerHeight) {	// all except Explorer
		windowWidth = self.innerWidth;
		windowHeight = self.innerHeight;
	} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
		windowWidth = document.documentElement.clientWidth;
		windowHeight = document.documentElement.clientHeight;
	} else if (document.body) { // other Explorers
		windowWidth = document.body.clientWidth;
		windowHeight = document.body.clientHeight;
	}	
	
	// for small pages with total height less then height of the viewport
	if(yScroll < windowHeight){
		pageHeight = windowHeight;
	} else { 
		pageHeight = yScroll;
	}

	// for small pages with total width less then width of the viewport
	if(xScroll < windowWidth){	
		pageWidth = windowWidth;
	} else {
		pageWidth = xScroll;
	}

	arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight);

};

/**
 * -------------------------------------------------------------------------------------------------------------------------- 
 * Inclusão do add-on w3FadingOpacity 
 * -------------------------------------------------------------------------------------------------------------------------- 
 */
function w3FadingOpacity(strID, intOpacityStart, intOpacityEnd, intFadeDuration, fnAfterFaded) {
	
	this.intOffset = 10;
	this.strID = strID; // String contendo o atributo ID do objeto desejado
	this.intOpacityStart = intOpacityStart; // Valor - inteiro - inicial para o Fade
	this.intOpacityEnd = intOpacityEnd; // Valor - inteiro - final para o Fade
	this.intFadeDuration = intFadeDuration; // Valor - inteiro - para a duração do ciclo do Fade
	this.fnAfterFaded = fnAfterFaded; // Nome da função a ser chamado após a conclusão do ciclco do Fade
	this.intInterval = 0;
	
};

/**
* Aqui iniciamos todo o processo. A chamada inicial
*/
w3FadingOpacity.prototype.start = function() {
	var thisClass = this;	
	this.intInterval = setInterval(function() { thisClass.fadeCycle(); }, (this.intFadeDuration / this.intOffset));
	
};

/**
* Aqui definimos o cliclo de vida do processo de Fading
*/
w3FadingOpacity.prototype.fadeCycle = function() {
	if ( this.intOpacityEnd < this.intOpacityStart ) {
		if ( this.intOpacityStart > this.intOpacityEnd ) {
			this.intOpacityStart -= this.intOffset;
		} else {
			this.finalize();
		}
	} else {
		if ( this.intOpacityStart < this.intOpacityEnd ) {
			this.intOpacityStart += this.intOffset;
		} else {
			this.finalize();
		}
	}
	
	this.setOpacity(this.intOpacityStart / 100);
};

w3FadingOpacity.prototype.setOpacity = function(intOpacity) {
	if ( $(this.strID) ) {
		$(this.strID).style.opacity = intOpacity;
		$(this.strID).style.filter = "alpha(opacity=" + (intOpacity*100) + ")";
	}
};

w3FadingOpacity.prototype.finalize = function() {
	this.intOpacityStart = this.intOpacityEnd;
	clearInterval(this.intInterval);
	if ( this.fnAfterFaded ) {
		this.fnAfterFaded();
	}
};