/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2000/02/10
// RCS-ID:      $Id: membereditor.cpp,v 1.10 2001/04/04 12:42:37 aleksandras Exp $
// Copyright:   (c) Aleksandras Gluchovas
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
    #pragma implementation "minimal.cpp"
    #pragma interface "minimal.cpp"
#endif

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#include "membereditor.h"
#include "eventgen.h"
#include "wx/pmf/pm.h"

//#define LOG(msg) wxLogMessage(wxString(msg));
#define LOG(msg)

// sorry, 4 .cpp's and .h's of AWT-layouts contrib. needed to compile this .cpp!

#include "wx/awtlay/gridbaglayout.h"
#include "wx/awtlay/flowlayout.h"
#include "wx/awtlay/boxlayout.h"
#include "wx/awtlay/gridlayout.h"

/***** Implementation for class EventEdtiorDialog *****/

BEGIN_EVENT_TABLE( EventEditorPanel, wxPanel )

	EVT_BUTTON( ID_DELETE_FUN, EventEditorPanel::OnDeleteFunction )
	EVT_BUTTON( ID_ADD_FUN,    EventEditorPanel::OnAddFunction )
	EVT_BUTTON( ID_EDIT_CODE,  EventEditorPanel::OnEditCode )

	EVT_LISTBOX( ID_IDS_BOX,    EventEditorPanel::OnIDSelected )
	EVT_LISTBOX( ID_EVENTS_BOX, EventEditorPanel::OnEventSelected )
	EVT_LISTBOX( ID_FUN_BOX,    EventEditorPanel::OnTableEntrySelected )

END_EVENT_TABLE()

EventEditorPanel::EventEditorPanel( wxWindow* pParent, 
									  const wxString& itemName,
									  ResourceItemInfo* pParentRes,
									  EventEntryInfo* pEntry, 
									  EventEntryInfoListT* pEntries,
									  ResourceItemInfoListT* pResItems )

	: wxPanel( pParent, -1 ),
	  mpIdsList( NULL ),
	  mpEventsList( NULL ),
	  mpEntriesList( NULL ),

	  mpAddBtn( NULL ),
	  mpDeleteBtn( NULL ),

	  mpCurEvent( NULL ),
	  mpSelectEvent( NULL ),

	  mpSelectedEntry( NULL ),
	  mpCurEntry( pEntry ),
	  mpCurResInfo( NULL ),

	  mpResItems( pResItems ),
	  mpEntries( pEntries ),

	  mpParentRes( pParentRes )
{
	for( size_t i = 0; i != pEntries->Count(); ++i )
	{
		EventEntryInfo* entry = new EventEntryInfo ( *(*pEntries)[i] );

		mOriginalEntries.Add( entry );
	}

	Container* cont = new Container( this );
	cont->setInsets( Insets( 5,4,5,4 ) );

	cont->setLayout( new GridBagLayout() );

	GridBagConstraints c;
	c.fill = GridBagConstraints::BOTH;
	c.weightx = 1.0;
	c.gridwidth = GridBagConstraints::REMAINDER;

	wxStaticBox* pSBox = new wxStaticBox( this,-1, "Objects related to " + itemName + " resource" );

	Container* editorPanel = new Container( pSBox );// ) );

	Container* btnPanel = new Container();

	Dimension dim = editorPanel->getMinimumSize();
	editorPanel->setInsets( Insets( dim.height+5,10, 10,10 ) );

	c.weighty = 1.0;
	cont->add( editorPanel, &c );

	c.insets = Insets( 4,4, 4,4 );
	c.weighty = 0.0; c.insets.top = 10;
	cont->add( btnPanel, &c );

	// creating events-panel

	editorPanel->setLayout( new GridBagLayout() );

	c = GridBagConstraints(); // reset defaults
	c.fill = GridBagConstraints::BOTH;
	c.insets = Insets( 0,5,2,5 );

	editorPanel->add( new wxStaticText( pSBox,-1,"Objects:" ), &c );
	editorPanel->add( new wxStaticText( pSBox,-1,"Events:"  ), &c );

	c.gridx = 0;
	c.gridy = 1;
	c.weighty = 1.0;
	c.weightx = 1.0;

	mpIdsList     = new wxListBox( editorPanel->getPeer(), ID_IDS_BOX );
	mpEventsList  = new wxListBox( editorPanel->getPeer(), ID_EVENTS_BOX );
	mpEntriesList = new wxListBox( editorPanel->getPeer(), ID_FUN_BOX );

	Container* btnPanel1 = new Container();

	editorPanel->add( mpIdsList, &c );
	c.weightx = 2.0; c.weighty = 0.0;
	editorPanel->add( mpEventsList, &c );

	c.weighty = 0.0;
	c.weightx = 0.0;c.gridwidth = GridBagConstraints::REMAINDER;
	editorPanel->add( btnPanel1, &c );

	c.gridx = 0; c.weighty = 0.0;
	c.gridy = 2; c.gridwidth = GridBagConstraints::REMAINDER;
	editorPanel->add( new wxStaticText( pSBox,-1,"Methods:"  ), &c );

	c.gridx = 0; c.weighty = 1.0;
	c.gridy = 3; c.gridwidth = GridBagConstraints::REMAINDER;
	editorPanel->add( mpEntriesList, &c );

	mpAddBtn = new wxButton( editorPanel->getPeer(), ID_ADD_FUN,    "&Add method" );
	mpDeleteBtn = new wxButton( editorPanel->getPeer(), ID_DELETE_FUN, "&Remove method" );
	mpEditBtn = new wxButton( pSBox, ID_EDIT_CODE,"&Edit code");
	mpEditBtn->Enable(FALSE);
	mpAddBtn->Enable(FALSE);
	mpDeleteBtn->Enable(FALSE);

	btnPanel1->setLayout( new GridBagLayout() );
	c = GridBagConstraints(); // reset defaults
	c.fill = GridBagConstraints::BOTH;
	c.insets = Insets( 5,0,2,5 ); c.weightx = 1.0;
	c.gridwidth = GridBagConstraints::REMAINDER;

	btnPanel1->add( mpAddBtn, &c );
	btnPanel1->add( mpDeleteBtn, &c );
	btnPanel1->add( mpEditBtn, &c );
	c.weighty = 1.0;
	btnPanel1->add( new Container(), &c );

	RefillIdsBox();
	RefillEntriesBox();

	UpdateButtons( FALSE, FALSE );

	cont->doLayout();
}

