/**
 * Variaveis staticas que auxiliam na construcao da mascara
 */
var MASK_TYPE_NUMBER = 1;
var MASK_TYPE_NORMAL = 0;

/**
 * Variaveis staticas que auxiliam no controle de funcionamento da mascara.
 */
var _MASK_POSITION_START_CURSOR = 0;

/** Fun??o responsavel por criacao da mascara. Para o funcionamento da mascara ? necessario utilizar alguns padr?es que serao descritos abaixo.
 * Os padr?es utilizados s?o espelhados nos padroes java. Para o completo funcionamento da mascara, s?o interceptados os metodos onKeyDown,
 * onFocus, onClick. 
 *
 * Paterns: (Normal)
 * 		# -> apenas numeros.
 * 		A -> letras e numeros.
 * 		? -> apenas letras.
 * 		* -> qualquer caracter, incluindo acentos e caracteres especiais.
 *
 * Paterns: (Number)
 * 		0 -> valor obrigatorio, inclui 0 caso n?o preenchido.
 * 		# -> valor n?o obrigatorio.
 * 		, -> separador de milhar.
 * 		. -> separador de decimal.

 * @param field <b>Campo que voc? deseja adicionar a mascara</b>
 * @param type  <b>Tipo de mascara que voce deseja aplicar, para auxilar foi criado algumas variaveis static, veja, MASK_TYPE_*</b>
 * @param patern <b>Veja acima os paterns por tipo</b>
 * 
 * @author Samuel Herrmann 
 */
function newMask(field, type, patern) {
	//SE FOR INTERNET EXPLORER CRIA A FUNCAO setSelectionRange NO CAMPO EM QUE ESTA ESTA SE ADICIONANDO A MASCARA.
	if (isIE) {
		field.setSelectionRange = _mask_setSelectionRange;
	}
	//ADICIONA OS CONTROLE DE EVENTO NECESSARIOS PARA O CORRETO FUNCIONAMENTO DO CAMPO
	//O COMPORTAMENTO INICIAL PODE E DIFERENTE, DEPENDENDO DO TIPO DE MASCARA ESCOLIDA.
	field.onkeydown = _mask_keyDown;
	if (type == MASK_TYPE_NORMAL) {
		field.onfocus   = _mask_selectFirstChar;
		field.onclick   = _mask_selectFirstChar;
	}else{
		field.onfocus   = _mask_selectLastChar;
		field.onclick   = _mask_selectLastChar;
	}
		
	if (type != MASK_TYPE_NUMBER) {

		var paternsValid = "#A?*";
		
		//CRIA A MASCARA INICIAL DE ACORDO COM O PATERN E TIPO DE MASCARA
		var startValue = "";
		for (var x = 0; x < patern.length; x++) {
			var charNow = patern.charAt(x);
			if (paternsValid.indexOf(charNow) == -1) {
				startValue+= charNow;
			}else{
				startValue+= "_";
			}
		}

		//SETA ATRIBUTOS INICIAS DO CAMPO COM AS DEVIDAS PROPRIEDADES DA MASCARA
		field.startValue = startValue;
		field.patern = patern;
		field.maxLength = patern.length;
		
		//SETANDO VALOR INICIAL
		field.value = startValue;
	}else{
		
		//SETA ATRIBUTOS INICIAS DO CAMPO COM AS DEVIDAS PROPRIEDADES DA MASCARA
		field.patern = patern.reverse();
		field.maxLength = patern.length;
		field.style.textAlign = "right";
	}
	
	//ADICIONA O TYPE DA MASCARA NAS PROPRIEDADES DO CAMPO
	field.typeMask = type;
		
}

