//
//  Copyright © 2004, RESON Inc. All Rights Reserved.
//
//  No part of this file may be reproduced or transmitted in any form or by
//  any means, electronic or mechanical, including photocopy, recording, or
//  information storage or retrieval system, without permission in writing
//  from RESON Inc.
//
//  Filename:   CircularBuffer.h
//
//  Project:    6046
//
//  Author(s):  W. Arcus
//
//  Purpose:    Template class to access a pool of memory as a circualar buffer.
//
//  Notes:  1)  The memory pool can be any contigious memory location provided the size criteria is met, viz: 
//              ( > sizeof( MEMORYPOOLHEADER ) + cells ).
//
//  Notes:  2)  The Read() method RETURNS A POINTER DIRECLTY INTO THE MEMORY POOL and pointing to the next available 
//              record to be read. In a multi-threaded environment, it should only be accessed from within 
//              a suitably guarded block and GetDataGuard() is provided for this purpose.FAILURE TO DO SO WILL
//              RESULT IN DATA CORRUPTION IN A MULTITHREADED ENVIRONMENT.
//
//          3)  It would be an error to handle synchronization within the Read() method since the client will
//              still be directly accessing the circular buffer thus a deadlock would result.
//

#if !defined(AFX_CIRCULARBUFFER_H__A93F104E_7F89_4934_8FE5_FB082CAB79D1__INCLUDED_)
#define AFX_CIRCULARBUFFER_H__A93F104E_7F89_4934_8FE5_FB082CAB79D1__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#pragma warning( disable : 4018 )
#pragma warning( disable : 4146 )
#pragma warning( push, 3 )
#include <memory>
#pragma warning( pop )
#pragma warning( default : 4146 )
#pragma warning( default : 4018 )

///////////////////////////////////////////////////////////////////////////////
// Module constants and definitions.

namespace NCIRCULARBUFFER                                                                                                   // Begin namespace NCIRCULARBUFFER
{
    const unsigned long                     ulVersion_c         =   1UL;                                                    // Version of the cicrular buffer header structure definition.
	const unsigned long                     ulNumberOfCells_c   =   1024UL; //255UL;                                                  // Number of data cells in the circular buffer.
    const unsigned long                     ulCellSizeInBytes_c =   128UL * 1024UL;                                         // Size of each data cell in bytes.
    const unsigned long                     ulReservedSpace_c   =   121868UL;                                               // Padding to make entire header 128k.
}

#pragma pack ( push, CIRCULARBUFFER_H_PACK, 1 )                                                                             // Single byte alignment.

typedef struct tagCELLINDEX
{
    unsigned long                           m_ulUsed;                                                                       // Cell is used (1) or unused (0).
    unsigned long                           m_ulCellsInSequence;                                                            // Number of cells that this sequence of data occupies.
    unsigned long                           m_ulSequenceNumberOfCell;                                                       // Cell number in sequence of cells for which data occupies.
    unsigned long                           m_TotalBytesInSequence;                                                         // Total bytes across all cell for data in sequence.
    unsigned long                           m_ulBytesInCell;                                                                // Total bytes used in this cell.
    unsigned long                           m_ulNextWriteIndex;                                                             // Write point of next cell allows a singly linked list of cells to be used for reading.
    bool                                    m_bHiddenRecord;                                                                // Record is flagged as hidden.
                                            
    BYTE                                    m_byReserved    [ 11 ];                                                         // Padding to 36 bytes.
}
CELLINDEX, *PCELLINDEX;

#pragma pack ( pop, CIRCULARBUFFER_H_PACK )                                                                                 // Single byte alignment.


template <typename tRecordHeader>
class CCircularBuffer
{
public:

    ///////////////
    // Services.

    // Construction, destruction etc.

                                            CCircularBuffer             (   BYTE * const            pbyMemoryPool,
                                                                            const unsigned long    &rulMemoryPoolSize,
                                                                            LPCTSTR                 lpszGuardName               = NULL,
                                                                            LPCTSTR                 lpszDataAvailableEventName  = NULL );