EventEditorPanel::~EventEditorPanel()
{
	WX_CLEAR_ARRAY( mOriginalEntries );
}

void EventEditorPanel::OnIDSelected( wxCommandEvent& event )
{
	LOG("OnIDSelected")

	mpEditBtn->Enable( FALSE );

	RefillEventsBox();

	UpdateButtons( FALSE, FALSE );
}

void EventEditorPanel::OnEventSelected( wxCommandEvent& event )
{
	LOG("OnEventSelected")

	wxString sel = mpEventsList->GetStringSelection();

	mpCurEvent = mCurEvents[ mpEventsList->GetSelection() ];

	bool isHandled = EventIsHandled( *mpCurEvent );

	size_t i = 0;
	for( ; i != mpEntries->Count(); ++i )

		if ( (*mpEntries)[i]->mpEventInfo == mpCurEvent && isHandled )
		{
			UpdateButtons( TRUE, FALSE );
			mpEditBtn->Enable( TRUE );

			mpEntriesList->SetSelection( i );
			break;
		}

	if ( i == mpEntries->Count() )
	{
		UpdateButtons( FALSE, TRUE );
		mpEditBtn->Enable( FALSE );

		if ( mpEntriesList->GetSelection() >= 0 )
		{
			//mpEntriesList->Deselect( mpEntriesList->GetSelection() );
			RefillEntriesBox();
		}
	}
}

void EventEditorPanel::OnTableEntrySelected( wxCommandEvent& event )
{
	LOG("OnTableEntrySelected")

	int sel = mpEntriesList->GetSelection();

	EventEntryInfo* pEntry = (*mpEntries)[sel];

	int n = -1;

	if ( pEntry->mId1 == "" )

		n = 0;
	else
	{
		for( size_t i = 0; i != mpResItems->Count(); ++i )
		
			if ( (*mpResItems)[i]->mId == pEntry->mId1 )
			{
				n = (int)i+1;
				break;
			}
	}

	if ( n != -1 )
	{
		LOG("Resource-Entry-Found!")

		mpSelectEvent = pEntry->mpEventInfo;
		mpIdsList->SetSelection( n );

		RefillEventsBox();

		for( size_t i = 0; i != mCurEvents.Count(); ++i )

			if ( mCurEvents[i] == mpSelectEvent )
			{
				LOG("EventList->SetSelection()!" )
				mpEventsList->SetSelection( (int)i );
				UpdateButtons( TRUE, FALSE );
				mpCurEvent = mCurEvents[ mpEventsList->GetSelection() ];
			}
	}

	mpEditBtn->Enable( TRUE );
}

