/******************************************************
Arquivo para funções javascript que tenham como objetivo o 
mascaramento.

Lista de funções:
  - addEvent: Adiciona uma função que será disparada quando ocorrer determinado evento no objeto. 
  - removeEvent: Remove um listener previamente adicionado em um objeto.
  - autoTab: A função irá adicionar a tabulação automática em todos os inputs.
  - alteraCssForm: Altera o label e a borda do campo especificado de acordo com o retorno da validação. 
  - trim: Remove caracteres na esquerda, direita ou ambos os lados da string.
  - maxLength: Controla o tamanho máximo de um campo removendo os excedentes.  
  - maskInput: Adiciona máscara a um campo. 
  - maskDec: Adiciona máscara (apenas para campos monetários e valor decimal) a um campo. 
  - resetForm: Reseta dados de um formulário.

TODO:
  - Fazer o MaskInput aceitar array, para executar ele apenas uma vez para vários campos.
    Hoje para cada campo precisa ser criado um MaskInput
******************************************************/


/******************************************************
formatCurrency(field: HTMLInput, [floatPoint: Integer = 2], [decimalSep: String = ","], [thousandsSep: String = "."]): String 
Formata o input de forma que ele assuma o comportamento de um campo monetário. 
- field: Campo que receberá a formatação 
- floatPoint: Número de casas decimais 
- decimalSep: String representando o separador decimal 
- thousandsSep: String representando o separador de milhar 

Exemplo de uso:
maskDec(f.salario, 2);
******************************************************/
function maskDec(o, n, dig, dec){
    o.c = !isNaN(n) ? Math.abs(n) : 2;
    o.dec = typeof dec != "string" ? "," : dec, o.dig = typeof dig != "string" ? "." : dig;
    addEvent(o, "keypress", function(e){
        if(e.key > 47 && e.key < 58){
            var o, s, l = (s = ((o = this).value.replace(/^0+/g, "") + String.fromCharCode(e.key)).replace(/\D/g, "")).length, n;
            if(o.maxLength + 1 && l >= o.maxLength) return false;
            l <= (n = o.c) && (s = new Array(n - l + 2).join("0") + s);
            for(var i = (l = (s = s.split("")).length) - n; (i -= 3) > 0; s[i - 1] += o.dig);
            n && n < l && (s[l - ++n] += o.dec);
            o.value = s.join("");
        }
        e.key > 30 && e.preventDefault();
    });
}

/******************************************************
maskInput(field: HTMLInputElement, mask: String): void 
Adiciona máscara a um campo. 
- field: campo que vai receber a máscara 
- mask: máscara que será aplicada 

Regras Padrões
- a = A-Z e 0-9 
- A = A-Z, acentos e 0-9 
- 9 = 0-9 
- C = A-Z e acentos 
- c = A-Z 
- * = qualquer coisa 

Regras Especiais
- E = (Except) exceção 
- O = (Only) somente 

Criação de Máscaras
- Máscara simples: nesse tipo de máscara o usuário pode digitar no máximo a mesma 
  quantidade de caracteres que a máscara contém. 
Exemplo: 
  Telefone = (99)9999-9999 
  Data = 99/99/9999 

Máscara especial "regra^exceções": esse tipo de máscara é composto por 2 partes, 
separadas por "^", o lado esquerdo especifica a regra e o direito as exceções para a regra selecionada. 
Exemplo: 
  9^abc = a regra é aceitar somente números "9" e a exceção são os caracteres a, b e c 
  c^123 = aceita somente caracteres de a-z e a exceção são os números 1, 2 e 3 

Uso das regras especiais: ela é semelhante a máscara especial, porém o lado esquerdo 
tem um significado diferente, podendo ser "E" (qualquer coisa, exceto...) ou "O" (somente...) 
Exemplo: 
  E^abc: aceita qualquer coisa, menos a, b e c 
  O^123: só permite os caracteres 1, 2 e 3

Exemplos de uso:
maskInput(f.nome, "C^ ");
maskInput(f.dtnasc, "99/99/9999");
maskInput(f.telefone, "(99) 9999-9999");
maskInput(f.email, "a^@-_.");
maskInput(f.cpf, "999.999.999-99");
maskInput(f.cnpj, "99.999.999/9999-99"); 
maskInput(f.edta0116_numero, "9999999999");  
******************************************************/
function maskInput(f, m){
    function mask(e){
        var patterns = {"1": /[A-Z]/i, "2": /[0-9]/, "4": /[À-ÿ]/i, "8": /./ },
            rules = { "a": 3, "A": 7, "9": 2, "C":5, "c": 1, "*": 8};
        function accept(c, rule){
            for(var i = 1, r = rules[rule] || 0; i <= r; i<<=1)
                if(r & i && patterns[i].test(c))
                    break;
                return i <= r || c == rule;
        }
        var k, mC, r, c = String.fromCharCode(k = e.key), l = f.value.length;
        (!k || k == 8 ? 1 : (r = /^(.)\^(.*)$/.exec(m)) && (r[0] = r[2].indexOf(c) + 1) + 1 ?
            r[1] == "O" ? r[0] : r[1] == "E" ? !r[0] : accept(c, r[1]) || r[0]
            : (l = (f.value += m.substr(l, (r = /[A|9|C|\*]/i.exec(m.substr(l))) ?
            r.index : l)).length) < m.length && accept(c, m.charAt(l))) || e.preventDefault();
    }
    for(var i in !/^(.)\^(.*)$/.test(m) && (f.maxLength = m.length), {keypress: 0, keyup: 1})
        addEvent(f, i, mask);
};

