
/***************************************************************************

                                 ChessV

                   COPYRIGHT (C) 2005 BY GREGORY STRONG

This file is part of ChessV.  ChessV is free software; you can redistribute
it and/or modify it under the terms of the GNU General Public License as 
published by the Free Software Foundation; either version 2 of the License, 
or (at your option) any later version.

ChessV is distributed in the hope that it will be useful, but WITHOUT ANY 
WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
more details; the file 'COPYING' contains the License text, but if for
some reason you need a copy, please write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

****************************************************************************/


#include "StdAfx.h"
#include "ChessV.h"
#include "Resource.h"
#include "GUI\Pen.h"


// *** DEBUG MEMORY ALLOCATION *** //
#ifdef _DEBUG
#define new SAFE_NEW
#endif


// DoLockDlgRes - loads and locks a dialog box template resource. 
// Returns the address of the locked resource. 
// lpszResName - name of the resource 
 
DLGTEMPLATE *WINAPI DoLockDlgRes
	( LPCSTR lpszResName )
{ 
    HRSRC hrsrc = FindResource( NULL, lpszResName, RT_DIALOG ); 
    HGLOBAL hglb = LoadResource( theInstance, hrsrc ); 
    return (DLGTEMPLATE *) LockResource( hglb ); 
} 

#define TAB_CONTROL_PAGE_COUNT 3 
 
struct DLGHDR
{ 
	HWND hwndTab;				// tab control 
	HWND hwndDisplay;			// current child dialog box 
	RECT rcDisplay;				// display rectangle for the tab control 
	DLGTEMPLATE *apRes[TAB_CONTROL_PAGE_COUNT];
};

//	OnChildDialogInit - Positions the child dialog box to fall 
//	within the display area of the tab control
VOID WINAPI OnChildDialogInit( HWND hWndDlg ) 
{ 
	HWND hwndParent = ::GetParent( hWndDlg ); 
	DLGHDR *pHdr = (DLGHDR *) ::GetWindowLongPtr( 
        hwndParent, GWLP_USERDATA ); 
	::SetWindowPos( hWndDlg, HWND_TOP, 
        pHdr->rcDisplay.left, pHdr->rcDisplay.top, 
        0, 0, SWP_NOSIZE ); 
} 

HBITMAP hChessBitmap;
HBITMAP hCapablancaBitmap;
HBITMAP hShatranjBitmap;
HBITMAP hGrandChessBitmap;

