#include "cGame.h"
#include "cPlayer.h"
#include "cBrick.h"
#include "cHole.h"
#include "cZombieGhost.h"
#include "MediaVars.h"
#include "cBrain.h"
#include "cSign.h"
#include "cDoor.h"
#include "cHeart.h"
#include <fstream>
#include <sstream>

string toString(double n)
{
	if (n == 0)
		return "0";
	string str = "";
	int numPlaces = (int) log10(n);
	for(int i = numPlaces;i>=0;i--)
	{
		int num = (int) (n / pow((double) 10,i)) % 10;
		str += ('0'+num);
	}
	return str;
}

cGame::cGame(sf::RenderWindow *win)
{
	window = win;
}
void cGame::Start()
{
	imgFont.SetSmooth(false);
	currentState = CS_TITLE;
	hasBrain = false;
	currentLevel = 0;
	transitioningRooms = false;
	spaceDown = false;
	spaceDownPrevious = true;
	timeGameBegin = -1;
	timeGameEnd = -1;
	// Stats
	totalNumberHearts = 0;
	totalNumberSigns = 0;
	tempNumberHearts = 0;
	tempNumberDead = 0;
	tempNumberDoors = 0;
	tempNumberSigns = 0;
	statSignsRead = 0;
	statDoorsOpened = 0;
	statTimesDied = 0;
	statHeartsObtained = 0;
	// End stats
	fstream file;
	unsigned int line = 0;
#ifdef WIN32
	file.open("./media/data/levels.txt",std::ios::in);
#elif __APPLE__
	file.open("./levels.txt",std::ios::in);
#endif
	std::string temp = "";
	while(!file.eof())
	{
		unsigned char c = file.get();
		while(c == 10 || c == 13)
			c = file.get();
		temp += c;
		unsigned char next = file.peek();
		if (next == 10 || next == 13)
		{
			vctrLevels.push_back(temp);
			vector<sf::Vector2i*> *bob = new vector<sf::Vector2i*>;
			vctrItemsObtained.push_back(bob);
			temp = "";
			line++;
		}
	}
	CalculateStatVars();
	gameRestarted = false;
	//MessageBox(0,(char*)toString(vctrLevels.size()).c_str(),"Number of levels:",0);
	playerHeart = 3;
	playerMaxHeart = 3;
	window->SetView(view);
	//GoToNextLevel();

}
cObject *cGame::GetPlayer(){return playerPtr;}
void cGame::Do()
{
	spaceDown = window->GetInput().IsKeyDown(sf::Key::Space);
	sKeyDown = window->GetInput().IsKeyDown(sf::Key::S);
	switch(currentState)
	{
		case CS_TITLE:
			view.SetFromRect(sf::FloatRect(0,0,640,480));
			if (IsKeyPressed(sf::Key::Space))
			{
				imgFont.SetSmooth(true);
				SetState(CS_STORY1);
			}
			sprTitle->SetPosition(0.0f,0.0f);
			window->Draw(*sprTitle);
			//sprFont->SetColor(sf::Color(255,0,0,255));
			imgFont.SetSmooth(true);
			draw_text(24,0,"Created in 48 hours for Ludum Dare 20",.5);
			imgFont.SetSmooth(false);
			draw_text(320-176,view.GetRect().Bottom-96,"Press space");// 11 chars * 32 = 352/2 = 176?
			draw_text(320-208,view.GetRect().Bottom-48,"to play game");// 13 chars * 32 = 416 = 208?
			//sprFont->SetColor(sf::Color(255,255,255,255));
			break;
		case CS_STORY1:
			view.SetFromRect(sf::FloatRect(0,0,640,480));
			if (IsKeyPressed(sf::Key::Space))
				SetState(CS_STORY2);
			sprStory1->SetPosition(0.0f,0.0f);
			window->Draw(*sprStory1);
			//sprFont->SetColor(sf::Color(255,0,0,255));
			draw_text(80,80,"Late last night,\n\nEdgar was not very tough.\n\n\nBoogie People stole his organs,\n\nand all of his stuff.\n\n\nBut there's a little problem,\n\nThat lies in Edgar's way.\n\n\n\n\nEdgar's getting married...",.5);
			draw_text(240,448,"press space",.5);
			//sprFont->SetColor(sf::Color(255,255,255,255));
			break;
		case CS_STORY2:
			view.SetFromRect(sf::FloatRect(0,0,640,480));
			if (IsKeyPressed(sf::Key::Space))
				SetState(CS_STORY3);
			sprStory2->SetPosition(0.0f,0.0f);
			window->Draw(*sprStory2);
			window->Draw(sf::Shape::Rectangle(16,16,624,432,sf::Color(0,0,0,176)));
			draw_text(48,48,"...Today!\n\n\n\n\nIn today's financial crisis,\n\nit's dangerous to go alone.\n\n\nAnd it seemed like Cupid,\n\nhad thrown Edgar a bone.\n\n\nEdgar needs his stuff back,\n\nand needs to marry Morgan.\n\n\nSo help Edgar get his stuff,\n\nand more importantly his organs!",.5);
			draw_text(240,448,"press space",.5);
			break;
		case CS_STORY3:
			view.SetFromRect(sf::FloatRect(0,0,640,480));
			if (IsKeyPressed(sf::Key::Space))
			{
				imgFont.SetSmooth(false);
				timeGameBegin = clock();
				GoToNextLevel();
			}
			sprStory2->SetPosition(0.0f,0.0f);
			window->Draw(*sprStory2);
			window->Draw(sf::Shape::Rectangle(16,16,624,432,sf::Color(0,0,0,176)));
			draw_text(48,48,"Oh yeah,\n\n\n\n\nControls:\n\n\n  Move - Arrow Keys\n\nAction - Space\n\n     S - Toggle sound\n\n\n\n\n\n\n\n\n                      Good luck!",.5);
			draw_text(240,448,"press space",.5);
			break;
		case CS_LOSE:
			view.SetFromRect(sf::FloatRect(0,0,640,480));
			if (IsKeyPressed(sf::Key::Space))
				RestartLevel();
			sprLose->SetPosition(0.0f,0.0f);
			window->Draw(*sprLose);
			//sprFont->SetColor(sf::Color(255,0,0,255));
			draw_text(320-176,view.GetRect().Bottom-96,"Press space");// 11 chars * 32 = 352/2 = 176?
			draw_text(320-208,view.GetRect().Bottom-48,"to lose again");// 13 chars * 32 = 416 = 208?
			//sprFont->SetColor(sf::Color(255,255,255,255));
			break;
		case CS_LEVEL:
			PerformLevel();
			if (transitioningRooms)
				return;
			/*for(int i=0;i<vctrItemsObtained[currentLevel-1]->size();i++)
			{
				string str = toString(vctrItemsObtained[currentLevel-1]->at(i)->x);
				str += " - ";
				str += toString(vctrItemsObtained[currentLevel-1]->at(i)->y);
				draw_text(view.GetRect().Left+42,view.GetRect().Top+128+40*i,str);
			}*/
			break;
		case CS_WINSTORY:
			if (timeGameEnd == -1)
			{
				imgFont.SetSmooth(true);
				timeGameEnd = clock();
			}
			view.SetFromRect(sf::FloatRect(0,0,640,480));
			if (IsKeyPressed(sf::Key::Space))
				SetState(CS_WIN);
			sprWinStory->SetPosition(0.0f,0.0f);
			window->Draw(*sprWinStory);
			//window->Draw(sf::Shape::Rectangle(16,16,624,432,sf::Color(0,0,0,176)));
			draw_text(24,64,"Edgar has gone and beaten,\n\nall of the Boogie People,\n\n\nJust to go get married,\n\nunder a church steeple.\n\n\n\n\n\nSo how does Edgar escape,\n\nto go and get mahr-rayed?\n\n\nI believe that's another game,\n\nfor a different Ludum Dare!",.5);
			draw_text(240,448,"press space",.5);
			break;
		case CS_WIN:
			view.SetFromRect(sf::FloatRect(0,0,640,480));
			if (PlayerHasBrain())
			{
				sprWinHasBrain->SetPosition(0.0f,0.0f);
				window->Draw(*sprWinHasBrain);
			}
			else
			{
				sprWin->SetPosition(0.0f,0.0f);
				window->Draw(*sprWin);
			}
			if (tempNumberDoors < statDoorsOpened)
				tempNumberDoors++;
			if (tempNumberDead < statTimesDied)
				tempNumberDead++;
			if (tempNumberHearts < statHeartsObtained)
				tempNumberHearts++;
			if (tempNumberSigns < statSignsRead)
				tempNumberSigns++;
			imgFont.SetSmooth(false);
			draw_text(16,16,"YOU WIN");
			imgFont.SetSmooth(true);
			draw_text(16,96,"Number of times died: "+toString(tempNumberDead),.5);
			draw_text(16,128,"Doors Broken: "+toString(tempNumberDoors),.5);
			draw_text(16,160,"Hearts Obtained: "+toString(tempNumberHearts)+"/"+toString(totalNumberHearts),.5);
			draw_text(16,192,"Signs Read: "+toString(tempNumberSigns)+"/"+toString(totalNumberSigns),.5);
			draw_text(16,224,"Time Taken: "+toString((timeGameEnd-timeGameBegin)/(60*CLOCKS_PER_SEC))+" minutes "+toString(((timeGameEnd-timeGameBegin)/CLOCKS_PER_SEC) % 60)+" seconds",.5);
			if (!PlayerHasBrain())
				draw_text(16,320,"You beat the game without a brain,\nA feat which caused you much pain,\nUnless you cheated.",.5);
			draw_text(72,view.GetRect().Bottom-64,"Press Space to restart the game,",.5);
			draw_text(72,view.GetRect().Bottom-32,"    Or press Escape to quit.",.5);
			if (IsKeyPressed(sf::Key::Space))
				RestartGame();
			break;
		/*case CS_TITLE:
			view.SetFromRect(sf::FloatRect(0,0,640,480));
			if (IsKeyPressed(sf::Key::Space))
				GoToNextLevel();
			sprTitle->SetPosition(0.0f,0.0f);
			window->Draw(*sprTitle);
			//sprFont->SetColor(sf::Color(255,0,0,255));
			draw_text(320-176,view.GetRect().Bottom-96,"Press space");// 11 chars * 32 = 352/2 = 176?
			draw_text(320-208,view.GetRect().Bottom-48,"to play game");// 13 chars * 32 = 416 = 208?
			//sprFont->SetColor(sf::Color(255,255,255,255));
			break;*/
	}
	if (!sKeyPrevious && sKeyDown)
		soundIsMuted = !soundIsMuted;
	spaceDownPrevious = spaceDown;
	sKeyPrevious = sKeyDown;
}
void cGame::PerformLevel()
{
	transitioningRooms = false;
	for(unsigned int i=0;i<vctrObjects.size();i++)
	{
		vctrObjects[i]->Update();
		if (transitioningRooms)
			return;
	}
	double xc, yc;
	if (playerPtr->GetX()+32 >= view.GetHalfSize().x)
	{
		if (playerPtr->GetX()+32 < levelWidth-view.GetHalfSize().x)
			xc = playerPtr->GetX()+32;
		else
			xc = levelWidth-view.GetHalfSize().x;
	}
	else
		xc = view.GetHalfSize().x;
	if (playerPtr->GetY()+32 >= view.GetHalfSize().y)
	{
		if (playerPtr->GetY()+32 < levelHeight-view.GetHalfSize().y)
			yc = playerPtr->GetY()+32;
		else
			yc = levelHeight-view.GetHalfSize().y;
	}
	else
		yc = view.GetHalfSize().y;
	view.SetCenter((float)xc,(float)yc);
	SortVector();
	float left, top, right, bottom;
	left = floor(view.GetRect().Left/64);
	top = floor(view.GetRect().Top/64);
	right = ceil(view.GetRect().Right/64);
	bottom = ceil(view.GetRect().Bottom/64);
	for(float i=left;i<right;i++)
		for(float j=top;j<bottom;j++)
		{
			floorSprite->SetPosition((float)64*i,(float)64*j);
			window->Draw(*floorSprite);
		}
	for(unsigned int i=0;i<vctrDrawObjects.size();i++)
		vctrDrawObjects[i]->Draw();
	window->Draw(sf::Shape::Rectangle(view.GetRect().Left,view.GetRect().Top,view.GetRect().Left+72+48*playerMaxHeart,view.GetRect().Top+64,sf::Color(255,255,255,128)));
	if (soundIsMuted)
	{
		sprSoundOff->SetPosition(view.GetRect().Left+12,view.GetRect().Top+12);
		window->Draw(*sprSoundOff);
	}
	else
	{
		sprSoundOn->SetPosition(view.GetRect().Left+12,view.GetRect().Top+12);
		window->Draw(*sprSoundOn);
	}
	// Draw Hearts
	for(int i=0;i<playerMaxHeart;i++)
	{
		sprHeartFade->SetPosition(view.GetRect().Left+56+48*i,view.GetRect().Top+16);
		window->Draw(*sprHeartFade);
		if (i+1 <= playerHeart)
		{
			sprHeart->SetPosition(view.GetRect().Left+56+48*i,view.GetRect().Top+16);
			window->Draw(*sprHeart);
		}
	}
	if (playerPtr->GetSignObject() != NULL)
	{
		window->Draw(sf::Shape::Rectangle(view.GetRect().Left+32,view.GetRect().Top+32,view.GetRect().Left+608,view.GetRect().Top+448,sf::Color(177,122,74,224)));
		draw_text(view.GetRect().Left+80,view.GetRect().Top+80,playerPtr->GetSignObject()->GetMessage());
		draw_text(view.GetRect().Left+400,view.GetRect().Top+400,"-Wade-");
	}
	// Delete all destroyed objects.
	for(unsigned int i=0;i<vctrObjects.size();i++)
	{
		if (vctrObjects[i]->IsDestroyed())
		{
			vctrObjects.erase(vctrObjects.begin()+i);
			i--;
		}
	}
	for(unsigned int i=0;i<vctrDrawObjects.size();i++)
	{
		if (vctrDrawObjects[i]->IsDestroyed())
		{
			cObject* temp = vctrDrawObjects[i];
			vctrDrawObjects.erase(vctrDrawObjects.begin()+i);
			delete temp;
			i--;
		}
	}
}
void cGame::End()
{

}
vector<cObject*> *cGame::GetObjectVector()
{
	return &vctrObjects;
}
sf::RenderWindow *cGame::GetWindow()
{
	return window;
}
cObject* cGame::AddObject(cObject* object)
{
	vctrObjects.push_back(object);
	vctrDrawObjects.push_back(object);
	return object;
}
sf::View *cGame::GetView()
{
	return &view;
}
void cGame::SortVector()
{
	// Crappiest sorting algorithm EVER!! EVER!! EVER!! EVER!!
	bool isSorted = false;
	while(1)
	{
		// Check
		isSorted = true;
		for(unsigned int i=0;i<vctrDrawObjects.size()-1;i++)
		{
			if (vctrDrawObjects[i]->GetDepth() > vctrDrawObjects[i+1]->GetDepth())
			{
				isSorted = false;
				i = vctrDrawObjects.size();
			}
		}
		if (isSorted)
			break;
		for(unsigned int i=0;i<vctrDrawObjects.size()-1;i++)
		{
			if (vctrDrawObjects[i]->GetDepth() > vctrDrawObjects[i+1]->GetDepth())
			{
				cObject* temp = vctrDrawObjects[i];
				vctrDrawObjects[i] = vctrDrawObjects[i+1];
				vctrDrawObjects[i+1] = temp;
			}
		}
	}
	//for(unsigned int i=0;i<vctrObjects.size();i++)
	//{
	//	cout << vctrObjects[i]->GetDepth() << endl;
	//}
	//cout << endl;
}
double cGame::GetLevelWidth()
{
	return levelWidth;
}
double cGame::GetLevelHeight()
{
	return levelHeight;
}
void cGame::ChangePlayerHeart(int amount)
{
	if (playerHeart + amount > playerMaxHeart)
		playerHeart = playerMaxHeart = playerHeart+amount;
	else
		playerHeart += amount;
}
unsigned int cGame::GetPlayerHeart()
{
	return playerHeart;
}
bool cGame::PlayerHasBrain()
{
	return hasBrain;
}
void cGame::ObtainedBrain()
{
	hasBrain = true;
}
unsigned int cGame::GetCurrentLevel()
{
	return currentLevel;
}
void cGame::GoToNextLevel()
{
	currentLevel++;
	transitioningRooms = true;
	if (currentLevel <= vctrLevels.size())
	{
		SetState(CS_LEVEL);
		for(unsigned int i=0;i<vctrObjects.size();i++)
			delete vctrObjects[i];
		vctrDrawObjects.clear();
		vctrObjects.clear();
		GenerateLevel(currentLevel);
	}
	else
	{
		for(unsigned int i=0;i<vctrObjects.size();i++)
			delete vctrObjects[i];
		vctrDrawObjects.clear();
		vctrObjects.clear();
		SetState(CS_WINSTORY);
	}
	//MessageBox(0,(char*)toString(currentLevel).c_str(),"currentLevel = ",0);
}
void cGame::RestartLevel()
{
	SetState(CS_LEVEL);
	playerHeart = playerMaxHeart;
	transitioningRooms = true;
	for(unsigned int i=0;i<vctrObjects.size();i++)
		delete vctrObjects[i];
	vctrDrawObjects.clear();
	vctrObjects.clear();
	GenerateLevel(currentLevel);
	//MessageBox(0,"Out","Debug",MB_ICONSTOP | MB_OK);
}
void cGame::CalculateStatVars()
{
	for(int q=0;q<vctrLevels.size();q++)
	{
#ifdef WIN32
		sf::Image bob;
		if (!bob.LoadFromFile("./media/data/"+vctrLevels[q]))
		{
			//MessageBox(0,(char*) ("Could not load level file: "+vctrLevels[q]).c_str(),"Division by Zero!! Oh noez",0);
			exit(42);
		}
#elif __APPLE__
		sf::Image bob;
		if (!bob.LoadFromFile(vctrLevels[q]))
		{
			//MessageBox(0,(char*) ("Could not load level file: "+vctrLevels[q]).c_str(),"Division by Zero!! Oh noez",0);
			exit(42);
		}
#endif
		bob.SetSmooth(false);
		for(unsigned int i=0;i<bob.GetWidth();i++)
			for(unsigned int j=0;j<bob.GetHeight();j++)
			{
				sf::Color col = bob.GetPixel(i,j);
				if (col == sf::Color(0,0,0,255))
					{}
				else if (col == sf::Color(255,0,0,255))
					{}
				else if (col == sf::Color(128,128,128,255))
					{}
				else if (col == sf::Color(255,0,255,255))
					{}
				else if (col == sf::Color(0,255,0,255))
					{}
				else if (col == sf::Color(128,128,0,255))
					{}
				else if (col == sf::Color(0,0,255,255))
					totalNumberHearts++;
				else if (col == sf::Color(128,64,0,255))
					totalNumberSigns++;
			}
	}
	// Subtract four hearts because those four in a square aren't obtainable.
	//totalNumberHearts -= 4;
}
void cGame::GenerateLevel(unsigned int lvl)
{
	currentLevel = lvl;
	view.SetFromRect(sf::FloatRect(0,0,640,480));
#ifdef WIN32
		sf::Image bob;
		if (!bob.LoadFromFile("./media/data/"+vctrLevels[currentLevel-1]))
		{
			//MessageBox(0,(char*) ("Could not load level file: "+vctrLevels[q]).c_str(),"Division by Zero!! Oh noez",0);
			exit(42);
		}
#elif __APPLE__
		sf::Image bob;
		if (!bob.LoadFromFile(vctrLevels[currentLevel-1]))
		{
			//MessageBox(0,(char*) ("Could not load level file: "+vctrLevels[q]).c_str(),"Division by Zero!! Oh noez",0);
			exit(42);
		}
#endif
	bob.SetSmooth(false);
	for(unsigned int i=0;i<bob.GetWidth();i++)
		for(unsigned int j=0;j<bob.GetHeight();j++)
		{
			sf::Color col = bob.GetPixel(i,j);
			if (col == sf::Color(0,0,0,255))
				AddObject(new cBrick(this, 64*i, 45*j));
			else if (col == sf::Color(255,0,0,255))
				playerPtr = (cPlayer*) AddObject(new cPlayer(this, 64*i, 45*j));
			else if (col == sf::Color(128,128,128,255))
				AddObject(new cHole(this, 64*i, 45*j));
			else if (col == sf::Color(255,0,255,255))
				AddObject(new cBrain(this, 64*i, 45*j));
			else if (col == sf::Color(0,255,0,255))
				AddObject(new cZombieGhost(this, 64*i, 45*j));
			else if (col == sf::Color(128,128,0,255))
				AddObject(new cDoor(this, 64*i, 45*j));
			else if (col == sf::Color(0,0,255,255))
			{
				bool canPlace = true;
				for(unsigned int k=0;k<vctrItemsObtained[currentLevel-1]->size();k++)
				{
					if (vctrItemsObtained[currentLevel-1]->at(k)->x == 64*i &&
						vctrItemsObtained[currentLevel-1]->at(k)->y == 45*j)
					{
						canPlace = false;
						k = vctrItemsObtained[currentLevel-1]->size();
					}
				}
				if (canPlace)
					AddObject(new cHeart(this, 64*i, 45*j));
			}
			else if (col == sf::Color(128,64,0,255))
			{
				bool isRead = false;
				for(unsigned int k=0;k<vctrItemsObtained[currentLevel-1]->size();k++)
				{
					if (vctrItemsObtained[currentLevel-1]->at(k)->x == 64*i &&
						vctrItemsObtained[currentLevel-1]->at(k)->y == 45*j)
					{
						isRead = true;
						k = vctrItemsObtained[currentLevel-1]->size();
					}
				}
				std::string message = "ERROR";
				if (vctrLevels[currentLevel-1] == "level1.png")
					message = "Thanks for\nplaying my game!";
				if (vctrLevels[currentLevel-1] == "level3.png")
					message = "38-bit Linux\n\nis for wizards,\n\n\n\nlike mrdude.";
				if (vctrLevels[currentLevel-1] == "level5.png")
					message = "Buddy Holly\n\n\nis awesome.";
				if (vctrLevels[currentLevel-1] == "level6.png")
					message = "The end is\n\nin the bottom\n\nleft corner.";
				if (vctrLevels[currentLevel-1] == "level7.png")
					message = "Bwahaha\n\nYou actually\n\nmade it.";
				AddObject(new cSign(this, 64*i, 45*j, message, isRead));
			}
		}
	levelWidth = 64*bob.GetWidth();
	levelHeight = 45*bob.GetHeight();
	if (currentLevel == 1)
		floorSprite = sprGrass;
	else
		floorSprite = sprUnderGrass;
}
bool cGame::IsKeyPressed(sf::Key::Code key)
{
	// Yeah, it doens't actually work for all keys. Just space.
	if (key == sf::Key::Space)
		return (spaceDown && !spaceDownPrevious);
	return false;
}
bool cGame::IsKeyReleased(sf::Key::Code key)
{
	// Yeah, it doens't actually work for all keys. Just space.
	if (key == sf::Key::Space)
		return (!spaceDown && spaceDownPrevious);
	return false;
}
void cGame::SetState(GAMESTATE state)
{
	currentState = state;
}
void cGame::AddItemToObtainedVector(double x, double y)
{
	vctrItemsObtained[currentLevel-1]->push_back(new sf::Vector2i((int)x,(int)y));
}
void cGame::StatIncrease(STATENUM st)
{
	switch(st)
	{
	case ST_DIED:
		statTimesDied++;
		break;
	case ST_DOOR:
		statDoorsOpened++;
		break;
	case ST_HEART:
		statHeartsObtained++;
		break;
	case ST_SIGN:
		statSignsRead++;
		break;
	}
}
bool cGame::IsGameRestarted()
{
	return gameRestarted;
}
void cGame::RestartGame()
{
	gameRestarted = true;
}
void cGame::PlaySound(sf::Sound *snd)
{
	if (!soundIsMuted)
		snd->Play();
}