/**
 * Libreria: Validacion
 * Por     : Jose Antonio Rojas V.
 * e_mail  : jor@opensoft.cl
 * Fecha   : 01-12-1998
**/


// Constantes con tipos de campos (cada uno debe tener asociado una funcion de validacion)
var TYPE_STRING      = 0;
var TYPE_NUMBER      = 1;
var TYPE_NUMBERINT   = 2;
var TYPE_NUMBERFLOAT = 3;
var TYPE_DATE        = 4;
var TYPE_EMAIL       = 5;
var TYPE_HTTP        = 6;
var TYPE_TIME        = 7;

// Constantes con separadores de cifras
var VAL_SEPARADOR_MILES     = ".";
var VAL_SEPARADOR_DECIMALES = ",";


// ======================================================================
// Funciones de validacion de tipos
// Obs: vacio, debe ser considerado como invalido, salvo en IsValid_Empty
// que precisamente retorna OK cuando el campo es vacio.
// ======================================================================
function LTrim(s){
  var s2    = "";
  var largo = s.length;

  for (var i = 0; (i<largo) && (s.substr(i,1)==" "); i++ )  ;
  for (         ;  i<largo                         ; i++ )  s2 = s2 + s.substr(i,1);
  return(s2);
}

function RTrim(s){
  var s2    = "";
  var largo = s.length;

  for (var i=largo-1; (i>=0) && (s.substr(i,1)==" "); i-- )  ;
  for (             ;  i>=0                         ; i-- )  s2 = s.substr(i,1) + s2;
  return(s2);
}


function IsValid_Empty( a_objeto ) {

  //"Combo"
  if (a_objeto.type == "select-one") {
    if (a_objeto.selectedIndex < 0)  return( true );
    return( ( RTrim( LTrim( a_objeto.options[a_objeto.selectedIndex].value ) ) == "" ) ? true : false );
  }

  //"Listbox"
  if (a_objeto.type == "select-multiple") {
    if (a_objeto.selectedIndex < 0)  return( true );
    return( ( RTrim( LTrim( a_objeto.options[a_objeto.selectedIndex].text ) ) == "" ) ? true : false );
  }

  //"Editbox"
  return( ( RTrim( LTrim( a_objeto.value ) ) == "" ) ? true : false )
}


function IsValid_String( a_objeto ) {
  return( !IsValid_Empty( a_objeto ) )
}


function IsValid_Number( a_objeto ) {
  //Vacio
  if( IsValid_Empty( a_objeto ) )  return( false );

  //Retorna
  return( IsValid_NumberInt( a_objeto ) || IsValid_NumberFloat( a_objeto ) );
}


function IsValid_NumberInt( a_objeto ) {
  //Vacio
  if( IsValid_Empty( a_objeto ) )  return( false );

  //Strings de expresiones regulares
  var ExpresionRegular_Str = "^(([0-9]+)|([0-9]{1,3}(\\" + VAL_SEPARADOR_MILES + "[0-9][0-9][0-9])*))$"

  //Objetos expresiones regulares
  var ExpresionRegular = new RegExp( ExpresionRegular_Str );

  //Retorna
  if (a_objeto.type == "select-one") {
    return( ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].value ) );
  }
  else if (a_objeto.type == "select-multiple") {
    return( ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].value ) );
  }
  else
    return( ExpresionRegular.test( a_objeto.value ) );
}


function IsValid_NumberFloat( a_objeto ) {
  //Vacio
  if( IsValid_Empty( a_objeto ) )  return( false );

  //Strings de expresiones regulares
  var ExpresionRegular_Str = "^(-)?(([0-9]+)|(([0-9]+)\\" + VAL_SEPARADOR_DECIMALES + "[0-9]+)|([0-9]{1,3}(\\" + VAL_SEPARADOR_MILES + "[0-9][0-9][0-9])*\\" + VAL_SEPARADOR_DECIMALES + "[0-9]+))$"

  //Objetos expresiones regulares
  var ExpresionRegular = new RegExp( ExpresionRegular_Str );

  //Retorna
  if (a_objeto.type == "select-one") {
    return( ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].text ) );
  }
  else if (a_objeto.type == "select-multiple") {
    return( ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].text ) );
  }
  else
    return( ExpresionRegular.test( a_objeto.value ) );
}


