#include "TickQueue.h"


TickQueue::TickQueue()
    : ReferenceCounter()
{
    maxSize = 0;
    readPosition = 0;
    writePosition = 0;
    queue = 0;
    exit = 0;
}

TickQueue::~TickQueue()
{
    delete[] queue;
}

void TickQueue::startNextTick( Framework::Array<Block*>* zSources )
{
    std::unique_lock<std::mutex> lk( mutex );
    readPosition = 0;
    writePosition = 0;
    int count = zSources->getEintragAnzahl();
    if( count >= maxSize )
    {
        Block** temp = new Block * [ count + 1000 ];
        memcpy( queue, temp, sizeof( Block* ) * maxSize );
        memset( temp + sizeof( Block* ) * maxSize, 0, sizeof( Block* ) * (count + 1000 - maxSize) );
        maxSize = count + 1000;
        delete[]queue;
        queue = temp;
    }
    for( Block* block : *zSources )
        queue[ writePosition++ ] = block;
    lk.unlock();
    hasBlocks.notify_all();
}

void TickQueue::addToQueue( Block* zBlock )
{
    std::unique_lock<std::mutex> lk( mutex );
    if( writePosition >= maxSize )
    {
        Block** temp = new Block * [ maxSize + 1000 ];
        memcpy( queue, temp, sizeof( Block* ) * maxSize );
        memset( temp + sizeof( Block* ) * maxSize, 0, sizeof( Block* ) * 1000 );
        maxSize += 1000;
        delete[]queue;
        queue = temp;
    }
    queue[ writePosition++ ] = zBlock;
    lk.unlock();
    hasBlocks.notify_one();
}

Block* TickQueue::zNextBlock( bool& waiting )
{
    std::unique_lock<std::mutex> lk( mutex );
    if( readPosition == writePosition && exit )
        return 0;
    if( readPosition == writePosition )
    {
        lk.unlock();
        hasNoBlocks.notify_all();
        lk.lock();
        waiting = 1;
        hasBlocks.wait( lk, [this] { return readPosition < writePosition || exit; } );
        waiting = 0;
    }
    if( readPosition < writePosition )
        return queue[ readPosition++ ];
    return 0;
}

void TickQueue::requestExit()
{
    std::unique_lock<std::mutex> lk( mutex );
    exit = 1;
    lk.unlock();
    hasBlocks.notify_all();
    hasNoBlocks.notify_all();
}

void TickQueue::waitForEmpty()
{
    std::unique_lock<std::mutex> lk( mutex );
    if( readPosition != writePosition )
        hasNoBlocks.wait( lk, [this] { return readPosition == writePosition || exit; } );
}