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

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


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


DiamondBoard::DiamondBoard
	( int ranks, 
	  int files ):
		Board( ranks, files )
{
	gameSpecificBoardDisplayDescription = "Rotate board 45 degrees";
}

int DiamondBoard::GetBoardRightEdge()
{
	if( gameSpecificBoardDisplay )
	{
		int topMargin    = 75;
		int leftMargin   = 20;
		if( theBoard->GetNumberOfFiles() < 8 )
			leftMargin += 54;

		int diamondWidth = (int) (squareWidth * 1.414);
		diamondWidth = diamondWidth + (diamondWidth % 2) + 4;
		int halfDiamondWidth = diamondWidth / 2;

		return 2 * borderWidth + nFiles * halfDiamondWidth + nRanks * halfDiamondWidth + halfDiamondWidth + leftMargin;
	}
	else
		return Board::GetBoardRightEdge();
}

int DiamondBoard::GetBoardBottomEdge()
{
	if( gameSpecificBoardDisplay )
	{
		int topMargin    = 75;
		int leftMargin   = 20;
		if( theBoard->GetNumberOfFiles() < 8 )
			leftMargin += 54;

		int diamondWidth = (int) (squareWidth * 1.414);
		diamondWidth = diamondWidth + (diamondWidth % 2) + 4;
		int halfDiamondWidth = diamondWidth / 2;

		return 2 * borderWidth + nFiles * halfDiamondWidth + nRanks * halfDiamondWidth + halfDiamondWidth + topMargin;
	}
	else
		return Board::GetBoardBottomEdge();
}


void DiamondBoard::DrawPiecesOnBoard
	( HWND hwnd, 
	  HDC hdc, 
	  LPPAINTSTRUCT ps )
{
	if( gameSpecificBoardDisplay )
	{
		RECT rect;
		int topMargin    = 75;
		int leftMargin   = 20;
		if( theBoard->GetNumberOfFiles() < 8 )
			leftMargin += 54;
		Piece *liftedPiece = theBoard->GetPieceBeingLifted();
		int diamondWidth = (int) (squareWidth * 1.414);
		diamondWidth = diamondWidth + (diamondWidth % 2) + 4;
		int halfDiamondWidth = diamondWidth / 2;

		//	loop through all pieces, and display those that have not been captured
		for( int playerNumber = 0; playerNumber < 2; playerNumber++ )
		{
			for( int pieceNumber = 0; pieceNumber < nPieces[playerNumber]; pieceNumber++ )
			{
				Piece *piece = pieces[playerNumber][pieceNumber];
				int squareNumber = piece->GetRealSquareNumber();
				if( !piece->IsReallyCaptured() )
				{
					if( rotateBoard )
						squareNumber = flipSquare[1][squareNumber];

					int rank = GetSquareRank( squareNumber );
					int file = GetSquareFile( squareNumber );

	//				if( (ps->rcPaint.right >= leftMargin + borderWidth + file * squareWidth &&  
	//					ps->rcPaint.left <= leftMargin + borderWidth + file * squareWidth + squareWidth + 1) && 
	//					(ps->rcPaint.bottom >= topMargin + borderWidth + totalHeightOfSquares - ((rank + 1) * squareHeight) && 
	//					ps->rcPaint.top <= topMargin + borderWidth + totalHeightOfSquares - ((rank + 1) * squareHeight) + squareHeight + 1) )
	//				{
						rect.left = leftMargin + borderWidth + file * halfDiamondWidth + rank * halfDiamondWidth + 13;
						rect.top = topMargin + borderWidth + (nRanks - rank + file) * halfDiamondWidth - halfDiamondWidth + 12;
						rect.right = rect.left + halfDiamondWidth + halfDiamondWidth - 12;
						rect.bottom = rect.top + halfDiamondWidth + halfDiamondWidth - 10;

						//	DRAW PIECE
						if( piece != liftedPiece )
						{
							HBITMAP hBitmap = piece->GetBitmap();
							if( hBitmap != NULL )
							{
								DrawTransparentBitmap( hdc, hBitmap, (short) rect.left /*- (liftedPiece != NULL && theBoard->CanMoveToSquare( squareNumber ) ? 5 : 0)*/, 
									(short) rect.top /* - (liftedPiece != NULL && theBoard->CanMoveToSquare( squareNumber ) ? 5 : 0)*/, RGB(0, 255, 0), true,
									playerNumber == 0 ? RGB(255, 255, 255) : RGB(255, 0, 0), 
									playerNumber == 0 ? pieceColor1 : pieceColor2 );
							}
						}
	//				}
				}
			}
		}
		//	loop through all the squares and draw a red 'X' over 
		//	all those which are in the extraCaptures array
		for( int rank = 0; rank < nRanks; rank++ )
		{
			for( int file = 0; file < nFiles; file++ )
			{
				int squareNumber = rank * theBoard->GetNumberOfFiles() + file;
				if( rotateBoard )
					squareNumber = flipSquare[1][squareNumber];

				rect.left = leftMargin + borderWidth + file * halfDiamondWidth + rank * halfDiamondWidth + 13;
				rect.top = topMargin + borderWidth + (nRanks - rank + file) * halfDiamondWidth - halfDiamondWidth + 11;
				rect.right = rect.left + halfDiamondWidth + halfDiamondWidth - 13;
				rect.bottom = rect.top + halfDiamondWidth + halfDiamondWidth - 11;

				if( extraCaptures > 0 )
				{
					for( int x = 0; x < extraCaptures; x++ )
						if( extraCaptureSquares[x] == squareNumber )
						{
							Pen redPen( RGB(255, 0, 0), 8 );
							Pen oldPen( (HPEN) ::SelectObject( hdc, redPen ), false );
							::MoveToEx( hdc, rect.left + 15, rect.top + 15, NULL );
							::LineTo( hdc, rect.right - 15, rect.bottom - 15 );
							::MoveToEx( hdc, rect.right - 15, rect.top + 15, NULL );
							::LineTo( hdc, rect.left + 15, rect.bottom - 15 );
							::SelectObject( hdc, oldPen );
						}
				}
			}
		}
		if( liftedPiece != NULL )
		{
			HBITMAP hBitmap = liftedPiece->GetBitmap();
			DrawTransparentBitmap( hdc, hBitmap, mouseX, mouseY, RGB(0, 255, 0), false,
				liftedPiece->GetPlayerNumber() == 0 ? RGB(255, 255, 255) : RGB(255, 0, 0), 
				liftedPiece->GetPlayerNumber() == 0 ? pieceColor1 : pieceColor2, false, true );
		}
	}
	else
		Board::DrawPiecesOnBoard( hwnd, hdc, ps );
}