function IsValid_Date( a_objeto ) {
  //Vacio
  if( IsValid_Empty( a_objeto ) )  return( false );

  //Strings de expresiones regulares
  var meses                = "01|02|03|04|05|06|07|08|09|10|11|12";
  var dias                 = "01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31";
  var ExpresionRegular_Str = "^("+dias+")\\/("+meses+")\\/[0-9][0-9][0-9][0-9]$"

  //Objetos expresiones regulares
  var ExpresionRegular = new RegExp( ExpresionRegular_Str );

  //Evaluar expresiones
  var resultado;
  var valorObjeto;
  var largoObjeto;

  if (a_objeto.type == "select-one") {
    resultado = ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].text );
    valorObjeto = a_objeto.options[a_objeto.selectedIndex].text;
    largoObjeto = valorObjeto.length;
  }
  else if (a_objeto.type == "select-multiple") {
    resultado = ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].text );
    valorObjeto =a_objeto.options[a_objeto.selectedIndex].text;
    largoObjeto = valorObjeto.length;
  }
  else {
    resultado = ExpresionRegular.test( a_objeto.value );
    valorObjeto = a_objeto.value;
    largoObjeto = valorObjeto.length;
  }

  if ( resultado ){
    var largo= largoObjeto;
    var dia  = valorObjeto.substr(0,2);
    var mes  = valorObjeto.substr(3,2);
    var anno = valorObjeto.substr(largo-4,4);
    if (mes == "02") {
      //Si es divisible por 4 y no por 100 a no ser que
      //          sea div por 400 -> 29 2000 si 1900 no
      var bisiesto = (((anno%4 == 0) & (anno%100 != 0)) | (anno%400 == 0))?true:false;
      resultado = (bisiesto)?(eval(dia+"<30")):(eval(dia+"<29"))
    }
    //Revisa los dias 31 del mes
    else if (dia=="31" && ( (eval(mes+"<8")) && (mes%2==0) || (eval(mes+">7")) && (mes%2==1)))
      resultado = false;
  }
  //Retorna
  return( resultado );
}


function IsValid_EMail( a_objeto ) {
  //Vacio
  if( IsValid_Empty( a_objeto ) )  return( false );

  //Strings de expresiones regulares: username y hostname
  var ExpresionRegular1_Str = "(@.*@)|(\\.\\.)|(@\\.)|(\\.@)|(^\\.)";
  var ExpresionRegular2_Str = "^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$";

  //Objetos expresiones regulares
  var ExpresionRegular1 = new RegExp( ExpresionRegular1_Str );
  var ExpresionRegular2 = new RegExp( ExpresionRegular2_Str );

  //Retorna
  if (a_objeto.type == "select-one") {
    return( !ExpresionRegular1.test( a_objeto.options[a_objeto.selectedIndex].text )  &&
             ExpresionRegular2.test( a_objeto.options[a_objeto.selectedIndex].text ) );
  }
  else if (a_objeto.type == "select-multiple") {
    return( !ExpresionRegular1.test( a_objeto.options[a_objeto.selectedIndex].text )  &&
             ExpresionRegular2.test( a_objeto.options[a_objeto.selectedIndex].text ) );
  }
  else
    return( !ExpresionRegular1.test( a_objeto.value )  &&
             ExpresionRegular2.test( a_objeto.value ) );
}


