//////////////////////////////////////////////////////////////////////
//
// Queue.cpp: implementation of the Queue class.
//
// This module is a part of the PMCA COM package. It contains Queue
// service routines
//
// Amptek Inc. 2000
//
//////////////////////////////////////////////////////////////////////

#include "windows.h"
#include "Queue.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

QueueType::QueueType()
{
    m_id = 0;
    m_last = NULL;
    m_first = NULL;
    m_getSemaphore = ::CreateSemaphore(NULL, 0, 100000, NULL);
    m_access = ::CreateMutex(NULL, FALSE, NULL);
}

long QueueType::Put(QueueEntryType *entry)
{
    long id;
    long count;
    BOOL success;
    LockAccess();
    entry->prev = m_last;
    entry->next = NULL;
    if (m_last)
        m_last->next = entry;
    else
        m_first = entry;
    m_last = entry;
    m_id++;
    m_id &= 0x3FFFFFFF;
    id = m_id;
    entry->id = id;
    success = ::ReleaseSemaphore(m_getSemaphore, 1, &count);
    UnlockAccess();
    return(id);
}

QueueEntryType *QueueType::Get(void)
{
    QueueEntryType *entry;
    int stat = WaitForSingleObject(m_getSemaphore, INFINITE);
    LockAccess();
    entry = m_first;
    m_first = entry->next;
    if (m_first)
        m_first->prev = NULL;
    else
        m_last = NULL;
    UnlockAccess();
    return(entry);
}

QueueEntryType *QueueType::LockedFind(long id)
{
    QueueEntryType *entry;
    LockAccess();
    entry = m_first;
    if (id >= 0)
    {
        while (entry)
        {
            if (entry->id == id)
                break;
            else
                entry = entry->next;
        }
    }
    if (!entry)
        UnlockAccess();
    return(entry);
}       

QueueEntryType *QueueType::Remove(long id)
{
    QueueEntryType *entry = LockedFind(id);
    if (entry)
    {
        int stat = WaitForSingleObject(m_getSemaphore, INFINITE);
        if (entry->prev)
            entry->prev->next = entry->next;
        else
            m_first = entry->next;
        if (entry->next)
            entry->next->prev = entry->prev;
        else
            m_last = entry->prev;
        UnlockAccess();
    }
    return(entry);
}

