/**
 * Project: STpl
 * File: validade.js
 *
 * Contem funções para efetuar 
 * validações de formulários.
 *
 * @author Frederico Galvão <fredgalvao@gmail.com>
 * @Last-Modified: 01/11/2007 10:49
 * @Version: 2.1
 */





/**
 * Verifica se a string 'str' é nula.
 *
 * @param string str: string a ser verificada.
 * @return boolean
 */
function isBlank ( str )
{
	if( ( str != null ) && ( str != '' ) )
	{
		for ( var i = 0; i < str.length; i++ )
		{
		   var c = str.charAt ( i );

			if ( ( c != ' ' ) && ( c != '\n' ) && ( c != '\t' ) ) {
				return false;
			}
		}
	}

	return true;
}


/**
 * Verifica se a string 'str' é um número inteiro 
 * não-negativo sem sinal, ou seja, apenas dígitos.
 *
 * @param string str: dígito a ser verificado.
 * @return boolean
 */
function isDigit ( str )
{
	var pattern = /^\d+$/;
	var result  = str.match ( pattern );

	return ( ( result != null ) ? true : false );
}


/**
 * Verifica se a string 'str' é um número real 
 * em ponto flutuante (decimal). Permite o uso de 
 * sinal, separadores de milhar e casas decimais.
 *
 * @param string str: número real a ser verificado.
 * @return boolean
 */
function isDecimal ( str )
{
	var pattern = /^[+-]?((\d+|\d{1,3}(\.\d{3})+)(\,\d*)?|\,\d+)$/;
	var result  = str.match ( pattern );

	return ( ( result != null ) ? true : false );
}


/**
 * Verifica se a string 'str' é um valor monetário.
 * Permite o uso de separadores de milhar e casas decimais.
 *
 * @param string str: valor monetário a ser verificado.
 * @return boolean
 */
function isMoney ( str )
{
	var pattern = /^\d{1,3}(\.\d{3})*\,\d{2}$/;
	var result  = str.match ( pattern );

	return ( ( result != null ) ? true : false );
}


/**
 * Verifica se a string 'str' é um endereço de e-mail válido.
 *
 * @param string str: e-mail a ser verificado.
 * @return boolean
 */
function isEmail ( str )
{
	var pattern = /^[\w-]+(\.[\w-]+)*@(([A-Za-z\d][A-Za-z\d-]{0,61}[A-Za-z\d]\.)+[A-Za-z]{2,6}|\[\d{1,3}(\.\d{1,3}){3}\])$/;
	var result  = str.match ( pattern );

	return ( ( result != null ) ? true : false );
}


/**
 * Verifica se a string 'str' é um número de telefone válido. 
 * Segue máscara definida pela função 'compPhone' - (NNN) NNNN-NNNN.
 * O DDD é opcional e o traço separador são opcionais.
 *
 * @param string str: número de telefone a ser verificado.
 * @return boolean
 */
function isPhone ( str )
{
	var pattern = /^(\(\d{3}\)\s)?\d{4}(\-)?\d{4}$/;
	var result  = str.match ( pattern );

	return ( ( result != null ) ? true : false );
}


/**
 * Verifica se a string 'str' é um CEP válido.
 * Segue máscara definida pela função 'compCEP' - NNNNN-NNN
 *
 * @param string str: CEP a ser verificado.
 * @return boolean
 */
function isCEP ( str )
{
	var pattern = /^\d{5}(\-)?\d{3}$/;
	var result  = str.match ( pattern );

	return ( ( result != null ) ? true : false );
}


/**
 * Verifica se a string 'str' é uma data/hora válida.
 *
 * @param string str: data/hora a ser verificada.
 * @param string mask: máscara a ser adotada.
 * @return boolean
 * ---------------------------------------------------
 * mask:
 * 1. DATE -> DD/MM/YYYY
 * 2. DATETIME -> DD/MM/YYYY HH24:MI
 * 3. DATETIMESEC -> DD/MM/YYYY HH24:MI:SS
 * 4. TIME -> HH24:MI
 * 5. TIMESEC -> HH24:MI:SS
 */