function IsValid_HTTP( a_objeto ) {
  //Vacio
  if( IsValid_Empty( a_objeto ) )  return( false );

  //Strings de expresiones regulares
  var alphadigit = "[A-Za-z0-9]";
  var safe       = "[\\$\\-\\_\\.\\+]";
  var hex        = "[0-9A-F-a-f]";
  var extra      = "[\\!\\*\\'\\(\\)\\,]";
  var reserved   = "[\\;\\/\\?\\:\\@\\&\\=]";
  var escape     = "\\%"+hex+hex;
  var unreserved = "([A-Za-z0-9]|"+safe+"|"+extra+")";
  var uchar      = "("+unreserved+"|"+escape+")";
  var xchar      = "("+unreserved+"|"+reserved+"|"+escape+")";

  var domainlabel = "("+alphadigit+"|("+alphadigit+"("+alphadigit+"|\\-)*"+alphadigit+"))";
  var toplabel    = "([A-Za-z]|([A-Za-z]("+alphadigit+"|\\-)*"+alphadigit+"))";
  var hostname    = "("+domainlabel+"\\.)*"+toplabel;
  var hostnumber  = "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+";
  var host        = "("+hostname+"|"+hostnumber+")";
  var port        = "[0-9]+";


  var search      = "("+uchar+"|[\\;\\:\\@\\&\\=])*";
  var hsegment    = "("+uchar+"|[\\;\\:\\@\\&\\=])*";
  var hpath       = "("+hsegment+"(\\/"+hsegment+")*)";
  var hostport    = "("+host+"(\\:"+port+")?)";
  var httpurl     = "(http\\:\\/\\/)?"+hostport+"(\\/"+hpath+"(\\?"+search+")?)?";

  var user        = "("+uchar+"|[\\;\\?\\&\\=])*";
  var password    = "("+uchar+"|[\\;\\?\\&\\=])*";
  var login       = "("+user+"(\\:"+password+")?\\@)?";
  var fsegment    = "("+uchar+"|[\\?\\:\\@\\&\\=])*";
  var fpath       = "("+fsegment+"(\\/"+fsegment+")*)";
  var ftptype     = "[AIDaid]";
  var ftpurl      = "ftp\\:\\/\\/"+login+"(\\/"+fpath+"(\\;type\\="+ftptype+")?)?";

  var fileurl     = "file\\:\\/\\/("+host+"|localhost)?\\/"+fpath;

  var url         = "^"+httpurl+"|"+ftpurl+"|"+fileurl+"$";

  var ExpresionRegular_Str = url;

  //Objetos expresiones regulares
  var ExpresionRegular = new RegExp( ExpresionRegular_Str );

  //Retorna
  if (a_objeto.type == "select-one") {
    return( ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].text ) );
  }
  else if (a_objeto.type == "select-multiple") {
    return( ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].text ) );
  }
  else
    return( ExpresionRegular.test( a_objeto.value ) );
}


function IsValid_Time( a_objeto ) {
  //Vacio
  if( IsValid_Empty( a_objeto ) )  return( false );

  //Strings de expresiones regulares
  var horas                = "(00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23)";
  var minutos              = "([0-5])[0-9]";
  var segundos             = "([0-5])[0-9]";
  var ExpresionRegular_Str = "^"+horas+":"+minutos+":"+segundos+"$"

  //Objetos expresiones regulares
  var ExpresionRegular = new RegExp( ExpresionRegular_Str );

  //Evaluar expresiones
  var resultado;
  var valorObjeto;
  var largoObjeto;

  if (a_objeto.type == "select-one") {
    resultado = ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].text );
    valorObjeto = a_objeto.options[a_objeto.selectedIndex].text;
    largoObjeto = valorObjeto.length;
  }
  else if (a_objeto.type == "select-multiple") {
    resultado = ExpresionRegular.test( a_objeto.options[a_objeto.selectedIndex].text );
    valorObjeto =a_objeto.options[a_objeto.selectedIndex].text;
    largoObjeto = valorObjeto.length;
  }
  else {
    resultado = ExpresionRegular.test( a_objeto.value );
    valorObjeto = a_objeto.value;
    largoObjeto = valorObjeto.length;
  }

  if ( resultado ){
    var largo= largoObjeto;
    var hora  = valorObjeto.substr(0,2);
    var min   = valorObjeto.substr(3,2);
    var seg   = valorObjeto.substr(largo-4,4);
    //resultado = false;
  }
  //Retorna
  
  return( resultado );
  
}

