#include <stdio.h>
#include "dllist.h"

T_Dllist_ptr Dllist_create(void(* freeItem) (void * item)) {
  T_Dllist_ptr l;

  l = (T_Dllist_ptr)malloc(sizeof(struct T_Dllist));
  l->first = l->last = NULL;

  l->freeItem = freeItem;

  return l;
}

void Dllist_destroy(T_Dllist_ptr l) {
  while (l->first) { Dllist_remove(l, l->first); }
  free(l);
};

int Dllist_isEmpty(T_Dllist_ptr l) {
	if (l != NULL){
		return l->first == NULL;
	}else{
		printf("Dllist is NULL\n"); 
		return 1;
	}
}

Dllist_item_ptr Dllist_insert(T_Dllist_ptr l, void * i) {
  Dllist_item_ptr item;

  item = (Dllist_item_ptr)malloc(sizeof(struct Dllist_item));
  item->item = i;
  item->prev = item->next = NULL;
  if (l->first == NULL) { l->first = item; }
  else {
    l->last->next = item;
    item->prev = l->last;
  }
  l->last = item;

  return item;
};

void Dllist_remove(T_Dllist_ptr l, Dllist_item_ptr item) {
  if (l->first == NULL) {
    printf("ERROR remove from an empty list\n");
    return;
  }

  if (l->first->next == NULL) {
    /* Element to remove is the unique item */
    l->freeItem(item);
    l->first = NULL;
    l->last = l->first;    
    
  } else {
    if (item->prev == NULL) {
      /* Element to remove is the first */
      l->first = item->next;
      l->first->prev = NULL;
      l->freeItem(item);
    } else if (item->next == NULL) {
      /* Element to remove is the last */
      l->last = item->prev;
      l->last->next = NULL;
      l->freeItem(item);
    } else {
      item->prev->next = item->next;
      item->next->prev = item->prev;      
      l->freeItem(item);
    }
  }
}

void Dllist_extract(T_Dllist_ptr l, Dllist_item_ptr item) {
  if (l->first == NULL) {
    printf("ERROR remove from an empty list\n");
    return;
  }

  if (l->first->next == NULL) {
    /* Element to remove is the unique item */
    //l->freeItem(item);
    l->first = NULL;
    l->last = l->first;    
    
  } else {
    if (item->prev == NULL) {
      /* Element to remove is the first */
      l->first = item->next;
      l->first->prev = NULL;
      //l->freeItem(item);
    } else if (item->next == NULL) {
      /* Element to remove is the last */
      l->last = item->prev;
      l->last->next = NULL;
      //l->freeItem(item);
    } else {
      item->prev->next = item->next;
      item->next->prev = item->prev;      
      //l->freeItem(item);
    }
  }
}

Dllist_item_ptr Dllist_enqueue(T_Dllist_ptr l, Dllist_item_ptr item) {  
  item->prev = item->next = NULL;
  if (l->first == NULL) { l->first = item; }
  else {
    l->last->next = item;
    item->prev = l->last;
  }
  l->last = item;

  return item;
};

Dllist_item_ptr Dllist_dequeue(T_Dllist_ptr l) {
  Dllist_item_ptr elem = NULL;
  	
  if (l->first == NULL) {
    //printf("dequeue from an empty list\n");
    return NULL;
  
  }else{
  	if (l->first->next == NULL) {
	    /* Element to dequeue is the unique item */
		elem = l->first;
	    l->first = NULL;
	    l->last = l->first;  
  	}else{
	    /* Element to dequeue is not the unique item */
	    elem = l->first;    
	    l->first = l->first->next;
	    l->first->prev = NULL;                   
  	}
  }
  
  return elem;
}

Dllist_item_ptr Dllist_first(T_Dllist_ptr l) { return l->first; }

Dllist_item_ptr Dllist_next(Dllist_item_ptr item){return item->next;}

Dllist_item_ptr Dllist_prev(Dllist_item_ptr item){return item->prev;}

void Dllist_print(T_Dllist_ptr l, void * item) { printf("Dllist_item_ptr: not implemented yet.\n"); }
