with Unchecked_Deallocation;
 
package body Listas_Secuenciales is
  
  procedure Libera is new Unchecked_Deallocation(Nodo_Lista, TNodo_Lista);
 
  -- El procedimiento Insertar, inserta el elemento indicado por el
  -- segundo parámetro en la lista indicada por el primero. Si el
  -- elemento a insertar ya se encuentra en la lista, lo sustituirá
  -- por el nuevo si el tercer parámetro tiene el valor True o lanzará
  -- la excepción Error_Repetido si tiene el valor False. Los elementos
   -- en la lista estarán organizados secuencialmente según el orden de llegada,
    -- salvo en caso de sustitución que se mantiene la posición original. El
    -- elemento recién insertado se convierte en el actual a efectos de acceso. Si,
    -- cuando se intenta insertar, la lista está llena, se lanza la excepción 
  -- predefinida Constraint_Error y la lista queda como estaba.
  procedure Insertar(Lis: in out Lista; ELista: in ElementoLista; NoExiste: in Boolean) is
     
    begin  
     
      if Lis.Tamaño = 0 then        
        Lis.Actual:= Lis.Inicio;
        Lis.Fin:= Lis.Inicio;
        Lis.Tamaño := Lis.Tamaño + 1;
       END IF;
      
      IF lis.tamaño /= 0 THEN
        if Lis.Tamaño /= Lis.TamañoMaximo then        
          if NoExiste = True then
            Lis.Actual:= Lis.ELista;
          else
              raise Error_Repetido;
          end if;
        else
          raise Constraint_Error;
        end if;
      end if;
  end Insertar;
 
 
  -- El procedimiento Inicial, designa como actual al elemento
  -- más antiguo de la lista. Si la lista está vacía el actual
  -- queda indefinido.
  procedure Inicio(Lis: in out Lista) is
  
    begin  
      if Lis.Tamaño = 0 then
        Lis.Actual:= Lis.Inicio;
      end if;
  end Inicio;
 
 
  -- El procedimiento Siguiente, prepara la lista para
  -- acceder al elemento siguiente al actual, según el
  -- orden secuencial de la misma. Si actual ya está
  -- en el último elemento, queda indefinido. Si la
  -- lista está vacía o el actual está indefinido, actual
  -- queda indefinido.
  procedure Siguiente(Lis: in out Lista) is                                 
     
     begin   
     if Lis.Tamaño /= 0 then
      if Lis.Actual /= Lis.Fin then
        Lis.Actual:= Nodo_Lista.sig;
         else
          Lis.Actual:= null;        
      end if;
      
      else
        Lis.Actual:= null;
    end if;
  end Siguiente;
 
 
    -- la Función Examinar devuelve el elemento actual
    -- de la lista. Si el elemento actual está indefinido
    -- se lanzará la excepción Constraint_Error.  
  function Examinar(Lis: in Lista)return Lista is                                  
    
  begin         
       if Lis.Actual /= null then
        return Lis.Actual;
        else
          raise Constraint_Error;
    end if;
 
  end Examinar;
 
 
   -- La función Fin_Lista, devuelve True si actual está indefinido.     
  function Fin_Lista(Lis: in Lista)return boolean is                          
  
     begin
      if Lis.Actual = null then
        return True;
      else
          return False;
      end if;
 
  end Fin_Lista; 
 
    
    -- El procedimiento Extraer, elimina de la lista el
    -- elemento actual. Si actual está indefinido no se
    -- producirá ningún efecto apreciable. Tras la
    -- extracción, actual debe quedar situado en el
    -- elemento siguiente al extraído; si el elemento
    -- que se extrae es el último de la lista, actual
    -- queda indefinido.
     procedure Extraer(Lis: in out Lista) is 
      Aux: Nodo_Lista;                         
    begin
    if Lis.Actual /= null then
      if Lis.Actual /= Lis.Fin then
        Aux:= Nodo_Lista.sig;
          Libera(Lis.Actual);
        Lis.Actual:= Aux;
        Lis.Tamaño := Lis.Tamaño - 1;
      end if;
 
      if Lis.Actual = Lis.Fin then
          Libera(Lis.Actual);
        Lis.Actual:= Null;
        Lis.Tamaño := Lis.Tamaño - 1;
      end if;
    end if;
  end Extraer;
 
end Listas_Secuenciales;