function IsValid_DV( a_objetoRut, a_objetoDV ) {
  if( IsValid_Empty( a_objetoRut ) || IsValid_Empty( a_objetoDV ) )  return( true );
  l_DV = DigitoVerificadorRut( a_objetoRut );
  l_DVCampo = a_objetoDV.value;
  l_DVCampo = l_DVCampo.toUpperCase();

  if ( l_DVCampo != l_DV ) //Si el digito no corresponde retorno false
    return( false );
  //Retorna
  return( true )
}

function DigitoVerificadorRut( a_objeto ) {
  var rut = 0;
  var s = 0;
  var l_dv = "";

  rut = a_objeto.value;
  for (i=2; i< 8; i++){
    s = s + ( rut % 10 ) * i;
    rut = (rut - ( rut % 10 )) / 10;
  }
  s = s + ( rut % 10 ) * 2;
  rut = (rut - ( rut % 10 )) / 10;
  s = s + ( rut % 10 ) * 3;
  rut = (rut - ( rut % 10 )) / 10;
  s = 11 - ( s % 11 );
  if ( s == 10 )
     l_dv = "K";
  else
     if ( s == 11 )
        l_dv = "0"
     else
        l_dv = s + "";   // Se convierte el numero s a string
  return( l_dv );
}

//Construye arreglo con funciones de validacion
//Obs: deben estar en el mismo orden que el dado por las constantes de tipos!
var IsValid = new Array( IsValid_String,      IsValid_Number, IsValid_NumberInt,
                         IsValid_NumberFloat, IsValid_Date,   IsValid_EMail,
                         IsValid_HTTP,        IsValid_Time );


// ================================
// Funciones generales
// ================================

function Campo( a_objeto, a_nombre, a_tipo, a_obligatorio ) {
  this.length        = 4;
  this.Objeto        = a_objeto;
  this.Nombre        = a_nombre;
  this.Tipo          = a_tipo;
  this.EsObligatorio = a_obligatorio;
}


//Arreglo con campos a validar
var g_CamposDeFormulario = new Array();

function ValidaCampos( a_Campos ) {

  //Variables que almacenan los nombres de campos con error y mensaje de error general
  var l_ErrorFaltan = "";
  var l_ErrorTipo   = "";
  var l_ErrorLogica = "";
  var l_Mensaje     = "";

  //Recorre campos del arreglo dado
  for( var i = 0; i < a_Campos.length; i++ ) {

    //Si campo no existe se lo salta
    if( !a_Campos[ i ].Objeto )  continue;

    //Si el campo esta vacio...
    if ( IsValid_Empty( a_Campos[ i ].Objeto ) )  {

      //y es obligatorio, significa que hay error
      if( a_Campos[ i ].EsObligatorio )  {
        if( l_ErrorFaltan != "" ) l_ErrorFaltan += ",";
        l_ErrorFaltan += "\n  - " + a_Campos[ i ].Nombre;
      }

      //Continua con siguiente campo
      continue;
    }

    //Verifica error de tipo
    if( !IsValid[ a_Campos[ i ].Tipo ]( a_Campos[ i ].Objeto ) )  {
      if( l_ErrorTipo   != "" ) l_ErrorTipo   += ",";
      l_ErrorTipo   += "\n  - " + a_Campos[ i ].Nombre;
    }
  }

  //Mensaje de error: Faltantes
  if( l_ErrorFaltan != "" ) {
    if( l_Mensaje != "" ) l_Mensaje += "\n\n";
    l_Mensaje += "Los siguientes campos son obligatorios debe ingresarlos: "       + l_ErrorFaltan + "."
  }

  //Mensaje de error: Tipos
  if( l_ErrorTipo   != "" ) {
    if( l_Mensaje != "" ) l_Mensaje += "\n\n";
    l_Mensaje += "Los valores ingresados en los siguientes campos no son válidos: " + l_ErrorTipo   + "."
  }

  //Mensaje de error: Logica
  if( window.ValidaLogica )  {
    l_ErrorLogica = ValidaLogica();
    if( l_ErrorLogica != "" ) {
      if( l_Mensaje != "" ) l_Mensaje += "\n\n";
      l_Mensaje += "Se han detectado los siguientes errores de lógica: "            + l_ErrorLogica + "."
    }
  }

  //Retorna string con errores de validaciones
  return( l_Mensaje );
}


