/* Josh Pieper, (c) 2000 */

/* This file is distributed under the GPL, see file COPYING for details */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "gnut_lib.h"
#include "Gnut_List.h"

void free_gl(Gnut_List **x, int bugnum)
{
  gd_s(5, "free_gl x=");
  gd_p(5, x);
  gd_s(5, "\n");

  yfree((void **) x, bugnum);
}

Gnut_List * gnut_list_unlink(Gnut_List *list, void *data, Gnut_List **unlinked)
{
  Gnut_List *tmp,*prev;
  
  gd_s(5, "gnut_list_unlink list=");
  gd_p(5, list);
  gd_s(5, " data=");
  gd_p(5, data);
  gd_s(5, "\n");

  prev = 0;
  tmp=list;
  while (tmp) {
    if (tmp->data == data) {
      if (prev) {
	prev->next=tmp->next;
      }

      if (list==tmp) {
	list=list->next;
      }
      
      *unlinked=tmp;
      break;
    }
    prev=tmp;
    tmp=tmp->next;
  }
  
  gd_s(5, "gnut_list_unlink new list=");
  gd_p(5, list);
  gd_s(5, "\n");
  return list;
}
  

/* Gnut_List * gnut_list_remove(Gnut_List *list, void *data)
 *
 * removes the first occurence of data in list. It does NOT try
 * to call xfree on the data block.
 * returns the pointer to the new head of the list, does not indicate
 * whether the data was actually found */
Gnut_List * gnut_list_remove(Gnut_List *list, void *data)
{
  Gnut_List *tmp;
  Gnut_List *prev;
  int flag;

  gd_s(5, "gnut_list_remove list=");
  gd_p(5, list);
  gd_s(5, " data=");
  gd_p(5, data);
  gd_s(5, "\n");

  flag = 0;
  prev = 0;
  tmp = list;
  while (tmp) {
    gd_s(5, "glr prev=");
    gd_p(5, prev);
    gd_s(5, " tmp=");
    gd_p(5, tmp);
    gd_s(5," tmp->next=");
    gd_p(5, tmp->next);
    gd_s(5," tmp->data=");
    gd_p(5, tmp->data);
    gd_s(5, "\n");
    if (tmp->data == data) {
      /* Found it! */
      flag=1;
      /* Remove from list by changing previous element's next-pointer
       * (unless we're the first) */
      if (prev) {
	prev->next=tmp->next;
      }
      /* If we are the first, update our copy of the list head pointer */
      if (list==tmp) {
	list=list->next;
      }
      
      tmp->next = 0;

      gd_s(5, "glr tmp=");
      gd_p(5, tmp);
      gd_s(5, " &tmp==");
      gd_p(5, &tmp);
      gd_s(5, "\n");

      free_gl(&tmp, 151);

      break;
    }
    prev=tmp;
    tmp=tmp->next;
  }
  
  if (flag==0) {
    gd_s(0, "gnut_list_remove item not found to remove!!\n");
  }
  gd_s(5, "gnut_list_remove new list=");
  gd_p(5, list);
  gd_s(5, "\n");

  return list;
}
  
/* Gnut_List * gnut_list_prepend(Gnut_List *list, void *data)
 *
 * prepends data into the linked list list
 * returns the new head pointer into the list */
Gnut_List * gnut_list_prepend(Gnut_List *list, void *data)
{
  Gnut_List *gltmp;

  gd_s(5, "gnut_list_prepend list=");
  gd_p(5, list);
  gd_s(5, " data=");
  gd_p(5, data);
  gd_s(5, "\n");
  
  gltmp=(Gnut_List *) xmalloc(sizeof(Gnut_List));
  assert(gltmp);
  gltmp->data=data;
  gltmp->next=list;
  
  gd_s(5, "gnut_list_prepend  new list=");
  gd_p(5, gltmp);
  gd_s(5, "\n");
  return gltmp;
}

Gnut_List * gnut_list_append(Gnut_List *list, void *data)
{
  Gnut_List *gltmp;
  Gnut_List *glnew;

  glnew = (Gnut_List *) xmalloc(sizeof(Gnut_List));
  assert(glnew);
  glnew->data = data;
  glnew->next = 0;

  if (list == 0) {
    return glnew;
  } else {
    gltmp = list;
    while(gltmp->next) {
      gltmp = gltmp->next;
    }
    gltmp->next = glnew;
    return list;
  }
}

/* Gnut_List * gnut_list_next(Gnut_List *list)
 *
 * convenience function to return next item in list */
Gnut_List * gnut_list_next(Gnut_List *list)
{
  return list->next;
}

/* void gnut_list_foreach(Gnut_List * list, void (*GFunc)(void *, void *),
 *       void *userdata)
 *
 * for each element in list, call GFunc */
int gnut_list_foreach(Gnut_List *list, int (*GFunc)(void *,void *),
      void *userdata)
{
  Gnut_List *gltmp;
  
  gd_s(5, "gnut_list_foreach list=");
  gd_p(5, list);
  gd_s(5, "\n");
  for (gltmp=list; gltmp; gltmp=gltmp->next) {
    if ((*GFunc)(gltmp->data,userdata)==-1) {
      return -1;
    }
  }
  gd_s(5, "gnut_list_foreach returning\n");
  return 0;
}

/* Gnut_List * gnut_list_fre(Gnut_List *list)
 *
 * free's all list items and deallocates (xfree) all data blocks
 * in a list, returns a null head pointer */
Gnut_List * gnut_list_fre(Gnut_List *list)
{
  Gnut_List *gltmp, *gltmp2;

  gd_s(5, "gnut_list_free list=");
  gd_p(5, list);
  gd_s(5, "\n");
  for (gltmp=list; gltmp; gltmp=gltmp2) {
    gd_s(5, "gnut_list_free gltmp=");
    gd_p(5, gltmp);
    gd_s(5, " gltmp->next=");
    gd_p(5, gltmp->next);
    gd_s(5, "\n");

    gltmp2=gltmp->next;
    free_v(&(gltmp->data), 152);
    free_gl(&gltmp, 153);
  }
  
  gd_s(5, "gnut_list_free returning\n");
  return 0;
}

/* int gnut_list_size(Gnut_List *list)
 *
 * returns the number of items stored in list */
int gnut_list_size(Gnut_List *list)
{
  Gnut_List *glt;
  int i;
  
  gd_s(5, "gnut_list_size list=");
  gd_p(5, list);
  gd_s(5, "\n");
  
  for (i=0,glt=list; glt; glt=glt->next) {
    gd_s(5, "gnut_list_size i=");
    gd_i(5, i);
    gd_s(5, " glt=");
    gd_p(5, glt);
    gd_s(5, " glt->next=");
    gd_p(5, glt->next);
    gd_s(5, "\n");
    i++;
  }
  
  gd_s(5, "gnut_list_size returning: ");
  gd_i(5, i);
  gd_s(5, "\n");
  
  return i;
}

/* gnut_list_seek looks through a list to see if a given void * data
 * is in the list. */
int gnut_list_seek(Gnut_List *list, void *dat)
{
  int rv;
  Gnut_List *glt;

  rv = 0;
  glt = list;
  while(glt && (rv == 0)) {
    if (glt->data == dat) {
      rv = 1;
    } else {
      glt = glt->next;
    }
  }
  
  return rv;
}