    virtual                                ~CCircularBuffer             (   void );

    bool                                    IsInitialized               (   void ) const;

    bool                                    InitializeHeader            (   void );

    bool                                    Write                       (   const tRecordHeader    *psRecordHeader,
                                                                            const BYTE             *pbyRecord,
                                                                            const unsigned long    &rulTotalBytesThisRecord,
                                                                            const bool             &rbHiddenRecord              = false );

    bool                                    Read                        (   unsigned long          &rulNextToRead,
                                                                            unsigned long          &rulTotalBytesThisRecord,
                                                                            tRecordHeader        * &rpsRecord,
                                                                            bool                   &rbHiddenRecord );

    HANDLE                                  GetWriteEvent               (   void );

    CSWMRG *                                GetDataGuard                (   void );

private:

    ///////////////
    // Definitions.

#pragma pack ( push, CIRCULARBUFFER_H_PACK, 1 )                                                                             // Single byte alignment.

    typedef struct tagMEMORYPOOLHEADER
    {
        // General structure information.

        unsigned long                       m_ulVersionNumber;                                                              // Version number of this structure.

        // Data relative parameters.

        unsigned long                       m_ulNumberOfCells;                                                              // Number of cells in this circular buffer.
        unsigned long                       m_ulCellSizeInBytes;                                                            // Cell size in bytes.

        unsigned long                       m_ulNextWritePoint;                                                             // Pointer for next write.
        unsigned long                       m_ulNextSequenceNumber;                                                         // Sequence number assigned to each block of cells written.
        unsigned long                       m_ulWrapPoint;                                                                  // Cell index at which wrap occured and therefore readers should not go beyond.

        // Cell occupancy index table.

        CELLINDEX                           m_sCellIndex[ NCIRCULARBUFFER::ulNumberOfCells_c ];                             // Cell occupancy data.

        // Add new elements here to maintain backward compatibility; reduce reserved space accordingly.

        BYTE                                m_byReserved[ NCIRCULARBUFFER::ulReservedSpace_c ];                             // Reserved space to pad header.

        // Data portion of the quantized circular buffer area immediately follows header.
    }
    MEMORYPOOLHEADER, *PMEMORYPOOLHEADER;

#pragma pack ( pop, CIRCULARBUFFER_H_PACK )                                                                                 // Single byte alignment.

    ///////////////
    // Attributes.

    MEMORYPOOLHEADER  * const               m_psMemoryPool;                                                                 // Pointer to our memory pool as a formated header.
    BYTE              * const               m_pbyCells;

    const unsigned long                     m_ulPoolSize;                                                                   // Total pool size in bytes.
    const unsigned long                     m_ulVersion;
    const unsigned long                     m_ulNumberOfCells;
    const unsigned long                     m_ulCellSizeInBytes;
    const unsigned long                     m_ulReservedSpace;

    bool                                    m_bInitialized;                                                                 // Construction success/failure indicator flag.
    HANDLE                                  m_hDataAvailable;                                                               // Data written event object.
    std::auto_ptr<CSWMRG>                   m_pSwmrGuard;                                                                   // Pointer to our read/write sync pointer.

    ///////////////
    // Services.

    bool                                    WriteRecord                 (   const tRecordHeader    *psRecordHeader,
                                                                            const BYTE             *pbyRecord,
                                                                            const unsigned long    &rulBytesThisRecord,
                                                                            const bool             &rbHiddenRecord );

    void                                    InvalidateCells             (   const unsigned long    &rulStartCell,
                                                                            const unsigned long    &rulStopCell,
                                                                            const bool             &rbHandleFinalSequence );

    void                                    SetCellSequence             (   const unsigned long    &rulStartCell,
                                                                            const unsigned long    &rulNumberOfCells,
                                                                            const unsigned long    &rulTotalBytesThisRecord,
                                                                            const bool             &rbHiddenRecord );

    void                                    DataIsAvailable             (   void )  const;

    void                                    MaintainCellLinkage         (   const unsigned long    &rulWriteCell,
                                                                            const unsigned long    &rulCellsForThisData );

