#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "generic_list.h"

void generic_node_init(generic_node *n, GENERIC_LIST_TYPE type, void* value) {
  n->data = malloc(sizeof(value));
  n->type = type;
  memcpy(n->data, value, sizeof(value));
}

void generic_list_init(generic_list *l) {
  l->size = 0;
  l->head = NULL;
  l->tail = NULL;
}

int generic_list_size(generic_list *l) {
  return l->size;
}

void generic_list_add(generic_list *l, GENERIC_LIST_TYPE type, void* value) {
  generic_node *node = malloc(sizeof(generic_node));

  node->data = malloc(sizeof(value));
  node->type = type;
  node->next = NULL;
  memcpy(node->data, value, sizeof(value));

  if (l->size == 0) {
    l->head = node;
    l->tail = node;
  } else {
    l->tail->next = node;
    l->tail = node;
  }

  l->size++;
}

generic_node generic_list_get(generic_list *l, int index) {
  assert(index >= l->size);
  int i = 0;
  generic_node* current = l->head;
  while(i < index) {
    current = current->next;
    i++;
  }
  return *current;
}

/*
int generic_list_get(generic_list *l, int index) {
  if (index >= l->count) {
    printf("error: index out of range");
    return 0;
  }

  return l->data[index];
}

void generic_list_set(generic_list *l, int index, int value) {
  if (index >= l->count) {
    printf("error: index out of range");
    return;
  }

  l->data[index] = value;
}

void generic_list_delete(generic_list *l, int index) {
  if (index >= l->count) {
    printf("error: index out of range");
    return;
  }

  int j = index;
  for (int i = index; i < l->count; i++) {
    l->data[j] = l->data[i];
    j++;
  }

  l->count--;
}

int generic_list_sum(generic_list *l) {
  int sum = 0;
  for (int i = 0; i < l->count; i++) {
    sum += (l->data[i]);
  }
  return sum;
}

*/
void generic_list_print(generic_list *l) {
  generic_node *node = l->head;
  while (node != NULL) {
    switch(node->type) {
      case INT:
        {
          int value = *(int*)(node->data);
          printf("%i ", value);
        }
        break;

      case LONG:
        {
          long value = *(long*)(node->data);
          printf("%li ", value);
        }
        break;

      case LONG_LONG:
        {
          long long value = *(long long*)(node->data);
          printf("%lli ", value);
        }
        break;
    }
    node = node->next;
  }
  printf("\n");
}

/*
void generic_list_free(generic_list *l) {
  free(l->data);
}
*/
