//-----------------------------------------------------------------------------
#include <apps/Common/wxAbstraction.h>
#include "PropViewFrame.h"
#include "ValuesFromUserDlg.h"
#include "wx/spinctrl.h"

using namespace std;

//=============================================================================
//============== Implementation OkAndCancelDlg ================================
//=============================================================================

BEGIN_EVENT_TABLE(OkAndCancelDlg, wxDialog)
	EVT_BUTTON(widBtnOk, OkAndCancelDlg::OnBtnOk)
	EVT_BUTTON(widBtnCancel, OkAndCancelDlg::OnBtnCancel)
END_EVENT_TABLE()

//-----------------------------------------------------------------------------
OkAndCancelDlg::OkAndCancelDlg( wxWindow* pParent, wxWindowID id, const wxString& title, const wxPoint& pos /*= wxDefaultPosition*/,
  const wxSize& size /*= wxDefaultSize*/, long style /*= wxDEFAULT_DIALOG_STYLE*/, const wxString& name /* = "OkAndCancelDlg" */ )
: wxDialog(pParent, id, title, pos, size, style, name)
//-----------------------------------------------------------------------------
{
}

//-----------------------------------------------------------------------------
void OkAndCancelDlg::AddButtons( wxWindow* pWindow, wxSizer* pSizer )
//-----------------------------------------------------------------------------
{
	// lower line of buttons
	wxBoxSizer* pButtonSizer = new wxBoxSizer(wxHORIZONTAL);
	pButtonSizer->AddStretchSpacer( 100 );
	pBtnOk_ = new wxButton(pWindow, widBtnOk, wxT("&Ok"));
	pButtonSizer->Add( pBtnOk_, wxSizerFlags().Right().Border( wxALL, 7 ) );
	pBtnCancel_ = new wxButton(pWindow, widBtnCancel, wxT("&Cancel"));
	pButtonSizer->Add( pBtnCancel_, wxSizerFlags().Right().Border( wxALL, 7 ) );
	pSizer->AddSpacer( 10 );
	pSizer->Add( pButtonSizer, wxSizerFlags().Expand() );
}

//-----------------------------------------------------------------------------
void OkAndCancelDlg::FinalizeDlgCreation( wxWindow* pWindow, wxSizer* pSizer )
//-----------------------------------------------------------------------------
{
	pWindow->SetSizer( pSizer );
	pSizer->SetSizeHints( this );
	SetClientSize( pSizer->GetMinSize() );
	SetSizeHints( GetSize() );
}

//-----------------------------------------------------------------------------
void OkAndCancelDlg::OnBtnOk( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	EndModal( wxID_OK );
}

//-----------------------------------------------------------------------------
void OkAndCancelDlg::OnBtnCancel( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	EndModal( wxID_CANCEL );
}

//=============================================================================
//============== Implementation ValuesFromUserDlg =============================
//=============================================================================
//-----------------------------------------------------------------------------
ValuesFromUserDlg::ValuesFromUserDlg( wxWindow* pParent, const wxString& title, const vector<ValueData*>& inputData )
  : OkAndCancelDlg(pParent, wxID_ANY, title)
