#ifndef LISTA_H
#define LISTA_H
#include <stdbool.h>
#include <stdlib.h>
#include <stddef.h>
/* Definición de los tipos de datos */
#ifndef LISTA_DATO_T
#define LISTA_DATO_T
typedef void* lista_dato_t;
#endif
typedef struct _lista_t lista_t;
typedef struct _iter lista_iter_t;
/* Primitivas de lista */
// Crea una lista simplemente enlazada vacía.
// Post: se devuelve un puntero a lista_t.
lista_t* lista_crear();
// Verifica si una lista está vacía.
// Pre: la lista fue creada.
bool lista_esta_vacia(const lista_t *lista);
// Devuelve la cantidad de elementos actuales de la lista.
// Pre: la lista fue creada.
// Post: se devuelve un número no negativo.
size_t lista_largo(const lista_t *lista);
// Agrega un elemento al principio de la lista.
// Pre: la lista fue creada.
// Post: la lista tiene un nuevo nodo al principio.
bool lista_insertar_primero(lista_t *lista, const lista_dato_t dato);
// Agrega un elemento al final de la lista.
// Pre: la lista fue creada.
// Post: la lista tiene un nuevo nodo al final.
bool lista_insertar_ultimo(lista_t *lista, const lista_dato_t dato);
// Almacena en "dato" el contenido del primer nodo de la lista. Si la
// lista está vacía, no se almacena nada en "dato".
// Pre: la lista fue creada.
// Post: 'true' si se almacenó correctamente, 'false' si la lista está vacía.
bool lista_ver_primero(const lista_t *lista, lista_dato_t *dato);
// Almacena en "dato" el contenido del último nodo de la lista. Si la
// lista está vacía, no se almacena nada en "dato".
// Pre: la lista fue creada.
// Post: 'true' si se almacenó correctamente, 'false' si la lista está vacía.
bool lista_ver_ultimo(const lista_t *lista, lista_dato_t *dato);
// Borra el primer nodo de la lista. Si la lista está vacía no se
// almacena nada en "dato".
// Pre: la lista fue creada.
// Post: 'true' si se borró, 'false' si la lista está vacía.
bool lista_borrar_primero(lista_t *lista, lista_dato_t *dato);
// Destruye la lista, todo lo que hay en ella y libera la memoria.
// Pre: la lista fue creada.
// Post: se destruye la lista.
void lista_destruir(lista_t *lista, void destruir_dato(lista_dato_t));
/* Primitivas de iteración */
// Devuelve un iterador.
// Pre: la lista fue creada.
// Post: el iterador está inicializado. El nodo actual es el primero de la lista.
lista_iter_t* lista_iter_crear(const lista_t* lista);
// Avanza el iterador.
// Pre: el iterador fue creado.
bool lista_iter_avanzar(lista_iter_t *iter);
// Almacena en "dato" el dato que está en la posición actual del iterador.
// Si el iterador está al final, no se almacena nada.
// Pre: el iterador fue creado.
// Post: 'dato' contiene el dato del nodo actual.
bool lista_iter_ver_actual(const lista_iter_t *iter, lista_dato_t *dato);
// Almacena en "dato" el dato que está en la posición anterior del iterador.
// Si el iterador está al principio, no se almacena nada.
// Pre: el iterador fue creado.
// Post: 'dato' contiene el dato del nodo anterior.
bool lista_iter_ver_anterior(const lista_iter_t *iter, lista_dato_t *dato);
// Verifica si el iterador está al final de la lista.
// Pre: el iterador fue creado.
// Post: 'true' si el iterador está en el final, 'false' si no.
bool lista_iter_al_final(const lista_iter_t *iter);
// Destruye el iterador.
// Pre: el iterador fue creado.
// Post: el iterador es eliminado.
void lista_iter_destruir(lista_iter_t *iter);
/* Primitivas de listas junto con iterador */
// Agrega un nodo con 'dato' luego de la posición anterior del iterador, y antes de la actual.
// Pre: la lista y el iterador fueron creados.
// Post: el nuevo nodo queda entre iter->anterior e iter->actual. El iterador apuntará
// al nuevo nodo. Si se inserta al final, "iter->actual" no apunta a nada. Si
// se inserta al principio, "iter->anterior" no apunta a nada.
bool lista_insertar(lista_t *lista, lista_iter_t *iter, const lista_dato_t dato);
// Elimina el nodo de la posición actual de la lista.
// Pre: la lista y el iterador fueron creados.
// Post: el nodo fue borrado y el iterador apunta al siguiente.
// Si se borra del final, "iter->actual" no apunta a nada.
bool lista_borrar(lista_t *lista, lista_iter_t *iter, lista_dato_t *dato);
#endif