//-----------------------------------------------------
// Name, first name: Hoet, Guntran
// Group: 1DAE3
//-----------------------------------------------------

//---------------------------
// Includes
//---------------------------
#include "Block.h"

//---------------------------
// Defines
//---------------------------
#define GAME_ENGINE (GameEngine::GetSingleton())
#define SOUND		(Sound::GetSingleton())

//---------------------------
// Constructor & Destructor
//---------------------------
Block::Block(int x, int y, Bitmap * bmpBitmapPtr, int blockType, int condition, int item, int mushroomType)		// condition = # hits till it breaks or turns to steel (
	:m_Position(x,y)
	,m_BmpBlockPtr(bmpBitmapPtr)
	,m_BlockSize(16)
	,m_BlockType(BlockType::BRICK_NORMAL)
	,m_BlockTypeNumber(blockType)
	,m_Condition(condition)
	,m_MarioFormState()
	,m_TickCount()
	,m_BlockAnimation()
	,m_LowestYPos(y)
	,m_DeltaTime()
	,m_IsDestroyed(false)
	,m_Item(item)
	,m_MushroomType(mushroomType)
	,m_IsIndestructable(false)
{
	// protect item value
	if (m_Item < 0 || m_Item > 4)
		m_Item = 0;

	// set block type
	switch (m_BlockTypeNumber)
	{
	case 0:
		m_BlockType = BlockType::BRICK_NORMAL;
		break;
	case 1:
		m_BlockType = BlockType::SPECIAL;
		if (m_Item == 0)
			m_Item = 1;		// special boxes have at least a coin in them
		break;
	case 2:
		m_BlockType = BlockType::STEEL;
		m_IsIndestructable = true;
		break;
	case 3:
		m_BlockType = BlockType::INVISIBLE;
		break;
	case 4:
		m_BlockType = BlockType::HIDDEN_BRICK;
		break;
	default:
		m_BlockType = BlockType::BRICK_NORMAL;
		break;
	}

	// setting the default RECT (optional actually...)
	m_ClipRect.top = 0;
	m_ClipRect.bottom = m_ClipRect.top + m_BlockSize;
	m_ClipRect.left = 0;
	m_ClipRect.right = m_ClipRect.left + m_BlockSize;
}

Block::~Block()
{
	// gets deleted in the BlockList!
}

//---------------------------
// Methods - Member functions
//---------------------------

void Block::Tick(double deltaTime)
{
	// if block is broken
	if (m_Condition < 0)
	{
		// do nothing
	}
	if (m_Condition == 0)
	{
		CheckBlockIfDestroyed();
	}
	else
	{
		++m_TickCount;
		m_DeltaTime = deltaTime;

		// sprite animation
		if ((m_TickCount % INTERVAL) == 0)
		{
			m_TickCount = 0;

			++m_BlockAnimation;
			m_BlockAnimation = m_BlockAnimation % 6;
		}

		// block grav for when it bounces
		BlockGravity(deltaTime);

		// clip rect
		DetermineClipRect();
	}
}

void Block::Paint(MATRIX3X2 matView)
{
	MATRIX3X2 matTransform, matCenter, matTranslate, matScale, matRotate;
	matTranslate.SetAsTranslate(m_Position);
	matScale.SetAsScale(1);
	matRotate.SetAsRotate(0);

	matTransform = matCenter * matScale * matRotate * matTranslate * matView;
	GAME_ENGINE->SetTransformMatrix(matTransform);

	GAME_ENGINE->DrawBitmap(m_BmpBlockPtr, 0, 0, m_ClipRect);
	GAME_ENGINE->SetColor(COLOR(0,0,0));
}