void EventEditorPanel::OnAddFunction( wxCommandEvent& event )
{
	if ( !mpCurEvent ) return;

	if ( EventIsHandled( *mpCurEvent ) )

		return;

	wxString hint = "On";
	wxString name = mpCurEvent->mEventMacro;

	size_t i = 0; size_t len = name.Length();

	while( i < len && name[i] != '_' ) ++i;

	++i; // skip '_'

	do
	{
		if ( i < len ) 
		{
			hint += name[i]; ++i;
		}

		while( i < len && name[i] != '_' ) 
		{
			hint += wxString( name[i] ).MakeLower();
			++i;
		}

		++i; // skip '-';

	} while( i < len );

	if ( mpCurResInfo != mpParentRes )
	{
		wxString suffix = mpCurResInfo->mId.Lower();
		suffix.SetChar( 0, wxString( suffix[0u] ).Upper()[0u] );

		hint += suffix;
	}

	wxTextEntryDialog dialog( wxPMBootSvc().GetMainWindow(), "Member function &name:",
	"Add Event-Handling Method", hint, wxOK|wxCANCEL);

	if (dialog.ShowModal() == wxID_OK)
	{
		// TBD:: make sure the method name is unique!

		EventEntryInfo& entry = *new EventEntryInfo();

		entry.mpEventInfo = mpCurEvent;
		entry.mMethod = dialog.GetValue();

		if ( mpIdsList->GetSelection() == 0 )
		{
			//entry.mClass = "";
			entry.mId1 = "";
		}
		else
		{
			ResourceItemInfo* pRes = (*mpResItems)[ mpIdsList->GetSelection() - 1 ];
			//entry.mClass = pRes->mClass;
			entry.mId1 = pRes->mId;
		}

		mpEntries->Add( &entry );

		mpEntriesList->Append( FormatEntryName( entry ) );
		mpEntriesList->SetSelection( mpEntriesList->Number()-1 );

		// this is needed to add "+" sign to the ids-box
		size_t idSel = mpIdsList->GetSelection();
		mpIdsList->Clear();
		RefillIdsBox();
		mpIdsList->SetSelection( idSel );

		// TBD:: just remove and insert the same event with "+"
		int sel = mpEventsList->GetSelection();
		RefillEventsBox();
		mpEventsList->SetSelection( sel );
		mpCurEvent = mCurEvents[ mpEventsList->GetSelection() ];

		mpEditBtn->Enable( TRUE );
		UpdateButtons( TRUE, FALSE );
	}
}

EventEntryInfo* EventEditorPanel::GetSelectedEntry()
{
	return mpSelectedEntry;
}

void EventEditorPanel::OnEditCode( wxCommandEvent& event )
{
	int sel = mpEntriesList->GetSelection();

	if ( sel < 0 ) return;

	for( size_t i = 0; i != mOriginalEntries.Count(); ++i )

		delete mOriginalEntries[i];

	mOriginalEntries.Clear();

	mpSelectedEntry = (*mpEntries)[sel];

	event.Skip(); // pass on to the containing dialog
}

void EventEditorPanel::OnDeleteFunction( wxCommandEvent& event )
{
	int sel = mpEntriesList->GetSelection();

	if ( sel < 0 ) return;

	delete (*mpEntries)[sel];
	mpEntries->Remove( sel );

	mpEntriesList->Delete( sel );

	// this is needed to remove "+" sign to the ids-box
	size_t idSel = mpIdsList->GetSelection();
	mpIdsList->Clear();
	RefillIdsBox();
	mpIdsList->SetSelection( idSel );

	mpEditBtn->Enable( FALSE );
	UpdateButtons( FALSE, FALSE );

	// TBD:: refresh events to remove "+"
	sel = mpEventsList->GetSelection();
	RefillEventsBox();
	mpEventsList->SetSelection( sel );
	mpCurEvent = mCurEvents[ mpEventsList->GetSelection() ];
}

void EventEditorPanel::DiscardChanges()
{
	WX_CLEAR_ARRAY( (*mpEntries) );

	*mpEntries = mOriginalEntries;

	mOriginalEntries.Clear(); // lose "ownership"
}

/*** protected methods ***/

void EventEditorPanel::UpdateButtons( bool canRemove, bool canAdd )
{
	mpAddBtn->Enable( canAdd );
	mpDeleteBtn->Enable( canRemove );
}

