// form_val_v3.js
// Validaçao de formulários
// 
// Versão: 3.3
// Utilizar com Javascript 1.2
//
// * Adicionado opção de campos opcionais (verificação se for preenchido)
//   Útil, por exemplo, para campos textos numéricos onde se preenchido, 
//   devem estar num certo intervalo
//
// * Adicionado verificaçao de CNPJ e CPF
//
//   _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//  _/  V  A  R  I  A  B  L  E  S   _/ 
// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

var defaultLang = 'pt_BR';

var msgs = new Object();

msgs['pt_BR'] = new Object();
msgs['pt_BR']['MandatoryField']  = 'O campo "<!--label-->" é de preenchimento obrigatório.';
msgs['pt_BR']['FileFieldEmpty']  = 'É necessário especificar um arquivo no campo "<!--label-->".';
msgs['pt_BR']['ValidFileTypes']  = 'Os tipos de arquivos válidos são: <!--val1-->';
msgs['pt_BR']['InvalidEmail']    = 'O campo "<!--label-->" parece não conter um e-mail válido.';
msgs['pt_BR']['InvalidRGBColor'] = 'O campo "<!--label-->" parece não conter uma cor no formato RGB válida.';
msgs['pt_BR']['IntegerField']    = 'O campo "<!--label-->" deve conter um número inteiro.';
msgs['pt_BR']['FieldMinVal']     = 'O valor mínimo do campo "<!--label-->" é <!--val1-->.';
msgs['pt_BR']['FieldMaxVal']     = 'O valor máximo do campo "<!--label-->" é <!--val2-->.';
msgs['pt_BR']['NumberField']     = 'O campo "<!--label-->" deve conter um número.';
msgs['pt_BR']['FieldMinLen']     = 'O campo "<!--label-->" deve conter pelo menos <!--val1--> caracteres.';
msgs['pt_BR']['FieldMaxLen']     = 'O campo "<!--label-->" deve conter no máximo <!--val2--> caracteres.';
msgs['pt_BR']['SelectAnOption']  = 'Escolha uma opção de "<!--label-->".';
msgs['pt_BR']['MustBeChecked']   = '"<!--label-->" deve estar selecionado.';
msgs['pt_BR']['InvalidCNPJF']    = "\"<!--label-->\" não contém um número de CNPJ válido.\nPor favor confira o número e utilize o formato XX.XXX.XXX/XXXX-XX";
msgs['pt_BR']['InvalidCNPJU']    = "\"<!--label-->\" não contém um número de CNPJ válido.\nPor favor confira o número e preencha o campo apenas com números.";
msgs['pt_BR']['InvalidCPFF']     = "\"<!--label-->\" não contém um número de CPF válido.\nPor favor confira o número e utilize o formato XXX.XXX.XXX-XX";
msgs['pt_BR']['InvalidCPFU']     = "\"<!--label-->\" não contém um número de CPF válido.\nPor favor confira o número e preencha o campo apenas com números.";

msgs['en_US'] = new Object();
msgs['en_US']['MandatoryField']  = 'The field "<!--label-->" is mandatory.';
msgs['en_US']['FileFieldEmpty']  = 'Please specify a file in "<!--label-->".';
msgs['en_US']['ValidFileTypes']  = 'Valid file types are: <!--val1-->';
msgs['en_US']['InvalidEmail']    = '"<!--label-->" doesn\'t seem to have a valid e-mail address.';
msgs['en_US']['InvalidRGBColor'] = '"<!--label-->" doesn\'t seem to have a valid RGB format color.';
msgs['en_US']['IntegerField']    = '"<!--label-->" must be an integer.';
msgs['en_US']['FieldMinVal']     = 'The minimum value of "<!--label-->" is <!--val1-->.';
msgs['en_US']['FieldMaxVal']     = 'The maximum value of "<!--label-->" is <!--val2-->.';
msgs['en_US']['NumberField']     = '"<!--label-->" must be a number.';
msgs['en_US']['FieldMinLen']     = '"<!--label-->" must have at least <!--val1--> chars.';
msgs['en_US']['FieldMaxLen']     = '"<!--label-->" must have up to <!--val2--> chars.';
msgs['en_US']['SelectAnOption']  = 'Select a "<!--label-->" option.';
msgs['en_US']['MustBeChecked']   = '"<!--label-->" must be checked.';
msgs['en_US']['InvalidCNPJF']    = "\"<!--label-->\" is not a valid Brazilian CNPJ number.\nPlease re-type it using the XX.XXX.XXX/XXXX-XX format";
msgs['en_US']['InvalidCNPJU']    = "\"<!--label-->\" is not a valid Brazilian CNPJ number.\nPlease re-type it using only numbers.";
msgs['en_US']['InvalidCPFF']     = "\"<!--label-->\" is not a valid Brazilian CPF number.\nPlease re-type it using the XXX.XXX.XXX-XX format";
msgs['en_US']['InvalidCPFU']     = "\"<!--label-->\" is not a valid Brazilian CPF number.\nPlease re-type it using only numbers.";



