#include <wx/grid.h>
#include "AnalysisDataGridTable.h"
#include "DrawingCanvas.h"
#include "ImageCanvas.h"

using namespace mvIMPACT::acquire;

//=============================================================================
//================= Implementation DrawingCanvas ==============================
//=============================================================================
IMPLEMENT_DYNAMIC_CLASS(DrawingCanvas, wxScrolledWindow)

BEGIN_EVENT_TABLE(DrawingCanvas, wxScrolledWindow)
  EVT_SIZE(DrawingCanvas::OnSize)
END_EVENT_TABLE()


//-----------------------------------------------------------------------------
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)
//-----------------------------------------------------------------------------
{

}

//-----------------------------------------------------------------------------
void DrawingCanvas::HandleSizeEvent( wxSizeEvent& e )
//-----------------------------------------------------------------------------
{
	Refresh( true );
	e.Skip();
}

//-----------------------------------------------------------------------------
void DrawingCanvas::OnSize( wxSizeEvent& e )
//-----------------------------------------------------------------------------
{
	HandleSizeEvent( e );
}

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

//=============================================================================
//================= Implementation PlotCanvas =================================
//=============================================================================
//-----------------------------------------------------------------------------
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 */ )
  : DrawingCanvas( parent, id, pos, size, style, name, boActive ), m_BorderWidth(25), m_ImageCount(-1), m_UpdateFrequency(3)
//-----------------------------------------------------------------------------
{

}

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

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

//=============================================================================
//================= Implementation ImageAnalysisPlotCanvas ====================
//=============================================================================
const wxColour ImageAnalysisPlotCanvas::m_ADarkerKindOfGreen = wxColour(0, 150, 0);

//-----------------------------------------------------------------------------
ImageAnalysisPlotCanvas::ImageAnalysisPlotCanvas( wxWindow* parent, const wxString& configName, 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 */ ) :
	PlotCanvas(parent, id, pos, size, style, name, boActive), m_AOIColour(*wxBLUE),
	m_pImageCanvas(0), m_ConfigName(configName), m_boAOIFullMode(false), m_DisplayMethod(dmGraphical),
	m_valCount(VAL_COUNT_8_BIT), m_AOIx(0), m_AOIy(0), m_AOIw(640), m_AOIh(480), m_pAOI(0), m_GridStepsX(1), m_GridStepsY(1),
	m_ChannelCount(channelCount), m_pixelFormat(ibpfRaw), m_bayerParity(bmpUndefined), m_boUnsupportedPixelFormat(false), m_DrawStart_percent(0), m_DrawWindow_percent(100),
	m_pNumericalDisplay(0)