/******************************************************
maxLength(campo: String, tammax: Integer): void
Controla o tamanho máximo de um campo removendo os excedentes.
- campo: Objeto do campo
- tammax: Tamanho máximo que deve ter o campo
******************************************************/
function maxLength(campo, tammax) {
  if (campo.value.length > tammax) campo.value = campo.value.substr(0,tammax);
}

/******************************************************
autoTab(void): void 
Apenas chame a função depois das tags <form> ou então no evento onload. 
A função irá adicionar a tabulação automática em todos os inputs que tiverem 
o atributo maxlenght setado. Os inputs devem estar dentro de uma tag form, 
caso contrário eles não receberão o comportamento. 
******************************************************/
function autoTab(){
    var c = 0, lastKey = function(e){c = e.key;}, next = function(e){
        var i, j, f = (e = e.target).form.elements, l = e.value.length, m = e.maxLength;
        if(c && m > -1 && l >= m){
            for(i = l = f.length; f[--i] != e;);
            for(j = i; (j = (j + 1) % l) != i && (!f[j].type || f[j].disabled || f[j].readOnly || f[j].type.toLowerCase() == "hidden"););
            j != i && f[j].focus();
        }
    };
    for(var f, i = (f = document.forms).length; i; addEvent(f[--i], "keyup", next), addEvent(f[i], "keypress", lastKey));
};

/******************************************************
alteraCssForm(string,boolean): void 
- campo: nome do campo
- valido: <true|false> resultado da validação
Altera o label e a borda do campo especificado de acordo com o retorno
da validação. 
******************************************************/
function alteraCssForm(campo,valido,css) {
  if(!css) css = 'FORM';
  if(valido) {
    document.getElementById('lbl_'+campo).className = css+'_label';
    f[campo].className = css+'_campo';
  } else {
    document.getElementById('lbl_'+campo).className = css+'_label_erro';
    f[campo].className = css+'_campo_erro';  
  }
}
/**
* Altera css de um elemento html.
* id string - id do elemento.
* css string - nome da classe css.
* @return boolean
*/
function alteraCss(id,css) {
	try{
		document.getElementById(id).className = css;
	}catch(e){
		return false;
	}
	return true;
}

/******************************************************
String.prototype.trim([chars: String = " "], [type: Integer = 0]): String
Remove caracteres na esquerda, direita ou ambos os lados da string.
- caracteres: sequência de caracteres que deverão ser removidos
- type: especifica onde irá ocorrer o trim, possíveis valores são:
          - 0 = remove em ambos os lados
          - 1 = remove caracteres na esquerda
          - 2 = remove caracteres na direita
******************************************************/
String.prototype.trim = function(c, t){
    return c = "[" + (c == undefined ? " " : c.replace(/([\^\]\\-])/g, "\\\$1")) + "]+",
    this.replace(new RegExp((t != 2 ? "^" : "") + c + (t != 1 ? "|" + c + "$" : ""), "g"), "");
};

/**
* Deixa somente numeros na string.
* @return string
*/
String.prototype.sonumero = function(){
	return this.replace(/[^0-9]/gi,"");
};


/******************************************************
addEvent(object: Object, event: String, handler: Function(e: Event): Boolean, [scope: Object = object]): Boolean 
Adiciona uma função que será disparada quando ocorrer determinado evento no objeto. 
- object: objeto que receberá o listener 
- event: nome do evento sem o prefixo "on" (click, mouseover, ...) 
- handler: função que será chamada quando o evento ocorrer, será enviado como argumento 
              para esta função o objeto de evento, que além das propriedades normais, *sempre* irá conter: 
              - target: objeto que gerou o evento 
              - key: código do caractere em eventos de teclado 
              - stopPropagation: método para evitar a propagação do evento 
              - preventDefault: método para evitar que a ação default ocorra. O preventDefault pode ser emulado retornando "false" na função 
- scope: escopo (quem o "this" irá referenciar dentro do handler) que será usado quando a função for chamada, o default é o objeto no primeiro argumento 
******************************************************/
function addEvent(o, e, f, s){
	try{
    var r = o[r = "_" + (e = "on" + e)] = o[r] || (o[e] ? [[o[e], o]] : []), a, c, d;
    r[r.length] = [f, s || o], o[e] = function(e){
        try{
            (e = e || event).preventDefault || (e.preventDefault = function(){e.returnValue = false;});
            e.stopPropagation || (e.stopPropagation = function(){e.cancelBubble = true;});
            e.target || (e.target = e.srcElement || null);
            e.key = (e.which + 1 || e.keyCode + 1) - 1 || 0;
        }catch(f){}
        for(d = 1, f = r.length; f; r[--f] && (a = r[f][0], o = r[f][1], a.call ? c = a.call(o, e) : (o._ = a, c = o._(e), o._ = null), d &= c !== false));
        return e = null, !!d;
    }
  }catch(e){
  	//alert('Erro: '+e.message);
  }
};