//   _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//  _/  G  E  N  E  R  A  L    F  U  N  C  T  I  O  N  S  _/ 
// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

function getLang(lang) {
  
  for (var i in msgs) {
    if (i == lang) return i;
  }

  return defaultLang;

}


function getMsg(definicao, lang, qual) {

  if (definicao.msg && definicao.msg != '') return definicao.msg;

  var msg = msgs[lang][qual];
  msg = msg.replace(/<\!--label-->/, definicao.label);
  msg = msg.replace(/<\!--val1-->/, definicao.val1);
  msg = msg.replace(/<\!--val2-->/, definicao.val2);

  return msg;

}



// verifica se a entrada é um e-mail válido
function isEmail (str) {

  if (str == null) return false;

  if (str.search(/^\w+((-\w+)|(\.\w+))*\@\w+((\.|-)\w+)*\.\w+$/) != -1)
    return true;
  else
    return false;
                    
}


// verifica se a entrada é uma cor RGB válida
function isRGBColor(str) {

  var hexa = '0123456789AaBbCcDdEeFf';

  var sIdx = -1;

  if (str.length == 6) sIdx = 0;
  else if (str.length == 7 && str.charAt(0) == '#') sIdx = 1;

  if (sIdx == -1) return false;

  for (i=sIdx; i<str.length; i++) {
    if (hexa.indexOf(str.charAt(i)) == -1) return false; 
  }

  return true;
}



// verifica se o campo contém algum caractere alem de espaços
function isBlank (str) {

  if (str == null) return false;

  if (str.search(/^\W*$/) != -1)
    return true;
  else 
    return false;

}


// verifica se a string é um inteiro
function isInteger (str) {

  if (str == null) return false;

  if (str.search(/^-*[0123456789]+$/) != -1)
    return true;
  else 
    return false;

}


// verifica se a string é um float
function isFloat (str) {

  if (str == null) return false;

  if (str.search(/^-*[0123456789]*\.*[0123456789]+$/) != -1)
    return true;
  else 
    return false;

}


// verifica se a extensao do arquivo e' valida
function isValidFileType(definicao, str) {

  var types = definicao.val1.split(',');
  
  var str_len = str.length;
  
  for (var i=0; i<types.length; i++) {

    var ext_len = types[i].length;
    
    if (types[i] == str.substr((str_len-ext_len), ext_len)) 
      return true;
  
  }
  
  return false;
  
}

//------------------------
// VERIFICAÇÃO DE CNPJ
// original em: http://www.imasters.com.br/artigo.php?cn=2451&cc=78
//------------------------

function onlyDigits(str)
{
  str = str.replace(/[^0-9]/g, '');
  return str;
}
	

// verificação apenas dígitos: AABBBCCCDDDDEE
function validaCNPJ(CNPJ)
{

  if (CNPJ == null) return false;
		
  if (CNPJ.length < 12) return false;
  var a = [];
  var b = new Number;
  var c = [6,5,4,3,2,9,8,7,6,5,4,3,2];

  for (i=0; i<12; i++){
    a[i] = CNPJ.charAt(i);
    b += a[i] * c[i+1];
  }

  if ((x = b % 11) < 2) { a[12] = 0 } else { a[12] = 11-x }

  b = 0;
  for (y=0; y<13; y++) {
    b += (a[y] * c[y]); 
  }
  
  if ((x = b % 11) < 2) { a[13] = 0; } else { a[13] = 11-x; }
  
  if ((CNPJ.charAt(12) != a[12]) || (CNPJ.charAt(13) != a[13])){
    return false;
  }

    return true;
	
}

