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

                                 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 "GUI/Pen.h"
#include "GUI/Brush.h"


#define PI 3.1415926


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


void FindIntersectionOfLineAndRectangle
	( int lineStartX,
	  int lineStartY,
	  int lineEndX,
	  int lineEndY,
	  int rectLeft, 
	  int rectTop, 
	  int rectRight, 
	  int rectBottom, 
	  int &intersectX, 
	  int &intersectY )
{
	int rectX1 = rectLeft;
	int rectX2 = rectRight;
	int rectY1 = rectTop;
	int rectY2 = rectTop;

	ASSERT(lineStartX > rectLeft && lineStartX < rectRight &&
		lineStartY > rectTop && lineStartY < rectBottom);
	double slope = 0.0;
	bool slopeIsInfinite = false;
	if( lineStartX == lineEndX )
		slopeIsInfinite = true;
	else if( lineStartY != lineEndY )
		slope = (double) (lineStartY - lineEndY) / (double) (lineEndX - lineStartX);

	//	does line intersect with right edge?
	if( slope <= 1.0 && slope >= -1.0 && lineEndX > lineStartX )
	{
		intersectX = rectRight;
		intersectY = (int) (slope * (lineStartX - intersectX) + lineStartY);
	}
	//	does line intersect with top edge?
	else if( (slopeIsInfinite || slope >= 1.0 || slope <= -1.0) &&
		lineEndY < lineStartY )
	{
		intersectY = rectTop;
		if( slopeIsInfinite )
			intersectX = lineStartX;
		else
			intersectX = (int) ((lineStartY - intersectY) / slope + lineStartX);
	}
	//	does line intersect with left edge?
	else if( slope <= 1.0 && slope >= -1.0 && lineEndX < lineStartX )
	{
		intersectX = rectLeft;
		intersectY = (int) (slope * (lineStartX - intersectX) + lineStartY);
	}
	//	must intersect with bottom edge
	else
	{
		intersectY = rectBottom;
		if( slopeIsInfinite )
			intersectX = lineStartX;
		else
			intersectX = (int) ((lineStartY - intersectY) / slope + lineStartX);
	}
}

