/**
 * Linked List templates
 *
 * @file linkedList.h
 * @date 2017
 * @author Lukas Vykydal
 *
 * This file contains macros for creating linkedList structures in memory. 
 *
 * List of t_Element(s) named "List" will look like this:
 *
 * t_Element *List;
 *     |
 *     V
 * -------------- |-> -------------- |-> --------------
 * | *Next -----+-|   | *Next -----+-|   | *Next -----+-->NULL
 * | Property A |     | Property A |     | Property A |
 * | Property B |     | Property B |     | Property B |
 * | ....       |     | ....       |     | ....       |
 * --------------     --------------     --------------
 *
 * <code>
 *   // ---> *.h file
 *   //Typedef for t_Element
 *   LINKEDLIST(Element, {
 *    int PropertyA;
 *    int PropertyB; });
 *   
 *   // ---> *.c file
 *   //Function *CreateElement() for creation of new element
 *   FCN_LIST_NEW(Element);
 *  
 *   //Function *AppendList(*list, *newItem) for appending new item into list
 *   FCN_LIST_APPEND(Element);
 *
 *   ...
 * </code>
 *
 */

#include "utils.h"

#ifndef __LINKED_LIST_H__
#define __LINKED_LIST_H__

/**
 * \def LINKEDLIST
 * 
 * Create new type of structure t_\a T that is ready to be used as Linked List
 *
 * \a Content refers to data items that should be in structure. Enclose tham in {} brackets
 *
 * \param T Name of type
 * \param Content Other properties in items
 * \return C code for definition
 */
#define LINKEDLIST(T,Content)   \
typedef struct linkedList_##T { \
  struct linkedList_##T *Next;  \
  Content                       \
} t_##T

/**
 * \def FCN_LIST_NEW
 * 
 * Create new item for linked list of type t_\a T
 *
 * Method will be called Create\a T(params) params array shall be encapsulated in ().
 * initializer code shall be encapsulated in {}
 *
 * \param T Name of type
 * \param params Parameters for method
 * \param initializer Initialize of elements in new t_\a T item
 * \return New t_\a T item 
 */
#define FCN_LIST_NEW(T, params, initializer)           \
t_##T *Create##T params {                              \
  t_##T *newItem = malloc(sizeof(t_##T));              \
  C_ERROR((newItem == NULL), "Can't allocate memory"); \
  newItem->Next = NULL;                                \
  initializer;                                         \
  return newItem;                                      \
}
  
/**
 * \def FCN_LIST_APPEND
 */
#define FCN_LIST_APPEND(T)                 \
t_##T *Append##T( t_##T *op1, t_##T *op2){ \
  t_##T *listEnd = op1;                    \
                                           \
  if(op1 == NULL) return op2;              \
                                           \
  while(listEnd->Next != NULL)             \
    listEnd = listEnd->Next;               \
  listEnd->Next = op2;                     \
                                           \
  return op1;                              \
}

/**
 * \def LIST_FOREACH
 */
#define LIST_FOREACH(T, list, body)       \
do {                                      \
  t_##T *current##T = list;               \
  while(current##T != NULL) {             \
    t_##T *next##T = current##T->Next;    \
    body;                                 \
    current##T = next##T;                 \
  }                                       \
} while (0) 

#define LIST_FOREACH_BEGIN(T, list)       \
do {                                      \
  t_##T *current##T = list;               \
  while(current##T != NULL) {             \
    t_##T *next##T = current##T->Next;    

#define LIST_FOREACH_END(T)               \
    current##T = next##T;                 \
  }                                       \
} while (0) 

/**
 * \def FCN_LIST_DROP
 * 
 * Delete item from linkedList starting from \a list item
 *
 * \param T type name of LinkedList
 * \param destructor what to do de free resources allocated in this item
 * \return C code 
 */
#define FCN_LIST_DROP(T, destructor)    \
void Drop##T(t_##T *list) { \
  LIST_FOREACH( T, list, {destructor; free(current##T);} ); \
}

#endif 
