function getChars(desde, hasta){
  var result = "";
  for (var i = desde; i <= hasta; i++)
    if(i != 10 && i != 13)
      result += String.fromCharCode(i);
  return result;
}

function getInvalidChars(){
  var result = "";
  for (var i = 0; i < 32; i++)
    if(i != 10 && i != 13)
      result += String.fromCharCode(i);
  for (var i = 127; i < 256; i++)
    result += String.fromCharCode(i);
  return result;
}

function escapeToEval(cadena){
  var carsCadena = cadena.split("");
  var result = "";
  for(var i in carsCadena)
    result += "\\" + carsCadena[i];
  return result;
}

//todos los caracteres antes del 127 que no son letras: !#$%&'()*+,-./:;<=>?[\]^_{|}~@`
function getInvalidBasicChars(){
  return "!#$%&'()*+,:;<=>?[]^{|}~@`";
}

function getInvalidName(){
  var cadena = "!#$%&()*+,:;<=>?[]^{|}~@" + "d";
  cadena += getChars(145, 146);
  cadena += getChars(155, 159);
  cadena += getChars(164, 208);
  cadena += getChars(208, 240);
  cadena += getChars(242, 255);
  return cadena;
}

function getInvalidNameFileChars(){
  return getInvalidBasicChars() + getInvalidChars();
}

function isEachInvalidChar(filter, string){
  for(var i in string)
    if(!filter.test(string[i]))
      alert(string[i] + "(" + string[i].charCodeAt(0) + ")" + "is valid");
}

function validacionException(error, formato, message, objetos) {
   this.name = error;
   this.error = error;
   this.formato = formato;
   this.message = message;
   this.objetos = objetos;
}

/* tipos de error en validacionException

URLException

EMailException

NumberException
NumberLowerException
NumberUpperException

DateFormatException
DateException
DateLowerException
DateUpperException

TimeFormatException
TimeLowerException

PhoneFormatException

FileFormatException
FileInvalidCharException

StrLowerException
StrUpperException

InvalidCharException
StrLowerException
StrUpperException

*/

function validarUrl(elemento){
  var filtro = /^(http(s)?|ftp):\/\/(.+)\.(.+)$/;
  if (!filtro.test(elemento.value))
    throw new validacionException("URLException", "/^(http(s)?|ftp):\/\/(.+)\.(.+)$/", "El formato de la url no es correcto");
  return true;
}

function validarMail(elemento){
  var filtro = /^[A-Za-z][A-Za-z0-9_.\-]*@[A-Za-z0-9_\-]+\.[A-Za-z0-9_.]+[A-za-z]$/;
  if (!filtro.test(elemento.value))
    throw new validacionException("EMailException", "/^[A-Za-z][A-Za-z0-9_.\-]*@[A-Za-z0-9_\-]+\.[A-Za-z0-9_.]+[A-za-z]$/", "El formato del mail no es correcto");
  return true;
}

function validarNum(elemento, num1, num2){
  var filtro = /^\d+$/;
  if (!filtro.test(elemento.value))
    throw new validacionException("NumberException", "/^\d+$/", "No es un numero valido");

  var num = elemento.value;
  if(filtro.test(num1))
    if(eval(num) < num1)
      throw new validacionException("NumberLowerException", "/^\d+$/", "El numero " + num + " debe ser mayor o igual a " + num1, {num1:num1} );
  if(filtro.test(num2))
    if(eval(num) > num2)
      throw new validacionException("NumberUpperException", "/^\d+$/", "El numero " + num + " debe ser menor o igual a " + num2, {num2:num2});
  return true;
}

function getDateFormatNormal(texto, formatoOriginal){
  //formato final yyyy/mm/dd
  switch(formatoOriginal){
    case "mm/dd/yyyy":
      var arreglo = texto.split("/");
      return arreglo[2] + "/" + arreglo[0]+ "/" + arreglo[1];
    case "dd/mm/yyyy":
      var arreglo = texto.split("/");
      return arreglo[2] + "/" + arreglo[1]+ "/" + arreglo[0];
  }
  return texto;
}