function isDate ( str, mask )
{
	switch(mask)
	{
		case 'DATE':
			var pattern = /^((0?[1-9]|[12]\d)\/(0?[1-9]|1[0-2])|30\/(0?[13-9]|1[0-2])|31\/(0?[13578]|1[02]))\/(19|20)?\d{2}$/;
			break;

		case 'DATETIME':
			var pattern = /^((0?[1-9]|[12]\d)\/(0?[1-9]|1[0-2])|30\/(0?[13-9]|1[0-2])|31\/(0?[13578]|1[02]))\/(19|20)?\d{2}\s([0-1]\d|2[0-3]):[0-5]\d$/;
			break;

		case 'DATETIMESEC':
			var pattern = /^((0?[1-9]|[12]\d)\/(0?[1-9]|1[0-2])|30\/(0?[13-9]|1[0-2])|31\/(0?[13578]|1[02]))\/(19|20)?\d{2}\s([0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/;
			break;

		case 'TIME':
			var pattern = /^([0-1]\d|2[0-3]):[0-5]\d$/;
			break;

		case 'TIMESEC':
			var pattern = /^([0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/;
			break;
	}

	var result = str.match ( pattern );

	return ( ( result != null ) ? true : false );
}


/**
 * Verifica se a string 'str' é um CPF válido.
 *
 * @param string str: CPF a ser verificado.
 * @return boolean
 */
function isCPF ( str )
{
	if ( str )
	{
		var posicao = 10, soma = 0, dv, dvInform, cpf;
		var digito = new Array ( 10 );

		cpf = String( str ).replace(/\D/g, ''); // Remove da string 'str' todos os caracteres especiais

		if ( isBlank ( cpf ) ) {
			return false;
		} // Entrada não numérica.

		dvInform = cpf.substr(9, 2);

		for ( var i = 0; i <= 8; i++ )
		{
			digito[i] = cpf.charAt( i );

			soma += digito[i] * posicao;

			posicao--;
		}

		digito[9] = soma % 11;
		digito[9] = ( digito[9] < 2 ) ? 0 : ( 11 - digito[9] );

		posicao = 11;
		soma = 0;

		for ( i = 0; i <= 9; i++ )
		{
			soma += digito[i] * posicao;
			posicao--;
		}

		digito[10] = soma % 11;
		digito[10] = ( digito[10] < 2 ) ? 0 : ( 11 - digito[10] );

		dv = digito[9] * 10 + digito[10];

		return ( ( dv != dvInform ) ? false : true );
	}

	return false;
}


/**
 * Verifica se a string 'str' é um CNPJ válido.
 *
 * @param string str: CNPJ a ser verificado.
 * @return boolean
 */
function isCNPJ ( str )
{
	if( str )
	{
		var soma = 0, cnpj, aux2;
		var digito = new Array;
		var aux = [6,5,4,3,2,9,8,7,6,5,4,3,2];

		cnpj = String( str ).replace(/\D/g, ''); // Remove da string 'str' todos os caracteres especiais

		if( isBlank ( cnpj ) ) {
			return false;
		} // Entrada não numérica.

		for ( var i = 0; i < 12; i++ ) {
			digito[i] = cnpj.charAt( i );
			soma += digito[i] * aux[i + 1];
		}

		digito[12] = ( ( aux2 = soma % 11 ) < 2 ) ? 0 : ( 11 - aux2 );

		soma = 0;

		for ( i = 0; i < 13; i++ ) {
			soma += (digito[i] * aux[i]);
		}

		digito[13] = ( ( aux2 = soma % 11 ) < 2 ) ? 0 : ( 11 - aux2 );

		return ( ( ( cnpj.charAt( 12 ) != digito[12] ) || ( cnpj.charAt( 13 ) != digito[13] ) ) ? false : true );
	}

	return false;
}










/**
 * Classe que valida formulários html.
 */


/**
 * Contrutor.
 *
 * @param string formId: Id do formulário
 * @param string array arrElemtMdT: Id dos elementos de preenchimento obrigatório.
 */
function Validate( formId, arrElemtMdT )
{
	this.numError = 0;

	this.formObj  = document.getElementById ( formId );
	this.arrLabel = this.formObj.getElementsByTagName ( 'label' );

	if ( arrElemtMdT )
	{
		this.arrMdtT = arrElemtMdT;

		this.displayMdtImg( );
	}
}


/**
 * Define a cor em hexadecimal quando o campo passou pela validação.
 */
Validate.prototype.hexColorPassed = '#000000';

/**
 * Define a cor em hexadecimal quando o campo não passou pela validação.
 */
Validate.prototype.hexColorError = '#CC0000';

/**
 * Define a cor em hexadecimal quando o campo não passou pela validação.
 */
Validate.prototype.elemtBGColor = '#F5F5F5';

/**
 * Define o path do diretório onde a imagem de obrigatoriedade se encontra.
 */
Validate.prototype.imgDir = '../../img/';

/**
 * Define o nome da imagem de obrigatoriedade.
 */
Validate.prototype.imgName = 'bolinha.gif';


/**
 * Insere no formulário as imagens de obrigatoriedade.
 */
Validate.prototype.displayMdtImg = function ( )
{
	var elemt;

	for ( var i = 0; i < this.arrMdtT.length; i++ )
	{
		var image = document.createElement ( 'img' );

		image.setAttribute ( 'src', vldImgDir + this.imgName );
		image.setAttribute ( 'alt', 'Campo Obrigatório' );

		elemt = this.formObj[ this.arrMdtT[i] ];
		elemt.parentNode.appendChild( image );
	}
}

/**
 * Remove do formulário as imagens de obrigatoriedade.
 */
Validate.prototype.removeMdtImg = function ( )
{
	var elemt, imgMdt;

	for ( var i = 0; i < this.arrMdtT.length; i++ )
	{
		elemt  = this.formObj[ this.arrMdtT[ i ] ];

		imgMdt = elemt.parentNode.childNodes;

		for ( var j = 0; j < imgMdt.length; j++) {
			if ( imgMdt[ j ].tagName == 'IMG' ) {
				elemt.parentNode.removeChild ( imgMdt[ j ] );
			}
		}
	}
}


/**
 * Valida todos os campos obrigatórios 
 * e aplica as regras de estilo.
 */
Validate.prototype.validEmptyInput = function ( )
{
	this.removeErrorMsg ( );

	for ( var i = 0; i < this.arrMdtT.length; i++ )
	{
		var elemt = this.formObj[this.arrMdtT[i]];

		if( this.isElemtEmpty ( elemt ) )
		{
			this.numError++;

			this.setStyleColor ( elemt, this.hexColorError );
			this.appendErrorMsg ( elemt, 'Campo Obrigatório' );

			elemt.onfocus = function()
			{
				var pai = this.parentNode;
				var child = pai.childNodes;

				vld.setStyleColor( this, vld.hexColorPassed );

				for ( var j = 0; j < child.length; j++ ) {
					if( child[j].tagName == 'DIV' ) {
						pai.removeChild ( child[j] );
					}
				}
			}

			continue;
		}

		this.setStyleColor( elemt, this.hexColorPassed );
	}
}


/**
 * Insere na arvore do documento a mensagem de erro.
 *
 * @param mixed elemt: objeto do elemento do form.
 * @param string msg: Mensagem de erro.
 */
Validate.prototype.appendErrorMsg = function ( elemt, msg )
{
	var divElemt = document.createElement ( 'div' );
	divElemt.innerHTML = msg;

	elemt.parentNode.appendChild( divElemt );
}


/**
 * Remove da arvore do documento as mensagens de erro.
 */
Validate.prototype.removeErrorMsg = function ( )
{
	var tdTag = this.formObj.getElementsByTagName( 'TD' );

	for ( var i = 0; i < tdTag.length; i++ )
	{
		var child = tdTag[i].childNodes;

		for ( var j = 0; j < child.length; j++ ) {
            if( child[j].tagName == 'DIV' ) {
				tdTag[i].removeChild ( child[j] );
			}
		}
	}
}


/**
 * Verifica se o elemento não foi preenchido.
 *
 * @param mixed elemt: objeto do elemento do formulário.
 * @return boolean
 */
Validate.prototype.isElemtEmpty = function ( elemt )
{
	switch( elemt.type )
	{
		case 'text':
		case 'file':
		case 'textarea':
		case 'password':
			if ( !isBlank( elemt.value ) ) {
				return false;
			}
			break;

		case 'select-one':
		case 'select-multiple':
			for ( var i = 0; i < elemt.options.length; i++ )	{
				if( elemt.options[i].selected && elemt.options[i].value ) {
					return false;
				}
			}
			break;

		case 'checkbox':
			/* Ainda não foi implementado o array de checkboxes */
			if ( elemt.checked ) {
				return false;
			}
			break;

		default: // radio
			for ( var i = 0; i < this.formObj.length; i++ )
			{
				if ( this.formObj.elements[i].name == elemt.name && this.formObj.elements[i].checked ) {
					return false;
				}
			}
	}

	return true;
}


/**
 * Aplica regras de estilo no elemento.
 *
 * @param mixed elemt: objeto do elemento do formulário.
 * @param string strHexColor: cor em hexadecimal.
 */
Validate.prototype.setStyleColor = function ( elemt, strHexColor )
{
	var indice = this.getArrLabelKey ( elemt.id );

	this.arrLabel[ indice ].style.color = strHexColor;

	if ( strHexColor == this.hexColorError )
	{
		elemt.style.backgroundColor = this.elemtBGColor;
		elemt.style.borderColor = strHexColor;
	}
	else // strHexColor == this.hexColorPassed
	{
		elemt.style.borderColor = '';
		elemt.style.backgroundColor = '';
	}
}


/**
 * Retorna o identificador do label do elemento.
 *
 * @param string elemtId: identificador do elemento.
 * @return int
 */
Validate.prototype.getArrLabelKey = function ( elemtId )
{
	for( var i = 0; i < this.arrLabel.length; i++ )	{
		if( this.arrLabel[i].getAttributeNode( 'for' ).value == elemtId ) {
			return i;
		}
	}

	return false;
}


/**
 * Imprime as mensagens de erro caso existam.
 *
 * @return boolean
 */
Validate.prototype.getErrorMsg = function ()
{
	if ( this.numError )
	{
	    this.msgHeader  = "----===x ERRO AO SUBMETER O FORMULÁRIO x===----\n\n"
	    this.msgHeader += "Foram encontrado(s) " + this.numError + " erro(s).\n";
	    this.msgHeader += "Corrija os campos que apresentaram problemas e \n";
	    this.msgHeader += "submeta novamente o formulário.\n\n";
	    this.msgHeader += "===================================\n\n"

		alert ( this.msgHeader );

		this.numError = 0;

		return true;
	}

	return false;
}


/**
 * Aplica regras de estilo no elemento inválido.
 *
 * @param mixed elemt: objeto do elemento do formulário.
 */
Validate.prototype.setElemtStyleEror = function ( elemt )
{
	this.numError++;

	this.setStyleColor ( elemt, this.hexColorError );
	this.appendErrorMsg ( elemt, 'Campo Inválido' );

	elemt.onfocus = function()
	{
		var pai = this.parentNode;
		var child = pai.childNodes;

		vld.setStyleColor( this, vld.hexColorPassed );

		for ( var j = 0; j < child.length; j++ ) {
			if( child[j].tagName == 'DIV' ) {
				pai.removeChild ( child[j] );
			}
		}
	}
}


/**
 * Verifica se a string 'str' é um número inteiro 
 * não-negativo sem sinal, ou seja, apenas dígitos.
 *
 * @param string elemtId: identificador do elemento.
 */
Validate.prototype.isDigit = function ( elemtId )
{
	var elemt = this.formObj[elemtId];

	if( !this.isElemtEmpty ( elemt ) )
	{
		if ( !isDigit ( elemt.value ) ) {
			this.setElemtStyleEror( elemt );
		}
		else {
			this.setStyleColor( elemt, this.hexColorPassed );
		}
	}
}


/**
 * Verifica se a string 'str' é um número real 
 * em ponto flutuante (decimal). Permite o uso de 
 * sinal, separadores de milhar e casas decimais.
 *
 * @param string elemtId: identificador do elemento.
 */
Validate.prototype.isDecimal = function ( elemtId )
{
	var elemt = this.formObj[elemtId];

	if( !this.isElemtEmpty ( elemt ) )
	{
		if ( !isDecimal ( elemt.value ) ) {
			this.setElemtStyleEror( elemt );
		}
		else {
			this.setStyleColor( elemt, this.hexColorPassed );
		}
	}
}


/**
 * Verifica se a string 'str' é um valor monetário.
 * Permite o uso de separadores de milhar e casas decimais.
 *
 * @param string elemtId: identificador do elemento.
 */
Validate.prototype.isMoney = function ( elemtId )
{
	var elemt = this.formObj[elemtId];

	if( !this.isElemtEmpty ( elemt ) )
	{
		if ( !isMoney ( elemt.value ) ) {
			this.setElemtStyleEror( elemt );
		}
		else {
			this.setStyleColor( elemt, this.hexColorPassed );
		}
	}
}


/**
 * Verifica se a string 'str' é um endereço de e-mail válido.
 *
 * @param string elemtId: identificador do elemento.
 */
Validate.prototype.isEmail = function ( elemtId )
{
	var elemt = this.formObj[elemtId];

	if( !this.isElemtEmpty ( elemt ) )
	{
		if ( !isEmail ( elemt.value ) ) {
			this.setElemtStyleEror( elemt );
		}
		else {
			this.setStyleColor( elemt, this.hexColorPassed );
		}
	}
}


/**
 * Verifica se a string 'str' é um número de telefone válido. 
 * Segue máscara definida pela função 'compPhone' - (NNN) NNNN-NNNN.
 * O DDD é opcional e o traço separador são opcionais.
 *
 * @param string elemtId: identificador do elemento.
 */
Validate.prototype.isPhone = function ( elemtId )
{
	var elemt = this.formObj[elemtId];

	if( !this.isElemtEmpty ( elemt ) )
	{
		if ( !isPhone ( elemt.value ) ) {
			this.setElemtStyleEror( elemt );
		}
		else {
			this.setStyleColor( elemt, this.hexColorPassed );
		}
	}
}


/**
 * Verifica se a string 'str' é um CEP válido.
 * Segue máscara definida pela função 'compCEP' - NNNNN-NNN
 *
 * @param string elemtId: identificador do elemento.
 */
Validate.prototype.isCEP = function ( elemtId )
{
	var elemt = this.formObj[elemtId];

	if( !this.isElemtEmpty ( elemt ) )
	{
		if ( !isCEP ( elemt.value ) ) {
			this.setElemtStyleEror( elemt );
		}
		else {
			this.setStyleColor( elemt, this.hexColorPassed );
		}
	}
}


/**
 * Verifica se a string 'str' é uma data/hora válida.
 *
 * @param string elemtId: identificador do elemento.
 * @param string mask: máscara a ser adotada.
 * ---------------------------------------------------
 * mask:
 * 1. DATE -> DD/MM/YYYY
 * 2. DATETIME -> DD/MM/YYYY HH24:MI
 * 3. DATETIMESEC -> DD/MM/YYYY HH24:MI:SS
 * 4. TIME -> HH24:MI
 * 5. TIMESEC -> HH24:MI:SS
 */
Validate.prototype.isDate = function ( elemtId, mask )
{
	var elemt = this.formObj[elemtId];

	if( !this.isElemtEmpty ( elemt ) )
	{
		if ( !isDate ( elemt.value, mask ) ) {
			this.setElemtStyleEror( elemt );
		}
		else {
			this.setStyleColor( elemt, this.hexColorPassed );
		}
	}
}


/**
 * Verifica se a string 'str' é um CPF válido.
 *
 * @param string elemtId: identificador do elemento.
 */
Validate.prototype.isCPF = function ( elemtId )
{
	var elemt = this.formObj[elemtId];

	if( !this.isElemtEmpty ( elemt ) )
	{
		if ( !isCPF ( elemt.value ) ) {
			this.setElemtStyleEror( elemt );
		}
		else {
			this.setStyleColor( elemt, this.hexColorPassed );
		}
	}
}


/**
 * Verifica se a string 'str' é um CNPJ válido.
 *
 * @param string elemtId: identificador do elemento.
 */
Validate.prototype.isCNPJ = function ( elemtId )
{
	var elemt = this.formObj[elemtId];

	if( !this.isElemtEmpty ( elemt ) )
	{
		if ( !isCNPJ ( elemt.value ) ) {
			this.setElemtStyleEror( elemt );
		}
		else {
			this.setStyleColor( elemt, this.hexColorPassed );
		}
	}
}
