#include "stdafx.h"
#include "FrameBuffer.h"

int IoAFrameBuffer::Allocate( int BufferSize )
{
    Free( );

    if ( BufferSize <= 0 ) return FALSE;

    void *pBuffer = (void *) new unsigned char[ BufferSize ];

    if ( pBuffer == NULL ) return FALSE;

    m_pBuffer    = pBuffer;
    m_BufferSize = BufferSize;

    return TRUE;
}

void IoAFrameBuffer::Free( )
{
    delete [ ] (unsigned char *) m_pBuffer;

    m_pBuffer    = NULL;
    m_BufferSize = 0;

    ClearFrame( );
}

int IoAFrameBuffer::Copy( const IoAFrameBuffer& Other )
{
    if ( ! Other.IsAllocated( ) ) return FALSE;

    if ( ! IsAllocated( ) || BufferSize( ) != Other.BufferSize( ) )
    {
        if ( ! Allocate( Other.BufferSize( ) ) ) return FALSE;
    }
    if ( Other.IsHistogramAllocated( ) )
    {
        if ( ! AllocateHistogram( Other.BitsPerPixel( ) ) ) return FALSE;
    }

    //.Copy data
    if ( Other.IsFrameValid( ) )
    {
        ::CopyMemory( Address( ), Other.Address( ), Other.FrameBytes( ) );
    }

    // Copy frame properties
    m_XSize = Other.XSize( );
    m_YSize = Other.YSize( );

    m_BytesPerPixel = Other.BytesPerPixel( );

    m_MinPixel = Other.MinPixel( );
    m_MaxPixel = Other.MaxPixel( );

    m_CCDNumber   = Other.CCDNumber( );
    m_FrameNumber = Other.FrameNumber( );

    m_FrameIndex = Other.FrameIndex( );
    m_GrabIndex  = Other.GrabIndex( );
    m_SaveIndex  = Other.SaveIndex( );

    m_UTCTimeStamp = Other.UTCTimeStamp( );

    m_PixelClockCount = Other.PixelClockCount( );
    m_DataClockCount  = Other.DataClockCount( );

    m_LocalTimeBias = Other.m_LocalTimeBias;

    // Copy histogram
    if ( Other.IsHistogramValid( ) )
    {
        ::CopyMemory( Histogram( ), Other.Histogram( ), Other.HistogramBytes( ) );

        m_NonEmptyBinCount = Other.NonEmptyBinCount( );

        m_HistogramValid = TRUE;
    }

    return TRUE;
}

int IoAFrameBuffer::AllocateHistogram( int BitsPerPixel )
{
    FreeHistogram( );

    if ( BitsPerPixel <= 0 || BitsPerPixel > 16 ) return FALSE;

    int HistogramSize = 0x1 << BitsPerPixel;

    m_pHistogram = new unsigned int[ HistogramSize ];

    if ( m_pHistogram == NULL ) return FALSE;

    m_BitsPerPixel  = BitsPerPixel;
    m_HistogramSize = HistogramSize;

    return TRUE;
}

void IoAFrameBuffer::FreeHistogram( )
{
    m_BitsPerPixel  = 0;
    m_HistogramSize = 0;

    m_NonEmptyBinCount = 0;

    delete [ ] m_pHistogram;

    m_pHistogram = NULL;

    m_HistogramValid = FALSE;
}

int IoAFrameBuffer::UpdateHistogram( const unsigned int *Histogram )
{
    if ( ! IsFrameValid( ) || ! IsHistogramAllocated( ) ) return FALSE;

    if ( Histogram == NULL ) return FALSE;

    ::CopyMemory( m_pHistogram, Histogram, m_HistogramSize * sizeof( unsigned int ) );

    m_NonEmptyBinCount = 0;

    for ( int i = 0; i < m_HistogramSize; i++ )
    {
        if ( m_pHistogram[ i ] > 0 )
        {
            m_NonEmptyBinCount += 1;
        }
    }

    m_HistogramValid = TRUE;

    return TRUE;
}

int IoAFrameBuffer::UpdateHistogram( )
{
    if ( ! IsFrameValid( ) || ! IsHistogramAllocated( ) ) return FALSE;

    ::ZeroMemory( m_pHistogram, m_HistogramSize * sizeof( unsigned int ) );

    if ( m_BytesPerPixel == 1 )
    {
        unsigned char *pPixels = ByteAddress( );

        unsigned char BitMask = (unsigned char) 0xff >> ( 8 - m_BitsPerPixel );

        for ( int i = 0; i < FramePixels( ); i++ )
        {
            m_pHistogram[ pPixels[ i ] & BitMask ] += 1;
        }
    }
    else if ( m_BytesPerPixel == 2 )
    {
        unsigned short *pPixels = ShortAddress( );

        unsigned short BitMask = (unsigned short) 0xffff >> ( 16 - m_BitsPerPixel );

        for ( int i = 0; i < FramePixels( ); i++ )
        {
            m_pHistogram[ pPixels[ i ] & BitMask ] += 1;
        }
    }
    else
    {
        return FALSE;  // can't do 32-bit histograms
    }

    m_NonEmptyBinCount = 0;

    for ( int i = 0; i < m_HistogramSize; i++ )
    {
        if ( m_pHistogram[ i ] > 0 )
        {
            m_NonEmptyBinCount += 1;
        }
    }

    m_HistogramValid = TRUE;

    return TRUE;
}