void Block::DetermineClipRect()
{
	switch (m_BlockType)
	{
	case Block::BlockType::BRICK_NORMAL:
		m_ClipRect.top = 0;
		m_ClipRect.bottom = m_ClipRect.top + m_BlockSize;
		m_ClipRect.left = 0;
		m_ClipRect.right = m_ClipRect.left + m_BlockSize;
		break;

	case Block::BlockType::SPECIAL:
		m_ClipRect.top = 16;
		m_ClipRect.bottom = m_ClipRect.top + m_BlockSize;
		m_ClipRect.left = 16 * m_BlockAnimation;
		m_ClipRect.right = m_ClipRect.left + m_BlockSize;
		break;

	case Block::BlockType::STEEL:
		m_ClipRect.top = 32;
		m_ClipRect.bottom = m_ClipRect.top + m_BlockSize;
		m_ClipRect.left = 0;
		m_ClipRect.right = m_ClipRect.left + m_BlockSize;
		break;

	case Block::BlockType::INVISIBLE:
		m_ClipRect.top = 48;
		m_ClipRect.bottom = m_ClipRect.top + m_BlockSize;
		m_ClipRect.left = 0;
		m_ClipRect.right = m_ClipRect.left + m_BlockSize;
		break;

	case Block::BlockType::HIDDEN_BRICK:
		m_ClipRect.top = 64;
		m_ClipRect.bottom = m_ClipRect.top + m_BlockSize;
		m_ClipRect.left = 0;
		m_ClipRect.right = m_ClipRect.left + m_BlockSize;
		break;
	}
}

RECT2 Block::GetAABBRect()
{
	RECT2 blockRect;

	if (!m_IsDestroyed || m_BlockType == BlockType::STEEL)
	{
		blockRect.top = m_Position.y;
		blockRect.bottom = blockRect.top + m_BlockSize;
		blockRect.left = m_Position.x;	
		blockRect.right = blockRect.left + m_BlockSize;
	}
	else
	{
		blockRect.top = 0;
		blockRect.bottom = 0;
		blockRect.left = 0;	
		blockRect.right = 0;
	}

	return blockRect;
}

void Block::PaintHitregions(MATRIX3X2 matView)
{
	GAME_ENGINE->SetTransformMatrix(matView);
	GAME_ENGINE->SetColor(COLOR(255,0,0));
	GAME_ENGINE->DrawRect(GetAABBRect());
	GAME_ENGINE->SetColor(COLOR(0,0,0));
}

void Block::BounceUp()
{
	if (!m_IsDestroyed)
	{
		m_Position.y -= FORCE_BOUNCE * m_DeltaTime;
	}
}

void Block::BlockGravity(double deltaTime)
{
	m_Position.y += (FORCE_BOUNCE/FORCE_GRAVITY) * deltaTime;

	if (m_Position.y > m_LowestYPos)
		m_Position.y = m_LowestYPos;
}

void Block::TakeDamageToCondition()
{
	--m_Condition;
}

void Block::CheckBlockIfDestroyed()
{
	if (m_Condition == 0)
	{
		switch (m_BlockType)
		{
		case Block::BlockType::BRICK_NORMAL:
			SOUND->SFX(10);
			m_BlockType = BlockType::INVISIBLE;
			break;
		case Block::BlockType::SPECIAL:
			m_BlockType = BlockType::STEEL;
			break;
		case Block::BlockType::STEEL:
			m_IsIndestructable = true;
			// remains
			break;
		case Block::BlockType::INVISIBLE:
			m_BlockType = BlockType::STEEL;
			// remains
			break;
		case Block::BlockType::HIDDEN_BRICK:
			m_BlockType = BlockType::STEEL;
			break;
		}

		m_IsDestroyed = true;
		--m_Condition;		 // so this wont be called again
	}
}

int Block::GetBlockType()
{
	int type;

	switch (m_BlockType)
	{
	case Block::BlockType::BRICK_NORMAL:
		type = 0;
		break;
	case Block::BlockType::SPECIAL:
		type = 1;
		break;
	case Block::BlockType::STEEL:
		type = 3;
		break;
	case Block::BlockType::INVISIBLE:
		type = 4;
		break;
	case Block::BlockType::HIDDEN_BRICK:
		type = 5;
		break;
	}

	return type;
}

int Block::GetItemType()
{
	return m_Item;
}

int Block::GetMushroomType()
{
	return m_MushroomType;
}

DOUBLE2 Block::GetPos()
{
	return m_Position;
}