    // Standard methods that are not implemented thus private to highlight sleazy compiler usage.

                                            CCircularBuffer             (   void );                                         // Not implemented thus private.
                                            CCircularBuffer             (   const CCircularBuffer  &rRhs );                 // Not implemented thus private.
    CCircularBuffer &                       operator =                  (   const CCircularBuffer  &rRhs );                 // Not implemented thus private.

};

//////////////////////////////////////////////////////////////////////
// CCircularBuffer class implemenation.

template <typename tRecordHeader>
inline CCircularBuffer<tRecordHeader>::CCircularBuffer      (   BYTE * const            pbyMemoryPool,
                                                                const unsigned long    &rulMemoryPoolSize,
                                                                LPCTSTR                 lpszGuardName,
                                                                LPCTSTR                 lpszDataAvailableEventName )

                                      :m_psMemoryPool       (   reinterpret_cast<MEMORYPOOLHEADER  * const>( pbyMemoryPool ) ),
                                       m_pbyCells           (   pbyMemoryPool + sizeof (MEMORYPOOLHEADER ) ),
                                       m_ulPoolSize         (   rulMemoryPoolSize   ),
                                       m_ulVersion          (   NCIRCULARBUFFER::ulVersion_c  ),
                                       m_ulNumberOfCells    (   NCIRCULARBUFFER::ulNumberOfCells_c ),
                                       m_ulCellSizeInBytes  (   NCIRCULARBUFFER::ulCellSizeInBytes_c ),
                                       m_ulReservedSpace    (   NCIRCULARBUFFER::ulReservedSpace_c )
{
    try
    {
        m_bInitialized   = false;     // Assume failure for now.
        m_hDataAvailable = NULL;
        m_pSwmrGuard     = std::auto_ptr<CSWMRG>( NULL );

        // Validate the expected memory pool.
        if ( ( m_psMemoryPool == NULL ) || ( m_ulPoolSize < sizeof( MEMORYPOOLHEADER ) ) )
        {
            ThrowMessage_m( "Memory pool is invalid" );
        }

        // Create our SWMR sync object (to help with thread synchonization).

        m_pSwmrGuard = std::auto_ptr<CSWMRG>( new CSWMRG( lpszGuardName ) );

        if ( m_pSwmrGuard.get() == NULL )
        {
            ThrowMessage_m( "Can't construct SWMRG object." );
        }

        // Get the write event object's handle (process relative) using the specified name.

        if ( ( m_hDataAvailable = ::CreateEvent( NULL, TRUE, FALSE, lpszDataAvailableEventName ) ) == NULL )
        {
            TRACE( _T( "Can't create data event, error code: %lu\n" ), ::GetLastError() );
            ThrowMessage_m( "Can't create our data event object" );
        }

        // Ok, so now the object should be correctly constructed.

        m_bInitialized = true;
    }
    catch ( LPCTSTR lpszMessage )
    {
        m_bInitialized = false;
        TRACE( _T( "CCircularBuffer<tRecordHeader>::CCircularBuffer(), %s\n" ), lpszMessage );
    }
    catch ( ... )
    {
        m_bInitialized = false;
        TRACE( _T( "CCircularBuffer<tRecordHeader>::CCircularBuffer(), unspecified exception caught\n" ) );
    }

    ASSERT( m_bInitialized );
}

template <typename tRecordHeader>
inline CCircularBuffer<tRecordHeader>::~CCircularBuffer( void )
{
    try
    {
        // Invalidate our object.

        m_bInitialized = false;

        // Close and invalidate our data available event object.

        if ( m_hDataAvailable != NULL )
        {
            ::CloseHandle( m_hDataAvailable );
            m_hDataAvailable = NULL;
        }

        // Destroy our std::auto_ptr<> objects; of course, we don't really need to bother.

        if ( m_pSwmrGuard.get() != NULL )
        {
            delete ( m_pSwmrGuard.release() );
            m_pSwmrGuard = std::auto_ptr<CSWMRG>( NULL );
        }
    }
    catch ( ... )
    {
        TRACE( _T( "CCircularBuffer<tRecordHeader>::~CCircularBuffer(), Unspecified exception caught.\n" ) );
    }
}

