#include "queue.h"
#include <assert.h>

queue* new_queue(void)
{
    queue* Q = malloc(sizeof(queue));
    Q->in = new_stack();
    Q->out = new_stack();
    Q->size = 0;
    return Q;
}

void free_queue(queue* Q)
{
    free_stack(Q->in);
    free_stack(Q->out);
    free(Q);
}

int is_empty_queue(queue* Q) { return is_empty_stack(Q->in) && is_empty_stack(Q->out); }

void enqueue(queue* Q, size_t elem)
{
    push_stack(Q->in, elem);
    Q->size += 1;
}

int dequeue(queue* Q, size_t* elem)
{
    if (is_empty_stack(Q->out)) {
        assert(Q->in->size == Q->size);
        size_t tmp;
        while (!is_empty_stack(Q->in)) {
            pop_stack(Q->in, &tmp);
            push_stack(Q->out, tmp);
        }
        assert(Q->out->size + Q->in->size == Q->size);
    }
    int r = pop_stack(Q->out, elem);
    Q->size -= r;
    return r;
}

void empty_queue(queue* Q)
{
    empty_stack(Q->in);
    empty_stack(Q->out);
    Q->size = 0;
}

void remove_from_queue(queue* Q, size_t elem)
{
    assert(Q->out->size + Q->in->size == Q->size);
    remove_from_stack(Q->in, elem);
    remove_from_stack(Q->out, elem);
    Q->size = Q->out->size + Q->in->size;
}

void bulk_remove_from_queue(queue* Q, const size_t* ToRemove)
{
    assert(Q->out->size + Q->in->size == Q->size);
    bulk_remove_from_stack(Q->in, ToRemove);
    bulk_remove_from_stack(Q->out, ToRemove);
    Q->size = Q->out->size + Q->in->size;
}

int contains_queue(queue* Q, size_t elem)
{
    return contains_stack(Q->in, elem) || contains_stack(Q->out, elem);
}

// vim: textwidth=100 foldmethod=indent