void DiamondBoard::DrawBoard
	( HWND hwnd, 
	  HDC hdc, 
	  LPPAINTSTRUCT ps )
{
	if( gameSpecificBoardDisplay )
	{
		Brush lightSquareBrush( squareColor1 );
		Brush darkSquareBrush( squareColor2 );
		Brush thirdSquareBrush( squareColor3 );
		Brush borderBrush( borderColor );
		Brush hilightedSquareBrush( RGB(31, 254, 31) );
		Brush captureSquareBrush( RGB(240, 0, 0) );

		int topMargin    = 75;
		int leftMargin   = 20;
		if( theBoard->GetNumberOfFiles() < 8 )
			leftMargin += 54;
		int diamondWidth = (int) (squareWidth * 1.414);
		diamondWidth = diamondWidth + (diamondWidth % 2) + 4;
		int halfDiamondWidth = diamondWidth / 2;
		POINT points[4];

		//	DRAW CHESS BOARD
		::SelectObject( hdc, borderBrush );
		points[0].x = leftMargin;
		points[0].y = topMargin + borderWidth + nRanks * halfDiamondWidth;
		points[1].x = leftMargin + borderWidth + (nRanks - 1) * halfDiamondWidth + halfDiamondWidth;
		points[1].y = topMargin + halfDiamondWidth - halfDiamondWidth;
		points[2].x = leftMargin + borderWidth + borderWidth + (nFiles - 1) * halfDiamondWidth + (nRanks - 1) * halfDiamondWidth + diamondWidth;
		points[2].y = points[0].y;
		points[3].x = points[1].x;
		points[3].y = topMargin + borderWidth + borderWidth + (nRanks + nFiles - 1) * halfDiamondWidth + halfDiamondWidth;
		::Polygon( hdc, points, 4 );

		Pen blackPen( RGB(0, 0, 0), 1 );
		if( boardDisplayType == BOARD_IS_UNCHECKERED )
		{
			::SelectObject( hdc, blackPen );
		}

//		int totalHeightOfSquares = theBoard->GetNumberOfRanks() * squareHeight;
		Piece *liftedPiece = theBoard->GetPieceBeingLifted();

		//	draw rank & file labels
/*		if( borderColor == RGB(192, 192, 192) )
			::SetTextColor( hdc, RGB(0, 0, 0) );
		else
			::SetTextColor( hdc, RGB(255, 255, 0) );
		if( ps->rcPaint.left < leftMargin + borderWidth )
		{
			for( int x = 0; x < nRanks; x++ )
			{
				RECT r;
				r.left = leftMargin;
				r.right = leftMargin + borderWidth;
				r.top = topMargin + borderWidth + ((nRanks - x - 1) * squareHeight);
				r.bottom = r.top + squareHeight;
				char *str;
				str = GetNameOfRank( rotateBoard ? nRanks - x - 1 : x );
				::DrawText( hdc, str, (int) strlen( str ), &r, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
			}
		}
		if( ps->rcPaint.top < topMargin + borderWidth + squareWidth * nRanks )
		{
			for( int y = 0; y < nFiles; y++ )
			{
				RECT r;
				r.left = leftMargin + borderWidth + y * squareWidth;
				r.right = r.left + squareWidth;
				r.top = topMargin + borderWidth + squareWidth * nRanks;
				r.bottom = r.top + borderWidth;
				char *str;
				str = GetNameOfFile( rotateBoard ? nFiles - y - 1 : y );
				::DrawText( hdc, str, (int) strlen( str ), &r, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
			}
		}
		::SetTextColor( hdc, RGB(255, 255, 255) );
*/
		//	draw squares
		HBITMAP *squareTexture = NULL;
		for( int rank = 0; rank < nRanks; rank++ )
		{
			for( int file = 0; file < nFiles; file++ )
			{
//				if( (ps->rcPaint.right >= leftMargin + borderWidth + file * squareWidth &&  
//					ps->rcPaint.left <= leftMargin + borderWidth + file * squareWidth + squareWidth + 1) && 
//					(ps->rcPaint.bottom >= topMargin + borderWidth + totalHeightOfSquares - ((rank + 1) * squareHeight) && 
//					ps->rcPaint.top <= topMargin + borderWidth + totalHeightOfSquares - ((rank + 1) * squareHeight) + squareHeight + 1) )
//				{
					bool onDestinationSquare = false;
					Pen destinationOutlinePen;
					int squareNumber = rank * theBoard->GetNumberOfFiles() + file;
					if( rotateBoard )
						squareNumber = flipSquare[1][squareNumber];

					//	select appropriate brush and/or texture based on the square 
					//	and the board display type selected
					if( boardDisplayType == BOARD_IS_UNCHECKERED )
					{
						::SelectObject( hdc, lightSquareBrush );
						squareTexture = squareTextureBitmaps[0];
					}
					else if( boardDisplayType == BOARD_IS_CHECKERED )
					{
						if( (rank + file) % 2 == 1 )
						{
							::SelectObject( hdc, lightSquareBrush );
							squareTexture = squareTextureBitmaps[0];
						}
						else
						{
							::SelectObject( hdc, darkSquareBrush );
							squareTexture = squareTextureBitmaps[1];
						}
					}
					else if( boardDisplayType == BOARD_IS_THREE_COLORED )
					{
						if( (rank + file) % 2 == 1 )
						{
							::SelectObject( hdc, lightSquareBrush );
							squareTexture = squareTextureBitmaps[0];
						}
						else
						{
							if( rank % 2 == 0 )
							{
								::SelectObject( hdc, darkSquareBrush );
								squareTexture = squareTextureBitmaps[1];
							}
							else
							{
								::SelectObject( hdc, thirdSquareBrush );
								squareTexture = squareTextureBitmaps[2];
							}
						}
					}
					//	draw the square
					points[0].x = leftMargin + borderWidth + file * halfDiamondWidth + rank * halfDiamondWidth;
					points[0].y = topMargin + borderWidth + (nRanks - rank + file) * halfDiamondWidth;
					points[1].x = points[0].x + halfDiamondWidth;
					points[1].y = points[0].y - halfDiamondWidth;
					points[2].x = points[1].x + halfDiamondWidth;
					points[2].y = points[0].y;
					points[3].x = points[1].x;
					points[3].y = points[0].y + halfDiamondWidth;
					if( liftedPiece != NULL && squareNumber == destinationSquare )
					{
						onDestinationSquare = true;
						destinationOutlinePen.CreateSolidPen( RGB(0, 0, 0), 4 );
						::SelectObject( hdc, destinationOutlinePen );
						points[0].x += 2;
						points[1].y += 2;
						points[2].x -= 2;
						points[3].y -= 2;
					}
					if( squareTexture == NULL || onDestinationSquare )
					{
						::Polygon( hdc, points, 4 );
					}
					if( squareTexture != NULL )
					{
						int bitmapNumber = squareNumber % 19;
						HDC hMemDC = ::CreateCompatibleDC( hdc );
						HBITMAP hbmOld = (HBITMAP) ::SelectObject( hMemDC, squareTexture[bitmapNumber] );
//						if( onDestinationSquare )
//							::BitBlt( hdc, rect.left + 2, rect.top + 2, squareWidth - 8, squareHeight - 8, hMemDC, 5, 5, SRCCOPY );
//						else
//							::BitBlt( hdc, rect.left, rect.top, squareWidth, squareHeight, hMemDC, 2, 2, SRCCOPY );
						::SelectObject( hMemDC, hbmOld );
						::DeleteDC( hMemDC );
					}
					if( onDestinationSquare )
					{
						::SelectObject( hdc, ::GetStockObject( NULL_PEN ) );
						points[0].x -= 2;
						points[1].y -= 2;
						points[2].x += 2;
						points[3].y += 2;
					}
					if( liftedPiece != NULL && theBoard->CanMoveToSquare( squareNumber ) != 0 )
					{
						Piece *target = theBoard->GetSquareContents( squareNumber );
						if( theBoard->CanMoveToSquare( squareNumber ) == 1 )
							::SelectObject( hdc, hilightedSquareBrush );
						else
							::SelectObject( hdc, captureSquareBrush );
						if( selectedPieceSet == PIECE_SET_EURASIAN )
						{
//							rect.right -= 1;
//							rect.bottom -= 1;
							::SelectObject( hdc, blackPen );
							::RoundRect( hdc, points[0].x + 12, points[1].y + 12, points[2].x - 12, points[3].y - 12, 56, 56 );
							::SelectObject( hdc, ::GetStockObject( NULL_PEN ) );
						}
						else
						{
//							rect.left += 4;
//							rect.top += 4;
//							rect.right -= 4;
//							rect.bottom -= 4;
							::SelectObject( hdc, blackPen );
							::RoundRect( hdc, points[0].x + 16, points[1].y + 16, points[2].x - 16, points[3].y - 16, 56, 56 );
							::SelectObject( hdc, ::GetStockObject( NULL_PEN ) );
						}
						if( boardDisplayType == BOARD_IS_UNCHECKERED )
							::SelectObject( hdc, blackPen );
					}
//				}
			}
		}
	}
	else
	{
		Board::DrawBoard( hwnd, hdc, ps );
	}
}