void EventEditorPanel::RefillIdsBox()
{
	mpIdsList->Append( "this" );

	for( size_t i = 0; i != mpResItems->Count(); ++i )
	{
		wxString name = (*mpResItems)[i]->mId;

		for( size_t k = 0; k != mpEntries->Count(); ++k )
		{
			if ( (*mpEntries)[k]->mId1 == name )
			{
				name = " +" + name;
				break;
			}
		}

		mpIdsList->Append( name );
	}
}

void EventEditorPanel::RefillEventsBox()
{
	LOG("RefillEventsBox")

	mpCurEvent = NULL;
	mCurEvents.Clear();

	int sel = mpIdsList->GetSelection();

	if ( sel == 0 ) 
		
		mpCurResInfo = mpParentRes;
	else
	if ( sel > 0 )

		mpCurResInfo = (*mpResItems)[ sel - 1 ];

	if ( mpEventsList->Number() )

		mpEventsList->Clear();

	if ( mpCurResInfo == mpParentRes )
	{
		for( int i = 0; gEventInfoArray[i].mEventMacro != NULL; ++i )

			if ( gEventInfoArray[i].mItemClass[0] == '\0' &&
			     gEventInfoArray[i].mEventClass[0] != '\0'
				)
				AddEventToList( gEventInfoArray[i] );
	}
	else
	{
		for( int i = 0; gEventInfoArray[i].mEventMacro != NULL; ++i )

			if ( gEventInfoArray[i].mEventClass[0] != '\0' )
			{
				if ( strcmp( gEventInfoArray[i].mItemClass, "ANY" ) == 0 ||
					 strcmp( gEventInfoArray[i].mItemClass, mpCurResInfo->mClass ) == 0 
				   )
					AddEventToList( gEventInfoArray[i] );
			}
	}
}

void EventEditorPanel::RefillEntriesBox()
{
	LOG("RefillEntriesBox")

	if ( mpEntriesList->Number() )
	{
		mpEntriesList->Clear();
	}

	for( size_t i = 0; i != mpEntries->Count(); ++i )
	{
		mpEntriesList->Append( FormatEntryName( *(*mpEntries)[i] ) );
	}
}

wxString EventEditorPanel::FormatEntryName( EventEntryInfo& entry )
{
	wxString name = mpParentRes->mClass + "::" +
					entry.mMethod + "( " + entry.mpEventInfo->mEventClass + "& )";

	if (  entry.mId1.Length() ) name += "  [ " + entry.mId1 + " ]";
						   else name += "  [ this ]";

	return name;
}

bool EventEditorPanel::EventIsHandled( EventInfo& evt )
{
	bool match = FALSE;

	for( size_t i = 0; i != mpEntries->Count(); ++i )
	{
		EventEntryInfo& entry = *(*mpEntries)[i];

		if ( entry.mpEventInfo == &evt )
		{
			if ( mpCurResInfo == mpParentRes &&
				 entry.mId1 == "" )
			{
				return TRUE;
				break;
			}

			if ( mpCurResInfo != mpParentRes &&
				 entry.mId1 == mpCurResInfo->mId )
			{
				return TRUE;
				break;
			}
		}
	}
	
	return FALSE;
}

void EventEditorPanel::AddEventToList( EventInfo& evt )
{
	if ( EventIsHandled( evt ) )

		mpEventsList->Append( "  +" + wxString(evt.mEventMacro) );
	else
		mpEventsList->Append( evt.mEventMacro );

	mCurEvents.Add( &evt );
}

void EventEditorPanel::UnselectMethod()
{
	if ( mpEntriesList->GetSelection() >= 0 )

		RefillEntriesBox();
}

/***** Implementation for class MemberEditorGrid *****/

BEGIN_EVENT_TABLE( MemberEditorGrid, wxGrid )

    EVT_GRID_CELL_LEFT_CLICK( MemberEditorGrid::OnCellLeftClick )
	EVT_GRID_CELL_RIGHT_CLICK( MemberEditorGrid::OnCellRightClick )
	EVT_GRID_COL_SIZE( MemberEditorGrid::OnColSize )
    EVT_GRID_CELL_CHANGE( MemberEditorGrid::OnCellValueChanged )

	EVT_IDLE( MemberEditorGrid::OnIdle )
	EVT_SIZE( MemberEditorGrid::OnSize )

	EVT_COMMAND_RANGE( -65535, 65535, wxEVT_COMMAND_COMBOBOX_SELECTED, 
					   MemberEditorGrid::OnChoice )

