#include "DeviceConfigureFrame.h"
#include "DeviceListCtrl.h"
#include "KernelDriverUpdate.h"
#include <limits>
#include "Info.h"
#include "LogOutputHandlerDlg.h"
#include "mvIcon.xpm"
#include <string>
#include "wx/config.h"
#include "wx/image.h"

using namespace mvIMPACT::acquire;
using namespace std;

//-----------------------------------------------------------------------------
class MyApp : public wxApp
//-----------------------------------------------------------------------------
{
public:
	virtual bool OnInit();
};

// ----------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// ----------------------------------------------------------------------------

// the event tables connect the wxWidgets events with the functions (event
// handlers) which process them. It can be also done at run-time, but for the
// simple menu events like this the static method is much simpler.
BEGIN_EVENT_TABLE(DeviceConfigureFrame, wxFrame)
	EVT_MENU(miAbout, DeviceConfigureFrame::OnAbout)
	EVT_MENU(miQuit,  DeviceConfigureFrame::OnQuit)
	EVT_MENU(miSetID, DeviceConfigureFrame::OnSetID)
	EVT_MENU(miUpdateFW, DeviceConfigureFrame::OnUpdateFirmware)
	EVT_MENU(miUpdateKernelDriver, DeviceConfigureFrame::OnUpdateKernelDriver)
	EVT_MENU(miConfigureLogOutput, DeviceConfigureFrame::OnConfigureLogOutput)
	EVT_SIZE(DeviceConfigureFrame::OnSize)
	EVT_TIMER(wxID_ANY, DeviceConfigureFrame::OnTimer)
END_EVENT_TABLE()

// Create a new application object: this macro will allow wxWidgets to create
// the application object during program execution (it's better than using a
// static object for many reasons) and also declares the accessor function
// wxGetApp() which will return the reference of the right type (i.e. MyApp and
// not wxApp)
IMPLEMENT_APP(MyApp)

//-----------------------------------------------------------------------------
// `Main program' equivalent: the program execution "starts" here
bool MyApp::OnInit()
//-----------------------------------------------------------------------------
{
	wxImage::AddHandler(new wxPNGHandler);
	// Create the main application window
	DeviceConfigureFrame *frame = new DeviceConfigureFrame( _( "Device configure tool for MATRIX VISION GmbH devices"), wxDefaultPosition, wxDefaultSize );
	frame->Show(true);
	SetTopWindow(frame);
	// success: wxApp::OnRun() will be called which will enter the main message
	// loop and the application will run. If we returned false here, the
	// application would exit immediately.
	return true;
}

//-----------------------------------------------------------------------------
class FramePositionStorage
//-----------------------------------------------------------------------------
{
	wxConfigBase* m_pConfig;
	wxWindow* m_pWin;
public:
	FramePositionStorage( wxWindow* pWin ) : m_pWin(pWin), m_pConfig(wxConfigBase::Get()) {}
	void store( void ) const
	{
		int Height, Width, XPos, YPos;
		m_pWin->GetSize( &Width, &Height );
		m_pWin->GetPosition( &XPos, &YPos );
		m_pConfig->Write( wxT("/MainFrame/h"), Height );
		m_pConfig->Write( wxT("/MainFrame/w"), Width );
		m_pConfig->Write( wxT("/MainFrame/x"), XPos );
		m_pConfig->Write( wxT("/MainFrame/y"), YPos );
	}
	wxRect restore( const wxRect& defaultDimensions ) const
	{
		wxRect rect;
		rect.height = m_pConfig->Read( wxT("/MainFrame/h"), defaultDimensions.height );
		rect.width = m_pConfig->Read( wxT("/MainFrame/w"), defaultDimensions.width );
		rect.x = m_pConfig->Read( wxT("/MainFrame/x"), defaultDimensions.x );
		rect.y = m_pConfig->Read( wxT("/MainFrame/y"), defaultDimensions.y );
		int displayWidth = 0;
		int displayHeight = 0;
		wxDisplaySize( &displayWidth, &displayHeight );
		if( ( rect.x >= displayWidth ) || ( rect.x < 0 ) )
		{
			rect.x = 0;
		}
		if( ( rect.y >= displayHeight ) || ( rect.y < 0 ) )
		{
			rect.y = 0;
		}
		return rect;
	}
};