template <typename tRecordHeader>
inline bool CCircularBuffer<tRecordHeader>::IsInitialized( void ) const
{
    return m_bInitialized;
}

template <typename tRecordHeader>
inline bool CCircularBuffer<tRecordHeader>::InitializeHeader( void )
{
    // Call this member to initialize the memory pool header contents; typically done only once by the primary writer.

    bool bSuccess = false;          // Assume failure for now.

    try
    {
        if ( ! m_bInitialized )
        {
            ThrowMessage_m( "Object has not been correctly constructed" );
        }

        ASSERT( m_pSwmrGuard.get() != NULL );

        __TRY
        {
            m_pSwmrGuard->WaitToWrite();

            // Zero the header but don't bother with the circular buffer itself (for efficiency).
            // Note: this will zero all CELLINDEX data too. If non-zero data is to be the default,
            // it should be initialized following the memset().

            ::memset( m_psMemoryPool, 0x00, sizeof( MEMORYPOOLHEADER ) );

            // Explicitly set the relevant header components.

            m_psMemoryPool->m_ulVersionNumber      = m_ulVersion;
            m_psMemoryPool->m_ulNumberOfCells      = m_ulNumberOfCells;
            m_psMemoryPool->m_ulCellSizeInBytes    = m_ulCellSizeInBytes;

            m_psMemoryPool->m_ulWrapPoint          = m_ulNumberOfCells - 1UL;
            m_psMemoryPool->m_ulNextSequenceNumber = 0UL;
            m_psMemoryPool->m_ulNextWritePoint     = 0UL;

            // Set the CELLINDEX data here, if necessary.

            // ...
        }
        __FINALLY
        {
            m_pSwmrGuard->DoneWriting();
        }
        __ENDFINALLY

        bSuccess = true;
    }
    catch ( LPCTSTR lpszMessage )
    {
        m_bInitialized = false;
        TRACE( _T( "CCircularBuffer<tRecordHeader>::InitializeHeader(), %s\n" ), lpszMessage );
    }
    catch ( ... )
    {
        bSuccess = false;
        TRACE( _T( "CCircularBuffer<tRecordHeader>::InitializeHeader(), Unspecified exception caught!\n" ) );
    }

    return bSuccess;
}

template <typename tRecordHeader>
inline CSWMRG * CCircularBuffer<tRecordHeader>::GetDataGuard( void )
{
    ASSERT( m_bInitialized );
    ASSERT( m_pSwmrGuard.get() != NULL );
    return ( m_pSwmrGuard.get() );
}

template <typename tRecordHeader>
inline HANDLE CCircularBuffer<tRecordHeader>::GetWriteEvent( void )
{
    ASSERT( m_bInitialized );
    ASSERT( m_hDataAvailable != NULL );

    return m_hDataAvailable;
}

template <typename tRecordHeader>
inline bool CCircularBuffer<tRecordHeader>::Write(  const tRecordHeader    *psRecordHeader,
                                                    const BYTE             *pbyRecord,
                                                    const unsigned long    &rulTotalBytesThisRecord,
                                                    const bool             &rbHiddenRecord )
{
    bool bSuccess = false;                          // Assume failure for now.

    try
    {
        if ( ! m_bInitialized )
        {
            ThrowMessage_m( "Object has not been correctly constructed" );
        }

        if ( rulTotalBytesThisRecord == 0UL )
        {
            bSuccess = true;                        // Nothing to do.
        }
        else if ( ( psRecordHeader != NULL ) && ( pbyRecord != NULL ) )
        {
            bSuccess = WriteRecord( psRecordHeader, pbyRecord, rulTotalBytesThisRecord, rbHiddenRecord );

            if ( bSuccess )
            {
                DataIsAvailable();
            }
        }
    }
    catch ( LPCTSTR lpszMessage )
    {
        bSuccess = false;
        TRACE( _T( "CCircularBuffer<tRecordHeader>::Write(), %s\n" ), lpszMessage );
    }
    catch ( ... )
    {
        bSuccess = false;
        TRACE( _T( "CCircularBuffer<tRecordHeader>::Write(), unspecified exception caught\n" ) );
    }

    return bSuccess;
}