END_EVENT_TABLE()

MemberEditorGrid::MemberEditorGrid( wxWindow* pParent, 
									GenSourceProcessor* pProc )

	: wxGrid( pParent, -1, wxDefaultPosition, wxDefaultSize,  
			  wxSUNKEN_BORDER  ),

	  READ_ONLY_CELL_BG( wxColour( 0xE0,0xE0,0xE0 ) ),
	  EMPTY_CELL_BG	   ( wxColour( 0xFF,0xFF,0xFF ) ),
	  FILLED_CELL_BG   ( wxColour( 0xEE,0xEE,0xFF ) ),

	  mpProc( pProc ),
	  mpOrignialItems( NULL ),
	  mLeftClicked( FALSE ),
	  mApplyPending( FALSE )
{									  
	mpItems = &pProc->GetResourceItems();

	mpOrignialItems = new ResourceItemInfoListT();

	for( size_t i = 0; i != mpItems->Count(); ++i )
	{
		ResourceItemInfo* pCopy = new ResourceItemInfo();

		*pCopy = *(*mpItems)[i];

		mpOrignialItems->Add( pCopy );
	}


	BeginBatch();

	ClearGrid();

	if ( mpItems->Count() )
	{
		CreateGrid( mpItems->Count(), LAST_COLUMN+1 );

		// FIXME:: somehow to columns cannot share single instance of
		//		   wxGridCellAttr - get a crash when deleting some gdi-object.
		//		   so this is just workaround..

		mpReadOnlyAttr = new wxGridCellAttr();
		mpReadOnlyAttr->SetTextColour(*wxBLACK);
		mpReadOnlyAttr->SetBackgroundColour( READ_ONLY_CELL_BG );
		mpReadOnlyAttr1 = new wxGridCellAttr();
		mpReadOnlyAttr1->SetTextColour(*wxBLACK);
		mpReadOnlyAttr1->SetBackgroundColour( READ_ONLY_CELL_BG );

		mpEmptyAttr = new wxGridCellAttr();
		mpFilledAttr = new wxGridCellAttr();
		mpEmptyAttr->SetTextColour(*wxBLACK);
		mpEmptyAttr->SetBackgroundColour( EMPTY_CELL_BG );
		mpFilledAttr->SetTextColour(*wxBLACK);
		mpFilledAttr->SetBackgroundColour( FILLED_CELL_BG );

		SetColAttr( COL_RES_NAME, mpReadOnlyAttr );
		SetColAttr( COL_RES_CLASS, mpReadOnlyAttr1 );

		for( size_t k = 0; k != mpItems->Count(); ++k )
		{
			ResourceItemInfo& item = *(*mpItems)[k];

			if ( item.mpRule && item.mpRule->mVarTypes.Count() )
			{
				wxGridCellChoiceEditor* pEditor = new wxGridCellChoiceEditor();
				SetCellEditor(k, COL_MEMBER_TYPE, pEditor);

				wxString params;
				for( size_t j = 0; j != item.mpRule->mVarTypes.Count(); ++j )
				{
					if ( j != 0 ) params += ",";

					params += item.mpRule->mVarTypes[j]->mBoundAs;
				}

				pEditor->SetParameters( params );
			}
			else
				SetReadOnly( k, COL_MEMBER_TYPE );

			RefillRow( k );
		}
	}
	else
		CreateGrid( 1,1 );

	SetRowLabelSize( 0 );
	SetLabelValue( wxHORIZONTAL, "Resource", COL_RES_NAME );
	SetLabelValue( wxHORIZONTAL, "Ctrl. class", COL_RES_CLASS );
	SetLabelValue( wxHORIZONTAL, "Ctrl. ref", COL_CTL_MEMBER );
	SetLabelValue( wxHORIZONTAL, "Type", COL_MEMBER_TYPE );
	SetLabelValue( wxHORIZONTAL, "Name", COL_MEMBER );
	SetLabelValue( wxHORIZONTAL, "Init. value", COL_MEMBER_INIT_VALUE );
	SetLabelValue( wxHORIZONTAL, "Getter", COL_GETTER );
	SetLabelValue( wxHORIZONTAL, "Setter", COL_SETTER );
	
	//SetGridLineColour( *wxGREEN );
	m_gridLineColour = *wxBLACK;

	EnableDragRowSize( FALSE );

	EndBatch();

	int cols = GetCols();
}