function ValidaFormulario() {

  //Valida los campos y guarda mensaje en variable
  var l_MensajeValidacion = ValidaCampos( g_CamposDeFormulario );

  //Si no hay error ejecuta submit antiguo y retorna
  if( l_MensajeValidacion == "" )  return( true );

  //Muestra mensaje
  alert( l_MensajeValidacion );

  //Retorna
  return( false );
}


//Cambia metodos de submit del formulario para anteponer la validacion
//document.forms[0].onsubmitOLD = document.forms[0].onsubmit;
//document.forms[0].onsubmit    = new Function( "if( !ValidaFormulario() ) return(false); return( this.onsubmitOLD() );" );


function InstalaValidacion( a_obj ) {
  a_obj.onclickOLD = a_obj.onclick;
  a_obj.onclick    = new Function( "if( !ValidaFormulario() ) return(false); return( this.onclickOLD() );" );
}

function DesinstalaValidacion( a_obj )  {
  if( a_obj.onclickOLD )  a_obj.onclick = a_obj.onclickOLD;
}

//Esta funcion permite instalar la validacion sobre un tag A. Se asume que
//el "nombre" del tag se indica en el atributo href. Esto se hace asi para
//tener una forma unica de recuperar el objeto tag A en Explorer y Netscape.
//Ej:
//  tag                      : <A href="Buscar" onclick="...">
//  instalacion de validacion: InstalaValidacionEnLinkPorHREF( "Buscar" )
//
function InstalaValidacionEnLinkPorHREF( a_txt ) {

  //Busca link donde href sea texto dado
  for( var i = document.links.length - 1; i >= 0; i-- )
    if( document.links[i].href.indexOf( a_txt ) == ( document.links[i].href.length - a_txt.length ) )  break;

  //Si lo encuentra, instala la validacion
  if( i >= 0 )  InstalaValidacion( document.links[ i ] );
}


function validaCreaCampo( a_obj, a_label, a_type, a_flagObligatorio ) {
  g_CamposDeFormulario[ g_CamposDeFormulario.length ] = new Campo( a_obj, a_label, a_type, a_flagObligatorio );
}

function DestacaCamposObligatorios() {

  //Verifica browser
  if( !document.all )  return;
    
  //Recorre campos a validar
  for( var i = 0; i < g_CamposDeFormulario.length; i++ )  {

    //Si no es obligatorio se lo salta
    if( !g_CamposDeFormulario[ i ].EsObligatorio )  continue;

    //Si campo no existe se lo salta
    if( !g_CamposDeFormulario[ i ].Objeto        )  continue;

    //Lo destaca si es obligatorio
    g_CamposDeFormulario[ i ].Objeto.style.borderColor = "#EF7523";
  }
}