/******************************************************
removeEvent(object: Object, event: String, handler: function(e: Event): Boolean, [scope: Object = object]): Boolean 
Remove um listener previamente adicionado em um objeto e retorna true em caso de sucesso. 
- object: objeto que recebeu o listener 
- event: nome do evento sem o prefixo "on" (click, mouseover, ...) 
- handler: mesma função que foi atribuida no addEvent 
- scope: escopo em que a função foi adicionada, caso você tenha fornecido um escopo diferente no addEvent, 
            é necessário que você passe como parâmetro o mesmo objeto, 
            caso contrário a remoção do evento não será realizada 
******************************************************/
function removeEvent(o, e, f, s){
    for(var i = (e = o["_on" + e] || []).length; i;)
        if(e[--i] && e[i][0] == f && (s || o) == e[i][1])
            return delete e[i];
    return false;
};

/**
* Limpa dados de um formulário.
*
* @param frm : object form  - objeto do tipo formulário.
*/
function resetForm(frm){
	try{  
	  // Para cada um dos elementos do formulário
	  for (var i=0;i<frm.elements.length;i++) {
			if(frm.elements[i].type != 'button'){
		    switch(frm.elements[i].type){		    
		    	case 'radio':
		    		frm.elements[i].checked = false;
		    	break;
		    	
		    	case 'checkbox':
		    		frm.elements[i].checked = false;
		    	break;
		    	
		    	case 'select-multiple':
		    		frm.elements[i].value=0;
		    	break;
		    	
		    	case 'select-one':
		    		frm.elements[i].value=0;
		    	break;	    	
		    	
		    	case 'select':
		    		frm.elements[i].value=0;
		    	break;	    	
	
		    	case 'text':
		    		frm.elements[i].value = '';
		    	break;	   
		    	
		    	case 'password':
		    		frm.elements[i].value = '';
		    	break;	 
		    	
		    	case 'hidden':
		    		frm.elements[i].value = '';
		    	break;	 	    		    	 
		    }
	    }
	  }
	}catch(e){
		alert(msgErroResetForm + ': ' + e.message);
	}
}


/**
* Muda propriedade display do objeto.
* @param string  id - propriedade id do elemento
* @param boolean vl - 1 será mudado para block e 0 para none
*/
function mudaDisplay(id,vl){
	try{
		 st = document.getElementById(id).style;
		 if(vl)
		  st.display  = '';
		 else
		  st.display  = 'none';
	}catch(e){
		alert('Erro: '+e.message);
	}
}

/**
* Método para mover um option de um campo select para outro campo select.
* @return void.
*/
function adicionaRemove(cpSelO,cpSelD) {
  if (cpSelO.selectedIndex>-1) {
    cpSelD.options[cpSelD.length]=new Option(cpSelO.options[cpSelO.selectedIndex].text, cpSelO.options[cpSelO.selectedIndex].value);
    cpSelO.options[cpSelO.selectedIndex]=null;
  }  
}

/**
* Método para mover todos os options de um campo select para outro campo select.
* @return void.
*/
function adicionaRemoveAll(cpSelO,cpSelD) {
	for(i=0;i < cpSelO.length; i++){
    cpSelD.options[cpSelD.length]=new Option(cpSelO.options[i].text, cpSelO.options[i].value);
	}
	cpSelO.length = 0;
}

function Esconder(sp) {
  var obj = document.getElementById(sp);
  obj.style.display = 'none';
  obj.style.visibility = 'hidden';
}

function Mostrar(sp) {
  var obj = document.getElementById(sp);
  obj.style.display = "block";
  obj.style.visibility = 'visible';
}

/**
* Método para retornar values de options de um select no formato de string separado por ;
* @return string
*/
function optionsToString(cp){
	var str = false;
	for(i=0;i<cp.length;i++){
		str = (str==false) ? cp.options[i].value :  str+';'+cp.options[i].value;
	}
	return str;
}
