//************************************************************
//ThreadSafeQueue
//************************************************************
#include "stdafx.h"
#include "semaphore.h"
#include "tsq.h"

ThreadSafeQueue::ThreadSafeQueue(LONG MaxQueueSize)
{
    First = NULL;
    ElementCounter = new Semaphore(MaxQueueSize);
}

ThreadSafeQueue::~ThreadSafeQueue()
{
    TSElement * pElement;

    while (First)
    {
        pElement = First;
        First = First->Next;
        delete pElement;
    }

    delete ElementCounter;
}

LONG ThreadSafeQueue::Count()
{
    return ElementCounter->Count;
}

BOOL ThreadSafeQueue::Push(void * Data)
{
    TSElement * pElement = new TSElement;
    pElement->Data = Data;
    pElement->Next = NULL;

    QueueLock.Lock();

    //Increment the semaphore
    if(!ElementCounter->Release())
    {
        //Not allowed to insert, semaphore is maxed out
        QueueLock.Unlock();
        delete pElement;
        return FALSE;
    }

    if (!First)
    {
        //First element in the queue
        First = Last = pElement;

        QueueLock.Unlock();
        return TRUE;
    }

    //Critical path
    Last->Next = pElement; //Link new element
    Last = pElement; //Move Last pointer

    QueueLock.Unlock();
    return TRUE;
}

void * ThreadSafeQueue::Pop(int Timeout,HANDLE hEvent) //Defaults to false to emulate standard behavior
{
    TSElement * pElement;
    void * ReturnValue;

    //Decrement the semaphore
    if(!ElementCounter->Acquire(Timeout,hEvent)) //If waiting on queue sleep here
        return NULL; //Nothing on the queue and didn't want to wait

    QueueLock.Lock();

    // Save the pointer
    pElement = First;
    // Update the first element
    First = First->Next;

    QueueLock.Unlock();

    ReturnValue = pElement->Data;
    delete pElement;

    return ReturnValue;
}