// verificação formato padrão: AA.BBB.CCC/DDDD-EE
function isCNPJ(CNPJ) {

  if (CNPJ == null) return false;
  if ( CNPJ.length != 18 )
  {
    if (CNPJ.length < 18) return false;
    if (CNPJ.length == 19 && CNPJ.charAt(0) == '0') CNPJ = CNPJ.substring(1);
    else return false;
  }
		
  if ((CNPJ.charAt(2) != ".") || (CNPJ.charAt(6) != ".") || (CNPJ.charAt(10) != "/") || (CNPJ.charAt(15) != "-"))
  {
    return false;
  }

  return validaCNPJ(onlyDigits(CNPJ));

}


//------------------------
// VERIFICAÇÃO DE CPF
// original em http://www.imasters.com.br/artigo.php?cn=664&cc=2
//------------------------

// verifica apenas dígitos: AAABBBCCCDD
function validaCPF(st2)
{

  if (st2 == null) return false;
		
  if ( st2.length != 11) 
  {
    if (st2.length == 10) st2 = '0' + st2;
    else if (st2.length == 9) st2 = '00' + st2;
    return false;
  }

  digito1 = st2.substring(9,10);
  digito2 = st2.substring(10,11);
  digito1 = parseInt(digito1,10);
  digito2 = parseInt(digito2,10);
  sum = 0; mul = 10;
  
  for (i = 0; i < 9 ; i++) 
  {
    digit = st2.substring(i,i+1);
    tproduct = parseInt(digit ,10) * mul;
    sum += tproduct;
    mul--;
  }
  
  dig1 = ( sum % 11 );
  if ( dig1==0 || dig1==1 ) dig1=0;
  else dig1 = 11 - dig1;
  
  if (dig1!=digito1) return (false);
  sum = 0;
  mul = 11;
  
  for (i = 0; i < 10 ; i++) 
  {
    digit = st2.substring(i,i+1);
    tproduct = parseInt(digit ,10)*mul;
    sum += tproduct;
    mul--;
  }
  
  dig2 = (sum % 11);
  if ( dig2==0 || dig2==1 ) dig2=0;
  else dig2 = 11 - dig2;
  
  if (dig2 != digito2) return (false);

  return (true);
	
}


// verifica formato padrão: AAA.BBB.CCC-DD
function isCPF(st) {

  if (st == null) return false;
  
  if (st.length != 14) 
  {
    if (st.length == 13) st = '0' + st;
    else if (st.length == 12) st = '00' + st;
    else return false;
  }
  
  if ( (st.charAt(3) != ".") || (st.charAt(7) != ".") || (st.charAt(11) != "-") )
  {
    return false;
  }
  
  return validaCPF(onlyDigits(st));
  
}

//------------------------


// retorna uma mensagem de erro ao usuário
function dadoInvalido(campo, msg) {
  alert (msg);
  campo.focus();
  return false;
}


// verifica se o campo foi preenchido corretamente:
function dadosValidos(definicao, campo, lang) {

  // BLANK
  if (isBlank(campo.value)) { 
    if (definicao.categ == "file") 
      return dadoInvalido(campo, getMsg(definicao, lang, 'FileFieldEmpty'));
    else 
      return dadoInvalido(campo, getMsg(definicao, lang, 'MandatoryField')); 
  }
  
  
  // FILE
  if (definicao.categ == "file" && !isValidFileType(definicao, campo.value)) {
    return dadoInvalido(campo, getMsg(definicao, lang, 'ValidFileTypes'));
  }
  


  // EMAIL
  if (definicao.categ == "email" && !isEmail(campo.value)) {
    return dadoInvalido(campo, getMsg(definicao, lang, 'InvalidEmail'));
  }
  
  
  // RGB COLOR
  if (definicao.categ == "rgbcolor" && !isRGBColor(campo.value)) {
    return dadoInvalido(campo, getMsg(definicao, lang, 'InvalidRGBColor'));
  }
  
  
  // NUMBERS
  
    // INTEGERS
  if (definicao.categ == "integer") {
  
    if (!isInteger(campo.value)) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'IntegerField'));
    }
    
    // MIN
    if (definicao.val1 != null && campo.value < definicao.val1) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'FieldMinVal'));
    }
    
    // MAX
    if (definicao.val2 != null && campo.value > definicao.val2) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'FieldMaxVal'));
    }
  
    return true;
    
  }
  
    // FLOATS
  if (definicao.categ == "float") {
  
    if (!isFloat(campo.value)) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'NumberField'));
    }
    
    // MIN
    if (definicao.val1 != null && campo.value < definicao.val1) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'FieldMinVal'));
    }
    
    // MAX
    if (definicao.val2 != null && campo.value > definicao.val2) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'FieldMaxVal'));
    }
  
    return true;
    
  }
  
  
  // STR LEN
  if (definicao.categ == "length") {

    if (definicao.val1 != null && campo.value.length < definicao.val1) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'FieldMinLen'));
    }  
 
    if (definicao.val2 != null && campo.value.length > definicao.val2) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'FieldMaxLen'));
    } 
    
    return true;
    
  }


  // CNPJ
  if (definicao.categ == "cnpj") {

    if ( (definicao.val1 == null || definicao.val1 == 'formatado') && !isCNPJ(campo.value) ) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'InvalidCNPJF'));
    }  
 
    if ( definicao.val1 == 'numerico' && !validaCNPJ(campo.value) ) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'InvalidCNPJU'));
    } 
    
    return true;
    
  }
  

  // CPF
  if (definicao.categ == "cpf") {

    if ( (definicao.val1 == null || definicao.val1 == 'formatado') && !isCPF(campo.value) ) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'InvalidCPFF'));
    }  
 
    if ( definicao.val1 == 'numerico' && !validaCPF(campo.value) ) {
      return dadoInvalido(campo, getMsg(definicao, lang, 'InvalidCPFU'));
    } 
    
    return true;
    
  }
  


  
  return true;

} 