template <typename tRecordHeader>
inline bool CCircularBuffer<tRecordHeader>::Read(   unsigned long   &rulNextToRead,
                                                    unsigned long   &rulTotalBytesThisRecord,
                                                    tRecordHeader * &rpsRecord,
                                                    bool            &rbHiddenRecord )
{
    // Notes:   1)  A return code of false can mean either: a) an error, or b) no new data is available.
    //            
    //          2)  THIS MEMBER RETURNS A POINTER DIRECLTY INTO THE CIRCULAR BUFFER AND POINTING TO THE NEXT AVAILABLE RECORD TO BE READ.
    //              As such, it should be used within the m_pSwmrGuard->WaitToRead() and m_pSwmrGuard->DoneReading() block. 
    //              Failure to synchonize different threads will likely lead to data corruption in a multithreaded environment.
    //              Clients may use the operator SWMRG *() to access the appropriate sync object.
    //          
    //          3)  It would be an error to handle synchronization in this routine since the client will still be directly
    //              accessing a pointer into the cirular buffer during which its conents could be modified by the writer.

    bool bSuccess = false;      // Assume failure or now data available for now.

    try
    {
        rulTotalBytesThisRecord = 0;
        rpsRecord               = NULL;
        rbHiddenRecord          = false;

        if ( ! m_bInitialized )
        {
            ThrowMessage_m( "Object has not been correctly constructed" );
        }

        ASSERT( m_psMemoryPool != NULL );

        TRACE( _T( "READ, Next: %lu, Wrap: %lu, Write: %lu\n" ),    rulNextToRead,
                                                                    m_psMemoryPool->m_ulWrapPoint,
                                                                    m_psMemoryPool->m_ulNextWritePoint );

        // Get the total bytes and the pointer to the beginning of the data (cell sequence) then
        // advance the read point to the first cell of the next sequence. Note: forward linkages to cells are required in order to 
        // maintain read continuity -- particularly important in cases where the writer has overwritten partial cells of stale sequences.

        if (  rulNextToRead != m_psMemoryPool->m_ulNextWritePoint )
        {
            if ( rulNextToRead >= m_psMemoryPool->m_ulWrapPoint )
            {
				printf("CircularBuffer::Read - resetting read pointer to beginning of buffer\n");
                rulNextToRead = 0UL;
//				m_psMemoryPool->m_ulWrapPoint = m_ulNumberOfCells - 1UL;
//				printf("resetting wrap pointer to %d\n", m_psMemoryPool->m_ulWrapPoint);
            }

            if ( m_psMemoryPool->m_sCellIndex[ rulNextToRead ].m_ulUsed )
            {
                rulTotalBytesThisRecord = m_psMemoryPool->m_sCellIndex[ rulNextToRead ].m_TotalBytesInSequence;
                rpsRecord               = reinterpret_cast<tRecordHeader *>( &(m_pbyCells[ rulNextToRead * m_psMemoryPool->m_ulCellSizeInBytes ]) );
                rulNextToRead           = m_psMemoryPool->m_sCellIndex[ rulNextToRead ].m_ulNextWriteIndex;
                rbHiddenRecord          = m_psMemoryPool->m_sCellIndex[ rulNextToRead ].m_bHiddenRecord;
                bSuccess = true;
			} else {
				printf("CCircularBuffer::Read() - next buffer to read is unused\n");
			}
        }
    }
    catch ( LPCTSTR lpszMessage )
    {
        bSuccess    = false;
        rulNextToRead = 0UL;
        TRACE( _T( "CCircularBuffer<tRecordHeader>::Read(), %s\n" ), lpszMessage );
		printf("CCircularBuffer<tRecordHeader>::Read(), %s\n", lpszMessage);
    }
    catch ( ... )
    {
        bSuccess    = false;
        rulNextToRead = 0UL;
        TRACE( _T( "CCircularBuffer<tRecordHeader>::Read(), Unspecified exception caught!\n" ) );
		printf("CCircularBuffer<tRecordHeader>::Read(), Unspecified exception caught!\n" );
    }

    if ( ! bSuccess )
    {
        rulTotalBytesThisRecord = 0UL;
        rpsRecord               = NULL;
    }

    return bSuccess;
}