function getFormatToDate(fecha, formatoOriginal){
  fecha = (formatoOriginal)? getDateFormatNormal(fecha, formatoOriginal): fecha;
  fecha = fecha.split("/");
  return new Date(fecha[0], fecha[1] - 1, fecha[2]);
}

function getFiltroFecha(formato){
  switch(formato){
    case "mm/dd/yyyy": case "dd/mm/yyyy":
      return /^\d{1,2}\/\d{1,2}\/\d{4}$/;
    case "yyyy/mm/dd": case "yyyy/dd/mm":
      return /^\d{4}\/\d{1,2}\/\d{1,2}$/;
  }
  return /^\d{1,2}\/\d{1,2}\/\d{4}$/;
}

function validarFecha(elemento, fecha1, fecha2, formato){
  formato = (formato)? formato: "dd/mm/yyyy";
  var fecha = elemento.value;
  var filtro = getFiltroFecha(formato);
  if (!filtro.test(fecha))
    throw new validacionException("DateFormatException", formato, "El formato de la fecha de ser: " + formato);
	
  var arreglo = getDateFormatNormal(fecha, formato).split("/");
  if(arreglo[1] < 1 || arreglo[1] > 12 || arreglo[2] < 1 || arreglo[0] < 1)
    throw new validacionException("DateException", formato, "La fecha no es valida");

  var meses = [0,31,28,31,30,31,30,31,31,30,31,30,31];
  if(arreglo[0] % 4 == 0)
    meses[2] = 29;
  if(eval(arreglo[2]) > eval(meses[eval(arreglo[1])]) )
    throw new validacionException("DateException", formato, "La fecha no es valida");
  
  var fecha = getFormatToDate(fecha, formato);

  var fecha1Original = fecha1;
  if(filtro.test(fecha1)){
    fecha1 = getFormatToDate(fecha1, formato);
    if((fecha.getTime() - fecha1.getTime()) < 0)
      throw new validacionException("DateLowerException", formato, "La fecha " + fecha + " debe ser mayor o igual a " + fecha1, {fecha1:fecha1Original});
  }

  var fecha2Original = fecha2;
  if(filtro.test(fecha2)){
    fecha2 = getFormatToDate(fecha2, formato);
    if((fecha.getTime() - fecha2.getTime()) > 0)
      throw new validacionException("DateUpperException", formato, "La fecha " + fecha + " debe ser menor o igual a " + fecha2, {fecha2:fecha2Original} );
  }
  return true;
}

function validarFecha2(elementos, fecha1, fecha2, formato){
  formato = (formato)? formato: "dd/mm/yyyy";
  var arreglo = elementos.split(',');
  var fechaArreglo = new Array();
  for(var i in arreglo)
    fechaArreglo[i] = jQuery("#" + arreglo[i]).val();
  var fecha = fechaArreglo.join('/');

  var filtro = getFiltroFecha(formato);
  if (!filtro.test(fecha))
    throw new validacionException("DateFormatException", formato, "El formato de la fecha de ser: " + formato);
	
  var arreglo = getDateFormatNormal(fecha, formato).split("/");
  if(arreglo[1] < 1 || arreglo[1] > 12 || arreglo[2] < 1 || arreglo[0] < 1)
    throw new validacionException("DateException", formato, "La fecha no es valida");

  var meses = [0,31,28,31,30,31,30,31,31,30,31,30,31];
  if(arreglo[0] % 4 == 0)
    meses[2] = 29;
  if(eval(arreglo[2]) > eval(meses[eval(arreglo[1])]) )
    throw new validacionException("DateException", formato, "La fecha no es valida");
  
  var fecha = getFormatToDate(fecha, formato);

  var fecha1Original = fecha1;
  if(filtro.test(fecha1)){
    fecha1 = getFormatToDate(fecha1, formato);
    if((fecha.getTime() - fecha1.getTime()) < 0)
      throw new validacionException("DateLowerException", formato, "La fecha " + fecha + " debe ser mayor o igual a " + fecha1, {fecha1:fecha1Original});
  }

  var fecha2Original = fecha2;
  if(filtro.test(fecha2)){
    fecha2 = getFormatToDate(fecha2, formato);
    if((fecha.getTime() - fecha2.getTime()) > 0)
      throw new validacionException("DateUpperException", formato, "La fecha " + fecha + " debe ser menor o igual a " + fecha2, {fecha2:fecha2Original} );
  }
  return true;
}

