
_sv_enter_init();

function _sv_enter_init() {
  var x;
  _sv._sventer = {};
  x = _sv._sventer;
  x.trans = {};         //# Almacena trancisiones de visible a invisible y al revés de cada ID
  x.estados = {};        //# Almacena el estado visible/invisible (1/0) de cada ID.
  x.depends = {};       //# 
  x.id_actual = false;       //# 

  _sv.init_sv_enter = init_sv_enter;
  _sv.load_function(_l_load,20);

/* ***
**  sv_type = 'enter'
**  sv_conf = value:  string . ID del elemento. Varios elementos pueden tener un mismo ID
**                    modo que las acciones enter/leave realizadas sobre uno cualquiera
**                    de ellos se considera que actuan sobre todos.
**  sv_conf = master_value:  string . ID del elemento maestro. Las acciones enter/leave
**                    sobre los objetos esclavos, repercutirán también en los maestros.
**            master: Si es verdadero, se trata del objeto maestro (no se oculta
**                    ni se deja de apuntar).
**            y:      Si se define, será la posición en la y referida a la del objeto maestro.
**            x:      Si se define, será la posición en la x referida a la del objeto maestro.
**             
*/
//# Se mantiene _sv._enter, que es un array asociativo donde cada clave es un ID de objeto
//# sventer, y cada item es un array numérico con las siguientes propiedades:
//# 
//# _sv._enter[id].master => Referencia al objeto maestro.
//# _sv._enter[id][0] => Referencia a un objeto esclavo.
//# _sv._enter[id][1] => Referencia a otro objeto esclavo.
//# ...
//# _sv._enter[id][N] => Referencia al objeto esclavo N.
//# 
//# 
//# 
//# 
//# Cuando el cursor entra en un objeto sventer, la librería se encarga de que todos los
//# objetos esclavos del mismo ID, sean mostrados, así como aquellos que contengan
//# 
  function init_sv_enter(o) {
    var c,d,v,s,m,mv;
    c = o.getAttribute("sv_conf");
    if(_sv.is_emp(c)) { c=''; }
    o._sv_conf = new Object();
    d = o._sv_conf;

    _sv.parse_atts(c,d);
    if(d.value) {                       //# Si tiene atributo value.
      v = d.value;                      //# | Se toma en v.
    } else {                            //# Si no lo tiene.
      v = "qwerty";                     //# | v = value por defecto.
      d.value = v;                      //# | Se guarda éste en o._sv_conf.
    }                                   //# 
    if(d.master_value) {                //# Si tiene atributo master_value.
      mv = d.master_value;              //# | Se toma en mv.
    } else {                            //# Si no lo tiene.
      mv = 0;                           //# | mv = master_value por defecto.
      d.master_value = mv;              //# | Se guarda éste en o._sv_conf.
    }                                   //# 
    if(d.master) {                      //# Si tiene atributo master.
      m = d.master;                     //# | Se toma en m.
    } else {                            //# Si no lo tiene.
      m = 0;                            //# | m = master por defecto.
      d.master = m;                     //# | Se guarda éste en o._sv_conf.
    }                                   //# 
    //#------------------------------------
    //# Ahora se deja en _sv._enter[v] un array de objetos esclavos con el mismo
    //# ID, con una propiedad master que se refiere al objeto maestro, y otra
    //# propiedad master_value que se refiere al objeto maestro.
    //#------------------------------------
    if(!_sv._enter) {
      _sv._enter = {};
    }
    if(!_sv._enter[v]) {
      _sv._enter[v] = [];
    }
    s = _sv._enter[v];
    if(m) {
      s.master = o;
    } else {
      s[s.length] = o;
    }
    if(mv!=0) {
        s.master_value = mv;
    }
    _sv.add_event_handler(o, 'm_enter', hme);
    _sv.add_event_handler(o, 'm_leave', hml);
  }

  /**
   * Función manejadora del evento m_enter (mouse_enter) para los objetos DOM de este tipo.
   * 
   * Muestra todos los objetos DOM esclavos con este mismo ID.
   * 
   * @param: Objeto sv_event
   * @author: a_vera.
   */
  function hme(e) {
    var t,cc;
    t = e.self;                         //# t = El propio objeto DOM.
    if(t!=e.target) {
      return;
    }
    if(!t._sv_conf) {                   //# Si no tiene configuración.
      return;                           //# | Final sin más.
    }                                   //# -------------------------------------------------------
    cc = t._sv_conf;                    //# cc = Configuración del objeto DOM.
    if(!cc) {                           //# Si no es válida.
      return;                           //# | Final sin más.
    }                                   //# -------------------------------------------------------
    _mostrar(cc.value);
  } //#--------------------------------------------------------------------------------------------

  /**
   * Función manejadora del evento m_leave (mouse_leave) para los objetos DOM de este tipo.
   * 
   * @param: Objeto sv_event
   * @author: a_vera.
   */
  function hml(e) {
    var id;
    id = _get_id(e.fromto);
    _mostrar(id);
  } //#--------------------------------------------------------------------------------------------

  //# Dado un objeto, que está actualmente apuntado, deja en el array 
  
  // Al entrar en un objeto sv_enter, se comprueba su ID de objeto, y se comprueba si
  // sale de un objeto con el mismo ID, si es así, no hace nada.

  /**
   * Obtiene el ID de objeto sventer de un determinado objeto. Si este objeto no es un sventer
   * busca uno que lo sea entre sus padres en el modelo DOM y devuelve su ID. Si no se
   * encuentra devuelve false.
   * 
   * @param: objeto DOM. El objeto DOM cuyo ID (o de alguno de sus padres) se desea.
   * @return: string o false. Si se encuentra un ID válido, una cadena con dicho ID. false si
   *          este ID no se encuentra
   * @author: a_vera.
   */
  //# Calcula las transiciones necesarias para que se muestren los objetos sventer con un ID
  //# determinado. Las transiciones se guardan en _sv._sventer.trans, que es un array asociativo
  //# donde cada clave es un ID de objeto sventer, y el item es un entero. El bit 0 de este entero
  //# indica el estado actual, y el bit 1 el que debe tener tras la trancisión. Un valor 0 en un
  //# bit indica "invisible" y un bit igual a 1 indica "visible".
  //# 
  //# Aunque la función recibe un ID de objeto sventer, calcula las transiciones para todos los
  //# objetos sventer. El ID pasado es el de aquel objeto sventer que debe ser mostrado en primera
  //# instancia (por ejemplo, el objeto apuntado por el ratón), pero eso puede implicar que otros
  //# también sean mostrados (si la visibilidad del pasado depende de otros), o que otros sean
  //# ocultados (si estaban siendo mostrados, ya que solo se puede mostrar un objeto sventer y sus
  //# 'padres' en cada momento).
  //# 
  //# En realidad esta función solo calcula directamente el bit 0 de las transiciones, y delega
  //# en _mostrar_aux2 para que calcule el bit 1 (el estado futuro).
  function _get_id(o) {
    var p,tp;
    while(1) {                              //# Bucle para buscar el ID.
      if(!o.getAttribute) {                 //# | Si el objeto no tiene getAttribute().
        break;                              //# | | Salir del bucle para volver con false.
      }                                     //# | 
      tp = o.getAttribute('sv_type');       //# | Tomar el atributo 'sv_type'.
      if(tp) {                              //# | Si es válido.
        if(tp=='enter') {                   //# | | Si es 'enter'
          return o._sv_conf.value;          //# | | | Devolver el ID.
        }                                   //# | | -----------------------------------------------
      }                                     //# | 
      p = o.parentNode;                     //# | p = Objeto padre.
      if(!p) {                              //# | Si no es válido.
        break;                              //# | | Salir del bucle para volver con false.
      }                                     //# | 
      if(p==o) {                            //# | Si es el propio objeto.
        break;                              //# | | Salir del bucle para volver con false.
      }                                     //# | 
      o = p;                                //# | Probar con el padre en la siguiente iteración.
    }                                       //# 
    return false;                           //# Terminar con false.
  } //#--------------------------------------------------------------------------------------------

  /**
   * Muestra aquellos objetos sventer cuyo ID coincida con uno dado, y aquellos de los que depende
   * y oculta todos los demás.
   * 
   * @param: string. El ID de objeto sventer.
   * @author: a_vera.
   */
  //# Esta función mantiene actualizado _sv._sventer.id_actual, con el último ID con el que fue
  //# llamada, de modo que ignora llamadas consecutivas con el mismo ID. También mantiene el
  //# estado de visible/invisible de cada ID por separado en _sv._sventer.estados (puede que
  //# mostrar un ID, fuerce que también se muestren otros, de ahí que sea necesario un control
  //# individual).
  //# 
  //# El algorimo consiste en llamar a _mostrar_aux1 que calculara transiciones de visible a
  //# invisible y al revés de cada objeto por separado, después, para cada transición, los
  //# objetos DOM afectados por un ID, se muestran con __mostrar, al tiempo que se guarda
  //# en un array los bordes del rectangulo que encierra a cada objeto mostrado.
  //# 
  //# Finalmente, este array se usa (solo en versiones anteriores de IE) para ocultar los
  //# campos select que colisionen con los objetos mostrados.
  //# 
  function _mostrar(id) {
    var se,t,rcts,i,ii,o,r,rr,ua;
    se = _sv._sventer;                      //# se => referencia a los datos de sventer.
    if(se.id_actual==id) {                  //# Si el ID actual coincide con el pasado.
      return;                               //# | Final sin hacer nada.
    }                                       //# ---------------------------------------------------
    rcts = [];                              //# Aquí se guardan los rectangulos mostrados.
    _mostrar_aux1(id);                      //# Calcular las transiciones.
    for(var x in se.trans) {                //# Para x = cada ID de objeto sventer.
      t = 3 & se.trans[x];                  //# | t = transicion del objeto.
      if(t==1) {                            //# | Si el ID se debe ocultar
        __mostrar(x, false, rcts);          //# | | Se oculta.
        se.estados[x] = 0;                  //# | | Se actualiza su estado (invisible)
      } else if(t==2) {                     //# | Si el ID se debe mostrar,
        __mostrar(x, true, rcts);           //# | | Se muestra
        se.estados[x] = 1;                  //# | | Se actualiza su estado (visible)
      } else if(t==3) {                     //# | Si el ID debe permanecer mostrado,
        __mostrar(x, true, rcts);           //# | | Se muestra (en realidad ya está mostrado
                                            //# | | pero es necesario actualizar rcts).
      }                                     //# | 
    }                                       //# 
    se.id_actual = id;                      //# Actualizado el ID mostrado actual.
    //#----------------------------------------
    //# El resto del código oculta los campos SELECT que colisionen con alguna capa mostrada pero
    //# sólo si el navegador es alguna versión de Internet Explorer anterior a la 7.
    //#----------------------------------------
    ua = _sv.user_agent();                  //# Tomar el User Agent.
    if(ua!='IE') {                          //# Si no es una versión de IE anterior a la 7.
      return;                               //# | Final.
    }                                       //# ---------------------------------------------------
    ii = _sv.select_list.length;            //# ii = Número de campos select.
    rr = rcts.length;                       //# rr = Número de objetos mostrados.
    for(i=0; i<ii; i++) {                   //# Para cada campos select,
      o = _sv.select_list[i];               //# | o => referencia a un campo select de la página.
      if(rr) {                              //# | Si hay objetos mostrados.
        _sv.object_rec(o);                  //# | | _sv.rv => bordes del campo select.
        for(r=0; r<rr; r++) {               //# | | Para cada objeto mostrado.
          if( (_sv.rv[0]<rcts[r][2]) &&     //# | | | Si el rectángulo del objeto mostrado
              (_sv.rv[1]<rcts[r][3]) &&     //# | | | colisiona con el rectángulo del campo
              (_sv.rv[2]>rcts[r][0]) &&     //# | | | select.
              (_sv.rv[3]>rcts[r][1]) ) {    //# | | | 
            break;                          //# | | | | Hay que ocultar el select, salir del bucle.
          }                                 //# | | | 
        }                                   //# | | 
        if(r>=rr) {                         //# | | Si se rastreó sin colisiones el array entero.
          o.style.visibility='visible';     //# | | | El campo select se muestra.
        } else {                            //# | | Si se halló alguna colisión.
          o.style.visibility='hidden';      //# | | | El campo select se oculta.
        }                                   //# | | 
      } else {                              //# | Si no hay campos mostrados.
        o.style.visibility='visible';       //# | | El campo se muestra siempre.
      }                                     //# | 
    }                                       //# Fin del bucle de campos SELECT.
  } //#--------------------------------------------------------------------------------------------

  /**
   * Calcula las transiciones de visibilidad/invisibilidad de todos los objetos sventer, teniendo
   * en cuenta el ID de aquel que debe ser mostrado en primera instancia.
   * 
   * @param: string. El ID de aquel objeto sventer que debe ser mostrado en primera instancia.
   * @return: Directamente no devuelve nada, pero indirectamente _sv._sventer.trans será
   *          modificado para que contenga las transiciones.
   * @author: a_vera.
   */
  //# Calcula las transiciones necesarias para que se muestren los objetos sventer con un ID
  //# determinado. Las transiciones se guardan en _sv._sventer.trans, que es un array asociativo
  //# donde cada clave es un ID de objeto sventer, y el item es un entero. El bit 0 de este entero
  //# indica el estado actual, y el bit 1 el que debe tener tras la trancisión. Un valor 0 en un
  //# bit indica "invisible" y un bit igual a 1 indica "visible".
  //# 
  //# Aunque la función recibe un ID de objeto sventer, calcula las transiciones para todos los
  //# objetos sventer. El ID pasado es el de aquel objeto sventer que debe ser mostrado en primera
  //# instancia (por ejemplo, el objeto apuntado por el ratón), pero eso puede implicar que otros
  //# también sean mostrados (si la visibilidad del pasado depende de otros), o que otros sean
  //# ocultados (si estaban siendo mostrados, ya que solo se puede mostrar un objeto sventer y sus
  //# 'padres' en cada momento).
  //# 
  //# En realidad esta función solo calcula directamente el bit 0 de las transiciones, y delega
  //# en _mostrar_aux2 para que calcule el bit 1 (el estado futuro).
  //# 
  function _mostrar_aux1(id) {
    var se;
    se = _sv._sventer;                      //# se => referencia a los datos de sventer.
    for(var x in se.estados) {              //# Para x = cada ID de objeto sventer.
      se.trans[x] = se.estados[x];          //# | Actualizado el bit 0 con su estado actual y el
                                            //# | bit 1 es cero provisionalmente.
    }                                       //# 
    _mostrar_aux2(id);                      //# Calcular el bit 1 de las transiciones.
  } //# -------------------------------------------------------------------------------------------


  /**
   * Hace parte del cáculo de transiciones de visibilidad/invisibilidad de los objetos sventer.
   * 
   * @param: string. El ID de un objeto sventer que debe ser mostrado.
   * @author: a_vera.
   */
  //# Calcula el bit 1 de las transiciones de explicadas en los comentarios de _mostrar_aux1.
  //# 
  //# Se hace en una función aparte porque se necesita recursión en el algoritmo. Es recursivo
  //# por definición, ya que si un objeto debe ser mostrado también lo deben ser aquellos de
  //# los que depende, en los cuales se debe volver a aplicar el mismo criterio.
  //# 
  function _mostrar_aux2(id) {
    var se,i,ii;
    if(!id) {                               //# Si el ID no es válido.
      return;                               //# | Final sin hacer nada.
    }                                       //# ---------------------------------------------------
    se = _sv._sventer;                      //# se => referencia a los datos de sventer.
    if(se.trans[id]>=2) {                   //# Si ya se ha tratado este ID.
      return;                               //# | Final sin hacer nada.
    }                                       //# ---------------------------------------------------
    se.trans[id] |= 2;
    ii = se.depends[id].length;             //# ii = Número de ID de los que depende.
    for(i=0; i<ii; i++) {                   //# Para cada uno de ellos.
      _mostrar_aux2(se.depends[id][i]);     //# | Marcar la transición.
    }                                       //# 
  }

  /**
   * Muestra u oculta aquellos objetos sventer cuyo ID coincida con uno dado.
   * 
   * @param: string. El ID de objeto sventer.
   * @author: a_vera.
   */
  //# En el último parámetro debe dejar las coordenadas del rectangulo que encierra a cada objeto
  //# mostrado (pero solo si se muestra, no si se oculta).
  function __mostrar(n, v, rcts) {
    var l, i, ii, xm, ym, nn, o, o2, yp;
    if(!_sv._enter) {
      return;
    }
    if(!_sv._enter[n]) {
      return;
    }
    l = _sv._enter[n];                          
    t = l.master;                               
    if(t._sv_conf) {
      cc = t._sv_conf;
    } else {
        cc={};
    }
    xm = ym = -10000;
    if(l.master) {
      o = l.master;
      _sv.object_rec(o);
      xm = _sv.rv[0];
      ym = _sv.rv[1];
    }
    ii = l.length;
    for(i=0; i<ii; i++) {
      o2 = l[i];
      if(v) {
        //#------------------------------------
        //# Si se debe mostrar también hay que establecer su posición Y, esta posición se establece
        //# antes y después de visualizarlo porque antes puede evitar parpadeos, pero también puede
        //# no funcionar.
        //#------------------------------------
        yp = ym + o2._sv_conf.y;        //# | | yp = Posición Y que tendrá el objeto visualizado.
        o2.style.top = yp;              //# | | Establecer la posición antes de visualizarlo.
        o2.style.display='block';       //# | | Visualizarlo.
        o2.style.top = yp;              //# | | Establecer la posición después de visualizarlo.
        _sv.object_rec(o2);
        rcts.push([_sv.rv[0], _sv.rv[1], _sv.rv[2], _sv.rv[3]]);
      } else {
        o2.style.display='none';
      }
    }
    if(v) {
      if(cc.pointer_class) {
        if(!t._sv_act_clas) {
          t._sv_act_clas = t.className;
        }
        t.className = cc.pointer_class;
      }
    } else {
      if(t._sv_act_clas) {
        t.className = t._sv_act_clas;
      }
    }
  }

  //# Carga el módulo, sv_enter. Realiza todas las tareas de inicialización que hay que hacer
  //# una vez esté cargada la página y los objetos inicializados.
  //# 
  //# Establece las dependencias entre ID's de objetos sventer. Se dice que el ID de objeto
  //# A depende del ID de objeto B, si para mostrar el maestro del objeto A es necesario que
  //# B esté mostrado.
  //# 
  //# En _sv._sventer.depends[id] deja un array por cada ID, con los ID's de los que depende
  //# directa o indirectamente.
  //# 
  function _l_load() {
    var m,p,tp,x2,d,da;
    for(var x in _sv._enter) {              //# Para x = cada ID de objeto sventer.
      _sv._sventer.depends[x] = [];
      da = _sv._sventer.depends[x];
      d = 0;
      m = _sv._enter[x].master;             //# 
      if(!m) {
        continue;
      }
      while(1) {                            //# 
        p = m.parentNode;                   //# 
        if(!p) {                            //# 
          break;                            //# 
        }                                   //# 
        if(p==m) {                          //# 
          break;                            //# 
        }                                   //# 
        m = p;                              //# 
        if(!p.getAttribute) {               //# 
          break;                            //# 
        }                                   //# 
        tp = p.getAttribute('sv_type');     //# Tomar el atributo 'sv_type'.
        if(!tp) {                           //# 
          continue;                         //# 
        }                                   //# 
        if(tp!='enter') {                   //# 
          continue;                         //# 
        }                                   //# 
        x2 = p._sv_conf.value;              //# 
        if(x2==x) {                         //# 
          continue;                         //# 
        }                                   //# 
        da[d] = x2;
        d++;
      }
    }
  }
}