//=============================================================================
//================= Implementation DeviceConfigureFrame =======================
//=============================================================================
//-----------------------------------------------------------------------------
DeviceConfigureFrame::DeviceConfigureFrame( const wxString& title, const wxPoint& pos, const wxSize& size )
	: wxFrame((wxFrame *)NULL, wxID_ANY, title, pos, size),
	m_pDevListCtrl(0), m_pLogWindow(0), m_lastDevMgrChangedCount(numeric_limits<unsigned int>::max())
//-----------------------------------------------------------------------------
{
	wxMenu *menuAction = new wxMenu;
	m_pMIActionSetID = menuAction->Append( miSetID, wxT("&Set ID\tCTRL-S") );
	m_pMIActionUpdateFW = menuAction->Append( miUpdateFW, wxT("&Update firmware\tCTRL-U") );
	m_pMIActionUpdateKernelDriver = menuAction->Append( miUpdateKernelDriver, wxT("&Update kernel driver\tCTRL-K") );
	menuAction->AppendSeparator();
	menuAction->Append( miConfigureLogOutput, wxT("&Configure log output\tCTRL-C") );
	menuAction->AppendSeparator();
	menuAction->Append( miQuit, wxT("E&xit\tALT-X"));

	wxMenu *menuHelp = new wxMenu;
	menuHelp->Append( miAbout, wxT("&About mvDeviceConfigure\tCTRL-H"));

	wxMenuBar *menuBar = new wxMenuBar;
	menuBar->Append( menuAction, wxT("&Action") );
	menuBar->Append( menuHelp, wxT("&Help") );
	// ... and attach this menu bar to the frame
	SetMenuBar(menuBar);

	// define the applications icon
	wxIcon icon(mvIcon_xpm);
	SetIcon( icon );

	m_pPanel = new wxPanel( this, wxID_ANY );
	m_pLogWindow = new wxTextCtrl( m_pPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_RICH | wxTE_READONLY );
	BuildList();
	
	wxTextAttr style( wxColour(0, 0, 255) );
	WriteLogMessage( wxT("Right click on a list entry to get a menu with available options for this device\n"), style );
	WriteLogMessage( wxT("double click on a list entry to start live acquisiton in an instance of wxPropView from this device (wxPropView must be locatable via the systems path or must reside in the same directory as mvDeviceConfigure!)\n"), style );
	WriteLogMessage( wxT("'Action' menu entries will be enabled and disabled whenever a change in the currently selected device occurs.\n"), style );
	// restore previous state
	wxConfigBase* pConfig = wxConfigBase::Get();
	FramePositionStorage frameStorage(this);
	wxRect defaultRect(0, 0, 640, 480);
	wxRect rect = frameStorage.restore( defaultRect );
	for( unsigned int i=0; i<lcLAST_COLUMN; i++ )
	{
		int width = pConfig->Read( wxString::Format( wxT("/MainFrame/ListCtrl/%d"), i ), -1l );
		if( width >= 0 )
		{
			m_pDevListCtrl->SetColumnWidth( i, width );
		}
	}
	SetSizeHints( 500, 300 );
	SetSize( rect );
	UpdateMenu( -1 );

	m_listUpdateTimer.SetOwner( this, teListUpdate );
	m_listUpdateTimer.Start(500);
}

