//-----------------------------------------------------------------
// Game File
// C++ Source - SuperMarioBros.cpp - version v2_13 jan 2014 
// Copyright Kevin Hoefman - kevin.hoefman@howest.be
// http://www.digitalartsandentertainment.be/
//-----------------------------------------------------------------

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

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "SuperMarioBros.h"	
#include "Mario.h"

SuperMarioBros* SuperMarioBros::m_SuperMarioBrosPtr = nullptr;
//-----------------------------------------------------------------
// Defines
//-----------------------------------------------------------------
#define GAME_ENGINE		(GameEngine::GetSingleton())
#define LEVEL			(Level::GetSingleton())
#define HUD				(HUD::GetSingleton())
#define HANDY			(Handy::GetSingleton())
#define SOUND			(Sound::GetSingleton())
#define MARIO			(Mario::GetSingleton())
#define ENEMY_LIST		(EnemyList::GetSingleton())
#define BLOCK_LIST		(BlockList::GetSingleton())
#define ENTITY_LIST		(EntityList::GetSingleton())
#define COLLISION_LIST	(CollisionList::GetSingleton())

//-----------------------------------------------------------------
// SuperMarioBros methods																				
//-----------------------------------------------------------------

SuperMarioBros::SuperMarioBros()
	// booleans
	:m_PaintHitregions(false)
	,m_FreeCamera(false)
	,m_ShowQuitMessage(true)
	,m_IsPaused(false)
	,m_InvincibleMode(false)

	// integers
	,m_WorldScale(WORLD_SCALE)
	,m_TickCount()
	,m_PlayTimeLeft(PLAY_TIME)

	// doubles
	,m_CameraSpeed(150)
	,m_CameraRotation()
	,m_CameraScale()
	,m_DeltaTime()
	,m_DeltaTimeMax()

	// bitmaps
	,m_BmpWorldPtr(nullptr)
	//,m_BmpMarioPtr(nullptr)

	//sounds
	,m_AudOverworldPtr(nullptr)
	,m_AudOverworldHurryPtr(nullptr)

	// hero
	//,m_MarioPtr(nullptr)

	// hitregions
	,m_HitWorldPtr(nullptr)

	// other pointers
	,m_BitFontPtr(nullptr)
	//,m_CollisionListPtr(nullptr)


{
	// nothing to create
}

SuperMarioBros::~SuperMarioBros()																						
{
	// nothing to destroy
}

SuperMarioBros* SuperMarioBros::GetSingleton()
{
	if (m_SuperMarioBrosPtr == nullptr)
	{
		m_SuperMarioBrosPtr = new SuperMarioBros();
	}
	return m_SuperMarioBrosPtr;
}

void SuperMarioBros::GameInitialize(HINSTANCE hInstance)			
{
	// Set the required values
	AbstractGame::GameInitialize(hInstance);
	GAME_ENGINE->SetTitle("SuperMarioBros - Hoet, Guntran - 1DAE3");					
	GAME_ENGINE->RunGameLoop(true);

	int width = 256*m_WorldScale;
	int height = 224*m_WorldScale;

	// Set the optional values
	GAME_ENGINE->SetWidth(width);
	GAME_ENGINE->SetHeight(height);
	GAME_ENGINE->SetKeyList(String("EQOUPI") + (TCHAR) VK_SPACE + (TCHAR) VK_ESCAPE + (TCHAR) VK_HOME + (TCHAR) VK_END + (TCHAR) VK_DELETE + (TCHAR) VK_ESCAPE + (TCHAR) VK_TAB);
	//GAME_ENGINE->ConsoleCreate();
	GAME_ENGINE->LockFramerateToVerticalSynchronisation(true);
}

void SuperMarioBros::GameStart()
{
	GAME_ENGINE->SetBitmapInterpolationModeNearestNeighbor();
	SOUND->Theme(0,1,-1);

	// camera
	m_CameraScale = (1./m_WorldScale);			// to compensate with the increased window size (m_WorldScale)

	// Bitmaps
	//m_BmpWorldPtr = new Bitmap(IDB_WORLD);
	//m_BmpMarioPtr = new Bitmap(IDB_MARIOS);

	// Set hitregions of world
	//m_HitWorldPtr = new HitRegion();
	//m_HitWorldPtr->CreateFromSVG("Resources/Images/World1-1_Collision.svg");

	// Audio
	m_AudOverworldPtr = new Audio("Resources/Sound/Overworld.mp3");
	m_AudOverworldHurryPtr = new Audio("Resources/Sound/HurryOverworld.mp3");

	// Font
	String fontLocation = String("courier");
	m_BitFontPtr = new Font("emulogic", 24);		// needs to be installed!! (Resources/Font/emulogic/emulogic.ttf)
	GAME_ENGINE->SetFont(m_BitFontPtr);

	// create entities
	ENTITY_LIST->Create();

	// start theme
}

