/** \file
 *
 *  Contains the RingBufferVoid and RingBuffer class declarations.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef RINGBUFFER_H_
#define RINGBUFFER_H_

#include <cstdlib>
#include <cstdio>

#include "ListEntry.h"
#include "Mutex.h"

/**
 *  Thread-safe ring buffer for storing void pointers
 *
 *  \li On Construction: start_ = end_ = NULL
 *  \li On push(T1), start_ = end_ = ListEntry1(T1-->ListEntry1);
 *  \li On push(T2), start_ = ListEntry1(T1-->ListEntry2), end_ = ListEntry2(T2-->ListEntry1);
 *  \li On push(T3), start_ = ListEntry1(T1-->ListEntry2), end_ = ListEntry3(T3-->ListEntry1);
 *  \li On pop()-->T1, start_ = ListEntry2(T2-->ListEntry3), end_ = ListEntry3(T3-->ListEntry1);
 *  \li On pop()-->T2, start_ = ListEntry3(T3-->ListEntry1), end_ = ListEntry3(T3-->ListEntry1);
 *  \li On pop()-->T3, start_ = NULL, end_ = ListEntry3(T3-->ListEntry1);
 *  \li On push(T4), start_ = end_ = ListEntry3(T3-->ListEntry1);
 *  \li On push(T5), start_ = ListEntry3(T3-->ListEntry2), end_ = ListEntry1(T5-->ListEntry2);
 *  \li On pop()-->T4, start_ = end_ = ListEntry1(T5-->ListEntry2);
 *  \li On pop()-->T5, start_ = NULL, end_ = ListEntry1(T5-->ListEntry1);
 *  \li isEmpty true when start_ == NULL
 *
 *  \ingroup utils
 */
class RingBufferVoid
{
public:
    RingBufferVoid( const bool freeOnCleanup = true );

    virtual ~RingBufferVoid();

    bool isEmpty();

    void freeAll();

    void push( void* item );

    void* pop();

    void* peek();

protected:
    ListEntry<void*>* start_;
    ListEntry<void*>* end_;
    const bool freeOnCleanup_;
    Mutex mutex_;

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    RingBufferVoid( const RingBufferVoid& old ); // disallow copy constructor

};

/**
 *  Thread-safe ring buffer for storing class pointers
 *
 *  \ingroup utils
 */
template< typename T >
class RingBuffer : public RingBufferVoid
{
public:
    RingBuffer( const bool deleteOnCleanup = true )
        : RingBufferVoid( deleteOnCleanup )
    {}
    ;

    virtual ~RingBuffer()
    {
        deleteAll();
    };

    void deleteAll()
    {
        while( freeOnCleanup_ && !isEmpty() )
        {
            T item( pop() );
            if( NULL != item )
            {
                delete item;
            }
        }
    };

    void push( T item )
    {
        RingBufferVoid::push( ( void* )item );
    };

    T pop()
    {
        return ( T )RingBufferVoid::pop();
    };

    T peek()
    {
        return ( T )RingBufferVoid::peek();
    };
};

#endif /*RINGBUFFER_H_*/