//-----------------------------------------------------------------------------
DeviceConfigureFrame::~DeviceConfigureFrame()
//-----------------------------------------------------------------------------
{
	// store the current state of the application
	FramePositionStorage frameStorage(this);
	frameStorage.store();
	wxConfigBase* pConfig = wxConfigBase::Get();	
	for( unsigned int i=0; i<lcLAST_COLUMN; i++ )
	{
		pConfig->Write( wxString::Format( wxT("/MainFrame/ListCtrl/%d"), i ), m_pDevListCtrl->GetColumnWidth( i ) );
	}
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::ActivateDeviceInPropView( int deviceIndex )
//-----------------------------------------------------------------------------
{
	wxString commandString(wxT( wxString::Format( "wxPropView device=%s live=1", m_devMgr.getDevice( deviceIndex )->serial.read().c_str() )));
	::wxExecute( commandString );
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::BuildList( void )
//-----------------------------------------------------------------------------
{
	if( m_lastDevMgrChangedCount == m_devMgr.changedCount() )
	{
		return;
	}

	m_lastDevMgrChangedCount = m_devMgr.changedCount();
	delete m_pDevListCtrl;
	m_pDevListCtrl = new DeviceListCtrl( m_pPanel, LIST_CTRL, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL | wxSUNKEN_BORDER, this );
	m_pDevListCtrl->InsertColumn( lcFamily, wxT("family") );
	m_pDevListCtrl->InsertColumn( lcProduct, wxT("product") );
	m_pDevListCtrl->InsertColumn( lcSerial, wxT("serial") );
	m_pDevListCtrl->InsertColumn( lcState, wxT("state") );
	m_pDevListCtrl->InsertColumn( lcFWVersion, wxT("firmware version") );
	m_pDevListCtrl->InsertColumn( lcKernelDriver, wxT("kernel driver") );
	m_pDevListCtrl->InsertColumn( lcDeviceID, wxT("device ID") );

	typedef map<int, int> IntIntMap;
	typedef pair<int, int> IntIntPair;
	typedef map<string, IntIntMap> String_IntIntMap_Map;
	typedef pair<string, IntIntMap> String_IntIntMap_Pair;
	String_IntIntMap_Map devMap;
	
	unsigned int devCnt = m_devMgr.deviceCount();
	for( unsigned int i=0; i<devCnt; i++ )
	{
		Device* pDev = m_devMgr[i];
		long index = m_pDevListCtrl->InsertItem( i, pDev->family.read().c_str() );
		pair<String_IntIntMap_Map::iterator, bool> p = devMap.insert( String_IntIntMap_Pair(pDev->family.read(), IntIntMap()) );
		if( !p.second )
		{
			IntIntMap::iterator it = p.first->second.find( pDev->deviceID.read() );
			if( it != p.first->second.end() )
			{
				// mark items that have a conflicting device ID
				m_pDevListCtrl->SetItemTextColour( index, *wxRED );
				m_pDevListCtrl->SetItemTextColour( it->second, *wxRED );
				wxTextAttr redStyle(wxColour(255, 0, 0));
				WriteLogMessage( wxString::Format( wxT("WARNING: The device in row %ld(%s) has the same ID as the device in row %d(%s) belonging to the same device family. This should be resolved.\n"), index, pDev->serial.read().c_str(), it->second, m_devMgr[it->second]->serial.read().c_str() ), redStyle );
			}
			else
			{
				p.first->second.insert( IntIntPair(pDev->deviceID.read(), index) );
			}
		}
		else
		{
			p.first->second.insert( IntIntPair(pDev->deviceID.read(), index ));
		}
		m_pDevListCtrl->SetItem( index, lcProduct, pDev->product.read().c_str() );
		m_pDevListCtrl->SetItem( index, lcSerial, pDev->serial.read().c_str() );
		m_pDevListCtrl->SetItem( index, lcState, pDev->state.readS().c_str() );
		m_pDevListCtrl->SetItemData( index, i );
		if( pDev->state.read() != dsPresent )
		{
			wxColor col(wxT("LIGHT GREY"));
			m_pDevListCtrl->SetItemBackgroundColour( index, col );
		}
		m_pDevListCtrl->SetItem( index, lcFWVersion, pDev->firmwareVersion.readS().c_str() );
		string kernelDriverName;
		bool newerDriverAvailable;
		bool boFeatureSupported = SupportsKernelDriverFeature( pDev, kernelDriverName, newerDriverAvailable );
		m_pDevListCtrl->SetItem( index, lcKernelDriver, kernelDriverName.c_str() );
		if( boFeatureSupported && newerDriverAvailable )
		{
			wxColor col(150, 75, 150);
			wxTextAttr oldKernelDriverStyle(col);
			WriteLogMessage( wxString::Format( wxT("WARNING: The device in row %ld(%s) is not running with the latest kernel driver. To update the kernel driver for each device of that family currently present right click on the device.\n"), index, pDev->serial.read().c_str() ), oldKernelDriverStyle );
			m_pDevListCtrl->SetItemBackgroundColour( index, col );
		}
		m_pDevListCtrl->SetItem( index, lcDeviceID, pDev->deviceID.readS().c_str() );
	}

	for( unsigned int i=0; i<lcLAST_COLUMN; i++ )
	{
		m_pDevListCtrl->SetColumnWidth( i, wxLIST_AUTOSIZE_USEHEADER );
	}

	DoSize();
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::DoSize( void )
//-----------------------------------------------------------------------------
{
	if ( !m_pLogWindow )
	{
		return;
	}
	wxSize size = GetClientSize();
	wxCoord y = (2*size.y)/3;
	m_pDevListCtrl->SetSize(0, 0, size.x, y);
	m_pLogWindow->SetSize(0, y + 1, size.x, size.y - y);
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::OnAbout(wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxBoxSizer *topsizer;
	wxDialog dlg(this, wxID_ANY, wxString(_("About mvDeviceConfigure")));
	wxIcon icon(mvIcon_xpm);
	dlg.SetIcon( icon );
	topsizer = new wxBoxSizer(wxVERTICAL);
	wxStaticText *pText = new wxStaticText( &dlg, wxID_ANY, wxString::Format( wxT("configure tool for %s devices"), COMPANY_NAME ) );
	topsizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5 );
	pText = new wxStaticText( &dlg, wxID_ANY, wxString::Format( wxT("(C) 2005 - %s by %s"), CURRENT_YEAR, COMPANY_NAME ) );
	topsizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5 );
	pText = new wxStaticText( &dlg, wxID_ANY, wxString::Format( wxT("Version %s"), VERSION_STRING ) );
	topsizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5 );
	pText = new wxStaticText( &dlg, wxID_ANY, wxT("Support contact: www.matrix-vision.de") );
	topsizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5 );
	wxButton *bu1 = new wxButton(&dlg, wxID_OK, _("OK"));
	bu1->SetDefault();
	topsizer->Add(bu1, 0, wxALL | wxALIGN_RIGHT, 15);
	dlg.SetSizer(topsizer);
	topsizer->Fit(&dlg);
	dlg.ShowModal();
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::OnConfigureLogOutput( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	LogOutputHandlerDlg dlg(this, m_devMgr, m_debugData);
	dlg.ShowModal();
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::OnQuit( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	// true is to force the frame to close
	Close(true);
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::OnSetID( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	SetID( m_pDevListCtrl->GetCurrentItemIndex() );
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::OnSize( wxSizeEvent& event )
//-----------------------------------------------------------------------------
{
    DoSize();
    event.Skip();
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::OnTimer( wxTimerEvent& event )
//-----------------------------------------------------------------------------
{
	switch( event.GetId() )
	{
	case teListUpdate:
		BuildList();
		break;
	}
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::OnUpdateFirmware( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	UpdateFirmware( m_pDevListCtrl->GetCurrentItemIndex() );
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::OnUpdateKernelDriver( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	UpdateKernelDriver( m_pDevListCtrl->GetCurrentItemIndex() );
}

//-----------------------------------------------------------------------------
int DeviceConfigureFrame::SetID( int deviceIndex )
//-----------------------------------------------------------------------------
{
	int result = 0;
	if( deviceIndex >= 0 )
	{
		Device* pDev = m_devMgr[deviceIndex];
		if( pDev )
		{
			string devSerial = pDev->serial.read();
			m_pLogWindow->WriteText( wxString::Format( wxT( "Trying to set new ID for %s. Current ID: %d\n"), devSerial.c_str(), pDev->deviceID.read() ) );
			long newID = wxGetNumberFromUser(	wxString::Format( wxT("Enter the new ID for device %s.\nMake sure that no other device of the same family already owns this new ID.\n"), devSerial.c_str() ),
												wxT("New ID:"),
												wxString::Format( wxT("Set new ID for %s(%s)"), devSerial.c_str(), pDev->family.read().c_str() ),
												0,			// start
												didlMin,	// min
												didlMax,	// max
												this );
			if( newID < didlMin )
			{
				result = -4;
				m_pLogWindow->WriteText( wxString::Format( wxT( "Operation canceled by the user.\n" ) ) );

			}
			else if( newID > didlMax )
			{
				result = -5;
				m_pLogWindow->WriteText( wxString::Format( wxT( "Invalid ID. Valid IDs range from %d to %d.\n" ), didlMin, didlMax ) );
			}
			else
			{
				Device* pDevByFamily = 0;
				string family = pDev->family.read();
				int devIndex = 0;
				while( ( pDevByFamily = m_devMgr.getDeviceByFamily( family, devIndex++ ) ) != 0 )
				{
					if( ( pDev != pDevByFamily ) && ( pDevByFamily->deviceID.read() == newID ) )
					{
						long posBefore = m_pLogWindow->GetLastPosition();
						m_pLogWindow->WriteText( wxString::Format( wxT( "WARNING: The new ID(%ld) is already assigned to at least one other device belonging to the same family(%s)(%s)????.\n" ), newID, pDevByFamily->serial.read().c_str(), family.c_str() ) );
						long posAfter = m_pLogWindow->GetLastPosition();
						wxTextAttr redStyle( wxColour( 255, 0, 0 ) );
						m_pLogWindow->SetStyle( posBefore, posAfter, redStyle );
						break;
					}
				}
			}

			if( result == 0 )
			{
				m_pLogWindow->WriteText( wxString::Format( wxT( "Trying to assign ID %ld to %s.\n" ), newID, devSerial.c_str() ) );
				int result = pDev->setID(newID);
				if( result == DMR_FEATURE_NOT_AVAILABLE )
				{
					m_pLogWindow->WriteText( wxT( "This device doesn't support setting the device ID.\n" ) );
				}
				else if( result != DMR_NO_ERROR )
				{
					m_pLogWindow->WriteText( wxString::Format( wxT( "An error occurred: %s(please refer to the manual for this error code).\n" ), ImpactAcquireException::getErrorCodeAsString( result ).c_str() ) );
				}
				else
				{
					m_pLogWindow->WriteText( wxString::Format( wxT( "%s.\n" ), pDev->HWUpdateResult.readS().c_str() ) );
				}
			}
		}
		else
		{
			m_pLogWindow->WriteText(wxString::Format( wxT( "Invalid item selection(index: %d).\n"), deviceIndex ) );
			result = -2;
		}
	}
	else
	{
		wxMessageDialog selectDlg( NULL,
								   wxT("Select a device."),
								   wxT("Error"),
								   wxOK | wxICON_INFORMATION );
		selectDlg.ShowModal();
		result = -1;
	}
	return result;
}

//-----------------------------------------------------------------------------
int DeviceConfigureFrame::UpdateFirmware( int deviceIndex )
//-----------------------------------------------------------------------------
{
	int result = 0;
	if( deviceIndex >= 0 )
	{
		Device* pDev = m_devMgr[deviceIndex];
		if( pDev )
		{
			SetCursor( *wxHOURGLASS_CURSOR );
			string serial = pDev->serial.read();
			wxMessageDialog AreYouSureDlg( NULL,
										   wxString::Format( wxT("Are you sure you want to update the firmware of device %s?\n"), serial.c_str() ),
										   wxT("Firmware update"),
										   wxNO_DEFAULT | wxYES_NO | wxICON_INFORMATION );

			if( AreYouSureDlg.ShowModal() == wxID_YES )
			{


				wxMessageDialog infoDlg( NULL,
										 wxT( "The firmware will now be updated. During this time(approx. 30 sec.) the application will not react. Please be patient.\n" ),
										 wxT( "information" ),
										 wxOK | wxICON_INFORMATION );
				infoDlg.ShowModal();

				m_pLogWindow->WriteText( wxString::Format( wxT( "Updating firmware of device %s. This might take some time. Please be patient.\n" ), serial.c_str() ) );
				int result = pDev->updateFirmware();
				if( result == DMR_FEATURE_NOT_AVAILABLE )
				{
					m_pLogWindow->WriteText( wxT( "This device doesn't support firmware updates.\n" ) );
				}
				else if( result != DMR_NO_ERROR )
				{
					m_pLogWindow->WriteText( wxString::Format( wxT( "An error occurred: %s(please refer to the manual for this error code).\n" ), ImpactAcquireException::getErrorCodeAsString( result ).c_str() ) );
				}
				else
				{
					m_pLogWindow->WriteText( wxString::Format( wxT( "%s.\n" ), pDev->HWUpdateResult.readS().c_str() ) );
				}
				if( pDev->HWUpdateResult.read() == urUpdateFWOK )
				{
					wxString str( "Update successful." );
					if( pDev->family.read() == "mvBlueFOX" )
					{
						str += " Please disconnect and reconnect the device now to activate the new firmware.";
					}
					wxMessageDialog updateOKDlg( NULL,
											    wxT( str.c_str() ),
												wxT( "Update result" ),
												wxOK | wxICON_INFORMATION );
					updateOKDlg.ShowModal();
				}
			}
			else
			{
				m_pLogWindow->WriteText( wxString::Format( wxT( "Firmware update canceled for device %s.\n" ), serial.c_str() ) );
				result = -3;
			}
			SetCursor( wxNullCursor );
		}
		else
		{
			m_pLogWindow->WriteText( wxString::Format( wxT( "Invalid item selection(index: %d).\n"), deviceIndex ) );
			result = -2;
		}
	}
	else
	{
		wxMessageDialog selectDlg( NULL,
								   wxT("Select a device."),
								   wxT("Error"),
								   wxOK | wxICON_INFORMATION );
		selectDlg.ShowModal();
		result = -1;
	}
	return result;
}

//-----------------------------------------------------------------------------
int DeviceConfigureFrame::UpdateKernelDriver( int deviceIndex )
//-----------------------------------------------------------------------------
{
	int result = 0;
	if( deviceIndex >= 0 )
	{
		Device* pDev = m_devMgr[deviceIndex];
		if( pDev )
		{
			SetCursor( *wxHOURGLASS_CURSOR );
			wxMessageDialog AreYouSureDlg( NULL,
										   wxString::Format( wxT("Are you sure you want to update the kernel driver for every device belonging to the\n%s family that is currently connected?\n"), pDev->family.read().c_str() ),
										   wxT("Kernel driver update"),
										   wxNO_DEFAULT | wxYES_NO | wxICON_INFORMATION );
			if( AreYouSureDlg.ShowModal() == wxID_YES )
			{
				ostringstream resultMsg;
				wxString str;
				m_listUpdateTimer.Stop();
				if( ::UpdateKernelDriver( pDev->family.read(), resultMsg ) != kdurOK )
				{
					wxTextAttr redStyle(wxColor(255, 0, 0));
					str = wxT("Failed to update kernel driver. Message: ");
					str.append( resultMsg.str().c_str() );
					WriteLogMessage( str, redStyle );
				}
				else
				{
					str = wxT("Update successful.");
				}
				wxMessageDialog updateDlg( NULL, wxT(str.c_str()), wxT("Update result"), wxOK | wxICON_INFORMATION );
				updateDlg.ShowModal();
				m_listUpdateTimer.Start(500);
			}
			else
			{
				m_pLogWindow->WriteText( wxString::Format( wxT( "Kernel driver update for %s devices canceled.\n" ), pDev->family.read().c_str() ) );
				result = -3;
			}
			SetCursor( wxNullCursor );
		}
		else
		{
			m_pLogWindow->WriteText( wxString::Format( wxT( "Invalid item selection(index: %d).\n"), deviceIndex ) );
			result = -2;
		}
	}
	else
	{
		wxMessageDialog selectDlg( NULL,
								   wxT("Select a device."),
								   wxT("Error"),
								   wxOK | wxICON_INFORMATION );
		selectDlg.ShowModal();
		result = -1;
	}
	return result;
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::UpdateMenu( int deviceIndex )
//-----------------------------------------------------------------------------
{
	m_pMIActionSetID->Enable( deviceIndex != -1 );
	m_pMIActionUpdateFW->Enable( deviceIndex != -1 );
	Device* pDev = 0;
	if( ( deviceIndex >= 0 ) && ( deviceIndex < static_cast<int>(m_devMgr.deviceCount()) ) )
	{		
		pDev = m_devMgr.getDevice( deviceIndex );
	}
	string dummy;
	bool boNewerDriverAvailable;
	bool boSupportsUpdate = SupportsKernelDriverFeature( pDev, dummy, boNewerDriverAvailable );
	m_pMIActionUpdateKernelDriver->Enable( boSupportsUpdate && boNewerDriverAvailable );
}

//-----------------------------------------------------------------------------
void DeviceConfigureFrame::WriteLogMessage( const wxString& msg, const wxTextAttr& style )
//-----------------------------------------------------------------------------
{
	if( m_pLogWindow )
	{
		long posBefore = m_pLogWindow->GetLastPosition();
		m_pLogWindow->WriteText( msg );
		long posAfter = m_pLogWindow->GetLastPosition();
		m_pLogWindow->SetStyle( posBefore, posAfter, style );
	}
}