MemberEditorGrid::~MemberEditorGrid()
{
	ClearGrid();

	if ( mpOrignialItems )
	{
		WX_CLEAR_ARRAY( (*mpOrignialItems) );

		delete mpOrignialItems;
	}
}

void MemberEditorGrid::DiscardChanges()
{
	WX_CLEAR_ARRAY( (*mpItems) );

	(*mpItems) = *mpOrignialItems; // trasnfer "ownership"

	mpOrignialItems->Clear(); // "detach: items
}

void MemberEditorGrid::OnCellLeftClick( wxGridEvent& event )
{
	mLeftClicked = TRUE;

	event.Skip();
}

void MemberEditorGrid::OnChoice( wxCommandEvent& event )
{
	//wxMessageBox( "OnChoice" );

	mApplyPending = TRUE;

	event.Skip();
}

void MemberEditorGrid::OnCellRightClick( wxGridEvent& event )
{
	int row = event.GetRow(), col = event.GetCol();

	if ( !IsReadOnly( row, col ) )
	{
		wxString val = GetCellValue( row, col );

		if ( val.Length() )
		{
			SetItemValue( row, col, "" );

			if ( col == COL_MEMBER_TYPE || 
				 col == COL_MEMBER      || 
				 col == COL_CTL_MEMBER  )
			{
				SetItemValue( row, COL_MEMBER_TYPE, "" );
				SetItemValue( row, COL_MEMBER, "" );
				SetItemValue( row, COL_MEMBER_INIT_VALUE, "" );
				SetItemValue( row, COL_GETTER, "" );
				SetItemValue( row, COL_SETTER, "" );
			}
		}
		else
			SetItemValue( row, col, GetDefautlValueForCell( row, col ) );

		RefillRow( row );
	}

	event.Skip();
}

void MemberEditorGrid::OnColSize( wxGridEvent& event )
{
	AdjustColumnSizes();

	event.Skip();
}

void MemberEditorGrid::OnCellValueChanged( wxGridEvent& event )
{
	int row = event.GetRow(), col = event.GetCol();

	SetItemValue( row, col, GetCellValue( row, col ) );

	RefillRow( row );

	DisableCellEditControl();
//	event.Skip();
}

void MemberEditorGrid::OnIdle( wxIdleEvent& event )
{
	if ( mLeftClicked )
	{
		mLeftClicked = FALSE;

		if ( CanEnableCellControl() )
		{
			EnableCellEditControl();
		}
	}

	if ( mApplyPending )
	{
		mApplyPending = FALSE;

		SaveEditControlValue();

		int row = GetCursorRow(), col = GetCursorColumn();
        wxGridCellAttr* attr = GetCellAttr( row, col );
		
		wxGridCellEditor* editor = attr->GetEditor(this, row, col);
		editor->BeginEdit(row, col, this);
	}

	event.Skip();
}

void MemberEditorGrid::OnSize( wxSizeEvent& event )
{
	AdjustColumnSizes();

	event.Skip();
}

/*** protected methods ***/

void MemberEditorGrid::AdjustColumnSizes()
{
	int w = 0;
    int h = 0;

	int cols = GetCols();
	if ( cols == 0 )
		return;

	GetClientSize( &w, &h );

	int sz = w / (LAST_COLUMN + 1 );

	for( size_t i = 0; i <= LAST_COLUMN; ++i )
	
		SetColSize( i, sz );
}