function validarHora(elemento, hora1, hora2){
  var filtro = /^(0[0-9]|1\d|2[0-3])(:[0-5]\d){1,2}$/;
  var formato = "hh:mm(:ss)* opcional";
  if (!filtro.test(elemento.value))
    throw new validacionException("TimeFormatException", formato, "El formato de la hora de ser: " + formato + " o no es una hora valida");

  var hora = elemento.value.split(":");
  if(hora.length == 2) hora[2] = 0;
    hora = new Date(0,0,0,hora[0],hora[1],hora[2]);

  var hora1Original = hora1;
  if(filtro.test(hora1)){
    hora1 = hora1.split(":");
    if(hora1.length == 2) hora1[2] = 0;
    hora1 = new Date(0,0,0,hora1[0],hora1[1],hora1[2]);
    if((hora.getTime() - hora1.getTime()) < 0)
      throw new validacionException("TimeLowerException", formato, "La hora " + hora + " debe ser mayor o igual a " + hora1, {hora1:hora1} );
  }

  var hora2Original = hora2;
  if(filtro.test(hora2)){
    hora2 = hora2.split(":");
    if(hora2.length == 2) hora2[2] = 0;
    hora2 = new Date(0,0,0,hora2[0],hora2[1],hora2[2]);
    if((hora.getTime() - hora2.getTime()) > 0)
      throw new validacionException("TimeUpperException", formato, "La hora " + hora + " debe ser menor o igual a " + hora2, {hora2:hora2} );
  }
  return true;
}

function validarTelefono(elemento){
  var filtro1 = /^(\d{5,20})|(\d{3}-\d{3}-\d{3})|(\(\d{3}\)\s\d{6})|(\d{3}\s\d{2}\s\d{2}\s\d{2})|(\+\d{2,3}\s\d{9})$/;
               // 900900900 | 900-900-900       | (900) 900900     | 900 90 09 00               | +34 900900900
  var formato = "\nddddd(ddddddddddddddd)*\nddd-ddd-ddd\n(ddd) dddddd\nddd dd dd dd\n+dd(d)* ddddddddd\n(*) opcional"
  
  if (!filtro1.test(elemento.value))
    throw new validacionException("PhoneFormatException", formato, "El formato de la hora de ser: " + formato);
  return true;
}

function validarFile(elemento, extensiones){
  var invalidChars = getInvalidNameFileChars();//caracteres y espacios en blanco
  var cadena = escapeToEval(invalidChars);
  var filtro = eval("(/[" + cadena + "]/)");

  var index = Math.max(elemento.value.lastIndexOf("/"),elemento.value.lastIndexOf("\\")) + 1;
  nameFile = elemento.value.substr(index)
  
  if (filtro.test(nameFile))
    throw new validacionException("FileInvalidCharException", invalidChars, "El archivo no debe de contener caracteres especiales, espacios o acentos");

  var ext = extensiones.split("|");
  var size = ext.length;
  var aux = "/^.+(";
  for(var key = 0; key < size; key++)
    if( (key + 1) != size)
      aux += "\\." + ext[key] + "|";
    else
      aux += "\\." + ext[key];
  aux += ")$/";
  filtro = eval( aux );
  if (!filtro.test(nameFile))
    throw new validacionException("FileFormatException", extensiones, "La extencion del archivo debe ser: " + extensiones);
  return true;
}

