/*
  * Copyright (C) 2002  Mihai RUSU (dizzy@roedu.net)
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#include "list.h"
#include <stdio.h>

/*
 * Initialize a double linked list
 */
struct list_struct * list_init(void)
{
   t_list *nlist;

   if ((nlist = malloc(sizeof(t_list))) == NULL) {
      fprintf(stderr, "Not enough memory: list.c : list_init()\n");
      return NULL;
   }
   nlist->head = NULL;
   nlist->tail = NULL;
   nlist->no = 0;

   return nlist;
}

int list_purge(t_list *list)
{
   t_list_elem *elem, *next;

   if (list == NULL) {
      fprintf(stderr, "Got NULL : list.c : list_purge()\n");
      return -1;
   }

   for(elem = list->head; elem; elem = next) {
      next = elem->next;
      free(elem);
   }

   list->no = 0;
   list->head = NULL;
   list->tail = NULL;

   return 0;
}

int list_free(t_list *list)
{
   if (list == NULL) {
      fprintf(stderr, "Got NULL : list.c : list_free()\n");
      return -1;
   }
   if (list_purge(list)<0) return -1;

   free(list);

   return 0;
}

int list_insert_data(t_list *list, void * data)
{
   t_list_elem *elem;

   if (list == NULL) {
      fprintf(stderr, "Got NULL list : list.c : list_append()\n");
      return -1;
   }
   
   if ((elem = malloc(sizeof(t_list_elem))) == NULL) {
      fprintf(stderr, "list.c : list_append() : not enough memory for elem\n");
      return -1;
   }

   elem->next = list->head;
   elem->prev = NULL;
   if (list->head) list->head->prev = elem;
   else list->tail = elem;
   list->head = elem;

   list->no++;

   elem->data = data;

   return 0;
}

extern int list_append_data(t_list *list, void *data)
{
   t_list_elem *elem;
   
   if (list == NULL) {
      fprintf(stderr, "list.c : list_append : got NULL list\n");
      return -1;
   }
   
   if ((elem = malloc(sizeof(t_list_elem))) == NULL) {
      fprintf(stderr, "list.c : list_append : could not allocate for elem\n");
      return -1;
   }
   
   elem->data = data;
   elem->prev = list->tail;
   elem->next = NULL;

   if (list->tail) list->tail->next = elem;
   else list->head = elem;
   
   list->tail = elem;
   
   list->no++;

   return 0;
}

extern void * list_fetch(t_list *list)
{
   void *res;

   if (list == NULL) {
      fprintf(stderr, "list.c : list_fetch : got NULL list\n");
      return NULL;
   }

   if (list->head) {
      t_list_elem *save;
      
      save = list->head;
      res = save->data;
      list->head = list->head->next;
      if (list->head) list->head->prev = NULL;
      else list->tail = NULL;

      list->no--;
      free(save);
   } else res = NULL;

   return res;
}

extern int list_delete_by_elem(t_list *list, t_list_elem *elem)
{
   if (list == NULL) {
      fprintf(stderr, "list.c : list_delete_by_elem : got NULL list\n");
      return -1;
   }

   if (elem == NULL) {
      fprintf(stderr, "list.c : list_delete_by_elem : got NULL elem\n");
      return -1;
   }

   if (list->no < 1) {
      fprintf(stderr, "list.c : list_delete_by_elem : list is empty\n");
      return -1;
   }

   if (elem->next) elem->next->prev = elem->prev;
   if (elem->prev) elem->prev->next = elem->next;
   if (list->head == elem) list->head = elem->next;
   if (list->tail == elem) list->tail = elem->prev;

   list->no--;
   free(elem);

   return 0;
}

extern int list_get_size(t_list *list)
{
   if (list == NULL) {
      fprintf(stderr, "list.c : list_get_size : got NULL list\n");
      return -1;
   }
   
   return list->no;
}

extern t_list_elem * elem_create(void)
{
   t_list_elem *elem;
   
   if ((elem = malloc(sizeof(t_list_elem))) == NULL) {
      fprintf(stderr, "list.c : elem_create : could not allocate elem\n");
      return NULL;
   }
   
   elem->data = NULL;
   elem->next = NULL;
   elem->prev = NULL;
   
   return elem;
}

extern void elem_destroy(t_list_elem *elem)
{
   if (elem == NULL) {
      fprintf(stderr, "list.c : elem_destroy : got NULL elem\n");
      return;
   }
   
   free(elem);
}

extern int elem_set_data(t_list_elem *elem, void * data)
{
   if (elem == NULL) {
      fprintf(stderr, "list.c : elem_set_data : got NULL elem\n");
      return -1;
   }
   
   elem->data = data;
   
   return 0;
}

extern void * elem_get_data(t_list_elem *elem)
{
   if (elem == NULL) {
      fprintf(stderr, "list.c : elem_get_data : got NULL elem\n");
      return NULL;
   }
   
   return elem->data;
}