///////////////////////////////////////////////////////////////////////////////
// Internal methods (private).

template <typename tRecordHeader>
inline bool CCircularBuffer<tRecordHeader>::WriteRecord(    const tRecordHeader    *psRecordHeader,
                                                            const BYTE             *pbyRecord,
                                                            const unsigned long    &rulBytesThisRecord,
                                                            const bool             &rbHiddenRecord )
{
    bool bSuccess = false;                  // Assume failure, for now.

    ASSERT( rulBytesThisRecord      >  0UL  );
    ASSERT( pbyRecord               != NULL );
    ASSERT( psRecordHeader          != NULL );
    ASSERT( m_psMemoryPool          != NULL );
    ASSERT( m_pSwmrGuard.get()      != NULL );

    unsigned long ulTempCellSize                = m_ulCellSizeInBytes;
    unsigned long ulTempTotalCells              = m_ulNumberOfCells;

    __TRY
    {
        m_pSwmrGuard->WaitToRead();

        ulTempCellSize                           = m_psMemoryPool->m_ulCellSizeInBytes;
        ulTempTotalCells                         = m_psMemoryPool->m_ulNumberOfCells;
    }
    __FINALLY
    {
        m_pSwmrGuard->DoneReading();
    }
    __ENDFINALLY

    const unsigned long ulCellSize               = ulTempCellSize;
    const unsigned long ulTotalCells             = ulTempTotalCells;
    const unsigned long ulMaxRecordSizePermitted = ulCellSize * ulTotalCells;
    const unsigned long ulRecordHeaderSize       = static_cast<unsigned long>( sizeof( tRecordHeader ) );
    const unsigned long ulTotalBytesThisRecord   = ulRecordHeaderSize + rulBytesThisRecord;
    const unsigned long ulCellsForThisData       = ( ulTotalBytesThisRecord / ulCellSize ) + 1UL;

    ASSERT( ulMaxRecordSizePermitted > 0UL );

    if ( ulTotalBytesThisRecord == 0UL )
    {
        bSuccess = true;                    // Nothing to do.
    }
    else if ( ulTotalBytesThisRecord >= ulMaxRecordSizePermitted )
    {
        bSuccess = false;
        TRACE( _T( "CCircularBuffer<tRecordHeader>::WriteRecord(),"
                   " Record is too big for memory pool! Record size: %lu (max allowed: %lu) bytes\n" ), ulTotalBytesThisRecord,
                                                                                                        ulMaxRecordSizePermitted );
        ASSERT( false );
    }
    else __TRY
    {
        // Acquire exclusive write access.

        m_pSwmrGuard->WaitToWrite();

        // Get the current write point and see whether the data will fit between the current point and the
        // end of the circular buffer. If not, invalidate the cells to the end of the circular buffer and set the write
        // point back to the beginning.

        unsigned long ulWriteCell = m_psMemoryPool->m_ulNextWritePoint;

        if ( ( ulWriteCell + ulCellsForThisData ) >= ulTotalCells )
        {
            // Invalidate cells to end of the circular buffer and set the wrap point at the end of the last valid sequence.

            m_psMemoryPool->m_ulWrapPoint = ulWriteCell;
            InvalidateCells( ulWriteCell, ulTotalCells - 1UL, false );

            // Adjust the previous cells next write index back to the beginning so that readers may look there.

            ASSERT( m_psMemoryPool->m_sCellIndex[ ulWriteCell - 1UL ].m_ulUsed != 0UL );
            m_psMemoryPool->m_sCellIndex[ ulWriteCell - 1UL ].m_ulNextWriteIndex = 0UL;

            // Set the write point back to the beginning cell.

            ulWriteCell = 0UL;
			printf("CCircularBuffer::WriteRecord - record wouldn't fit, wrapping buffer\n");
        }

        TRACE( _T( "WRITE (BEFORE): Cells required: %lu, Write Point: %lu, Wrap Point: %lu\n" ),    ulCellsForThisData,
                                                                                                    ulWriteCell,
                                                                                                    m_psMemoryPool->m_ulWrapPoint );

        // Invalidate cells that we're about to overwrite plus all cells in the previous cell's sequence.

        InvalidateCells( ulWriteCell, ulWriteCell + ulCellsForThisData - 1UL, true );

        // Copy the header then data to the circular buffer; a simple memcpy will work since we are guaranteed contigious memory from a sequence of cells.

        const unsigned long ulCellStartAddress = ulWriteCell * ulCellSize;

        ::memcpy( &(m_pbyCells[ ulCellStartAddress ]), psRecordHeader, ulRecordHeaderSize );
        ::memcpy( &(m_pbyCells[ ulCellStartAddress + ulRecordHeaderSize ]), pbyRecord, rulBytesThisRecord );

        // Set the new cell sequence info etc.

        SetCellSequence( ulWriteCell, ulCellsForThisData, ulTotalBytesThisRecord, rbHiddenRecord );

        // Move the write pointer to the next available cell position and increment the sequence number ahead of
        // the next write operation.

        m_psMemoryPool->m_ulNextSequenceNumber = ( m_psMemoryPool->m_ulNextSequenceNumber + 1UL ) % ULONG_MAX;
        m_psMemoryPool->m_ulNextWritePoint     = ulWriteCell + ulCellsForThisData;

        /*if ( m_psMemoryPool->m_ulNextWritePoint >= m_psMemoryPool->m_ulWrapPoint )*/
		if ( m_psMemoryPool->m_ulNextWritePoint >= m_psMemoryPool->m_ulWrapPoint )
        {
			printf("CCircularBuffer::WriteRecord() - next write point greater than wrap point next write point (%d) wrap point (%d) size (%d)\n",
					m_psMemoryPool->m_ulNextWritePoint, m_psMemoryPool->m_ulWrapPoint, ulCellsForThisData);
            m_psMemoryPool->m_ulWrapPoint = m_ulNumberOfCells - 1UL;
	
        }

        // Ensure forward cells are suitably linked so that readers can maintain continuity to the next sequence of cells after invalidation,

        MaintainCellLinkage( ulWriteCell, ulCellsForThisData );

        TRACE( _T( "WRITE (AFTER): Current: %lu, Next: %lu, Wrap: %lu, Link: %lu\n" ),  ulWriteCell,
                                                                                        m_psMemoryPool->m_ulNextWritePoint,
                                                                                        m_psMemoryPool->m_ulWrapPoint,
                                                                                        m_psMemoryPool->m_sCellIndex[ ulWriteCell ].m_ulNextWriteIndex );

        bSuccess = true;
    }
    __FINALLY
    {
        m_pSwmrGuard->DoneWriting();
    }
    __ENDFINALLY

    return bSuccess;
}