function minMaxCar(elemento, minCar, maxCar, filtro){
  if(filtro){
    if (!filtro.test(elemento.value))
      throw new validacionException("InvalidCharException", filtro, "No debe de contener caracteres especiales");
  }

  if(minCar != undefined && minCar != null &&  minCar != '')
    if( elemento.value.length < minCar)
      throw new validacionException("StrLowerException", minCar, "La longitud de la cadena debe ser minimo: " + minCar, {minCar:minCar});
  if(maxCar != undefined && maxCar != null &&  maxCar != '')
    if(elemento.value.length > maxCar)
      throw new validacionException("StrUpperException", maxCar, "La longitud de la cadena debe ser maximo: " + maxCar, {maxCar:maxCar});
  return true;
}

/*numero, fecha, hora, telefono, email, url, file, cadena, file*/

function valida(id, validador, expReg){
  var elemento;
  if(validador != 'fecha2')
    elemento = jQuery("#" + id).get(0);
  
  try{
    switch(validador){
      case "numero":
        return validarNum(elemento, null, null);
      case "fecha":
        return validarFecha(elemento, null, null, null)
      case "fecha2":
        return validarFecha2(id, null, null, null)
      case "hora":
        return validarHora(elemento, null, null)
      case "telefono":
        return validarTelefono(elemento)
      case "email":
        return validarMail(elemento)
      case "url":
        return validarUrl(elemento)
      case "file":
          return validarFile(elemento, []);
      default:
        var filtro = /^cadena,\w+,\w+,expReg*$/;
        if(filtro.test(validador)){
          var arreglo = validador.split(",");
          return minMaxCar(elemento, arreglo[1], arreglo[2], expReg);
        }
        var filtro = /^cadena,\w+,\w+$/;
        if(filtro.test(validador)){
          var arreglo = validador.split(",");
          return minMaxCar(elemento, arreglo[1], arreglo[2], false);
        }
        filtro = /^numero,\w+,\w+$/;
        if(filtro.test(validador)){
          var arreglo = validador.split(",");
          return validarNum(elemento, arreglo[1], arreglo[2]);
        }
        filtro = /^fecha,(.)+$/;
        if(filtro.test(validador)){
          var arreglo = validador.split(",");
          var formato = (arreglo[3])? arreglo[3] : null;
          return validarFecha(elemento, arreglo[1], arreglo[2], formato);
        }
        filtro = /^fecha2,(.)+$/;
        if(filtro.test(validador)){
          var arreglo = validador.split(",");
          var formato = (arreglo[3])? arreglo[3] : null;
          return validarFecha2(id, arreglo[1], arreglo[2], formato);
        }
        filtro = /^hora,(.)+$/;
        if(filtro.test(validador)){
          var arreglo = validador.split(",");
          return validarHora(elemento, arreglo[1], arreglo[2]);
        }
        filtro = /^file,(.)+$/;
        if(filtro.test(validador)){
          var arreglo = validador.split(",");
          return validarFile(elemento, arreglo[1]);
        }
     }
  }catch(e){ throw e; }
}

function validacion(id, validador){
  try{
    return valida(id, validador);
  }catch(e){
    return false;
  }
}

function contieneElementos(id){
  var elemento = jQuery("#" + id).get(0);
  for(var i = 0; i < elemento.options.length; i++)
    if(elemento.options[i].value != '')
      return true;
  return false;
}