void SuperMarioBros::GameEnd()
{
	delete LEVEL;
	delete HUD;
	delete HANDY;
	delete SOUND;

	//delete m_BmpWorldPtr;				// delete world bitmap pointer
	//m_BmpWorldPtr = nullptr;

	//delete m_HitWorldPtr;				// delete world hitregion pointer
	//m_HitWorldPtr = nullptr;

	delete m_AudOverworldPtr;			// delete overworld sound pointer
	m_AudOverworldPtr = nullptr;
	delete m_AudOverworldHurryPtr;
	m_AudOverworldHurryPtr = nullptr;

	delete m_BitFontPtr;				// delete font pointer
	m_BitFontPtr = nullptr;

	delete MARIO;					// delete mario class
	//m_MarioPtr = nullptr;

	delete BLOCK_LIST;				// delete BlockList

	// enemies
	delete ENEMY_LIST;

	// entities
	delete ENTITY_LIST;

	// collision list
	delete COLLISION_LIST;

	//delete m_CollisionListPtr;			// delete collision list
	//m_CollisionListPtr = nullptr;
}

//void SuperMarioBros::MouseButtonAction(bool isLeft, bool isDown, int x, int y, WPARAM wParam)
//{	
//	// Insert the code that needs to be executed when the game registers a mouse button action
//
//	/* Example:
//	if (isLeft == true && isDown == true) // is it a left mouse click?
//	{	
//	if ( x > 261 && x < 261 + 117 ) // check if click lies within x coordinates of choice
//	{
//	if ( y > 182 && y < 182 + 33 ) // check if click also lies within y coordinates of choice
//	{
//	GAME_ENGINE->MessageBox("Clicked.");
//	}
//	}
//	}
//	*/
//}
//
//void SuperMarioBros::MouseMove(int x, int y, WPARAM wParam)
//{	
//	// Insert the code that needs to be executed when the mouse pointer moves across the game window
//
//	/* Example:
//	if ( x > 261 && x < 261 + 117 ) // check if mouse position is within x coordinates of choice
//	{
//	if ( y > 182 && y < 182 + 33 ) // check if mouse position also is within y coordinates of choice
//	{
//	GAME_ENGINE->MessageBox("Da mouse wuz here.");
//	}
//	}
//	*/
//
//}
//
//void SuperMarioBros::CheckKeyboard()
//{	
//	// Here you can check if a key of choice is held down
//	// Is executed once per frame when the gameloop is running
//
//	/* Example:
//	if (GAME_ENGINE->IsKeyDown('K')) xIcon -= xSpeed;
//	if (GAME_ENGINE->IsKeyDown('L')) yIcon += xSpeed;
//	if (GAME_ENGINE->IsKeyDown('M')) xIcon += xSpeed;
//	if (GAME_ENGINE->IsKeyDown('O')) yIcon -= ySpeed;
//	*/
//}

void SuperMarioBros::KeyPressed(TCHAR cKey)
{	
	// DO NOT FORGET to use SetKeyList() !!
	double secretY = double(LEVEL->GetHeight()/2);
	switch (cKey)
	{
	case 'E':
		m_PaintHitregions = !m_PaintHitregions;
		OutputDebugString(String("Debug mode: ") + m_PaintHitregions + "\n");
		break;

	case 'Q':
		m_FreeCamera = !m_FreeCamera;
		OutputDebugString(String("Free camera mode: ") + m_FreeCamera + "\n");
		break;

	case VK_HOME:
		MARIO->WarpToSpawn();						// teleport to start || respawn
		MARIO->SetLife(true);
		MARIO->SetBehaviourState(0);
		m_CameraPosition = DOUBLE2 (0,0);
		break;

	case VK_END:
		//m_CameraPosition = DOUBLE2 (0.,secretY);
		MARIO->WarpToSecretArea();		// teleport to secret area
		MARIO->SetPosition(50., 300);
		m_CameraPosition = DOUBLE2 (0.,secretY);
		break;

	case VK_DELETE:
		MARIO->WarpToSecretAreaExit();				// teleport to secret area exit pipe
		break;

	case 'U':
		MARIO->SetFormState(0);
		break;

	case 'I':
		MARIO->SetFormState(1);
		break;

	case 'O':
		MARIO->SetFormState(2);
		break;

	case 'P':
		SOUND->SFX(0);
		m_IsPaused = !m_IsPaused;
		break;

	case VK_SPACE:
		if (MARIO->GetFormState() == 2)
			MARIO->ShootFireball();
		break;

	case VK_ESCAPE:
		GAME_ENGINE->QuitGame();
		break;

	case VK_TAB:
		m_InvincibleMode = !m_InvincibleMode;
		break;

	default:
		break;
	}
}

