#include "SimpleTypeSystem.h"
#include "test_macros.h"
#include <stdlib.h>
#include <stdint.h>
#include <time.h>

void
for_each_print_lst (SLinkedList * self, sint item, sint * itt) {
  s_print ("The number is: %d on iteration: %d\n", item, (*itt));
  (*itt)++;
}

int test_linked_list (void) {
  setup_unit ();
  
  SLinkedList * list = NULL;
  list = s_linked_list_new (NULL);
  
  test_case (list != NULL, "Linked list not null");
  
  s_print ("Adding a random number to the linked list (bettween 0 and 20).\n");
  
  srand(time(NULL));
  
  sint r_p = rand () % 20;
  
  s_print (YELLOW
           "------------------------\n"
           "APPEND TESTS\n"
           "------------------------\n"
           RESET);
  
  s_linked_list_append (list, (spointer)(intptr_t) r_p);
  
  test_case (s_linked_list_len (list) == 1, "The reported length of the linked"
                                            " list is 1.");
  
  test_case (s_linked_list_get_next (list) == NULL, "There are no next items in the"
                                             " linked list.");
  
  test_case (s_linked_list_get_prev (list) == NULL, "There are no previous items in"
                                             " the linked list.");
  
  test_case (s_linked_list_get_current (list) != NULL, "The current item exists.");
  
  test_case ((intptr_t) s_linked_list_get_current (list) == r_p, "The value"
                                 "addad was the same as the one retrieved.");
  
  s_print ("Removing current item in preperation for next test.\n");
  
  s_linked_list_remove_current (list, FALSE);
  
  s_print ("Item removed\n");
  
  test_case (s_linked_list_len (list) == 0, "The reported list length is 0");
  
  
  s_print ("Filling list with twenty items (0, 1, ... 18, 19)\n");
  
  for (sint i = 0; i < 20; i++) {
    s_linked_list_append (list, (spointer)(intptr_t) i);
  }
  
  
  test_case (s_linked_list_len (list) == 20, "The reported length of the list"
                                             " is 20.");
  
  s_print ("Will now print list using a callback.\n");
  
  sint itt = 0;
  
  s_linked_list_for_each (list, FOREACHFUNC (for_each_print_lst), &itt);
  
  s_print (YELLOW "Removing all items, from head.\n" RESET);
  
  for (sint i = 0; i < 20; i++) {
    s_linked_list_head (list);
    s_linked_list_remove_current (list, FALSE);
  }
  
  test_case (s_linked_list_len (list) == 0, "The reported length of the list"
                                            " is 0.");
  
  s_print ("Filling list with twenty items (19, 18, ... 1, 0)\n");
  
  for (sint i = 19; i >= 0; i--) {
    s_linked_list_append (list, (spointer)(intptr_t) i);
  }
  
  s_print (YELLOW "Removing all items, from tail.\n" RESET);
  
  for (sint i = 0; i < 20; i++) {
    s_linked_list_tail (list);
    s_linked_list_remove_current (list, FALSE);
  }
  
  test_case (s_linked_list_len (list) == 0, "The reported length of the list"
                                            " is 0.");
  
  s_print (YELLOW
           "------------------------\n"
           "PREPEND TESTS\n"
           "------------------------\n"
           RESET);

  s_linked_list_prepend (list, (spointer)(intptr_t) r_p);
  
  test_case (s_linked_list_len (list) == 1, "The reported length of the linked"
                                            " list is 1.");
  
  test_case (s_linked_list_get_next (list) == NULL, "There are no next items in the"
                                             " linked list.");
  
  test_case (s_linked_list_get_prev (list) == NULL, "There are no previous items in"
                                             " the linked list.");
  
  test_case (s_linked_list_get_current (list) != NULL, "The current item exists.");
  
  test_case ((intptr_t) s_linked_list_get_current (list) == r_p, "The value"
                                 "addad was the same as the one retrieved.");
  
  s_print ("Removing current item in preperation for next test.\n");
  
  s_linked_list_remove_current (list, FALSE);
  
  s_print ("Item removed\n");
  
  test_case (s_linked_list_len (list) == 0, "The reported list length is 0");
  
  
  s_print ("Filling list with twenty items (0, 1, ... 18, 19)\n");
  
  for (sint i = 0; i < 20; i++) {
    s_linked_list_prepend (list, (spointer)(intptr_t) i);
  }
  
  
  test_case (s_linked_list_len (list) == 20, "The reported length of the list"
                                             " is 20.");
  
  s_print ("Will now print list using a callback.\n");
  
  itt = 0;
  
  s_linked_list_for_each (list, FOREACHFUNC (for_each_print_lst), &itt);
  
  s_print (YELLOW "Removing all items, from head.\n" RESET);
  
  for (sint i = 0; i < 20; i++) {
    s_linked_list_head (list);
    s_linked_list_remove_current (list, FALSE);
  }
  
  test_case (s_linked_list_len (list) == 0, "The reported length of the list"
                                            " is 0.");
  
  s_print ("Filling list with twenty items (19, 18, ... 1, 0)\n");
  
  for (sint i = 19; i >= 0; i--) {
    s_linked_list_prepend (list, (spointer)(intptr_t) i);
  }
  
  s_print (YELLOW "Removing all items, from tail.\n" RESET);
  
  for (sint i = 0; i < 20; i++) {
    s_linked_list_tail (list);
    s_linked_list_remove_current (list, FALSE);
  }
  
  test_case (s_linked_list_len (list) == 0, "The reported length of the list"
                                            " is 0.");
  
  s_linked_list_free (list, FALSE);
  
  s_print ("Freed stuffs.\n");
  
  end_unit ();
}