//Inicializa libreria
window.onloadOld_Validacion = window.onload;
window.onload = function() {

  //Ejecuta evento onload original
  if( window.onloadOld_Validacion ) window.onloadOld_Validacion();
  
  //Instala validacion en los botones que tengar alguno de los siguientes textos
  var textos = "Guardar~Grabar~Aceptar~Aplicar";
  for( var i = 0; i < document.forms[0].elements.length; i++ ) {
    if( document.forms[0].elements[i].type != "button" )  continue;
    if( textos.indexOf( LTrim( RTrim( document.forms[0].elements[i].value ) ), 0 ) == -1 )  continue;
    InstalaValidacion( document.forms[0].elements[i] );
  }

  //Inicializa valores del arreglo con campos a validar
  if( window.defineCamposValida )  window.defineCamposValida();
  
  //Marca campos obligatorios
  //Desde el 26/04/2001 esta funcion ya no se invoca automaticamente
  //DestacaCamposObligatorios();
}
//chequeaRut: chequea si un campo text tiene un rut valido (con dv incluido)
//ademas formatea el rut con sep de miles y guion
function chequeaRut(obj_rut){
  var texto = obj_rut.value;
  var rut_limpio = "";

// Si esta vacio retorna
  if (texto.length == 0){
    return true;
  }

// Le quita los ptos, espacios  y raya (12.345.678-9 => 123456789)
  for ( i=0; i < texto.length ; i++ )
    if ( texto.charAt(i) != ' ' && texto.charAt(i) != '.' && texto.charAt(i) != '-' )
      rut_limpio = rut_limpio + texto.charAt(i);
  texto = rut_limpio;
  largo = texto.length;

// Descarta los ceros al inicio del rut (0010 => 10)
  for ( i=0; texto.charAt(i) == '0' ; i++ );
  texto = texto.substring(i, texto.length);
  largo = texto.length;

// Verifica el largo minimo (minimo 2 caracteres)
  if ( (largo < 2) && (largo > 0)){
    alert("Debe ingresar el rut completo.");
    obj_rut.focus();
    obj_rut.select();
    return false;
  }

// Verifica caracteres validos [1234567890kK)
  for (i=0; i < largo ; i++ ){
    if ( texto.charAt(i) !="0" && texto.charAt(i) != "1" && texto.charAt(i) !="2" && texto.charAt(i) != "3" && texto.charAt(i) != "4" && texto.charAt(i) !="5" && texto.charAt(i) != "6" && texto.charAt(i) != "7" && texto.charAt(i) !="8" && texto.charAt(i) != "9" && texto.charAt(i) !="k" && texto.charAt(i) != "K" ){
      alert("El valor ingresado no corresponde a un R.U.T valido.");
      obj_rut.select();
      obj_rut.focus();
      return false;
    }
  }

// Invierte el rut
  var invertido = "";
  for ( i=(largo-1),j=0; i>=0; i--,j++ )
    invertido = invertido + texto.charAt(i);

// Formatea el rut con separador de miles y el guion
  var dtexto = "";
  dtexto = invertido.charAt(0) + '-';
  cnt = 0;
  for ( i=1,j=2; i<largo; i++,j++ ){
    if ( cnt == 3 ){
      dtexto = dtexto + '.';
      j++;
      dtexto = dtexto + invertido.charAt(i);
      cnt = 1;
    }
    else{
      dtexto = dtexto + invertido.charAt(i);
      cnt++;
    }
  }

// Invierte el rut invertido ( o sea lo deja ok)
  invertido = "";
  for ( i=(dtexto.length-1),j=0; i>=0; i--,j++ )
    invertido = invertido + dtexto.charAt(i);

  obj_rut.value = invertido;

// Verifica el digito verificador
  if ( !chequeaDV(texto) ){
    alert("El rut es incorrecto.");
    obj_rut.focus();
    obj_rut.select();
    return false;
  }
  return true;
}


//si rut esta ok retorna true, sino false
function chequeaDV( crut ){

  largo = crut.length;

  if ( largo > 2 )
    rut_sin_dv = crut.substring(0, largo - 1);
  else
    rut_sin_dv = crut.charAt(0);
  dv = crut.charAt(largo-1);

  if ( rut_sin_dv == null || dv == null )
    return false;

  var dvr = '0';

  suma = 0;
  mul  = 2;

  for (i= rut_sin_dv.length -1 ; i >= 0; i--){
    suma = suma + rut_sin_dv.charAt(i) * mul;
    if (mul == 7)
      mul = 2;
    else
      mul++;
  }

  res = suma % 11;
  if (res==1)
    dvr = 'k';
  else if (res==0)
    dvr = '0';
  else{
    dvi = 11-res;
    dvr = dvi + "";
  }

  if ( dvr != dv.toLowerCase() ){
    //rut mal
    return false;
  }

  //rut ok
  return true;
}


