#include "DrawingCanvas.h"
#include "ImageCanvas.h"

using namespace mvIMPACT::acquire;

IMPLEMENT_DYNAMIC_CLASS(DrawingCanvas, wxScrolledWindow)

//-----------------------------------------------------------------------------
DrawingCanvas::DrawingCanvas( wxWindow* parent, wxWindowID id /* = -1 */, const wxPoint& pos /* = wxDefaultPosition */,
	const wxSize& size /* = wxDefaultSize */, long style /* = wxSUNKEN_BORDER */, const wxString& name /* = "DrawingCanvas" */, bool boActive /* = false */ )
  : wxScrolledWindow( parent, id, pos, size, style, name ), m_boActive(boActive), m_valCount(VAL_COUNT_8_BIT)
//-----------------------------------------------------------------------------
{

}

//-----------------------------------------------------------------------------
void DrawingCanvas::SetActive( bool boActive )
//-----------------------------------------------------------------------------
{
	m_boActive = boActive;
	Refresh( !boActive );
}


//-----------------------------------------------------------------------------
PlotCanvas::PlotCanvas( wxWindow* parent, wxWindowID id /* = -1 */, const wxPoint& pos /* = wxDefaultPosition */, const wxSize& size /* = wxDefaultSize */,
	long style /* = wxSUNKEN_BORDER */, const wxString& name /* = "DrawingCanvas" */, bool boActive /* = false */, int channelCount /* = 0 */ )
  : DrawingCanvas( parent, id, pos, size, style, name, boActive ), m_AOIColour( *wxRED ), m_BorderWidth(25),
	m_pImageCanvas(0), m_AOIx(0), m_AOIy(0), m_AOIw(640), m_AOIh(480), m_pAOI(0),
	m_ChannelCount(channelCount), m_pixelFormat(ibpfRaw), m_ImageCount(-1), m_UpdateFrequency(3)
//-----------------------------------------------------------------------------
{
	m_Pens[pRed] = wxRED;
	m_Pens[pGreen] = wxGREEN;
	m_Pens[pBlue] = wxBLUE;
}

//-----------------------------------------------------------------------------
void PlotCanvas::SetBorderWidth( int borderWidth )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker(m_critSect);
	m_BorderWidth = borderWidth;
}

//-----------------------------------------------------------------------------
void PlotCanvas::SetActive( bool boActive )
//-----------------------------------------------------------------------------
{
	if( boActive == IsActive() )
	{
		return;
	}

	if( m_pImageCanvas )
	{
		if( boActive )
		{
			m_pAOI = m_pImageCanvas->RegisterAOI( wxRect(m_AOIx, m_AOIy, m_AOIw, m_AOIh), m_AOIColour, GetName() );
		}
		else
		{
			m_pImageCanvas->RemoveAOI( m_pAOI );
			m_pAOI = 0;
		}
	}

	DrawingCanvas::SetActive( boActive );
}

//-----------------------------------------------------------------------------
bool PlotCanvas::MustUpdate( const ImageBuffer* pIB, int x, int y, int w, int h, bool boForceRefresh, bool* pboAOIChanged /* = 0 */, bool* pboImageFormatChanged /* = 0 */ )
//-----------------------------------------------------------------------------
{
	if( !pIB || !pIB->vpData || !IsActive() )
	{
		return false;
	}

	bool boResult = false;

	if( ( m_ChannelCount != pIB->iChannelCount ) || ( m_pixelFormat != pIB->pixelFormat ) )
	{
		boResult = true;
		if( pboImageFormatChanged )
		{
			*pboImageFormatChanged = true;
		}
		m_pixelFormat = pIB->pixelFormat;
	}

	if( SetAOI( pIB, x, y, w, h ) )
	{
		if( pboAOIChanged )
		{
			*pboAOIChanged = true;
		}
		boResult = true;
	}
	else if( pboAOIChanged )
	{
		*pboAOIChanged = false;
	}

	if( ( ( m_ImageCount++ % m_UpdateFrequency ) == 0 ) || boForceRefresh )
	{
		boResult = true;
	}

	return boResult;
}

//-----------------------------------------------------------------------------
bool PlotCanvas::SetAOI( const ImageBuffer* pIB, int x, int y, int w, int h )
//-----------------------------------------------------------------------------
{
	bool boChanged = false;

	// validate values
	// x-offset
	if( ( x >= 0 ) && ( m_AOIx != x ) )
	{
		m_AOIx = ( x >= pIB->iWidth ) ? 0 : x;
		boChanged = true;
	}
	else if( m_AOIx >= pIB->iWidth )
	{
		m_AOIx = 0;
		boChanged = true;
	}

	// y-offset
	if( ( y >= 0 ) && ( m_AOIy != y ) )
	{
		m_AOIy = ( y >= pIB->iHeight ) ? 0 : y;
		boChanged = true;
	}
	else if( m_AOIy >= pIB->iHeight )
	{
		m_AOIy = 0;
		boChanged = true;
	}

	// aoi width
	if( ( w > 0 ) && ( m_AOIw != w ) )
	{
		int newValue = ( w + m_AOIx > pIB->iWidth ) ? pIB->iWidth - m_AOIx : w;
		// if the AOI width is larger then x-offset + image width, the AOI width must be clipped
		// this might have been the case in the previous image as well and thus doesn't
		// implies that this is definitely a change -> check twice
		if( newValue != m_AOIw )
		{
			m_AOIw = newValue;
			boChanged = true;
		}
	}
	else if( ( m_AOIw + m_AOIx ) > pIB->iWidth )
	{
		m_AOIw = pIB->iWidth - m_AOIx;
		boChanged = true;
	}

	// aoi height
	if( ( h > 0 ) && ( m_AOIh != h ) )
	{
		int newValue = ( h + m_AOIy > pIB->iHeight ) ? pIB->iHeight - m_AOIy : h;
		// if the AOI height is larger then y-offset + image height, the AOI height must be clipped
		// this might have been the case in the previous image as well and thus doesn't
		// implies that this is definitely a change -> check twice
		if( newValue != m_AOIh )
		{
			m_AOIh = newValue;
			boChanged = true;
		}
	}
	else if( ( m_AOIh + m_AOIy ) > pIB->iHeight )
	{
		m_AOIh = pIB->iHeight - m_AOIy;
		boChanged = true;
	}

	if( m_pImageCanvas && ( m_pAOI != 0 ) && boChanged )
	{
		m_pImageCanvas->SetAOI( m_pAOI, m_AOIx, m_AOIy, m_AOIw, m_AOIh );
	}

	return boChanged;
}

//-----------------------------------------------------------------------------
void PlotCanvas::SetAOIColour( const wxColour& c )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker(m_critSect);
	m_AOIColour = c;
}

//-----------------------------------------------------------------------------
void PlotCanvas::RegisterImageCanvas( ImageCanvas* p )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker(m_critSect);
	m_pImageCanvas = p;
}

//-----------------------------------------------------------------------------
bool PlotCanvas::SetUpdateFrequency( int frequency )
//-----------------------------------------------------------------------------
{
	if( ( frequency >= ulMin ) && ( frequency <= ulMax ) )
	{
		m_UpdateFrequency = frequency;
		return true;
	}
	return false;
}