template <typename tRecordHeader>
inline void CCircularBuffer<tRecordHeader>::InvalidateCells(    const unsigned long    &rulStartCell,
                                                                const unsigned long    &rulStopCell,
                                                                const bool             &rbHandleFinalSequence )
{
    PCELLINDEX psCell = NULL;

    ASSERT( m_psMemoryPool != NULL );

    for ( unsigned long ulCell = rulStartCell; ulCell <= rulStopCell; ulCell++ )
    {
        psCell = &(m_psMemoryPool->m_sCellIndex[ ulCell ]);

        if ( ( psCell != NULL ) && psCell->m_ulUsed )
        {
            // If it is the last specified cell, ensure we invalidate all associated cells in its sequence.

            if (   rbHandleFinalSequence         && 
                 ( ulCell       == rulStopCell ) &&
                 ( rulStartCell != rulStopCell )  )
            {
                const unsigned long ulLastSequenceNumber = psCell->m_ulSequenceNumberOfCell;
                PCELLINDEX          psNextCell           = &(m_psMemoryPool->m_sCellIndex[ ulCell + 1UL ]);

                while ( ( psNextCell->m_ulUsed ) && 
                        ( psNextCell->m_ulSequenceNumberOfCell == ulLastSequenceNumber ) )
                {
                    psCell->m_ulUsed               = 0UL;
                    psCell->m_ulBytesInCell        = 0UL;
                    psCell->m_TotalBytesInSequence = 0UL;
                    psCell->m_bHiddenRecord        = false;
                    psNextCell++;
                }
            }

            // Now invalidate the current cell; done last o that the cell's data is preserved for the above algorithm.

            psCell->m_ulUsed               = 0UL;
            psCell->m_ulBytesInCell        = 0UL;
            psCell->m_TotalBytesInSequence = 0UL;
            psCell->m_bHiddenRecord        = false;
        }
    }
}