void SuperMarioBros::GameTick(double deltaTime)
{
	if (m_IsPaused)
		deltaTime = 0.;

	if (!m_IsPaused)
	{
		m_DeltaTime = deltaTime;

		// Overal
		++m_TickCount;
		if (m_InvincibleMode)
			MARIO->ActivateStarman(false);

		// Music
		//MusicHandler();

		// level tick
		LEVEL->Tick(deltaTime);

		// HUD tick
		HUD->Tick(deltaTime);

		// collision
		COLLISION_LIST->Tick(deltaTime);

		// Tick mario
		MARIO->Tick(deltaTime);

		// Enemies ticks
		ENEMY_LIST->Tick(deltaTime);

		// Tick blocks
		BLOCK_LIST->Tick(deltaTime);

		// Tick entities
		ENTITY_LIST->Tick(deltaTime);


		// Camera
		if (!m_FreeCamera)
			CameraTick(deltaTime);
		else 
			FreeCameraTick(deltaTime);


		// Debug
		OutputDebugConsole();
	}

	// sound can still be triggerd and keeps playing in pause mode.
	// sound tick
	SOUND->Tick(deltaTime);
}

void SuperMarioBros::GamePaint(RECT rect)
{
	// Camera
	MATRIX3X2 matView, matCameraTranslate, matCameraRotate, matCameraScale, matCameraTransform;

	matCameraTranslate.SetAsTranslate(m_CameraPosition);
	matCameraRotate.SetAsRotate(m_CameraRotation);
	matCameraScale.SetAsScale(m_CameraScale);
	matCameraTransform = matCameraScale * matCameraRotate * matCameraTranslate;
	matView = matCameraTransform.Inverse();
	GAME_ENGINE->SetTransformMatrix(matView);

	// Draw level
	LEVEL->Paint(matView);

	// Draw mario
	MARIO->Paint(matView);

	// Draw castle half where mario enters castle -> makes it look like he goes inside
	LEVEL->PaintCastleHalf(matView);
	LEVEL->PaintPipeParts(matView);

	// Draw all enemies
	ENEMY_LIST->Paint(matView);

	// Draw entities
	ENTITY_LIST->Paint(matView);

	// Draw blocks
	BLOCK_LIST->Paint(matView);

	// draw collision
	COLLISION_LIST->Paint(matView);

	// HUD paint
	HUD->Paint();

	// draw hitregions an debug stuff
	if (m_PaintHitregions)
		PaintHitregions(matView);
}	


void SuperMarioBros::CallAction(Caller* callerPtr)
{

}

void SuperMarioBros::CameraTick(double deltaTime)
{
	DOUBLE2 marioPos = MARIO->GetPosition();
	const int max = 80;								// max is amound of space left between cam border and mario
	const int halfWidth = MARIO->GetWidth()/2;
	const int windowWidth = GAME_ENGINE->GetWidth();
	const int lowerFloorTop = 224;
	const int lowerFloorRight = 255;
	const int levelWidth = LEVEL->GetWidth();

	// cam position
	if (m_CameraPosition.x < marioPos.x - halfWidth - max)
		m_CameraPosition.x = marioPos.x - halfWidth - max;

	//// prevent camera to look out of the level past the castle (only when camera is NOT in free mode)
	if ((m_CameraPosition.x + windowWidth/4) > levelWidth)
		m_CameraPosition.x = (levelWidth - windowWidth/4);

	// keep mario inside screen
	if (marioPos.x - halfWidth < m_CameraPosition.x)
		MARIO->SetPosition(m_CameraPosition.x + halfWidth, 0.123);

	//m_CameraPosition.x = MARIO->GetPosition().x - 100;

	// if mario goes underground
	if (marioPos.y > lowerFloorTop && marioPos.x > 0 && marioPos.x < lowerFloorRight && MARIO->IsAlive())
	{
		m_CameraPosition.y = lowerFloorTop;
		m_CameraPosition.x = 0;					// camera does not move in the undergound area
	}
	else	// mario is on the upper ground
	{
		m_CameraPosition.y = 0;
	}
}