//-----------------------------------------------------------------------------
{
	/*
		|-------------------------------------|
		| pTopDownSizer                       |
		|                spacer               |
		| |---------------------------------| |
		| | pInputControls                  | |
		| |---------------------------------| |
		|                spacer               |
		| |---------------------------------| |
		| | pButtonSizer                    | |
		| |---------------------------------| |
		|-------------------------------------|
	*/

	wxBoxSizer* pTopDownSizer = new wxBoxSizer(wxVERTICAL);
	pTopDownSizer->AddSpacer( 10 );
	
	wxPanel* pPanel = new wxPanel(this);

	int colCount = static_cast<int>(inputData.size());
	userInputData_.resize( colCount );
	ctrls_.resize( colCount );
	wxFlexGridSizer* pGridSizer = new wxFlexGridSizer(2, colCount);
	for( int i=0; i<colCount; i++ )
	{
		pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, inputData[i]->caption_));
		wxControl* p = 0;
		if( dynamic_cast<ValueRangeData*>(inputData[i]) )
		{
			ValueRangeData* pData = dynamic_cast<ValueRangeData*>(inputData[i]);
			p = new wxSpinCtrl(pPanel, widFirst + i, wxString::Format(wxT("%d"), pData->def_), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, pData->min_, pData->max_, pData->def_);
		}
		else if( dynamic_cast<ValueChoiceData*>(inputData[i]) )
		{
			ValueChoiceData* pData = dynamic_cast<ValueChoiceData*>(inputData[i]);
			p = new wxComboBox(pPanel, widFirst + i, pData->choices_[0], wxDefaultPosition, wxDefaultSize, pData->choices_);
		}
		else
		{
			wxASSERT( !"Invalid data type detected!" );
		}
		pGridSizer->Add( p, wxSizerFlags().Left() );
		ctrls_[i] = p;
	}
	pTopDownSizer->Add( pGridSizer );
	AddButtons( pPanel, pTopDownSizer );
	FinalizeDlgCreation( pPanel, pTopDownSizer );
}

