/*
   File:        stack.c
   Author:      Jeff Schneider
   Created:     Thurs Nov 23 14:38:00 EST 2000
   Description: FIFO stack implementation

   Copyright (C) 2000, Weng-Keen Wong
*/

#include "standard.h"
#include "stack.h"
#include "amma.h"

/* Makes a stack element with the data portion set.  The next and
   prev pointers are left NULL so that this element can be connected
   to the stack by the calling routine */
static stack_elem* mk_stack_elem(void* data)
{
  stack_elem* se = NULL;
  se = AM_MALLOC(stack_elem);
  se->data = data;
  se->prev = NULL;
  se->next = NULL;
  return se;
}

stack* mk_empty_stack(void (*free_data)(void* data),
		      void (*fprintf_data)(FILE* s, char* m1, void* data, char* m2))
{
  stack* s = NULL;
  s = AM_MALLOC(stack);
  s->size = 0;
  s->head = NULL;
  s->tail = NULL;
  s->free_data = free_data;
  s->fprintf_data = fprintf_data;
  return s;
}

void free_stack(stack* s)
{
  stack_elem* se = s->head;
  stack_elem* temp = NULL;

  while( se != NULL )
    {
      (*s->free_data)(se->data);
      temp = se;
      AM_FREE(temp,stack_elem);
      se = se->next;
    }
  AM_FREE(s,stack);
}

void stack_push(stack* s, void* data)
{
  stack_elem* se = NULL;
  stack_elem* temp = NULL;

  se = mk_stack_elem(data);
  if( s->head == NULL )
    {
      /* Stack is empty */
      s->head = se;
      s->tail = se;
    }
  else
    {
      /* Stack is not empty.  Since we pop from the tail and push onto
         the head of the stack, we put the new element to head */
      temp = s->head;
      s->head = se;
      se->next = temp;
      temp->prev = se;
    }
  s->size += 1;
}

void* stack_pop(stack* s)
{
  stack_elem *se = NULL;
  void* data = NULL;

  if(( s-> size == 0 ) || ( s->tail == NULL ))
    {
      my_error("Cannot pop from an empty stack\n");
    }
  se = s->tail;
  s->tail = se->prev;
  if( s->tail == NULL )
    {
      /* We popped the last one */
      s->head = NULL;
    }
  else
    {
      s->tail->next = NULL;
    }
  s->size -= 1;
  data = se->data;
  AM_FREE(se,stack_elem);
  return data;
}

void fprintf_stack(FILE* fp, char* m1, stack *s, char* m2)
{
  char buf[255];
  stack_elem* se = NULL;

  sprintf(buf,"%s = {\n",m1);
  fprintf(fp,buf);
  se = s->head;
  while( se != NULL ) {
      (*s->fprintf_data)(fp, "Data", se->data, m2);

      if( se->prev == NULL ) fprintf(fp,"Prev = (NULL)\n");
      else fprintf(fp,"Prev = %p\n", (void *) se->prev);

      if( se->next == NULL ) fprintf(fp,"Next = (NULL)");
      else fprintf(fp,"Next = %p\n", (void *) se->next);

      se = se->next;
  }
  sprintf(buf,"\n} %s\n", m2);
  fprintf(fp,buf);
}

int stack_size(stack* s)
{
  return s->size;
}