/** <B>FUNCAO INTERNA (N?o usar)</B>
 *
 * <B>NORMAL:</B>
 * Simula o comportamento das teclas, preenchendo valores quando esta de acordo com o patern e pulando para o proximo campo. Simula o 
 * comportametno das setas, delete e backspace apagando valores dos dois ultimos itens citados e reposiciona o cursor de acordo com
 * o sentido das mesmas. (delete ->, <- backspace).
 *
 * @return event <b>Essa variavel ? passada apenas pelo firefox</b>
 */	
 function _mask_keyDown(event) {
	
	//PEGA O KeyCode DA TECLA ACIONADA.
	var keyCode
	if (isIE) {
		keyCode = window.event.keyCode;
	}else{
		keyCode = event.which;
	}
	
	//ALTERA VALORES PARA N?O PRECISAR VALIDAR VARIACOES.
	keyCode = (keyCode >= 96 && keyCode <= 105) ? keyCode - 48 : keyCode;
	keyCode = (keyCode >= 97 && keyCode <= 122) ? keyCode - 32 : keyCode;

	//SE FOR TAB SAI DO CAMPO E N?O FAZ MAIS NADA
	if (keyCode == 9) {
		return true;
	}
	
	if (this.typeMask == MASK_TYPE_NORMAL) {

		//PEGA OS CARACTER QUE REPRESENTA A POSICAO ATUAL.
		var charType = this.patern.charAt(_MASK_POSITION_START_CURSOR);
		
		//VALIDA SE A TECLA ESTA DE ACORDO PATERN DESEJADO.	
		var flag = _mask_validCharType(keyCode,charType);
		
		if (flag) {
	
			//ADICIONA O VALOR DA TECLA NO TEXTO E PULA PARA O PROXIMO CAMPO.
			//ESSES PROCEDIMENTOS SO DEVEM SER EXECUTADOS QUANDO N?O FOREM TAB.
			if (keyCode != 9) {
				this.value = this.value.substring(0,_MASK_POSITION_START_CURSOR) + String.fromCharCode(keyCode) + this.value.substring(_MASK_POSITION_START_CURSOR + 1,this.value.length);
				_mask_selectNextChar(_MASK_POSITION_START_CURSOR,this);
			}
			
		}else{
			
			//SE A TECLA FOR 'delete' OU 'backspace' LIMPA A POSICAO ONDE O CURSOR ESTA.
			if (keyCode == 8 || keyCode == 46) {
				this.value = this.value.substring(0,_MASK_POSITION_START_CURSOR) + "_" + this.value.substring(_MASK_POSITION_START_CURSOR + 1,this.value.length);
			}
			
			if ((keyCode == 37 || keyCode == 8) && _MASK_POSITION_START_CURSOR >= 0) {
	
				//SE A TECLA FOR SETA ESQUERDA OU BACKSPACE VAI PARA A POSICAO ANTERIOR.
				_mask_selectPreviousChar(_MASK_POSITION_START_CURSOR,this);
				
			}else if ((keyCode == 39 || keyCode == 46)&& _MASK_POSITION_START_CURSOR < this.maxLength) {
	
				//SE A TECLA FOR SETA DIREITA OU DELETE VAI PARA A PROXIMA POSICAO.		
				_mask_selectNextChar(_MASK_POSITION_START_CURSOR,this);
				
			}
		}
	
	}else{ 

		//VALIDA SE A TECLA ? UM NUMERO.	
		var flag = _mask_validCharType(keyCode,"#");
		
		//DESCOBRE O NUMERO DE CASAS DECIMAIS
		var decimalPoint = this.patern.indexOf(".");
		
		var newValue = "";
		
		if (flag) {

			//SE O CAMPO JA ESTIVER COM O TAMANHO MAXIMO N?O ADICIONA A TECLA
			if (this.value.length == this.patern.length)
				return false;
			
			if (decimalPoint != -1 && this.value.substring(0,1) == "0") {

				//SE AINDA TIVER ZEROS A FRENTE DA VIRGULA ELE REMOVE UM E ADICIONA A TECLA NO FINAL
				newValue = this.value.substring(1) +  String.fromCharCode(keyCode);
				
			}else{
				
				//ADICIONA A TECLA NA ULTIMA LETRA
				newValue = this.value +  String.fromCharCode(keyCode);
				
			}
				
		}else if (keyCode == 8 || keyCode == 46) {

			//CASO A TECLA FOR DELETE OU BACKSPACE REMOVE O PRIMEIRO NUMERO
			newValue = this.value.substring(0,this.value.length - 1);
			
		}else{ 

			//CASO CONTRARIO RETORNA FALSO
			return false;
		}
		
		var zeros = "000000000000";
		
		//REVERTE O CONTEUDO DO CAMPO REMOVENDO AS VIRGULAS E PONTOS
		newValue = newValue.reverse(true);
		
		if (zeros.indexOf(newValue) == -1) {
			//SE N?O FOR APENAS ZEROS
			
			//SE HOUVER MENOS NUMEROS QUE CASAS DECIMAIS, ? ADICIONADO ZEROS A FRENTE
			if (newValue.length <= decimalPoint)
				newValue+= zeros.substring(0,(decimalPoint + 1)- newValue.length);
				
			//ADICIONA A VIRGULA PARA DIVIDIR AS CASAS DECIMAIS, SEMPRE QUE O VALOR FOR DIFERENTE DE VAZIO HAVERA CASAS DECIMAIS
			if (decimalPoint != -1)
				newValue = newValue.substring(0,decimalPoint) + "," + newValue.substring(decimalPoint);
			
			//PROCURA A POSICAO DO PONTO DE MILHAR
			decimalPoint = this.patern.indexOf(",",decimalPoint + 1);	
			
			
			if (decimalPoint < newValue.length && decimalPoint != -1) {
				//ENQUANTO O POSICAO DE MILHAR ENCONTRADA FOR MENOR QUE A QUANTIDADE DE NUMERO NO CAMPO, ADICIONA O PONTO
				do {
					
					//ADICIONA O PONTO
					newValue = newValue.substring(0,decimalPoint) + "." + newValue.substring(decimalPoint);		
			
					//PROCURA A POSICAO DO PROXIMO PONTO
					decimalPoint = this.patern.indexOf(",",decimalPoint + 1);

				}while (decimalPoint < newValue.length && decimalPoint != -1);
			}

			//REVERTE O VALOR E PREENCHE O CAMPO
			this.value = newValue.reverse();
			
		}else{

			//SE SO HOUVER ZEROS NO VALOR ELE LIMPA O CAMPO
			this.value = "";
			
		}
	}

	//SEMPRE RETORNA FALSE, TODO O MECANISMO ? MANIPULADO NA M?O
	return false;
}