//=============================================================================
//============== Implementation SettingHierarchyDlg ===========================
//=============================================================================
//-----------------------------------------------------------------------------
SettingHierarchyDlg::SettingHierarchyDlg( wxWindow* pParent, const wxString& title, const StringToStringMap& settingRelationships )
  : OkAndCancelDlg(pParent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
//-----------------------------------------------------------------------------
{
	/*
		|-------------------------------------|
		| pTopDownSizer                       |
		|                spacer               |
		| |---------------------------------| |
		| | pInputControls                  | |
		| |---------------------------------| |
		|                spacer               |
		| |---------------------------------| |
		| | pButtonSizer                    | |
		| |---------------------------------| |
		|-------------------------------------|
	*/

	wxBoxSizer* pTopDownSizer = new wxBoxSizer(wxVERTICAL);
	pTopDownSizer->AddSpacer( 10 );

	wxPanel* pPanel = new wxPanel(this);

	wxTreeCtrl* pTreeCtrl = new wxTreeCtrl(pPanel, wxID_ANY);
	wxTreeItemId rootId = pTreeCtrl->AddRoot( wxT("Base") );
	PopulateTreeCtrl( pTreeCtrl, rootId, wxString(wxT("Base")), settingRelationships );
	ExpandAll( pTreeCtrl );
	pTopDownSizer->Add( pTreeCtrl, wxSizerFlags(3).Expand() );
	AddButtons( pPanel, pTopDownSizer );
	FinalizeDlgCreation( pPanel, pTopDownSizer );
}

//-----------------------------------------------------------------------------
void SettingHierarchyDlg::ExpandAll( wxTreeCtrl* pTreeCtrl )
//-----------------------------------------------------------------------------
{
	ExpandAllChildren( pTreeCtrl, pTreeCtrl->GetRootItem() );
}

//-----------------------------------------------------------------------------
/// \brief this code is 'stolen' from the wxWidgets 2.8.0 source as this application
/// might be compiled with older versions of wxWidgets not supporting the wxTreeCtrl::ExpandAll function
void SettingHierarchyDlg::ExpandAllChildren( wxTreeCtrl* pTreeCtrl, const wxTreeItemId& item )
//-----------------------------------------------------------------------------
{
	// expand this item first, this might result in its children being added on
	// the fly
	pTreeCtrl->Expand(item);

	// then (recursively) expand all the children
	wxTreeItemIdValue cookie;
	for( wxTreeItemId idCurr = pTreeCtrl->GetFirstChild( item, cookie ); idCurr.IsOk(); idCurr = pTreeCtrl->GetNextChild( item, cookie ) )
	{
		ExpandAllChildren( pTreeCtrl, idCurr );
	}
}

//-----------------------------------------------------------------------------
void SettingHierarchyDlg::PopulateTreeCtrl( wxTreeCtrl* pTreeCtrl, wxTreeItemId currentItem, const wxString& currentItemName, const StringToStringMap& settingRelationships )
//-----------------------------------------------------------------------------
{
	StringToStringMap::const_iterator it = settingRelationships.begin();
	StringToStringMap::const_iterator itEND = settingRelationships.end();
	while( it != itEND )
	{
		if( it->second == currentItemName )
		{
			wxTreeItemId newItem = pTreeCtrl->AppendItem( currentItem, it->first );
			PopulateTreeCtrl( pTreeCtrl, newItem, it->first, settingRelationships );
		}
		++it;
	}
}

//=============================================================================
//============== Implementation DriverInformationDlg ===========================
//=============================================================================
//-----------------------------------------------------------------------------
DriverInformationDlg::DriverInformationDlg( wxWindow* pParent, const wxString& title, ComponentIterator itDrivers )
  : OkAndCancelDlg(pParent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
//-----------------------------------------------------------------------------
{
	/*
		|-------------------------------------|
		| pTopDownSizer                       |
		|                spacer               |
		| |---------------------------------| |
		| | pInputControls                  | |
		| |---------------------------------| |
		|                spacer               |
		| |---------------------------------| |
		| | pButtonSizer                    | |
		| |---------------------------------| |
		|-------------------------------------|
	*/

	wxBoxSizer* pTopDownSizer = new wxBoxSizer(wxVERTICAL);
	pTopDownSizer->AddSpacer( 10 );

	wxPanel* pPanel = new wxPanel(this);

	wxTreeCtrl* pTreeCtrl = new wxTreeCtrl(pPanel, wxID_ANY);
	PopulateTreeCtrl( pTreeCtrl, itDrivers );
	ExpandAll( pTreeCtrl );
	pTopDownSizer->Add( pTreeCtrl, wxSizerFlags(3).Expand() );
	AddButtons( pPanel, pTopDownSizer );
	FinalizeDlgCreation( pPanel, pTopDownSizer );
	SetSize( 500, 700 );
}

//-----------------------------------------------------------------------------
wxTreeItemId DriverInformationDlg::AddComponentListToList( wxTreeCtrl* pTreeCtrl, wxTreeItemId parent, mvIMPACT::acquire::ComponentLocator locator, const char* pName )
//-----------------------------------------------------------------------------
{
	ComponentList list;
	locator.bindComponent( list, string(pName) );
	if( !list.isValid() )
	{
		return wxTreeItemId();
	}
	return pTreeCtrl->AppendItem( parent, ConvertedString(list.name()) );
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::AddStringPropToList( wxTreeCtrl* pTreeCtrl, wxTreeItemId parent, ComponentLocator locator, const char* pName )
//-----------------------------------------------------------------------------
{
	PropertyS prop;
	locator.bindComponent( prop, string(pName) );
	if( prop.isValid() )
	{
		pTreeCtrl->AppendItem( parent, wxString::Format( wxT("%s: %s"), ConvertedString(prop.name()).c_str(), ConvertedString(prop.read()).c_str() ) );
	}
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::ExpandAll( wxTreeCtrl* pTreeCtrl )
//-----------------------------------------------------------------------------
{
	ExpandAllChildren( pTreeCtrl, pTreeCtrl->GetRootItem() );
}

//-----------------------------------------------------------------------------
/// \brief this code is 'stolen' from the wxWidgets 2.8.0 source as this application
/// might be compiled with older versions of wxWidgets not supporting the wxTreeCtrl::ExpandAll function
void DriverInformationDlg::ExpandAllChildren( wxTreeCtrl* pTreeCtrl, const wxTreeItemId& item )
//-----------------------------------------------------------------------------
{
	// expand this item first, this might result in its children being added on
	// the fly
	pTreeCtrl->Expand(item);

	// then (recursively) expand all the children
	wxTreeItemIdValue cookie;
	for( wxTreeItemId idCurr = pTreeCtrl->GetFirstChild( item, cookie ); idCurr.IsOk(); idCurr = pTreeCtrl->GetNextChild( item, cookie ) )
	{
		ExpandAllChildren( pTreeCtrl, idCurr );
	}
}

//-----------------------------------------------------------------------------
void DriverInformationDlg::PopulateTreeCtrl( wxTreeCtrl* pTreeCtrl, ComponentIterator itDrivers )
//-----------------------------------------------------------------------------
{
	wxTreeItemId rootId = pTreeCtrl->AddRoot( ConvertedString(itDrivers.name()) );
	itDrivers = itDrivers.firstChild();
	while( itDrivers.isValid() )
	{
		wxString msg;
		ComponentList clDriver(itDrivers.hObj());
		if( !clDriver.contentDescriptor().empty() )
		{
			msg = wxString::Format( wxT(" (%s)"), ConvertedString(clDriver.contentDescriptor()).c_str() );
		}
		wxTreeItemId newItem = pTreeCtrl->AppendItem( rootId, ConvertedString(itDrivers.name()) + msg );
		if( !msg.IsEmpty() )
		{
			pTreeCtrl->SetItemTextColour( newItem, wxColour(255, 0, 0) );
		}

		ComponentLocator locator(itDrivers.hObj());
		AddStringPropToList( pTreeCtrl, newItem, locator, "FullPath" );
		AddStringPropToList( pTreeCtrl, newItem, locator, "Version" );
		wxTreeItemId devices = AddComponentListToList( pTreeCtrl, newItem, locator, "Devices" );
		if( devices.IsOk() )
		{
			ComponentIterator itDev(locator.findComponent( "Devices" ));
			itDev = itDev.firstChild();
			while( itDev.isValid() )
			{
				pTreeCtrl->AppendItem( devices, ConvertedString(PropertyS(itDev).read()) );
				itDev = itDev.nextSibling();
			}
		}
		itDrivers = itDrivers.nextSibling();
	}
}

//=============================================================================
//============== Implementation AssignSettingsToDisplaysDlg ===================
//=============================================================================
//-----------------------------------------------------------------------------
AssignSettingsToDisplaysDlg::AssignSettingsToDisplaysDlg( wxWindow* pParent, const wxString& title,
  const std::vector<std::pair<std::string, int> >& settings, const SettingToDisplayDict& settingToDisplayDict, size_t displayCount )
  : OkAndCancelDlg(pParent, wxID_ANY, title)
//-----------------------------------------------------------------------------
{
	/*
		|-------------------------------------|
		| pTopDownSizer                       |
		|                spacer               |
		|                message              |
		|                spacer               |
		| |---------------------------------| |
		| | pInputControls                  | |
		| |---------------------------------| |
		|                spacer               |
		| |---------------------------------| |
		| | pButtonSizer                    | |
		| |---------------------------------| |
		|-------------------------------------|
	*/

	wxBoxSizer* pTopDownSizer = new wxBoxSizer(wxVERTICAL);
	pTopDownSizer->AddSpacer( 10 );
	wxPanel* pPanel = new wxPanel(this, wxID_ANY, wxPoint(5, 5));
	pTopDownSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT(" Whenever a request is returned by\n the driver it will be blitted onto the\n display the used capture setting\n has been assigned to.")) );
	pTopDownSizer->AddSpacer( 10 );
	int colCount = static_cast<int>(settings.size());
	ctrls_.resize( colCount );
	wxFlexGridSizer* pGridSizer = new wxFlexGridSizer(2, colCount);
	wxArrayString choices;
	for( size_t i=0; i<displayCount; i++ )
	{
		choices.Add( wxString::Format( wxT("Display %d"), i ) );
	}
	for( int i=0; i<colCount; i++ )
	{
		pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxString(wxT(" ")) + ConvertedString(settings[i].first)));
		SettingToDisplayDict::const_iterator it = settingToDisplayDict.find( settings[i].second );
		wxArrayString::size_type selection = 0;
		if( settingToDisplayDict.empty() )
		{
			selection = i % displayCount;
		}
		else
		{
			selection = ( it != settingToDisplayDict.end() ) ? static_cast<wxArrayString::size_type>(it->second) : 0;
		}
		ctrls_[i] = new wxComboBox(pPanel, widFirst + i, choices[selection], wxDefaultPosition, wxDefaultSize, choices);
		pGridSizer->Add( ctrls_[i], wxSizerFlags().Left() );
	}
	pTopDownSizer->Add( pGridSizer );
	AddButtons( pPanel, pTopDownSizer );
	FinalizeDlgCreation( pPanel, pTopDownSizer );
}

