/*
 * See Licensing and Copyright notice in naev.h
 */
/**
 * @file queue.c
 *
 * @brief A dodgy implementation of a queue.
 */

/** @cond */
#include <stdlib.h>
/** @endcond */

#include "queue.h"

#include "log.h"

/**
 * @brief Node struct.
 */
typedef struct Node_ *Node;
typedef struct Node_ {
   void *data; /**< Assosciated data. */
   Node  next; /**< Next node. */
} Node_;

/**
 * @brief Queue struct.
 */
typedef struct Queue_ {
   Node first; /**< First node in the queue. */
   Node last;  /**< Last node in the queue. */
} Queue_;

/**
 * @brief Creates a queue.
 *
 *    @return A pointer to a queue.
 */
Queue q_create( void )
{
   /* Create the queue. */
   Queue q = malloc( sizeof( Queue_ ) );

   /* Check that we didn't get a NULL. */
#ifdef DEBUGGING
   if ( q == NULL ) {
      WARN( "q == NULL" );
      return NULL;
   }
#endif /* DEBUGGING */

   /* Assign nothing into it. */
   q->first = NULL;
   q->last  = NULL;

   /* And return (a pointer to) the newly created queue. */
   return q;
}

/**
 * @brief Destroys a queue.
 *
 *    @param q Queue to destroy.
 */
void q_destroy( Queue q )
{
#ifdef DEBUGGING
   /* Check that we didn't get a NULL. */
   if ( q == NULL ) {
      WARN( "q == NULL" );
      return;
   }
#endif /* DEBUGGING */

   /* Free all the data. */
   while ( q->first != NULL )
      q_dequeue( q );

   free( q );

   return;
}

/**
 * @brief Enqueues an item.
 *
 *    @param q Queue to use.
 *    @param data Item to enqueue.
 */
void q_enqueue( Queue q, void *data )
{
   Node n;

#ifdef DEBUGGING
   /* Check that we didn't get a NULL. */
   if ( q == NULL ) {
      WARN( "q == NULL" );
      return;
   }
#endif /* DEBUGGING */

   /* Create a new node. */
   n       = malloc( sizeof( Node_ ) );
   n->data = data;
   n->next = NULL;
   if ( q->first == NULL )
      q->first = n;
   else
      q->last->next = n;
   q->last = n;

   return;
}

/**
 * @brief Dequeues an item.
 *
 *    @param q Queue to use.
 *    @return The data.
 */
void *q_dequeue( Queue q )
{
   void *d;
   Node  temp;

#ifdef DEBUGGING
   /* Check that we didn't get a NULL. */
   if ( q == NULL ) {
      WARN( "q == NULL" );
      return NULL;
   }
#endif /* DEBUGGING */

   /* Check that it's not empty. */
   if ( q->first == NULL )
      return NULL;

   d        = q->first->data;
   temp     = q->first;
   q->first = q->first->next;
   if ( q->first == NULL )
      q->last = NULL;
   free( temp );

   return d;
}

/**
 * @brief Checks if the queue is empty.
 *
 *    @param q Queue to use.
 *    @return 1 if it's empty, 0 if it has data.
 */
int q_isEmpty( Queue q )
{
#ifdef DEBUGGING
   /* Check that we didn't get a NULL. */
   if ( q == NULL ) {
      WARN( "q == NULL" );
      return -1;
   }
#endif /* DEBUGGING */

   if ( q->first == NULL )
      return 1;
   else
      return 0;
}
