/** 
 * \file linearlist.h
 * \brief linearlist header file
 * \details File contains structures, enumerations and functions declarations for linear list (type LIFO)
 *
 * \author Juraj Golej
 * \version 1.0
 */


#ifndef LINEARLIST_H_
#define LINEARLIST_H_

#include <stdlib.h>
#include <stdbool.h>
#include <inttypes.h>

/** 
 * \brief linearlist node structure
 *   
 * Declaration of one node in linear list. It contains one pointer on next node in linear list. 
 * Everything, what you must do, it's create your user structure, where first variable will be 
 * this structure, \c struct \c linearlist_node \c node; After that, you can use your struct 
 * as input parameter (node) in linear list functions.
 */
struct linearlist_node {
	struct linearlist_node* next;	///< Pointer on next node
}; /* struct linearlist_node */

/** 
 * \brief linearlist structure
 */
struct linearlist {
	struct linearlist_node* head;	///< Pointer on the top element (node) in list
}; /* struct linearlist */

/**
 * \brief Check, if the element is the member of the list
 * 
 * \param[in] list Pointer on linear list
 * \param[in] node Element
 * 
 * \return \b bool The result
 * \retval true Element is member of the list
 * \retval false Element isn't member of the list, or input parameters are \c NULL
 */
static inline bool linearlist_is_member(const struct linearlist* const list, const void *const node)
{
	if(!list || !node) {
		return false;
	}

	struct linearlist_node *actual;
	for(actual = list->head; actual; actual = actual->next) {
		if(actual == node) {
			return true;
		}
	}

	return false;
}

/**
 * \brief Push one element to list
 * 
 * \param[in] list Pointer on linear list
 * \param[in] node Element for pushing
 */
static inline void linearlist_push(struct linearlist* const list, void* const node)
{
	if(linearlist_is_member(list, node)) {
		return;
	}

	((struct linearlist_node*)node)->next = list->head;
	list->head = (struct linearlist_node*)node;
}

/**
 * \brief Pull one element from list
 * 
 * \param[in] list Pointer on linear list
 * 
 * \return \b void* Pointer on pulled element (or \c NULL, if list is empty)
 */
static inline void* linearlist_pull(struct linearlist* const list)
{
	if(!list || !list->head) {
		return NULL;
	}

	struct linearlist_node *tmp = list->head;

	list->head = list->head->next;
	return (void*)tmp;
}

/**
 * \brief Delete element from linear list
 * 
 * \param[in] list Pointer on linear list
 * \param[in] node Element
 * 
 * \return \b bool The result
 * \retval true Element was deleted from the list
 * \retval false Element isn't member of the list, input parameters are \c NULL or list is empty
 */
bool linearlist_delete(struct linearlist* const list, void *const node);

/**
 * \brief Erase linear list
 * 
 * \param[in] list Pointer on linear list
 */
static inline void linearlist_reset(struct linearlist* const list)
{
	while(linearlist_pull(list));
}

/**
 * \brief Get next element after \c node
 * 
 * \param[in] node The element from which we want to get the next one
 * 
 * \return \b void* Pointer on next element (can be \c NULL)
 */
static inline void* linearlist_get_next(const void *const node)
{
	if(!node) {
		return NULL;
	}
	
	return (void*)(((struct linearlist_node*)node)->next);
}

/**
 * \brief Get head element from list
 * 
 * \param[in] list Pointer on linear list
 * 
 * \return \b void* Pointer on head element (can be \c NULL)
 */
static inline void* linearlist_get_head(struct linearlist* const list)
{
	if(!list) {
		return NULL;
	}

	return (void*)list->head;
}

/**
 * \brief Check, if linear list is empty
 * 
 * \param[in] list Pointer on linear list
 * 
 * \return \c bool The result
 * \retval true Linear list is empty
 * \retval false Linear list isn't empty
 */
static inline bool linearlist_is_empty(const struct linearlist* const list)
{
	if(!list || !list->head) {
		return true;
	}

	return false;
}


#endif /* LINEARLIST_H_ */