//=============================================================================
//============== Implementation RawImageImportDlg =============================
//=============================================================================
//-----------------------------------------------------------------------------
RawImageImportDlg::RawImageImportDlg( PropViewFrame* pParent, const wxString& title, const wxFileName& fileName )
  : OkAndCancelDlg(pParent, wxID_ANY, title), pParent_(pParent)
//-----------------------------------------------------------------------------
{
	/*
		|-------------------------------------|
		| pTopDownSizer                       |
		|                spacer               |
		| |---------------------------------| |
		| | pInputControls                  | |
		| |---------------------------------| |
		|                spacer               |
		| |---------------------------------| |
		| | pButtonSizer                    | |
		| |---------------------------------| |
		|-------------------------------------|
	*/

	wxBoxSizer* pTopDownSizer = new wxBoxSizer(wxVERTICAL);
	pTopDownSizer->AddSpacer( 10 );
	
	wxPanel* pPanel = new wxPanel(this);
	wxFlexGridSizer* pGridSizer = new wxFlexGridSizer(2, 0);
	wxArrayString pixelFormatChoices;
	pixelFormatChoices.Add( wxT("Mono8") );
	pixelFormatChoices.Add( wxT("Mono10") );
	pixelFormatChoices.Add( wxT("Mono12") );
	pixelFormatChoices.Add( wxT("Mono12Packed_V2") );
	pixelFormatChoices.Add( wxT("Mono14") );
	pixelFormatChoices.Add( wxT("Mono16") );
	pixelFormatChoices.Add( wxT("BGR888Packed") );
	pixelFormatChoices.Add( wxT("BGR101010Packed_V2") );
	pixelFormatChoices.Add( wxT("RGB888Packed") );
	pixelFormatChoices.Add( wxT("RGB101010Packed") );
	pixelFormatChoices.Add( wxT("RGB121212Packed") );
	pixelFormatChoices.Add( wxT("RGB141414Packed") );
	pixelFormatChoices.Add( wxT("RGB161616Packed") );
	pixelFormatChoices.Add( wxT("RGBx888Packed") );
	pixelFormatChoices.Add( wxT("RGBx888Planar") );
	pixelFormatChoices.Add( wxT("YUV422Packed") );
	pixelFormatChoices.Add( wxT("YUV422_UYVYPacked") );
	pixelFormatChoices.Add( wxT("YUV422_10Packed") );
	pixelFormatChoices.Add( wxT("YUV422_UYVY_10Packed") );
	pixelFormatChoices.Add( wxT("YUV444_UYVPacked") );
	pixelFormatChoices.Add( wxT("YUV444_UYV_10Packed") );
	pixelFormatChoices.Add( wxT("YUV444Packed") );
	pixelFormatChoices.Add( wxT("YUV444_10Packed") );
	pixelFormatChoices.Add( wxT("YUV422Planar") );

	wxArrayString bayerParityChoices;
	bayerParityChoices.Add( wxT("Undefined") );
	bayerParityChoices.Add( wxT("Red-green") );
	bayerParityChoices.Add( wxT("Green-red") );
	bayerParityChoices.Add( wxT("Blue-green") );
	bayerParityChoices.Add( wxT("Green-blue") );

	wxString nakedName = fileName.GetName().BeforeFirst( wxT('.') );
	wxString resolution = fileName.GetName().AfterFirst( wxT('.') ).BeforeFirst( wxT('.') );
	wxString width(resolution.BeforeFirst( wxT('x') ));
	wxString height(resolution.AfterFirst( wxT('x') ));
	wxString format = fileName.GetName().AfterLast( wxT('.') );
	wxString formatNaked = format.BeforeFirst( wxT('(') );
	wxString bayerPattern = format.AfterFirst( wxT('=') ).BeforeFirst( wxT(')') );

	if( nakedName.IsEmpty() || resolution.IsEmpty() || format.IsEmpty() )
	{
		pParent_->WriteLogMessage( wxString::Format( wxT("Failed to extract file format from %s(%s %sx%s %s).\n"), fileName.GetFullPath().c_str(), nakedName.c_str(), width.c_str(), height.c_str(), format.c_str() ) );
	}

	const size_t pixelFormatCount = pixelFormatChoices.Count();
	wxString initalPixelFormat = pixelFormatChoices[0];
	for( size_t i=1; i<pixelFormatCount; i++ )
	{
		if( formatNaked == pixelFormatChoices[i] )
		{
			initalPixelFormat = pixelFormatChoices[i];
			break;
		}
	}

	const size_t bayerParityCount = bayerParityChoices.Count();
	wxString initalbayerParity = bayerParityChoices[0];
	for( size_t i=1; i<bayerParityCount; i++ )
	{
		if( bayerPattern == bayerParityChoices[i] )
		{
			initalbayerParity = bayerParityChoices[i];
			break;
		}
	}

	pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("Pixel Format:")) );
	pCBPixelFormat_ = new wxComboBox(pPanel, wxID_ANY, initalPixelFormat, wxDefaultPosition, wxDefaultSize, pixelFormatChoices);
	pGridSizer->Add( pCBPixelFormat_, wxSizerFlags().Left() );

	pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("Bayer Parity:")) );
	pCBBayerParity_ = new wxComboBox(pPanel, wxID_ANY, initalbayerParity, wxDefaultPosition, wxDefaultSize, bayerParityChoices);
	pGridSizer->Add( pCBBayerParity_, wxSizerFlags().Left() );

	long w;
	width.ToLong( &w );
	pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("Width:")) );
	pSCWidth_ = new wxSpinCtrl(pPanel, wxID_ANY, width, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 1024*256, w );
	pGridSizer->Add( pSCWidth_, wxSizerFlags().Left() );

	long h;
	height.ToLong( &h );
	pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("Height:")) );
	pSCHeight_ = new wxSpinCtrl(pPanel, wxID_ANY, height, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 1024*256, h );
	pGridSizer->Add( pSCHeight_, wxSizerFlags().Left() );

	pTopDownSizer->Add( pGridSizer );
	AddButtons( pPanel, pTopDownSizer );
	FinalizeDlgCreation( pPanel, pTopDownSizer );
}

//-----------------------------------------------------------------------------
wxString RawImageImportDlg::GetFormat( void ) const
//-----------------------------------------------------------------------------
{
	wxString format(pCBPixelFormat_->GetValue());
	if( pCBBayerParity_->GetValue() != wxT("Undefined") )
	{
		format.Append( wxString::Format( wxT("(BayerParity: %s)"), pCBBayerParity_->GetValue().c_str() ) );
	}
	return format;
}

//-----------------------------------------------------------------------------
long RawImageImportDlg::GetWidth( void ) const
//-----------------------------------------------------------------------------
{
	return pSCWidth_->GetValue();
}

//-----------------------------------------------------------------------------
long RawImageImportDlg::GetHeight( void ) const
//-----------------------------------------------------------------------------
{
	return pSCHeight_->GetValue();
}
