/* 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_Queue.h"

Gnut_Queue * gnut_queue_new()
{
  Gnut_Queue *a;
  
  a=(Gnut_Queue *) xmalloc(sizeof(Gnut_Queue));
  a->head = 0;
  a->tail = 0;
  a->size = 0;
  return a;
}

void gnut_queue_delete(Gnut_Queue *q, void *d)
{
  Gnut_List *tmp;
  int flag=0;
  
  if (q->tail && d==q->tail->data) {
    flag=1;
  }
  
  q->head = gnut_list_remove(q->head,d);
  
  if (flag==1) {
    /* we need to reset tail... */
    for (tmp=q->head; tmp; tmp=tmp->next) {
      if (tmp->next==0) {
	q->tail=tmp;
      }
    }
  }
}  

void gnut_queue_insert(Gnut_Queue *q, void *d)
{
  Gnut_List *tmp;

  if (!q) {
    gd_s(0, "gnut_queue_insert q=");
    gd_p(0, q);
    gd_s(0, " d=");
    gd_p(0, d);
    gd_s(0, "\n");
    exit(0);
  }
  gd_s(4,"gnut_queue_insert entering q=");
  gd_p(4, q);
  gd_s(4, " d=");
  gd_p(4, d);
  gd_s(4, "\n");
  
  tmp=(Gnut_List *) xmalloc(sizeof(Gnut_List));
  tmp->data = d;
  tmp->next = 0;
  q->size++;
  
  gd_s(4, "new size: ");
  gd_i(4, q->size);
  gd_s(4, "\n");
  
  if (q->head == 0) {
    q->head = q->tail = tmp;
  } else {
    gnut_mprobe(q->tail);
    q->tail->next = tmp;
    q->tail = tmp;
  }
}

/* Remove an item from the end of a queue, free the queue node but don't
 * free the data itself */
void * gnut_queue_remove(Gnut_Queue *q)
{
  Gnut_List *gltmp;
  void *ret;
  
  gnut_mprobe(q);
  
  if (!q) {
    gd_s(0, "gnut_queue_remove q=");
    gd_p(0, q);
    gd_s(0, "\n");
    exit(0);
  }
  
  gltmp=q->head;
  
  if (gltmp) {
    gnut_mprobe(gltmp);
    
    q->head=q->head->next;
    if (q->head==0) {
      q->tail=0;
    }
  
    ret=gltmp->data;
    free(gltmp);
  
    q->size--;
    return ret;
  }
  /* else */
  return 0;
}

Gnut_List * gnut_queue_list(Gnut_Queue *q)
{
  if (!q) {
    gd_s(0, "gnut_queue_list q=");
    gd_p(0, q);
    gd_s(0, "\n");
    exit(0);
  }
  return q->head;
}

void gnut_queue_free(Gnut_Queue *q)
{
  Gnut_List *gltmp,*gltmp2;
  
  gd_s(2, "gnut_queue_free entering q=");
  gd_p(2, q);
  gd_s(2, "\n");
  
  if (!q) {
    gd_s(0, "q=");
    gd_p(0, q);
    gd_s(0, "\n");
    exit(0);
  }
  
  for (gltmp=q->head;gltmp;gltmp=gltmp2) {
    gltmp2=gltmp->next;
    if (gltmp->data) {
      free(gltmp->data);
    }
    free(gltmp);
  }
  gd_s(2, "gnut_queue_free returning\n");
}