void MemberEditorGrid::RefillRow( int row )
{
	ResourceItemInfo& item = *(*mpItems)[row];

	SetCellValue( item.mId, row, COL_RES_NAME );
	SetCellValue( item.mClass, row, COL_RES_CLASS );

	if ( item.mpRule == NULL )
	{
		for( size_t i = 0; i <= LAST_COLUMN; ++i )

			DecorateCell( row, i, FALSE, TRUE );

		return;
	}

	if ( item.mGetter.Length() &&
		 !item.mMember.Length() )

		 item.mMember = GetDefautlValueForCell( row, COL_MEMBER );

	if ( item.mSetter.Length() &&
		 !item.mMember.Length() )

		 item.mMember = GetDefautlValueForCell( row, COL_MEMBER );

	if ( item.mInitValue.Length() &&
		 !item.mMember.Length() )

		 item.mMember = GetDefautlValueForCell( row, COL_MEMBER );

	if ( item.mType.Length() &&
		 !item.mMember.Length() )

		 item.mMember = GetDefautlValueForCell( row, COL_MEMBER );

	if ( item.mMember.Length() &&
		 !item.mType.Length() )

		 item.mType = GetDefautlValueForCell( row, COL_MEMBER_TYPE );

	if ( item.mMember.Length() &&
		 !item.mCtrlMember.Length() )

    item.mCtrlMember = GetDefautlValueForCell( row, COL_CTL_MEMBER );

	bool canHaveMember = (item.mpRule->mVarTypes.Count() != 0);

	DecorateCell( row, COL_CTL_MEMBER, (item.mCtrlMember.Length() != 0), FALSE );
	DecorateCell( row, COL_MEMBER_TYPE, (item.mType.Length() != 0), !canHaveMember );
	DecorateCell( row, COL_MEMBER, (item.mMember.Length() != 0), !canHaveMember );
	DecorateCell( row, COL_MEMBER_INIT_VALUE, (item.mInitValue.Length() != 0), !canHaveMember );
	DecorateCell( row, COL_GETTER, (item.mGetter.Length() != 0), !canHaveMember );
	DecorateCell( row, COL_SETTER, (item.mSetter.Length() != 0), !canHaveMember );

	SetCellValue( item.mCtrlMember, row, COL_CTL_MEMBER );

	if ( item.mpVarType )

		SetCellValue( item.mpVarType->mBoundAs, row, COL_MEMBER_TYPE );

	SetCellValue( item.mMember, row, COL_MEMBER );
	SetCellValue( item.mInitValue, row, COL_MEMBER_INIT_VALUE );
	SetCellValue( item.mGetter, row, COL_GETTER );
	SetCellValue( item.mSetter, row, COL_SETTER );

	SetReadOnly( row, COL_RES_NAME );
	SetReadOnly( row, COL_RES_CLASS );

	if ( item.mType )
	{
		item.mpVarType = NULL;

		for( size_t n = 0; n != item.mpRule->mVarTypes.Count(); ++n )

			if ( item.mpRule->mVarTypes[n]->mBoundAs == item.mType )
			{
				item.mpVarType = item.mpRule->mVarTypes[n];
				break;
			}
	}
}

wxString MemberEditorGrid::GetDefautlValueForCell( int row, int col )
{
	ResourceItemInfo& item = *(*mpItems)[row];

	mpProc->SetCommonItemVars( item, *mpProc->GetProcessorTemplate() );

	if ( col == COL_MEMBER_TYPE )
	
		return item.mpRule->mVarTypes[0]->mBoundAs;
	else
	if ( col == COL_GETTER )

		return item.mpRule->mGetterNameHint.SubstitueVariables();
	else
	if ( col == COL_SETTER )

		return item.mpRule->mSetterNameHint.SubstitueVariables();
	else
	if ( col == COL_MEMBER )
	{
		if ( !item.mpVarType )
		{
			item.mpVarType = item.mpRule->mVarTypes[0];
			item.mType = item.mpVarType->mBoundAs;
		}

		return item.mpVarType->mMemberNameHint.SubstitueVariables();
	}
	else
	if ( col == COL_CTL_MEMBER )

		return item.mpRule->mCtlMemberNameHint.SubstitueVariables();

	return "";
}

bool MemberEditorGrid::IsReadOnlyColumn( int col )
{
	return col == COL_RES_NAME || col == COL_RES_CLASS;
}

void MemberEditorGrid::DecorateCell( int row, int col, bool isFilled, bool isReadOnly )
{
	SetReadOnly( row, col, isReadOnly );

	if ( isReadOnly )
	{
		SetCellTextColour( row, col, *wxBLACK );
		SetCellBackgroundColour( row, col, READ_ONLY_CELL_BG );
	}
	else
	if ( isFilled )
	{
		SetCellTextColour( row, col, *wxBLACK );
		SetCellBackgroundColour( row, col, FILLED_CELL_BG );
	}
	else
	{
		SetCellTextColour( row, col, *wxBLACK );
		SetCellBackgroundColour( row, col, EMPTY_CELL_BG );
	}
}

void MemberEditorGrid::SetItemValue( int row, int col, const wxString& value )
{
	ResourceItemInfo& item = *(*mpItems)[row];

	switch( col )
	{
		case COL_CTL_MEMBER	: item.mCtrlMember = value; break;
		case COL_MEMBER_TYPE : item.mType = value; break;
		case COL_MEMBER : item.mMember = value; break;
		case COL_MEMBER_INIT_VALUE : item.mInitValue = value; break;
		case COL_GETTER : item.mGetter = value; break;
		case COL_SETTER : item.mSetter = value; break;
		default : break;
	}
}