void SuperMarioBros::FreeCameraTick(double deltaTime)
{
	// cam rotation
	//const double = M_PI_2;
	if (GAME_ENGINE->IsKeyDown(VK_NUMPAD6))
		m_CameraRotation += M_PI * deltaTime;
	if (GAME_ENGINE->IsKeyDown(VK_NUMPAD4))
		m_CameraRotation -= M_PI * deltaTime;

	// cam scale
	const int scaleRate = 1;
	if (GAME_ENGINE->IsKeyDown(VK_NUMPAD8))
		m_CameraScale += scaleRate * deltaTime;
	if (GAME_ENGINE->IsKeyDown(VK_NUMPAD2))
		m_CameraScale -= scaleRate * deltaTime;

	// reset scale and rotation
	if (GAME_ENGINE->IsKeyDown(VK_NUMPAD5))
	{
		m_CameraRotation = 0;
		m_CameraScale = 1. / m_WorldScale;
	}

	// cam movement
	if (m_FreeCamera)
	{
		double speedMult = 2.;
		if (GAME_ENGINE->IsKeyDown('W'))
			m_CameraPosition.y -= m_CameraSpeed * speedMult * deltaTime;
		if (GAME_ENGINE->IsKeyDown('S'))
			m_CameraPosition.y += m_CameraSpeed * speedMult * deltaTime;
		if (GAME_ENGINE->IsKeyDown('A'))
			m_CameraPosition.x -= m_CameraSpeed * speedMult * deltaTime;
		if (GAME_ENGINE->IsKeyDown('D'))
			m_CameraPosition.x += m_CameraSpeed * speedMult * deltaTime;
	}
	// keep cam on bitmap
	// upper limit
	if (m_CameraPosition.y < 0)
		m_CameraPosition.y = 0;
	// left limit
	if (m_CameraPosition.x < 0)
		m_CameraPosition.x = 0;

	// bottom limit
	const int lowerFloorTop = 224;
	if (m_CameraPosition.y > lowerFloorTop)
		m_CameraPosition.y = lowerFloorTop;

	// right limit
	const int windowWidth = GAME_ENGINE->GetWidth();
	const int levelWidth = LEVEL->GetWidth();
	if ((m_CameraPosition.x + windowWidth/4) > levelWidth)
		m_CameraPosition.x = (levelWidth - windowWidth/4);
}

void SuperMarioBros::OutputDebugConsole()
{
	//cout << "*** Super Mario Bros. debug console ***" << "\r";

	cout << "Position Mario: " << MARIO->GetPosition().x << ", " << MARIO->GetPosition().y << "\r";
}

bool SuperMarioBros::RectIntersectTest(RECT2 r1, RECT2 r2)
{
	bool noIntersect =
		(r1.right < r2.left || r1.left > r2.right ||
		r1.top > r2.bottom || r1.bottom < r2.top);

	return !noIntersect;
}

RECT2 SuperMarioBros::RectIntersect(RECT2 r1, RECT2 r2)
{
	RECT2 r;
	if (RectIntersectTest(r1, r2))
	{
		r.top = max(r1.top, r2.top);
		r.bottom = min(r1.bottom, r2.bottom);
		r.left = max(r1.left, r2.left);
		r.right = min(r1.right, r2.right);
	}
	return r;
}

void SuperMarioBros::PaintHitregions(MATRIX3X2 matView)	// and also other debug stuff
{
	LEVEL->DrawHitRegion(matView);
	LEVEL->DrawDebug(matView);
	MARIO->PaintHitregions(matView);
	ENEMY_LIST->DrawDebug(matView);
	BLOCK_LIST->PaintHitRegions(matView);
	ENTITY_LIST->DrawDebug(matView);
	HUD->DrawDeltaTimeBar(true);
}

DOUBLE2 SuperMarioBros::GetCamPos()
{
	return m_CameraPosition;
}

void SuperMarioBros::SetCamPos(double x, double y)
{
	m_CameraPosition.x = x;
	m_CameraPosition.y = y;
}