LRESULT CALLBACK TabChildrenDlgProc
	( HWND hWndDlg, 
	  UINT Msg, 
	  WPARAM wParam, 
	  LPARAM lParam )
{
	switch( Msg )
	{
	  case WM_INITDIALOG:
		{
			OnChildDialogInit( hWndDlg );
			hChessBitmap = (HBITMAP) ::LoadImage( NULL, "images\\Orthodox_Chess.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
			hCapablancaBitmap = (HBITMAP) ::LoadImage( NULL, "images\\Capablanca_Chess.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
			hShatranjBitmap = (HBITMAP) ::LoadImage( NULL, "images\\Shatranj.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
			hGrandChessBitmap = (HBITMAP) ::LoadImage( NULL, "images\\Grand_Chess.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
		}
		return TRUE;

	  case WM_DRAWITEM:
		{
		    LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam;
			HBRUSH hBG = ::GetSysColorBrush( COLOR_3DFACE );
			Pen hilightPen( ::GetSysColor( COLOR_3DHIGHLIGHT ) );
			Pen shadowPen( ::GetSysColor( COLOR_3DDKSHADOW ) );
			::SelectObject( lpdis->hDC, hBG );
			::Rectangle( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, lpdis->rcItem.right + 1, lpdis->rcItem.bottom + 1 );
			::SelectObject( lpdis->hDC, lpdis->itemState & ODS_SELECTED ? shadowPen : hilightPen );
			::MoveToEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.bottom, NULL );
			::LineTo( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top );
			::LineTo( lpdis->hDC, lpdis->rcItem.right, lpdis->rcItem.top );
			::MoveToEx( lpdis->hDC, lpdis->rcItem.left + 1, lpdis->rcItem.bottom, NULL );
			::LineTo( lpdis->hDC, lpdis->rcItem.left + 1, lpdis->rcItem.top + 1 );
			::LineTo( lpdis->hDC, lpdis->rcItem.right, lpdis->rcItem.top + 1 );
			::SelectObject( lpdis->hDC, shadowPen );
			::MoveToEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.bottom - 1, NULL );
			::LineTo( lpdis->hDC, lpdis->rcItem.right - 1, lpdis->rcItem.bottom - 1 );
			::LineTo( lpdis->hDC, lpdis->rcItem.right - 1, lpdis->rcItem.top );
			::MoveToEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.bottom - 2, NULL );
			::LineTo( lpdis->hDC, lpdis->rcItem.right - 2, lpdis->rcItem.bottom - 2 );
			::LineTo( lpdis->hDC, lpdis->rcItem.right - 2, lpdis->rcItem.top );
			HDC hdcMem = ::CreateCompatibleDC( lpdis->hDC );
			if( wParam == IDC_ORTHODOX_CHESS_BUTTON )
			{
				::SelectObject( hdcMem, hChessBitmap );
				if( lpdis->itemState & ODS_SELECTED )
					::BitBlt( lpdis->hDC, lpdis->rcItem.left + 27, lpdis->rcItem.top + 10, 180, 180, hdcMem, 0, 0, SRCCOPY );
				else
					::BitBlt( lpdis->hDC, lpdis->rcItem.left + 26, lpdis->rcItem.top + 9, 180, 180, hdcMem, 0, 0, SRCCOPY );
			}
			if( wParam == IDC_CAPABLANCA_CHESS_BUTTON )
			{
				::SelectObject( hdcMem, hCapablancaBitmap );
				if( lpdis->itemState & ODS_SELECTED )
					::BitBlt( lpdis->hDC, lpdis->rcItem.left + 27, lpdis->rcItem.top + 10, 219, 180, hdcMem, 0, 0, SRCCOPY );
				else
					::BitBlt( lpdis->hDC, lpdis->rcItem.left + 26, lpdis->rcItem.top + 9, 219, 180, hdcMem, 0, 0, SRCCOPY );
			}
			if( wParam == IDC_SHATRANJ_BUTTON )
			{
				::SelectObject( hdcMem, hShatranjBitmap );
				if( lpdis->itemState & ODS_SELECTED )
					::BitBlt( lpdis->hDC, lpdis->rcItem.left + 27, lpdis->rcItem.top + 10, 180, 180, hdcMem, 0, 0, SRCCOPY );
				else
					::BitBlt( lpdis->hDC, lpdis->rcItem.left + 26, lpdis->rcItem.top + 9, 180, 180, hdcMem, 0, 0, SRCCOPY );
			}
			if( wParam == IDC_GRAND_CHESS_BUTTON )
			{
				::SelectObject( hdcMem, hGrandChessBitmap );
				if( lpdis->itemState & ODS_SELECTED )
					::BitBlt( lpdis->hDC, lpdis->rcItem.left + 27, lpdis->rcItem.top + 10, 219, 219, hdcMem, 0, 0, SRCCOPY );
				else
					::BitBlt( lpdis->hDC, lpdis->rcItem.left + 26, lpdis->rcItem.top + 9, 219, 219, hdcMem, 0, 0, SRCCOPY );
			}
			::DeleteDC( hdcMem );
		}
		return TRUE;

	  case WM_COMMAND:
		{
			::SendMessage( ::GetParent( hWndDlg ), WM_COMMAND, wParam, lParam );
		}

	  case WM_DESTROY:
		::DeleteObject( hChessBitmap );
		::DeleteObject( hCapablancaBitmap );
		::DeleteObject( hShatranjBitmap );
		::DeleteObject( hGrandChessBitmap );
		break;

	  case WM_NOTIFY:
		if( ((LPNMHDR) lParam)->code == LVN_GETDISPINFO )
		{
			NMLVDISPINFO *plvdi = (NMLVDISPINFO *) lParam;
			char buffer[10];
			switch( plvdi->item.iSubItem )
			{
			  case 0:
				plvdi->item.pszText = ((GameInformation *) (plvdi->item.lParam))->name;
				break;

			  case 1:
				sprintf( buffer, "%dx%d", ((GameInformation *) (plvdi->item.lParam))->file_count,
					((GameInformation *) (plvdi->item.lParam))->rank_count );
				plvdi->item.pszText = buffer;
				break;

			  case 2:
				plvdi->item.pszText = ((GameInformation *) (plvdi->item.lParam))->year_of_invention;
				break;

			  case 3:
				plvdi->item.pszText = ((GameInformation *) (plvdi->item.lParam))->inventor;
				break;
			}
			return 0;
		}
	}
	return FALSE;
}

//	initialize the list control
BOOL InitListView( HWND hWndListView ) 
{ 
	LVCOLUMN lvc; 

	//	initialize the LVCOLUMN structure
	//	The mask specifies that the format, width, text, and subitem members
	//	of the structure are valid
	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; 

	//	add the columns
	lvc.iSubItem = 3;
	lvc.pszText = "Inventor";
	lvc.cx = 220;
	lvc.fmt = LVCFMT_LEFT;
	if( ListView_InsertColumn( hWndListView, 0, &lvc ) == -1 ) 
		return FALSE; 
	lvc.iSubItem = 2;
	lvc.pszText = "Year";
	lvc.cx = 46;
	lvc.fmt = LVCFMT_CENTER;
	if( ListView_InsertColumn( hWndListView, 0, &lvc ) == -1 ) 
		return FALSE; 
	lvc.iSubItem = 1;
	lvc.pszText = "Board";
	lvc.cx = 55;
	lvc.fmt = LVCFMT_CENTER;
	if( ListView_InsertColumn( hWndListView, 0, &lvc ) == -1 ) 
		return FALSE; 
	lvc.iSubItem = 0;
	lvc.pszText = "Game";
	lvc.cx = 195;
	lvc.fmt = LVCFMT_LEFT;
	if( ListView_InsertColumn( hWndListView, 0, &lvc ) == -1 ) 
		return FALSE; 

	ListView_SetExtendedListViewStyleEx( hWndListView, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT );

	//	add a row to the list control for each internal game
	for( int x = 0; x < nSupportedVariants; x++ )
	{
		LVITEM lvi;
		lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; 
		lvi.state = 0; 
		lvi.stateMask = 0; 
		lvi.iItem = x;
		lvi.iSubItem = 0;
		lvi.lParam = (LPARAM) (supportedVariants + x);
		lvi.pszText = supportedVariants[x].name;
		if( ListView_InsertItem( hWndListView, &lvi ) == -1 )
			return NULL;
	}
	//	add a row to the list control for each included game
	for( int x = 0; x < nIncludedVariants; x++ )
	{
		LVITEM lvi;
		lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; 
		lvi.state = 0; 
		lvi.stateMask = 0; 
		lvi.iItem = x;
		lvi.iSubItem = 0;
		lvi.lParam = (LPARAM) &(includedVariants[x]);
		lvi.pszText = includedVariants[x].name;
		if( ListView_InsertItem( hWndListView, &lvi ) == -1 )
			return NULL;
	}
	return TRUE; 
} 

//	OnSelChanged - processes the TCN_SELCHANGE notification. 
//	hwndDlg - handle to the parent dialog box. 
VOID WINAPI OnSelChanged( HWND hwndDlg ) 
{ 
	DLGHDR *pHdr = (DLGHDR *) ::GetWindowLongPtr( 
		hwndDlg, GWLP_USERDATA ); 
	int iSel = TabCtrl_GetCurSel( pHdr->hwndTab ); 

	//	destroy the current child dialog box, if any
	if( pHdr->hwndDisplay != NULL ) 
		DestroyWindow( pHdr->hwndDisplay ); 

	//	create the new child dialog box
	pHdr->hwndDisplay = ::CreateDialogIndirect( theInstance, 
		pHdr->apRes[iSel], hwndDlg, (DLGPROC) TabChildrenDlgProc ); 

	//	initialize list control, if we have switched to a tab 
	//	page that has a list control
	if( iSel == 1 )
	{
		HWND hWndListView = ::GetDlgItem( pHdr->hwndDisplay, IDC_LIST1 );
		InitListView( hWndListView );
	}

	//	show the dialog box contained on the new tab page
	::ShowWindow( pHdr->hwndDisplay, SW_SHOWNORMAL );
} 

LRESULT CALLBACK NewGameSelectDlgProc
	( HWND hWndDlg, 
	  UINT Msg, 
	  WPARAM wParam, 
	  LPARAM lParam )
{
	int rtn;
	switch( Msg )
	{
	  case WM_INITDIALOG:
		{
		    DLGHDR *pHdr = (DLGHDR *) LocalAlloc( LPTR, sizeof(DLGHDR) ); 
			//	save a pointer to the DLGHDR structure
			SetWindowLongPtr( hWndDlg, GWLP_USERDATA, /*(LONG)*/ (LONG_PTR) pHdr );

			//	create tabs for the tab control
			TCITEM tcitem;
			tcitem.pszText = "Popular Games";
			tcitem.mask = TCIF_TEXT;
			::SendDlgItemMessage( hWndDlg, IDC_TAB, TCM_INSERTITEM, 0, (LPARAM) &tcitem );
			tcitem.pszText = "All Games";
			::SendDlgItemMessage( hWndDlg, IDC_TAB, TCM_INSERTITEM, 1, (LPARAM) &tcitem );
			pHdr->hwndTab = ::GetDlgItem( hWndDlg, IDC_TAB );
			::GetWindowRect( pHdr->hwndTab, &pHdr->rcDisplay );

			//	lock the resources for the child dialog boxes 
			pHdr->apRes[0] = DoLockDlgRes( MAKEINTRESOURCE(IDD_TAB_PAGE_1_DIALOG) ); 
			pHdr->apRes[1] = DoLockDlgRes( MAKEINTRESOURCE(IDD_TAB_PAGE_2_DIALOG) ); 

			//	simulate selection of the first item. 
		    OnSelChanged( hWndDlg ); 
		}
		return TRUE;

	  case WM_NOTIFY: 
		switch( wParam )
		{
		  case IDC_TAB:
			LPNMHDR lpnmhdr = (LPNMHDR) lParam;
			if( lpnmhdr->code == TCN_SELCHANGE )
			{
				OnSelChanged( hWndDlg );
				return TRUE;
			}
		}
		return FALSE;

	  case WM_COMMAND:
		switch( wParam )
		{
		  case IDC_ORTHODOX_CHESS_BUTTON:
			rtn = (int) ::DialogBox( theInstance, MAKEINTRESOURCE(IDD_CHESS_SELECT_DIALOG), NULL, 
				reinterpret_cast<DLGPROC>(Chess_SelectDlgProc) );
			::EndDialog( hWndDlg, 0 );
			return TRUE;

		  case IDC_CAPABLANCA_CHESS_BUTTON:
			rtn = (int) ::DialogBox( theInstance, MAKEINTRESOURCE(IDD_CAPABLANCA_SELECT_DIALOG), NULL, 
				reinterpret_cast<DLGPROC>(Capablanca_SelectDlgProc) );
			::EndDialog( hWndDlg, 0 );
			return TRUE;

		  case IDC_GRAND_CHESS_BUTTON:
			strcpy( gameSelection, "Opulent Chess" );
			::EndDialog( hWndDlg, 0 );
			return TRUE;

		  case IDC_SHATRANJ_BUTTON:
			rtn = (int) ::DialogBox( theInstance, MAKEINTRESOURCE(IDD_SHATRANJ_SELECT_DIALOG), NULL, 
				reinterpret_cast<DLGPROC>(Shatranj_SelectDlgProc) );
			::EndDialog( hWndDlg, 0 );
			return TRUE;

		  case IDC_LOAD_GAME_BUTTON:
			::EndDialog( hWndDlg, IDC_LOAD_GAME_BUTTON );
			break;

		  case IDC_OK_BUTTON:
			{
				DLGHDR *pHdr = (DLGHDR *) ::GetWindowLongPtr( 
					hWndDlg, GWLP_USERDATA ); 
				HWND hTabCtrl = pHdr->hwndTab;
				int iSel = TabCtrl_GetCurSel( pHdr->hwndTab ); 
				if( iSel == 1 )
				{
					LVITEM item;
					HWND hListCtrl = ::GetDlgItem( pHdr->hwndDisplay, IDC_LIST1 );
					if( ListView_GetSelectedCount( hListCtrl ) < 1 )
						break;
					int sel = ListView_GetNextItem( hListCtrl, -1, LVNI_SELECTED );
					if( sel >= 0 )
					{
						item.mask = LVIF_PARAM;
						item.iItem = sel;
						ListView_GetItem( hListCtrl, &item );
						strcpy( gameSelection, ((GameInformation *) item.lParam)->name );
						::EndDialog( hWndDlg, IDOK );
						return TRUE;
					}
				}
			}
		}
		break;
	}

	return FALSE;
}