template <typename tRecordHeader>
inline void CCircularBuffer<tRecordHeader>::SetCellSequence(    const unsigned long    &rulStartCell,
                                                                const unsigned long    &rulNumberOfCells,
                                                                const unsigned long    &rulTotalBytesThisRecord,
                                                                const bool             &rbHiddenRecord )
{
    ASSERT( m_psMemoryPool                      != NULL );
    ASSERT( m_psMemoryPool->m_ulCellSizeInBytes >  0UL );

    PCELLINDEX psCell = &(m_psMemoryPool->m_sCellIndex[ rulStartCell ]);

    for ( unsigned long ulCell = rulStartCell; ulCell < ( rulStartCell + rulNumberOfCells ); ulCell++ )
    {
        psCell->m_ulUsed                 = 1UL;
        psCell->m_ulCellsInSequence      = rulNumberOfCells;
        psCell->m_ulSequenceNumberOfCell = ulCell;
        psCell->m_TotalBytesInSequence   = rulTotalBytesThisRecord;
        psCell->m_ulBytesInCell          = ( ulCell < ( rulStartCell + rulNumberOfCells - 1UL ) ) ?
                                               m_psMemoryPool->m_ulCellSizeInBytes :
                                               rulTotalBytesThisRecord % m_psMemoryPool->m_ulCellSizeInBytes;
        psCell->m_ulSequenceNumberOfCell = m_psMemoryPool->m_ulNextSequenceNumber;
        psCell->m_bHiddenRecord          = rbHiddenRecord;

        psCell++;
    }
}

template <typename tRecordHeader>
inline void CCircularBuffer<tRecordHeader>::DataIsAvailable( void ) const
{
    // Pulse the manual-reset event object hence releasing all waiting threads then transition
    // back to the non-signaled state.

    ASSERT( m_hDataAvailable != NULL );

    if ( m_hDataAvailable != NULL )
    {
        ::PulseEvent( m_hDataAvailable );
    }
}

template <typename tRecordHeader>
inline void CCircularBuffer<tRecordHeader>::MaintainCellLinkage(    const unsigned long &rulWriteCell,
                                                                    const unsigned long &rulCellsForThisData )
{
    // For each cell, maintain an index to the next cell's write position. This allows a forward list
    // to be maintained so that when cell overwrite occurs readers can mainatin continuity to next
    // sequence.

    ASSERT( m_psMemoryPool != NULL );

    const unsigned long ulNextWritePoint = ( ( rulWriteCell + rulCellsForThisData ) % m_psMemoryPool->m_ulWrapPoint );

    for ( unsigned long ulCell = rulWriteCell; ulCell < ( rulWriteCell + rulCellsForThisData ); ulCell++ )
    {
        m_psMemoryPool->m_sCellIndex[ ulCell ].m_ulNextWriteIndex = ulNextWritePoint;
    }
}

#endif // !defined(AFX_CIRCULARBUFFER_H__A93F104E_7F89_4934_8FE5_FB082CAB79D1__INCLUDED_)