//-----------------------------------------------------------------------------
{
	SetDefaultPens();
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::CreateGrid( wxWindow* pParent )
//-----------------------------------------------------------------------------
{
	m_pNumericalDisplay = new wxGrid(pParent, wxID_ANY);
	CreateGridCustom();
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::CreateGridCustom( void )
//-----------------------------------------------------------------------------
{
	m_pNumericalDisplay->SetTable( new AnalysisDataGridTable(this, m_valCount, m_ChannelCount), true );
}

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

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

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::SetDefaultPens( void )
//-----------------------------------------------------------------------------
{
	m_Pens[pRed].pColour_ = wxRED;
	m_Pens[pGreen].pColour_ = wxGREEN;
	m_Pens[pBlue].pColour_ = wxBLUE;
	m_Pens[pChannel1Ver].pColour_ = wxLIGHT_GREY;
	m_Pens[pChannel2Hor].pColour_ = wxCYAN;
	m_Pens[pChannel2Ver].pColour_ = wxBLACK;
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::SetBayerDescriptions( mvIMPACT::acquire::TBayerMosaicParity bayerParity )
//-----------------------------------------------------------------------------
{
	switch( bayerParity )
	{
	case bmpBG:
		m_Pens[pEvenEven].description_ = wxString(wxT("B"));
		m_Pens[pEvenOdd].description_ = wxString(wxT("G(blue)"));
		m_Pens[pOddEven].description_ = wxString(wxT("G(red)"));
		m_Pens[pOddOdd].description_ = wxString(wxT("R"));
		break;
	case bmpGB:
		m_Pens[pEvenEven].description_ = wxString(wxT("G(blue)"));
		m_Pens[pEvenOdd].description_ = wxString(wxT("B"));
		m_Pens[pOddEven].description_ = wxString(wxT("R"));
		m_Pens[pOddOdd].description_ = wxString(wxT("G(red)"));
		break;
	case bmpGR:
		m_Pens[pEvenEven].description_ = wxString(wxT("G(red)"));
		m_Pens[pEvenOdd].description_ = wxString(wxT("R"));
		m_Pens[pOddEven].description_ = wxString(wxT("B"));
		m_Pens[pOddOdd].description_ = wxString(wxT("G(blue)"));
		break;
	case bmpRG:
		m_Pens[pEvenEven].description_ = wxString(wxT("R"));
		m_Pens[pEvenOdd].description_ = wxString(wxT("G(red)"));
		m_Pens[pOddEven].description_ = wxString(wxT("G(blue)"));
		m_Pens[pOddOdd].description_ = wxString(wxT("B"));
		break;
	default:
		break;
	}
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::SetBayerPens( mvIMPACT::acquire::TBayerMosaicParity bayerParity )
//-----------------------------------------------------------------------------
{
	switch( bayerParity )
	{
	case bmpBG:
		m_Pens[pEvenEven].pColour_ = wxBLUE;
		m_Pens[pEvenOdd].pColour_ = wxGREEN;
		m_Pens[pOddEven].pColour_ = &m_ADarkerKindOfGreen;
		m_Pens[pOddOdd].pColour_ = wxRED;
		break;
	case bmpGB:
		m_Pens[pEvenEven].pColour_ = wxGREEN;
		m_Pens[pEvenOdd].pColour_ = wxBLUE;
		m_Pens[pOddEven].pColour_ = wxRED;
		m_Pens[pOddOdd].pColour_ = &m_ADarkerKindOfGreen;
		break;
	case bmpGR:
		m_Pens[pEvenEven].pColour_ = &m_ADarkerKindOfGreen;
		m_Pens[pEvenOdd].pColour_ = wxRED;
		m_Pens[pOddEven].pColour_ = wxBLUE;
		m_Pens[pOddOdd].pColour_ = wxGREEN;
		break;
	case bmpRG:
		m_Pens[pEvenEven].pColour_ = wxRED;
		m_Pens[pEvenOdd].pColour_ = &m_ADarkerKindOfGreen;
		m_Pens[pOddEven].pColour_ = wxGREEN;
		m_Pens[pOddOdd].pColour_ = wxBLUE;
		break;
	default:
		SetDefaultPens();
		break;
	}
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::SetDisplayMethod( TDisplayMethod displayMethod )
//-----------------------------------------------------------------------------
{
	if( displayMethod == m_DisplayMethod )
	{
		return;
	}

	m_DisplayMethod = displayMethod;
	UpdateAnalysisOutput( true );
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::SetAOIFullMode( bool boActive )
//-----------------------------------------------------------------------------
{
	m_boAOIFullMode = boActive;
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::SetDrawStartPercent( int value_percent )
//-----------------------------------------------------------------------------
{
	if( ( value_percent < 0 ) || ( value_percent > 99 ) )
	{
		return;
	}
	AssignDisplayParameter( m_DrawStart_percent, value_percent );
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::SetDrawWindowWidthPercent( int value_percent )
//-----------------------------------------------------------------------------
{
	if( ( value_percent < 1 ) || ( value_percent > 100 ) )
	{
		return;
	}
	AssignDisplayParameter( m_DrawWindow_percent, value_percent );
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::GetDrawRange( unsigned int* pFrom, unsigned int* pTo ) const
//-----------------------------------------------------------------------------
{
	unsigned int from = static_cast<unsigned int>( static_cast<double>(m_valCount) * (static_cast<double>(m_DrawStart_percent) / 100.));
	unsigned int to = from + static_cast<unsigned int>( static_cast<double>(m_valCount-1) * (static_cast<double>(GetPercentageToDraw()) / 100.));
	if( pFrom )
	{
		*pFrom = from;
	}
	if( pTo )
	{
		*pTo = to;
	}
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::HandleSizeEvent( wxSizeEvent& )
//-----------------------------------------------------------------------------
{
	if( GetDisplayMethod() == ImageAnalysisPlotCanvas::dmGraphical )
	{
		// otherwise not every window message will correctly repaint the window
		UpdateAnalysisOutput( true );
	}
}

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

	bool boResult = false;

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

	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 ImageAnalysisPlotCanvas::SetAOI( const ImageBuffer* pIB, int x, int y, int w, int h )
//-----------------------------------------------------------------------------
{
	bool boChanged = false;

	if( m_boAOIFullMode )
	{
		x = 0;
		y = 0;
		w = pIB->iWidth;
		h = pIB->iHeight;
	}

	// 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( this, m_AOIx, m_AOIy, m_AOIw, m_AOIh );
	}

	return boChanged;
}

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

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::SetGridSteps( int XSteps, int YSteps )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker(m_critSect);
	if( XSteps > 0 )
	{
		m_GridStepsX = XSteps;
	}
	if( YSteps > 0 )
	{
		m_GridStepsY = YSteps;
	}
}

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

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::UpdateAnalysisOutput( bool boEraseBackground )
//-----------------------------------------------------------------------------
{
	switch( m_DisplayMethod )
	{
	case dmGraphical:
		Refresh( boEraseBackground );
		break;
	case dmNumerical:
		UpdateGrid();
		break;
	}
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotCanvas::UpdateGrid( void )
//-----------------------------------------------------------------------------
{
	if( m_pNumericalDisplay )
	{
		m_pNumericalDisplay->Refresh();
	}
}
