/*
 * frost_queue.c
 *
 *  Created on: Jul 1, 2012
 *      Author: ergino
 */

#include "frost_queue.h"

#include <stdio.h>

frost_pointer
frost_queue_peek_head (FROST_Queue *queue)
{
  frost_return_val_if_fail (queue != NULL, NULL);

  return queue->head ? queue->head->data : NULL;
}

frost_pointer
frost_queue_peek_tail (FROST_Queue *queue)
{
  frost_return_val_if_fail (queue != NULL, NULL);

  return queue->tail ? queue->tail->data : NULL;
}

FROST_List *
frost_queue_peek_nth_link (FROST_Queue *queue,
               frost_uint   n)
{
    FROST_List *link;
    frost_int i;

    frost_return_val_if_fail (queue != NULL, NULL);

    if (n >= queue->length)
        return NULL;

    if (n > queue->length / 2)
    {
      n = queue->length - n - 1;

      link = queue->tail;
      for (i = 0; i < n; ++i)
          link = link->prev;
    }
    else
    {
      link = queue->head;
      for (i = 0; i < n; ++i)
          link = link->next;
    }

    return link;
}

frost_pointer
frost_queue_peek_nth (FROST_Queue *queue,
          frost_uint   n)
{
  FROST_List *link;

  frost_return_val_if_fail (queue != NULL, NULL);

  link = frost_queue_peek_nth_link (queue, n);

  if (link)
    return link->data;

  return NULL;
}

frost_int
frost_queue_index (FROST_Queue        *queue,
           frost_constpointer  data)
{
  frost_return_val_if_fail (queue != NULL, -1);

  return frost_list_index (queue->head, data);
}

frost_pointer
frost_queue_pop_head (FROST_Queue *queue)
{
    frost_pointer result;
    FROST_List *old_head;

    if (!queue || queue->length == 0)
        return NULL;

    result = queue->head->data;
    old_head = queue->head;
    queue->head = old_head->next;
    frost_list_free_1 (old_head);

    if (--queue->length)
        queue->head->prev = NULL;
    else
        queue->tail = NULL;

    return result;
}

frost_bool
frost_queue_is_empty (FROST_Queue *queue)
{
    if (!queue)
        return frost_true;

    return queue->length == 0;
}

void
frost_queue_push_head (FROST_Queue *queue, frost_pointer head)
{
    if (!queue)
        return;

    queue->head = frost_list_prepend (queue->head, head);

    if (!queue->tail)
        queue->tail = queue->head;

    queue->length ++;
}

void
frost_queue_push_tail (FROST_Queue *queue, frost_pointer data)
{
    if (!queue)
        return;

    queue->tail = frost_list_append (queue->tail, data);
    if (queue->head == NULL)
        queue->head = queue->tail;
    else
        queue->tail = queue->tail->next;
    queue->length++;
}

FROST_Queue *
frost_queue_new (void)
{
    return frost_new0 (FROST_Queue, 1);
}

void
frost_queue_free (FROST_Queue *queue)
{
    if (!queue)
        return;

    frost_list_free (queue->head);
    frost_free (queue);
}

void
frost_queue_foreach (FROST_Queue *queue, FROSTFunc func, frost_pointer user_data)
{
    frost_list_foreach (queue->head, func, user_data);
}