/** <B>FUNCAO INTERNA (N?o usar)</B>
 *
 * Valida se a tecla presionada esta dentro dos tipos de caractes validos informados no patern da mask. Para
 * mais informacoes sobre o patern veja o javadoc do metodo newMask.
 *
 * @param keyCode <b>Codigo da tecla presionada</b>
 * @param charType <b>Caracter do patern de acordo com a posicao do cursor</b>
 *
 * @return  
 */	
function _mask_validCharType(keyCode, charType) {

	//SEMPRE RETORNA TRUE QUANDO A TECLA FOR 'TAB'
	if (keyCode == 9)
		return true;
		
	if (charType == "#") {
		//VALIDA SE A TECLA ? UM NUMERO
		return (keyCode >= 48 && keyCode <= 57);
	}else if (charType == "?") {
		//VALIDA SE A TECLA ? UMA LETRA
		return (keyCode >= 65 && keyCode <= 90);
	}else if (charType == "A") {
		//VALIDA SE A TELCA ? UM NUMERO OU UMA LETRA
		return ((keyCode >= 65 && keyCode <= 90) || (keyCode >= 48 && keyCode <= 57));
	}else if (charType == '*') {
		//VALIDA SE A TECLA ? QUALQUER CARACTER QUE N?O SEJA DE CONTROLE
		return (keyCode > 48);
	}else{
		return false;
	}
}

