#include "TetrisBoard.h"
#include <SDL.h>
#include "InvControls.h"
#include  <SDL_ttf.h>

TetrisBoard::TetrisBoard()
{
	scoreImage = NULL;
	grid = SDL_LoadBMP("Media/grid.bmp");
	font = TTF_OpenFont("Media/LiberationMono-Regular.ttf", 30);

	SDL_Color color;
	color.r = color.g = color.b = color.unused = 255;
	gameoverText = TTF_RenderText_Blended(font, "Game Over", color);

	mobileBlock = NULL;
	reset();
}

TetrisBoard::~TetrisBoard()
{
	if (mobileBlock != NULL) delete mobileBlock;

	//Free resources
	SDL_FreeSurface(grid);
	SDL_FreeSurface(gameoverText);
	SDL_FreeSurface(scoreImage);
	TTF_CloseFont(font);
}

void TetrisBoard::update(double elapsedTime)
{
	//Restart
	if (gameOver)
	{
		if (keyPressed(SDLK_SPACE) || keyPressed(SDLK_RETURN)) reset();
	}
	else
	{
		//Drop block
		timeToNextDrop -= elapsedTime;
		if (timeToNextDrop <= 0)
		{
			timeToNextDrop += TET_DROP_INTERVAL;
			if (checkCollision(mobileBlock, mobileBlockX, mobileBlockY + 1))
				blockDropFinished();
			else
				mobileBlockY++;
		}

		//Take controls
		if (keyPressed(SDLK_LEFT))
		{
			if (!checkCollision(mobileBlock, mobileBlockX-1, mobileBlockY))
				mobileBlockX--;
		}
		if (keyPressed(SDLK_RIGHT))
		{
			if (!checkCollision(mobileBlock, mobileBlockX+1, mobileBlockY))
				mobileBlockX++;
		}
		if (keyPressed(SDLK_SPACE))
		{
			mobileBlock->rotateCW();
			checkMobileHorizontal();
		}
	}
}

void TetrisBoard::draw(SDL_Surface* surface, int posx, int posy)
{
	//Draw grid squares
	SDL_Rect grect;
	grect.w = grect.h = BLOCKIMAGE_SIZE;
	for (int x = 0; x < BOARD_WIDTH; x++)
	{
		for (int y = 0; y < BOARD_HEIGHT; y++)
		{
			grect.x = x * BLOCKIMAGE_SIZE + posx;
			grect.y = y * BLOCKIMAGE_SIZE + posy;
			SDL_BlitSurface(grid, NULL, surface, &grect);
		}
	}

	//Draw blocks on the board
	for (int x = 0; x < BOARD_WIDTH; x++)
	{
		for (int y = 0; y < BOARD_HEIGHT; y++)
		{
			if (board[x][y] != TET_EMPTY)
			{
				SDL_Rect dest;
				dest.x = x * BLOCKIMAGE_SIZE + posx;
				dest.y = y * BLOCKIMAGE_SIZE + posy;
				dest.w = dest.h = BLOCKIMAGE_SIZE;
				SDL_BlitSurface(TetriminoManager::getBlockImage(board[x][y]), NULL, surface, &dest);
			}
		}
	}

	//Draw mobile block
	for (int x = 0; x < TETRIMINO_SIZE; x++)
	{
		for (int y = 0; y < TETRIMINO_SIZE; y++)
		{
			if (y + mobileBlockY < 0) continue;
			SDL_Rect dest;
			dest.x = (x + mobileBlockX) * BLOCKIMAGE_SIZE + posx;
			dest.y = (y + mobileBlockY) * BLOCKIMAGE_SIZE + posy;
			dest.w = dest.h = BLOCKIMAGE_SIZE;
			SDL_BlitSurface(
				TetriminoManager::getBlockImage(mobileBlock->getBlockAt(x, y)), NULL,
				surface, &dest);
		}
	}

	//Draw score text
	SDL_Rect sdest;
	sdest.x = 100;
	sdest.y = 25;
	sdest.w = scoreImage->w;
	sdest.h = scoreImage->h;
	SDL_BlitSurface(scoreImage, NULL, surface, &sdest);

	//Draw game over indicator
	if (gameOver)
	{
		sdest.x = 360;
		sdest.y = 300;
		sdest.w = gameoverText->w;
		sdest.h = gameoverText->h;
		SDL_BlitSurface(gameoverText, NULL, surface, &sdest);
	}
}

bool TetrisBoard::checkCollision(const Tetrimino* tetrimino, int xpos, int ypos) const
{
	for (int x = 0; x < TETRIMINO_SIZE; x++)
		for (int y = 0; y < TETRIMINO_SIZE; y++)
			if (tetrimino->getBlockAt(x, y) != TET_EMPTY
				&& ((ypos + y >= 0 && (ypos + y >= BOARD_HEIGHT || board[xpos + x][ypos + y] != TET_EMPTY))
				|| x + xpos < 0 || x + xpos >= BOARD_WIDTH))
				return true;
	return false;
}

void TetrisBoard::checkMobileHorizontal()
{
	//Find leftmost real-world pos
	int l = mobileBlockX + mobileBlock->getLeftmost();
	int r = mobileBlockX + mobileBlock->getRightmost();

	if (l < 0) mobileBlockX -= l;
	if (r >= BOARD_WIDTH) mobileBlockX += (BOARD_WIDTH - r - 1);
}

void TetrisBoard::placeTetrimino(const Tetrimino* tetrimino, int xpos, int ypos)
{
	for (int x = 0; x < TETRIMINO_SIZE; x++)
		for (int y = 0; y < TETRIMINO_SIZE; y++)
		{
			if (ypos + y >= 0)
			{
				if (tetrimino->getBlockAt(x, y) != TET_EMPTY)
					board[xpos + x][ypos + y] = tetrimino->getBlockAt(x, y);
			}
		}
	checkRemoveRow();
}

void TetrisBoard::reset()
{
	if (mobileBlock != NULL) delete mobileBlock;
	clear();
	fetchNextMobile();
	score = 0;
	renderScore();
	timeToNextDrop = TET_DROP_INTERVAL;
	gameOver = false;
}

void TetrisBoard::clear()
{
	for (int x = 0; x < BOARD_WIDTH; x++)
		for (int y = 0; y < BOARD_HEIGHT; y++)
			board[x][y] = TET_EMPTY;
}

void TetrisBoard::checkRemoveRow()
{
	
}

void TetrisBoard::removeRow(int row)
{
	for (int x = 0; x < BOARD_WIDTH; x++)
	{
		for (int y = row; y >= 1; y--)
			board[x][y] = board[x][y-1];
		board[x][0] = TET_EMPTY;
	}
}

void TetrisBoard::fetchNextMobile()
{
	//Fetch new tetrimino and reset position
	mobileBlock = TetriminoManager::nextTetrimino();
	mobileBlockX = (BOARD_WIDTH - 4) / 2;
	mobileBlockY = -2;
}

void TetrisBoard::blockDropFinished()
{
	//Merge the tetrimino into the grid
	placeTetrimino(mobileBlock, mobileBlockX, mobileBlockY);

	//Delete it
	delete mobileBlock;
	mobileBlock = NULL;

	//Get a new one
	fetchNextMobile();
}

void TetrisBoard::renderScore()
{
	SDL_Color color;
	color.r = color.g = color.b = color.unused = 255;
	char buff[42] = "Score: ";
	char buff2[35];
	_itoa(score, buff2, 10);
	strcat(buff, buff2);
	if (scoreImage != NULL) SDL_FreeSurface(scoreImage);
	scoreImage = TTF_RenderText_Blended(font, buff, color);
}