Campo = function(id, nombre, validador, obligatorio, tipo, isfocus, expReg){
  this.id = id;
  this.nombre = (nombre != undefined && nombre != null && nombre != '')? nombre : id;
  this.validador = validador; 
  this.tipoValidador = (validador != null)? validador.split(",")[0] : "texto";
  this.obligatorio = obligatorio;
  this.tipo = (tipo != undefined && tipo != null)? tipo : '';
  this.isfocus = (isfocus != undefined && isfocus != null)? isfocus: true;
  this.expReg = (expReg != undefined && expReg != null)? expReg: null;
  
  this.validaCampo = function (){
    if(this.validador != null)
      return valida(this.id, this.validador, this.expReg);
    return true;
  };

  this.hayContenido = function(){
    var filtro = /^fecha2,(.)+$/;
    if((this.validador == 'fecha2') || filtro.test(validador)){
      var arreglo = this.id.split(',');
      for(var i in arreglo){
        var val = jQuery("#" + arreglo[i]).val();
        if( (val == '') || (val == 0) )
          return false;
      }
      return true;
    }else{
      var val = jQuery("#" + this.id).val();
      switch(this.tipo){
        case '':         return (val != '');
        case 'multiple': return contieneElementos(this.id);
        case 'select':   return !(val == '' || val == 0);
      }
    } 
  };

  this.focus = function(){
    if(this.isfocus){
      var filtro = /^fecha2,(.)+$/;
      if((this.validador == 'fecha2') || filtro.test(validador))
        jQuery("#" + this.id.split(',')[0]).get(0).focus();
      else
        jQuery("#" + this.id).get(0).focus();
    }
  };

  this.clone = function(id, nombe){
    return new Campo(id || this.id, nombre || this.nombre, this.validador, this.obligatorio, this.tipo, this.isfocus);
  }

}

function validaForm(campos, funcVacio, funcError){
  var size = campos.length;

  this.funcVacio = (funcVacio != undefined && funcVacio != null && funcVacio != '')? funcVacio : function(campo){
        alert("Es requerido el campo: " + campo.nombre);
      };
  this.funcError = (funcError != undefined && funcError != null && funcError != '')? funcError : function(campo, error){
        alert(error.message);
      };

  for(var i = 0; i < size; i++){
    var campo = campos[i];
    if(!campo.hayContenido()){
      if(campo.obligatorio){
        campo.focus();
        this.funcVacio(campo);
        return false;
      }
    }else 
	try{
	  if(!campo.validaCampo()){
        this.funcError(campo,e);
        return false;
      }
	}catch(e){
      campo.focus();
      this.funcError(campo,e);
      return false;
    }
  }
  return true;
}

function validaFormCompleto(campos, funcVacio, funcError){
  var size = campos.length;
  var result = true;
  var focus = false;

  this.funcVacio = (funcVacio != undefined && funcVacio != null && funcVacio != '')? funcVacio : function(campo){
        alert("Es requerido el campo: " + campo.nombre);
      };
  this.funcError = (funcError != undefined && funcError != null && funcError != '')? funcError : function(campo, error){
        alert(error.message);
      };

  for(var i = 0; i < size; i++){
    var campo = campos[i];
    if(!campo.hayContenido()){
      if(campo.obligatorio){
        if(!focus){
          campo.focus();
          focus = true;
        }
        this.funcVacio(campo);
        result = false;
      }
    }else 
      try{
        result &= campo.validaCampo();
      }catch(e){
        if(!focus){
          campo.focus();
          focus = true;
      }
      this.funcError(campo,e);
      result = false;
    }
  }
  return result;
}

/*        Validacion en linea       */

function validarNombreLinea(elemento){
  var filtro = /^([a-zA-Z�-��-�'\.\s_-])*$/;
  return (filtro.test(elemento.value))
}

function validarNumeroLinea(elemento){
  var filtro = /^(\d)*$/;
  return (filtro.test(elemento.value))
}

function validarFechaLinea(elemento){
  var filtro = /^([\d\/])*$/;
  return (filtro.test(elemento.value))
}

function validarHoraLinea(elemento){
  var filtro = /^([\d:])*$/;
  return (filtro.test(elemento.value))
}

function validaEnLinea(id, validador){
  var elemento = jQuery("#" + id).get(0);
  switch(validador){
    case "nombre":
      return validarNombreLinea(elemento);
    case "numero":
      return validarNumeroLinea(elemento);
    case "fecha":
      return validarFechaLinea(elemento);
    case "hora":
      return validarHoraLinea(elemento);
  }
}