/***** Implementation for class SourceWizardDialog *****/

static wxSize _gSrcWizardDlgLRUSize = wxSize( 500, 400 );

BEGIN_EVENT_TABLE( SourceWizardDialog, wxDialog )

	EVT_BUTTON( ID_EDIT_CODE,  SourceWizardDialog::OnEditCode )
	EVT_BUTTON( wxID_OK,  SourceWizardDialog::OnOk )

	EVT_SIZE( SourceWizardDialog::OnSize )

END_EVENT_TABLE()

SourceWizardDialog::SourceWizardDialog( wxWindow* pParent, GenSourceProcessor* pProc, 
										ResourceItemInfo* pParentRes,
										bool showMembersPane )

	: wxDialog( pParent, -1, "wxWindows Source Wizard", wxDefaultPosition, wxDefaultSize,
				wxSYSTEM_MENU | wxCAPTION | 
				wxTAB_TRAVERSAL | wxTHICK_FRAME | wxRESIZE_BORDER ),
	  mpProc( pProc )
{
	wxBoxSizer* pTopSizer = new wxBoxSizer( wxVERTICAL );

	mpNotebook = new wxNotebook( this, -1 );
	wxNotebookSizer* pNbSizer = new wxNotebookSizer( mpNotebook );

	mpApplyBtn  = new wxButton( this, wxID_OK, "A&pply", wxDefaultPosition );
	mpCancelBtn = new wxButton( this, wxID_CANCEL, "C&ancel", wxDefaultPosition );

	mpApplyBtn->SetDefault();

	wxBoxSizer* pBtnSizer = new wxBoxSizer( wxHORIZONTAL );

	pBtnSizer->Add( mpApplyBtn,  0 );
	pBtnSizer->Add( mpCancelBtn, 0, wxLEFT, 10 );

	pTopSizer->Add( pNbSizer, 1, wxALL | wxEXPAND, 5 );
	pTopSizer->Add( pBtnSizer, 0, wxALL | wxEXPAND, 5 );

	mpEventEditor = new EventEditorPanel( mpNotebook, pParentRes->mId, 
										  pParentRes, NULL, &pProc->GetEvents(),
										  &pProc->GetResourceItems() );

	mpNotebook->AddPage( mpEventEditor,  "Events",  showMembersPane );

	if ( pProc->GetResourceItems().Count() )
	{
		wxPanel* pPage = new wxPanel( mpNotebook, -1, wxDefaultPosition, 
									  wxDefaultSize, wxTAB_TRAVERSAL | wxSUNKEN_BORDER );
		wxBoxSizer* pPageSizer = new wxBoxSizer( wxVERTICAL );
		wxStaticText* pTip = new wxStaticText( pPage, -1, "TIP: right-click on a cell to toggle between emtpy and hint values" );

		mpMemberEditor = new MemberEditorGrid( pPage, pProc );

		pPageSizer->Add( mpMemberEditor, 1, wxEXPAND );
		pPageSizer->Add( pTip, 0, wxEXPAND | wxALL, 5 );

		pPage->SetSizer( pPageSizer );
		pPage->SetAutoLayout( TRUE );

		mpNotebook->AddPage( pPage, "Members", !showMembersPane );
	}

	mpNotebook->SetSelection( showMembersPane ? mpNotebook->GetPageCount() - 1 : 0 );

	SetAutoLayout( TRUE );
	SetSizer( pTopSizer );
	pTopSizer->SetSizeHints( this );
	this->SetSize( _gSrcWizardDlgLRUSize );
	Center( wxBOTH );
}

void SourceWizardDialog::OnEditCode( wxCommandEvent& event )
{
	EndModal( ID_EDIT_CODE );
}

void SourceWizardDialog::OnOk( wxCommandEvent& event )
{
	EndModal( wxID_OK );
}

MemberEditorGrid* SourceWizardDialog::GetMemberEditor()
{
	return mpMemberEditor;
}

EventEditorPanel* SourceWizardDialog::GetEventEditor()
{
	return mpEventEditor;
}

void SourceWizardDialog::OnSize( wxSizeEvent& event )
{
	int w = 0, h = 0;
	GetSize( &w, &h );

	_gSrcWizardDlgLRUSize.x = w;
	_gSrcWizardDlgLRUSize.y = h;

	event.Skip();
}