/** <B>FUNCAO INTERNA (N?o usar)</B>
 *
 * Seta o cursor para a PROXIMA posicao, de acordo com a posicao atual. Iguinorando caracteres da mascara.
 *
 *	@param positionOld <b>Deve ser informada a posicao atual do cursor</b>
 *  @param field <b>Campo que voc? deseja movimentar o cursor</b> 
 */
function _mask_selectNextChar(positionOld, field) {
	var value = field.startValue;
	var position = positionOld;
	
	//ENCONTRA A PROXIMA POSICAO VALIDA SE N?O ENCONTRAR PEGA O POSICAO ATUAL
	for(var x = positionOld + 1; x < value.length; x++) {
		if (value.charAt(x) == "_") {
			position = x;
			break;
		}
	}
	
	//SELECIONA O CARACTER
	field.setSelectionRange(position, position + 1);
	_MASK_POSITION_START_CURSOR = position;
}

/** <B>FUNCAO INTERNA (N?o usar)</B>
 *
 * Seta o cursor para a posicao ANTERIOR, de acordo com a posicao atual. Iguinorando caracteres da mascara.
 *
 *	@param positionOld <b>Deve ser informada a posicao atual do cursor</b>
 *  @param field <b>Campo que voc? deseja movimentar o cursor</b>
 */	
function _mask_selectPreviousChar(positionOld, field) {
	var value = field.startValue;
	var position = positionOld;
	
	//ENCONTRA A PROXIMA POSICAO VALIDA SE N?O ENCONTRAR PEGA O POSICAO ATUAL	
	for(var x = positionOld - 1; x >= 0; x--) {
		if (value.charAt(x) == "_") {
			position = x;
			break;
		}
	}
	
	//SELECIONA O CARACTER
	field.setSelectionRange(position, position + 1);
	_MASK_POSITION_START_CURSOR = position;
}

/** <B>FUNCAO INTERNA (N?o usar)</B>
 *	
 * Seta o cursor na PRIMEIRA posicao VAZIA, se n?o haver nenhuma posicao vazia seta no primeiro caracter.
 *
 *	@param positionOld <b>Deve ser informada a posicao atual do cursor</b>
 *  @param field <b>Campo que voc? deseja movimentar o cursor</b>
 */	
function _mask_selectFirstChar() {
	var value = this.value;
	var position = 0;
	
	//ENCONTRA A PROXIMA POSICAO VALIDA SE N?O ENCONTRAR PEGA O POSICAO ATUAL
	for(var x = 0; x < value.length; x++) {
		if (value.charAt(x) == "_") {
			position = x;
			break;
		}
	}
	
	//SELECIONA O CARACTER
	this.setSelectionRange(position, position + 1);
	_MASK_POSITION_START_CURSOR = position;
}

/** <B>FUNCAO INTERNA (N?o usar)</B>
 *
 * Seta o cursor para a ULTIMA POSICAO. Iguinorando caracteres da mascara.
 * Essa fun??o e utilizada para o tipo NUMBER, pois sempre no tipo NUMBER o cursor fica no final do campo.
 *
 *	@param positionOld <b>Deve ser informada a posicao atual do cursor</b>
 *  @param field <b>Campo que voc? deseja movimentar o cursor</b>
 */	
function _mask_selectLastChar() {
	var value = this.value;
	var position = value.length;
	
	this.setSelectionRange(position, position);
	
	_MASK_POSITION_START_CURSOR = position;
}

/** <B>FUNCAO INTERNA (N?o usar)</B>
 *	
 * Essa fun??o ? utilizada apenas no browser Internet Explorer para implementar a funcao setSelectionRange que ja ? nativa no firefox.
 * Ela seleciona um texto de uma posicao inicial at? uma posicao final. 
 *
 * @param star <b>Posicao inicial da selecao</b>
 * @param end  <b>Posicao final da selecao</b>
 */
function _mask_setSelectionRange(start,end) {
	var Range = this.createTextRange();
	var typeSelection = "character";
	
	Range.moveStart(typeSelection, start);
	Range.moveEnd(typeSelection, (end - this.value.length));
	Range.select(start,end);
	
	this.focus();
}