//   _/_/_/_/_/_/_/_/_/_/_/_/_/
//  _/  O  B  J  E  C  T    _/ 
// _/_/_/_/_/_/_/_/_/_/_/_/_/


function FormValidator(lang) {

//  var args = FormValidator.arguments;
  this.lang = getLang(lang);
  this.campos = new Array();
  this.adicionaCampo = adicionaCampo;
  this.validaForm = verificaCampos;
  this.campoOpcional = setOptional;

}



function adicionaCampo(name, label, type, categ, v1, v2, text) {
  this.campos[this.campos.length] = new cpObj(name, label, type, categ, v1, v2, text);
}


function setOptional(nomeCampo) {
  
  for (i=0; i<this.campos.length; i++) {
    if (this.campos[i].nome == nomeCampo) this.campos[i].opcional = true;
  }
  
}


function cpObj () {

  var args = cpObj.arguments;

  this.nome  = args[0];
  this.label = args[1];
  this.tipo  = args[2];

  this.categ = args[3];
  this.val1  = args[4];
  this.val2  = args[5];

  this.msg   = args[6];
  
  this.opcional = false;

}


// campoPreenchido: verifica se o campo foi preenchido com algum valor
// utilizado para validação de campo opcional
// verifica apenas os campos text, textarea e file pois radio, select e checkbox
// são opçãoes fechadas e são obrigatórios ou não
function campoPreenchido(tipo, campo) {
  if (tipo == "text" || tipo == "textarea" || tipo == "file") return campo.value != "";
  return false;
}



// verificação do preenchimento do formulário
function verificaCampos(form) {

  for (var i=0; i<this.campos.length; i++) {

    var cp = eval("form['" + this.campos[i].nome + "']");

    if (!this.campos[i].opcional || campoPreenchido(this.campos[i].tipo, cp)) {

      // campos em formato texto
      if (this.campos[i].tipo == "text" || this.campos[i].tipo == "textarea" || this.campos[i].tipo == "file") {
        if (!dadosValidos(this.campos[i], cp, this.lang)) { return false; }
      }

      // campos em formato radio
      else if (this.campos[i].tipo == "radio") {
        var checked = false;
        for (var j=0; j<cp.length; j++) {
          if (cp[j].checked) {
            checked = true;
            break;
          }
        }
        if (!checked) {
          alert (getMsg(this.campos[i], this.lang, 'SelectAnOption'));
          cp[0].focus();
          return false;
        }

      }
   
      // campos em formato select
      else if (this.campos[i].tipo == "select") {
        if (cp.selectedIndex == -1 || cp.options[cp.selectedIndex].value == "") {
          alert (getMsg(this.campos[i], this.lang, 'SelectAnOption'));
          cp.focus();
          return false;
        }
      } 
      
      // campos em formato checkbox
      else if (this.campos[i].tipo == "checkbox") {
        if (!cp.checked) {
          alert(getMsg(this.campos[i], this.lang, 'MustBeChecked'));
          cp.focus();
          return false;
        }
      }
      
    } // IF CAMPO OPCIONAL
  
  } // FOR

  return true;

}