int DiamondBoard::SquareHitTest
    ( int x, 
	  int y )
{
	if( gameSpecificBoardDisplay )
	{
		int topMargin    = 75;
		int leftMargin   = 20;
		if( theBoard->GetNumberOfFiles() < 8 )
			leftMargin += 54;
		int diamondWidth = (int) (squareWidth * 1.414);
		diamondWidth = diamondWidth + (diamondWidth % 2) + 4;
		int halfDiamondWidth = diamondWidth / 2;

		int leftCorner_x = leftMargin + borderWidth;
		int leftCorner_y = topMargin + borderWidth + (nRanks) * halfDiamondWidth;

		if( x + y < leftCorner_x + leftCorner_y )
			return -1;
		if( x - y < leftCorner_x - leftCorner_y )
			return -1;
		int file = (x + y - leftCorner_x - leftCorner_y) / diamondWidth;
		int rank = (x - y - leftCorner_x + leftCorner_y) / diamondWidth;
		if( rank >= nRanks || file >= nFiles )
			return -1;

		int nSquare = rank * nFiles + file;

		if( rotateBoard )
			return flipSquare[1][nSquare];

		return nSquare;
	}
	else
		return Board::SquareHitTest( x, y );
}

void DiamondBoard::InvalidateSquare
	( int nSquare )
{
	if( gameSpecificBoardDisplay )
	{
		int topMargin    = 75;
		int leftMargin   = 20;
		if( theBoard->GetNumberOfFiles() < 8 )
			leftMargin += 54;
		int diamondWidth = (int) (squareWidth * 1.414);
		diamondWidth = diamondWidth + (diamondWidth % 2) + 4;
		int halfDiamondWidth = diamondWidth / 2;

		int file = files[0][nSquare];
		int rank = ranks[0][nSquare];

		RECT rect;
		rect.left = leftMargin + borderWidth + file * halfDiamondWidth + rank * halfDiamondWidth;
		rect.top = topMargin + borderWidth + (nRanks - rank + file) * halfDiamondWidth - halfDiamondWidth;;
		rect.right = rect.left + diamondWidth;
		rect.bottom = rect.top + diamondWidth;
		::InvalidateRect( theWindow, &rect, false );
	}
	else
		Board::InvalidateSquare( nSquare );
}