LRESULT CALLBACK PiecePropertiesWndProc
	( HWND hWnd, 
	  UINT message, 
	  WPARAM wParam, 
	  LPARAM lParam )
{
	static Piece *selectedPiece;
	static HBITMAP targetBitmap;

	PAINTSTRUCT ps;
	HDC hdc;
	RECT clientRect;
	Brush br;
	CREATESTRUCT cs;

	switch( message ) 
	{
	  case WM_CREATE:
		cs = *((LPCREATESTRUCT) lParam);
		selectedPiece = (Piece *) cs.lpCreateParams;
		targetBitmap = (HBITMAP) ::LoadImage( theInstance, "images\\target.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
		break;

	  case WM_COMMAND:
		break;

	  case WM_PAINT:
		{
			hdc = ::BeginPaint( hWnd, &ps );
			clientRect;
			::GetClientRect( hWnd, &clientRect );
			br.GetBlackBrush();
			::SelectObject( hdc, br );
			::Rectangle( hdc, 0, 0, clientRect.right + 1, clientRect.bottom + 1 );
			DrawTransparentBitmap( hdc, selectedPiece->GetBitmap(), 102, 102, RGB(0, 255, 0), false, 
				selectedPiece->GetPlayerNumber() == 0 ? RGB(255, 255, 255) : RGB(255, 0, 0), 
				selectedPiece->GetPlayerNumber() == 0 ? pieceColor1 : pieceColor2, true, true );
			DrawTransparentBitmap( hdc, targetBitmap, 8, 12, RGB(0, 255, 0), false,
				RGB(0, 0, 0), RGB(0, 0, 0), false );
			HFONT hf = ::CreateFont( 25, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
				OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_MODERN, NULL );
			RECT r;
			r.left = 280;
			r.right = 600;
			r.top = 20;
			r.bottom = 40;
			::SetTextColor( hdc, RGB(255, 255, 255) );
			::SetBkMode( hdc, TRANSPARENT );
			::SelectObject( hdc, hf );
			::DrawText( hdc, selectedPiece->GetType().GetFullName(), 
				(int) strlen(selectedPiece->GetType().GetFullName()),
				&r, DT_LEFT | DT_VCENTER | DT_SINGLELINE );
			::SelectObject( hdc, ::GetStockObject( SYSTEM_FONT ) );
			HFONT hf2 = ::CreateFont( 15, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
				OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_MODERN, NULL );
			r.top = 50;
			r.bottom = 65;
			char buffer[80];
			sprintf( buffer, "Board Visibility: %d of %d", selectedPiece->GetSquaresVisible(), 
				theBoard->GetNumberOfSquares() );
			::SelectObject( hdc, hf2 );
			::DrawText( hdc, buffer, (int) strlen(buffer), &r, DT_LEFT | DT_VCENTER | DT_SINGLELINE );

			r.top = 65;
			r.bottom = 80;
			sprintf( buffer, "Average Squares Attacked: %2.2f", selectedPiece->GetAverageSquaresAttacked() );
			::DrawText( hdc, buffer, (int) strlen(buffer), &r, DT_LEFT | DT_VCENTER | DT_SINGLELINE );

			r.top += 15;
			r.bottom += 15;
			sprintf( buffer, "Average Directions Attacked: %2.2f", selectedPiece->GetAverageDirectionsAttacked() );
			::DrawText( hdc, buffer, (int) strlen(buffer), &r, DT_LEFT | DT_VCENTER | DT_SINGLELINE );

			if( theGame->IsGoalToCheckmate() )
			{
				r.top += 15;
				r.bottom += 15;
				sprintf( buffer, "Average Safe Checks: %2.2f", selectedPiece->GetAverageSafeChecks() );
				::DrawText( hdc, buffer, (int) strlen(buffer), &r, DT_LEFT | DT_VCENTER | DT_SINGLELINE );
			}

			r.top += 15;
			r.bottom += 15;
			sprintf( buffer, "Average Mobility: %2.2f", selectedPiece->GetAverageMobility() );
			::DrawText( hdc, buffer, (int) strlen(buffer), &r, DT_LEFT | DT_VCENTER | DT_SINGLELINE );

			r.top += 25;
			r.bottom += 25;

			//	determine piece value
			int value = selectedPiece->GetBaseValue();
			r.left = 280;
			r.right = 490;
			::DrawText( hdc, "Base Material Value:", 20, &r, DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
			r.right = 550;
			r.left = 490;
			sprintf( buffer, "%d", value );
			::DrawText( hdc, buffer, (int) strlen(buffer), &r, DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
			r.top += 15;
			r.bottom += 15;

			//	determine per-capture bonus
			int perCaptureAdj = theBoard->GetNumberOfCapturedPieces() > selectedPiece->GetType().GetPerCaptureBonusThreshold() ?
				(theBoard->GetNumberOfCapturedPieces() - selectedPiece->GetType().GetPerCaptureBonusThreshold()) *
				selectedPiece->GetType().GetPerCaptureValueBonus() : 0;
			value += perCaptureAdj;
			r.left = 280;
			r.right = 490;
			::DrawText( hdc, "Board Occupancy Adjustment:", 27, &r, DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
			r.right = 550;
			r.left = 490;
			if( perCaptureAdj > 0 )
				sprintf( buffer, "+%d", perCaptureAdj );
			else if( perCaptureAdj < 0 )
				sprintf( buffer, "-%d", -perCaptureAdj );
			else
				sprintf( buffer, "0" );
			::DrawText( hdc, buffer, (int) strlen(buffer), &r, DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
			r.top += 15;
			r.bottom += 15;

			//	add square bonuses
			int squareVal = 0;
			int square = selectedPiece->GetSquareNumber();
			if( selectedPiece->GetPlayerNumber() == 1 )
				square = (theBoard->GetNumberOfRanks() - (square / theBoard->GetNumberOfFiles()) - 1) * 
					theBoard->GetNumberOfFiles() + square % (theBoard->GetNumberOfFiles());
			if( selectedPiece->GetType().UsingSquareBonusTables() && !selectedPiece->IsPromoted() )
				//	add square bonus values
				squareVal = (selectedPiece->GetType().GetSquareBonusTable( 0 ))[square];
			else
				squareVal = theBoard->GetSquareValue( square );
			value += squareVal;
			r.left = 280;
			r.right = 490;
			::DrawText( hdc, "Square Value Adjustment:", 24, &r, DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
			r.right = 550;
			r.left = 490;
			if( squareVal > 0 )
				sprintf( buffer, "+%d", squareVal );
			else if( squareVal < 0 )
				sprintf( buffer, "-%d", -squareVal );
			else
				sprintf( buffer, "0" );
			::DrawText( hdc, buffer, (int) strlen(buffer), &r, DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
			r.top += 15;
			r.bottom += 15;

			//	display total value
			r.left = 280;
			r.right = 490;
			::DrawText( hdc, "Current Estimated Value:", 24, &r, DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
			r.right = 550;
			r.left = 490;
			sprintf( buffer, "%d", value );
			::DrawText( hdc, buffer, (int) strlen(buffer), &r, DT_RIGHT | DT_VCENTER | DT_SINGLELINE );

			//	draw movement diagram
			{
				COLORREF pieceColor = selectedPiece->GetPlayerNumber() == 0 || boardDisplayType == BOARD_IS_UNCHECKERED ? pieceColor1 : pieceColor2;
				HBRUSH pieceSquareBrush = ::CreateSolidBrush( pieceColor );
				HBRUSH lightSquareBrush = ::CreateSolidBrush( squareColor1 );
				HBRUSH darkSquareBrush = ::CreateSolidBrush( squareColor2 );
				HBRUSH thirdSquareBrush = ::CreateSolidBrush( squareColor3 );

				for( int x = 0; x < 9; x++ )
					for( int y = 0; y < 9; y++ )
					{
						if( x == 4 && y == 4 )
							::SelectObject( hdc, pieceSquareBrush );
						else
						{
							if( boardDisplayType == BOARD_IS_UNCHECKERED )
								::SelectObject( hdc, lightSquareBrush );
							else if( boardDisplayType == BOARD_IS_CHECKERED )
								::SelectObject( hdc, (x + y) % 2 == 1 ? lightSquareBrush : darkSquareBrush );
							else if( boardDisplayType == BOARD_IS_THREE_COLORED )
								::SelectObject( hdc, (x + y) % 2 == 1 ? lightSquareBrush : 
									(y % 2 == 0 ? darkSquareBrush : thirdSquareBrush) );
						}
						::Rectangle( hdc, 119 + 36 * x, 220 + 36 * y, 155 + 36 * x, 256 + 36 * y );
//						::Rectangle( hdc, 155 + 36 * x, 220 + 36 * y, 191 + 36 * x, 256 + 36 * y );
					}

				::SelectObject( hdc, ::GetStockObject( BLACK_BRUSH ) );
				::DeleteObject( pieceSquareBrush );
				::DeleteObject( lightSquareBrush );
				::DeleteObject( darkSquareBrush );
				::DeleteObject( thirdSquareBrush );

				sprintf( buffer, "%s", selectedPiece->GetType().GetNotation() );
				r.left = 119 + 36 * 4;
				r.right = 155 + 36 * 4;
				r.top = 220 + 36 * 4;
				r.bottom = 256 + 36 * 4;
				if( pieceColor == RGB(0, 0, 0) )
					::SetTextColor( hdc, RGB(255, 255, 255) );
				else
					::SetTextColor( hdc, RGB(0, 0, 0) );
				::SelectObject( hdc, hf );
				if( buffer[0] == '_' )
					::DrawText( hdc, buffer + 1, 2, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
				else
					::DrawText( hdc, buffer, (int) strlen( buffer ), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE );

				//	first pass ...
				for( int z = 0; z < selectedPiece->GetType().GetMoveCapabilityCount(); z++ )
				{
					MovementCapability &move = selectedPiece->GetType().GetMoveCapability( z );

					int steps = 1;
					bool inWindow = true;
					int rank = 4;
					int file = 4;
					int newRank;
					int newFile;
					if( true )
					{
						newRank = rank + move.GetRankDifference( 1 );
						newFile = rank + move.GetFileDifference( 1 );
					}
					else
					{
						newRank = rank + move.GetRankDifference( FLIP(selectedPiece->GetPlayerNumber()) );
						newFile = rank + move.GetFileDifference( selectedPiece->GetPlayerNumber() );
					}
					int oldFile = 4;
					int oldRank = 4;
					while( newRank >= 0 && newRank < 9 && 
						   newFile >= 0 && newFile < 9 && 
						   steps <= move.GetMaxSteps() )
					{
						//	draw indicator for this step
						if( move.GetMaxSteps() == 1 )
						{
							//	a single step (stepping move is displayed 
							//	differently from a sliding move
							Brush fillBr;
							Pen outlinePen;
							if( move.CanMove() && move.CanCapture() )
							{
								outlinePen.CreateSolidPen( RGB(0, 0, 0), 2 );
								fillBr.CreateSolidBrush( RGB(255, 0, 0) );
							}
							else if( move.CanMove() )
							{
								outlinePen.CreateSolidPen( RGB(0, 0, 0), 2 );
								fillBr.CreateSolidBrush( RGB(0, 255, 0) );
							}
							else if( move.CanCapture() )
							{
								outlinePen.CreateSolidPen( RGB(255, 0, 0), 2 );
								fillBr.CreateSolidBrush( RGB(0, 0, 0) );
							}
							else if( move.CanIguiCapture() )
							{
								outlinePen.CreateSolidPen( RGB(0, 0, 0), 2 );
								fillBr.CreateSolidBrush( RGB(255, 255, 0) );
							}
							else
							{
								outlinePen.GetNullPen();
								fillBr.GetNullBrush();
							}
							::SelectObject( hdc, outlinePen );
							::SelectObject( hdc, fillBr );
							::Ellipse( hdc, 123 + 36 * newFile, 224 + 36 * newRank, 151 + 36 * newFile, 252 + 36 * newRank );
							if( move.CanCapture() && !move.CanMove() )
							{
								::SetTextColor( hdc, RGB(255, 0, 0) );
								::SetBkMode( hdc, TRANSPARENT );
								RECT rect;
								rect.left = 123 + 36 * newFile;
								rect.right = 151 + 36 * newFile;
								rect.top = 224 + 36 * newRank;
								rect.bottom = 254 + 36 * newRank;
								::DrawText( hdc, "X", 1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
							}
							::SelectObject( hdc, (HPEN) ::GetStockObject( NULL_PEN ) );
							::SelectObject( hdc, (HBRUSH) ::GetStockObject( NULL_BRUSH ) );
						}
						else if( steps >= move.GetMinSteps() )
						{
							Brush fillBr;
							Pen outlinePen;
							if( move.CanMove() && move.CanCapture() )
							{
								outlinePen.CreateSolidPen( RGB(0, 0, 0), 2 );
								fillBr.CreateSolidBrush( RGB(255, 0, 0) );
							}
							else if( move.CanMove() )
							{
								outlinePen.CreateSolidPen( RGB(0, 0, 0), 2 );
								fillBr.CreateSolidBrush( RGB(0, 255, 0) );
							}
							else if( move.CanCapture() )
							{
								outlinePen.CreateSolidPen( RGB(255, 0, 0), 2 );
								fillBr.CreateSolidBrush( RGB(0, 0, 0) );
							}
							else if( move.CanIguiCapture() )
							{
								outlinePen.CreateSolidPen( RGB(0, 0, 0), 2 );
								fillBr.CreateSolidBrush( RGB(255, 255, 0) );
							}
							else
							{
								outlinePen.GetNullPen();
								fillBr.GetNullBrush();
							}
							::SelectObject( hdc, outlinePen );
							::SelectObject( hdc, fillBr );
							::Ellipse( hdc, 123 + 36 * newFile, 224 + 36 * newRank, 151 + 36 * newFile, 252 + 36 * newRank );
							if( move.CanCapture() && !move.CanMove() )
							{
								::SetTextColor( hdc, RGB(255, 0, 0) );
								::SetBkMode( hdc, TRANSPARENT );
								RECT rect;
								rect.left = 123 + 36 * newFile;
								rect.right = 151 + 36 * newFile;
								rect.top = 224 + 36 * newRank;
								rect.bottom = 254 + 36 * newRank;
								::DrawText( hdc, "X", 1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
							}
							::SelectObject( hdc, (HPEN) ::GetStockObject( NULL_PEN ) );
							::SelectObject( hdc, (HBRUSH) ::GetStockObject( NULL_BRUSH ) );
						}
						//	take another step...
						oldFile = newFile;
						oldRank = newRank;
						newRank += move.GetRankDifference( 1 );
						newFile += move.GetFileDifference( 1 );
						steps++;
					}
					steps--;
					if( steps > 1 )
					{
						int nextSquareCenterX;
						int nextSquareCenterY;
						int lineEndX;
						int lineEndY;
						int maxSteps = move.GetMaxSteps();
						if( steps >= move.GetMaxSteps() )
						{
							nextSquareCenterX = lineEndX = 137 + (36 * oldFile);
							nextSquareCenterY = lineEndY = 238 + (36 * oldRank);
						}
						else
						{
							newRank += move.GetRankDifference( 1 );
							newFile += move.GetFileDifference( 1 );
							nextSquareCenterX = 137 + (36 * newFile);
							nextSquareCenterY = 238 + (36 * newRank);
							if( move.GetFileDifference( 1 ) ==  move.GetRankDifference( 1 ) || 
								move.GetFileDifference( 1 ) == -move.GetRankDifference( 1 ) )
								FindIntersectionOfLineAndRectangle( 281, 382, nextSquareCenterX, 
								nextSquareCenterY, 129 - 36, 230 - 36, 144 + (36 * 9), 245 + (36 * 9), 
									lineEndX, lineEndY );
							else if( move.GetFileDifference( 1 ) == 0 || move.GetRankDifference( 1 ) == 0 )
								FindIntersectionOfLineAndRectangle( 281, 382, nextSquareCenterX, 
								nextSquareCenterY, 112 - 36, 213 - 36, 161 + (36 * 9), 262 + (36 * 9), 
									lineEndX, lineEndY );
							else
								FindIntersectionOfLineAndRectangle( 281, 382, nextSquareCenterX, 
								nextSquareCenterY, 120 - 36, 221 - 36, 153 + (36 * 9), 254 + (36 * 9), 
									lineEndX, lineEndY );
						}
						int lineStartX = 0;
						int lineStartY = 0;
						FindIntersectionOfLineAndRectangle( 281, 382, nextSquareCenterX, 
							nextSquareCenterY, 120 + (36 * 4), 221 + (36 * 4), 153 + (36 * 4), 254 + (36 * 4), 
							lineStartX, lineStartY );
						Pen linePen;
						Brush fillBrush;
						if( move.CanMove() && move.CanCapture() )
						{
							linePen.CreateSolidPen( RGB(255, 0, 0), 5 );
							fillBrush.CreateSolidBrush( RGB(255, 0, 0) );
						}
						else if( move.CanMove() )
						{
							linePen.CreateSolidPen( RGB(0, 255, 0), 5 );
							fillBrush.CreateSolidBrush( RGB(0, 255, 0) );
						}
						else if( move.CanCapture() )
						{
							linePen.CreateSolidPen( RGB(255, 0, 0), 5 );
							fillBrush.CreateSolidBrush( RGB(255, 0, 0) );
						}
						else if( move.CanIguiCapture() )
						{
							linePen.CreateSolidPen( RGB(255, 255, 0), 5 );
							fillBrush.CreateSolidBrush( RGB(255, 255, 0) );
						}
						else
						{
							linePen.GetNullPen();
							fillBrush.GetNullBrush();
						}
						::SelectObject( hdc, linePen );
						::SelectObject( hdc, fillBrush );
						::MoveToEx( hdc, lineStartX, lineStartY, NULL );
						::LineTo( hdc, lineEndX, lineEndY );
						if( steps < move.GetMaxSteps() )
						{
							double angle = 0.0;
							angle = atan2( (double) (lineEndY - lineStartY), 
								(double) (lineStartX - lineEndX) );
							POINT pt[3];
							pt[0].x = lineEndX;
							pt[0].y = lineEndY;
							pt[1].x = (int) ((lineEndX + (cos(angle) * 30)) + 
								(cos(angle + (PI/2)) * 10));
							pt[1].y = (int) ((lineEndY - (sin(angle) * 30)) - 
								(sin(angle + (PI/2)) * 10));
							pt[2].x = (int) ((lineEndX + (cos(angle) * 30)) + 
								(cos(angle - (PI/2)) * 10));
							pt[2].y = (int) ((lineEndY - (sin(angle) * 30)) -  
								(sin(angle - (PI/2)) * 10));
							::Polygon( hdc, pt, 3 );
						}
					}
				}

				//	second pass ...
				for( int z = 0; z < selectedPiece->GetType().GetMoveCapabilityCount(); z++ )
				{
					MovementCapability &move = selectedPiece->GetType().GetMoveCapability( z );

					int steps = 1;
					bool inWindow = true;
					int rank = 4;
					int file = 4;
					int newRank = rank + move.GetRankDifference( 1 );
					int newFile = rank + move.GetFileDifference( 1 );
					int oldFile = 4;
					int oldRank = 4;
					while( newRank >= 0 && newRank < 9 && 
						   newFile >= 0 && newFile < 9 && 
						   steps <= move.GetMaxSteps() )
					{
						if( move.GetMaxSteps() > 1 )
						{
							//	draw black inner dot
							::SelectObject( hdc, ::GetStockObject( BLACK_BRUSH ) );
							::SelectObject( hdc, (HPEN) ::GetStockObject( NULL_PEN ) );
							::Ellipse( hdc, 132 + 36 * newFile, 233 + 36 * newRank, 145 + 36 * newFile, 244 + 36 * newRank );
						}
						//	take another step...
						oldFile = newFile;
						oldRank = newRank;
						newRank += move.GetRankDifference( 1 );
						newFile += move.GetFileDifference( 1 );
						steps++;
					}
				}

				//	third pass ...
				for( int z = 0; z < selectedPiece->GetType().GetMoveCapabilityCount(); z++ )
				{
					Brush fillBr;
					Pen outlinePen;
					RECT rect;
					MovementCapability &move = selectedPiece->GetType().GetMoveCapability( z );
					if( move.CapturesByWithdrawing() )
					{
						outlinePen.CreateSolidPen( RGB(0, 0, 0), 2 );
						fillBr.CreateSolidBrush( RGB(0, 192, 0) );
						int rank = 4 - move.GetRankDifference( 1 );
						int file = 4 - move.GetFileDifference( 0 );
						::SelectObject( hdc, outlinePen );
						::SelectObject( hdc, fillBr );
						::Ellipse( hdc, 123 + 36 * file, 224 + 36 * rank, 151 + 36 * file, 252 + 36 * rank );
						::SetTextColor( hdc, RGB(255, 255, 0) );
						::SetBkMode( hdc, TRANSPARENT );
						rect.left = 123 + 36 * file;
						rect.right = 151 + 36 * file;
						rect.top = 224 + 36 * rank;
						rect.bottom = 254 + 36 * rank;
						::DrawText( hdc, "W", 1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
					}
					else if( move.CapturesByAdvancing() )
					{
						outlinePen.CreateSolidPen( RGB(0, 0, 0), 2 );
						fillBr.CreateSolidBrush( RGB(192, 192, 0) );
						int rank = 3 - move.GetRankDifference( 1 );
						int file = 3 - move.GetFileDifference( 0 );
						::SelectObject( hdc, outlinePen );
						::SelectObject( hdc, fillBr );

						if( move.GetRankDifference( 0 ) == 1 && move.GetFileDifference( 0 ) == 0 )
						{
							rect.left = 159 + 36 * 3;
							rect.right = 189 + 36 * 3;
							rect.top = 210 - 36;
							rect.bottom = 240 - 36;
						}
						else if( move.GetRankDifference( 0 ) == 0 && move.GetFileDifference( 0 ) == -1 )
						{
							rect.left = 159 - 50;
							rect.right = 189 - 50;
							rect.top = 224 + 36 * 3;
							rect.bottom = 254 + 36 * 3;
						}
						else if( move.GetRankDifference( 0 ) == -1 && move.GetFileDifference( 0 ) == 0 )
						{
							rect.left = 159 + 36 * 3;
							rect.right = 189 + 36 * 3;
							rect.top = 238 + 36 * 7;
							rect.bottom = 268 + 36 * 7;
						}
						else if( move.GetRankDifference( 0 ) == 0 && move.GetFileDifference( 0 ) == 1 )
						{
							rect.left = 173 + 36 * 7;
							rect.right = 203 + 36 * 7;
							rect.top = 224 + 36 * 3;
							rect.bottom = 254 + 36 * 3;
						}
						else if( move.GetRankDifference( 0 ) == 1 && move.GetFileDifference( 0 ) == 1 )
						{
							rect.left = 159 + 36 * 7;
							rect.right = 189 + 36 * 7;
							rect.top = 210 - 22;
							rect.bottom = 240 - 22;
						}
						else if( move.GetRankDifference( 0 ) == -1 && move.GetFileDifference( 0 ) == 1 )
						{
							rect.left = 159 + 36 * 7;
							rect.right = 189 + 36 * 7;
							rect.top = 224 + 36 * 7;
							rect.bottom = 254 + 36 * 7;
						}
						else if( move.GetRankDifference( 0 ) == 1 && move.GetFileDifference( 0 ) == -1 )
						{
							rect.left = 159 - 36;
							rect.right = 189 - 36;
							rect.top = 210 - 22;
							rect.bottom = 240 - 22;
						}
						else if( move.GetRankDifference( 0 ) == -1 && move.GetFileDifference( 0 ) == -1 )
						{
							rect.left = 159 - 36;
							rect.right = 189 - 36;
							rect.top = 224 + 36 * 7;
							rect.bottom = 254 + 36 * 7;
						}

						::Ellipse( hdc, rect.left, rect.top, rect.right, rect.bottom );
						::SetTextColor( hdc, RGB(0, 0, 0) );
						::SetBkMode( hdc, TRANSPARENT );
						::DrawText( hdc, "A", 1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
					}
				}
			}

			//	allow piece type to do any additional painting on the 
			//	movement diagram that may be necessary.
			selectedPiece->GetType().PostPaintMoveDiagram( &ps, hdc );

			::DeleteObject( hf );
			::DeleteObject( hf2 );
			::EndPaint( hWnd, &ps );
		}
		break;

	  default:
		return ::DefWindowProc( hWnd, message, wParam, lParam );
	}
	return 0;
};
