#include <cmath>
#define ALLEGRO_FIX_H
#include <allegro.h>
#include <winalleg.h>
#include "erkTypes.h"
#include "erkMap.h"
#include "erkBmpGen.h"

#define SCROLL_SPEED 4

gbList(erkTileType_p) g_pvTileTypes;
BITMAP* g_pRedWins = NULL;
BITMAP* g_pBlueWins = NULL;

void BuildTiles();
void RunGame(BITMAP* pBB, gbBool bAI);
void DrawSineSprite(BITMAP* pDest, BITMAP* pSprite, gbInt dwX, gbInt dwY);
void DoPlayer2(gbInt dwvBluePos[], erkMap_p pMap, gbInt dwMapW, gbInt dwMapH);

void InitAI(erkMap_p pMap, gbInt dwMapW, gbInt dwMapH, gbInt dwHiveX, gbInt dwHiveY);
void DoAI(gbInt dwvBluePos[], erkMap_p pMap, gbInt dwMapW, gbInt dwMapH);

volatile gbInt g_dwMainTime = 0;
void MainTimer()
{
	g_dwMainTime++;
}
END_OF_FUNCTION(MainTimer);

void main()
{
	LOCK_VARIABLE(g_dwMainTime);
	LOCK_FUNCTION(MainTimer);
	allegro_init();
	set_color_depth(32);
	if(set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0))
	{
		set_color_depth(16);
		if(set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0))
		{
			set_color_depth(24);
			if(set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0))
			{
				set_color_depth(15);
				if(set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0))
				{
					allegro_message("Couldn't set 640x480 graphics mode. Cannot continure sorry.");
					exit(-1);
				}
			}
		}
	}

	set_config_file("MaxUnits.cfg");
	EU_MAX_UNITS = get_config_int("Limits", "MaxUnits", 1500);
	set_config_file("");

	BITMAP* pBB = create_bitmap(SCREEN_W, SCREEN_H); // Back-buffer
	if(!pBB)
	{
		allegro_message("Couldn't create back-buffer. Something is seriously wrong if you're reading this:(");
		exit(-1);
	}

	BITMAP* pTitle = load_bitmap("Data\\Title.bmp", NULL);
	g_pRedWins = load_bitmap("Data\\RedWins.bmp", NULL);
	g_pBlueWins = load_bitmap("Data\\BlueWins.bmp", NULL);

	BITMAP* pvOption[3];
	pvOption[0] = load_bitmap("Data\\VsComputer.bmp", NULL);
	pvOption[1] = load_bitmap("Data\\VsPlayer.bmp", NULL);
	pvOption[2] = load_bitmap("Data\\Exit.bmp", NULL);

	install_keyboard();
	install_mouse();
	install_timer();

	BuildTiles();

	install_int(MainTimer, 10); // Start main timer at 100 ticks per second(10ms)

	gbInt dwSelection = 0;
	gbBool bQuit = false;	
	while(!bQuit)
	{
		if(key[KEY_ENTER])
		{
			switch(dwSelection)
			{
			case 0:
				{
					RunGame(pBB, true);
					break;
				}
			case 1:
				{
					RunGame(pBB, false);
					break;
				}
			case 2:
				{
					bQuit = true;
					break;
				}
			}
		}
		if(key[KEY_UP]  &&  dwSelection > 0)
		{
			key[KEY_UP] = 0;
			dwSelection--;
		}
		if(key[KEY_DOWN]  &&  dwSelection < 2)
		{
			key[KEY_DOWN] = 0;
			dwSelection++;
		}

		blit(pTitle, pBB, 0, 0, 0, 0, SCREEN_W, SCREEN_H);

		for(int lp=0; lp<3; lp++)
		{
			if(lp == dwSelection)
				DrawSineSprite(pBB, pvOption[lp], (SCREEN_W-pvOption[lp]->w)/2, 160+lp*80);
			else
				draw_sprite(pBB, pvOption[lp], (SCREEN_W-pvOption[lp]->w)/2, 160+lp*80);
		}

		vsync();
		blit(pBB, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
	}

	destroy_bitmap(pBB);
}
END_OF_MAIN();

void BuildTiles()
{
	BITMAP* pBlank = create_bitmap(EM_TILE_SIZE, EM_TILE_SIZE);
	clear_to_color(pBlank, makecol(0, 0, 0));
	erkTileType_p pType = new erkTileType();
	pType->Build(pBlank);
	pType->SetSolid(true);
	g_pvTileTypes.push_back(pType);
	destroy_bitmap(pBlank);

	BITMAP* pFloor = load_bitmap("Data\\Floor.bmp", NULL);
	pType = new erkTileType();
	pType->Build(pFloor);
	pType->SetSolid(false);
	g_pvTileTypes.push_back(pType);
	destroy_bitmap(pFloor);

	BITMAP* pHive = load_bitmap("Data\\Hive.bmp", NULL);
	pType = new erkTTHive();
	pType->Build(pHive);
	pType->SetSolid(false);
	g_pvTileTypes.push_back(pType);
	destroy_bitmap(pHive);

	BITMAP* pTrainer = load_bitmap("Data\\Trainer.bmp", NULL);
	pType = new erkTTTrainer();
	pType->Build(pTrainer);
	pType->SetSolid(false);
	g_pvTileTypes.push_back(pType);
	destroy_bitmap(pTrainer);

	BITMAP* pThorns = load_bitmap("Data\\Thorns.bmp", NULL);
	pType = new erkTTThorns();
	pType->Build(pThorns);
	pType->SetSolid(false);
	g_pvTileTypes.push_back(pType);
	destroy_bitmap(pThorns);
}

void RunGame(BITMAP* pBB, gbBool bAI)
{
	gbInt dwGameTime = 0;
	gbInt dwLastFrameCheck = 0;
	gbInt dwFrameCount = 0;
	gbInt dwFrameRate = 0;

	gbInt dwMapW = SCREEN_W/EM_TILE_SIZE;
	gbInt dwMapH = SCREEN_H/EM_TILE_SIZE-1;

	erkMap_p pMap = new erkMap();
	pMap->SetSize(dwMapW, dwMapH);
	pMap->FillBlanks(g_pvTileTypes[0]);

	for(int ly=0; ly<3; ly++)
	{
		for(int lx=0; lx<3; lx++)
		{
			pMap->SetTile(lx+1, ly+1, g_pvTileTypes[1]);
			pMap->SetTileLit(lx+1, ly+1, true);

			pMap->SetTile(lx+dwMapW-4, ly+dwMapH-4, g_pvTileTypes[1]);
			pMap->SetTileLit(lx+dwMapW-4, ly+dwMapH-4, false);
		}
	}

	pMap->SetTile(2, 2, g_pvTileTypes[2]);
	pMap->SetTile(dwMapW-3, dwMapH-3, g_pvTileTypes[2]);

	InitAI(pMap, dwMapW, dwMapH, dwMapW-3, dwMapH-3);

	gbInt dwvRedPos[2] = { 0, 0 };
	gbInt dwvBluePos[2] = { dwMapW-1, dwMapH-1 };

	gbBool bQuit = false;
	g_dwMainTime = 0;
	while(!bQuit)
	{
		if(key[KEY_ESC])
			bQuit = true;

		while(g_dwMainTime > 0)
		{
			g_dwMainTime--;
			dwGameTime++;

			if(dwGameTime-dwLastFrameCheck >= 100)
			{
				dwFrameRate = dwFrameCount*100/(dwGameTime-dwLastFrameCheck);
				dwFrameCount = 0;
				dwLastFrameCheck = dwGameTime;
			}

			if(key[KEY_A]  &&  dwvRedPos[0] > 0)
			{
				key[KEY_A] = 0;
				dwvRedPos[0]--;
			}
			if(key[KEY_D]  &&  dwvRedPos[0] < dwMapW-1)
			{
				key[KEY_D] = 0;
				dwvRedPos[0]++;
			}
			if(key[KEY_W]  &&  dwvRedPos[1] > 0)
			{
				key[KEY_W] = 0;
				dwvRedPos[1]--;
			}
			if(key[KEY_S]  &&  dwvRedPos[1] < dwMapH-1)
			{
				key[KEY_S] = 0;
				dwvRedPos[1]++;
			}
			if(key[KEY_Y])
			{
				key[KEY_Y] = 0;
				erkTile_p pTile = pMap->GetTile(dwvRedPos[0], dwvRedPos[1]);
				if(pTile  &&  !pTile->IsSolid()  &&  pTile->IsLit()  &&  pTile->GetHealth() > 16)
				{
					erkCommand_p pCmd = new erkCmdNorth();
					pCmd->SetSide(true);
					pTile->SetCommand(true, pCmd);
				}
			}
			if(key[KEY_J])
			{
				key[KEY_J] = 0;
				erkTile_p pTile = pMap->GetTile(dwvRedPos[0], dwvRedPos[1]);
				if(pTile  &&  !pTile->IsSolid()  &&  pTile->IsLit()  &&  pTile->GetHealth() > 16)
				{
					erkCommand_p pCmd = new erkCmdEast();
					pCmd->SetSide(true);
					pTile->SetCommand(true, pCmd);
				}
			}
			if(key[KEY_H])
			{
				key[KEY_H] = 0;
				erkTile_p pTile = pMap->GetTile(dwvRedPos[0], dwvRedPos[1]);
				if(pTile  &&  !pTile->IsSolid()  &&  pTile->IsLit()  &&  pTile->GetHealth() > 16)
				{
					erkCommand_p pCmd = new erkCmdSouth();
					pCmd->SetSide(true);
					pTile->SetCommand(true, pCmd);
				}
			}
			if(key[KEY_G])
			{
				key[KEY_G] = 0;
				erkTile_p pTile = pMap->GetTile(dwvRedPos[0], dwvRedPos[1]);
				if(pTile  &&  !pTile->IsSolid()  &&  pTile->IsLit()  &&  pTile->GetHealth() > 16)
				{
					erkCommand_p pCmd = new erkCmdWest();
					pCmd->SetSide(true);
					pTile->SetCommand(true, pCmd);
				}
			}
			if(key[KEY_T])
			{
				key[KEY_T] = 0;
				erkTile_p pTile = pMap->GetTile(dwvRedPos[0], dwvRedPos[1]);
				if(pTile  &&  pTile->IsSolid())
				{
					erkCmdClear_p pCmd = new erkCmdClear();
					pCmd->SetSide(true);
					pCmd->SetClearType(g_pvTileTypes[1]);
					pTile->SetCommand(true, pCmd);
				}
			}
			if(key[KEY_B])
			{
				key[KEY_B] = 0;
				erkTile_p pTile = pMap->GetTile(dwvRedPos[0], dwvRedPos[1]);
				if(pTile  &&  !pTile->IsSolid()  &&  pTile->IsLit()  &&  pTile->GetHealth() > 16)
				{
					erkCmdThorns_p pCmd = new erkCmdThorns();
					pCmd->SetSide(true);
					pCmd->SetThornsType(g_pvTileTypes[4]);
					pTile->SetCommand(true, pCmd);
				}
			}
			if(key[KEY_N])
			{
				key[KEY_N] = 0;
				erkTile_p pTile = pMap->GetTile(dwvRedPos[0], dwvRedPos[1]);
				if(pTile  &&  !pTile->IsSolid()  &&  pTile->IsLit()  &&  pTile->GetHealth() > 16)
				{
					erkCmdTrainer_p pCmd = new erkCmdTrainer();
					pCmd->SetSide(true);
					pCmd->SetTrainerType(g_pvTileTypes[3]);
					pTile->SetCommand(true, pCmd);
				}
			}
			if(key[KEY_M])
			{
				key[KEY_M] = 0;
				erkTile_p pTile = pMap->GetTile(dwvRedPos[0], dwvRedPos[1]);
				if(pTile  &&  !pTile->IsSolid()  &&  pTile->IsLit()  &&  pTile->GetHealth() > 16)
				{
					erkCmdHive_p pCmd = new erkCmdHive();
					pCmd->SetSide(true);
					pCmd->SetHiveType(g_pvTileTypes[2]);
					pTile->SetCommand(true, pCmd);
				}
			}
			if(key[KEY_U])
			{
				key[KEY_U] = 0;
				erkTile_p pTile = pMap->GetTile(dwvRedPos[0], dwvRedPos[1]);
				if(pTile)
				{
					pTile->SetCommand(true, NULL);
				}
			}

			if(bAI)
			{
				DoAI(dwvBluePos, pMap, dwMapW, dwMapH);
			}
			else
			{
				DoPlayer2(dwvBluePos, pMap, dwMapW, dwMapH);
			}

/*			if(key[KEY_L])
			{
				if(mouse_b&1)
				{
					pMap->SetTileLit(mouse_x/EM_TILE_SIZE, mouse_y/EM_TILE_SIZE, true);
				}
				if(mouse_b&2)
				{
					pMap->SetTileLit(mouse_x/EM_TILE_SIZE, mouse_y/EM_TILE_SIZE, false);
				}
			}
			if(key[KEY_O])
			{
				if(mouse_b&1)
				{
					pMap->SetTile(mouse_x/EM_TILE_SIZE, mouse_y/EM_TILE_SIZE, g_pvTileTypes[1]);
				}
				if(mouse_b&2)
				{
					pMap->SetTile(mouse_x/EM_TILE_SIZE, mouse_y/EM_TILE_SIZE, g_pvTileTypes[0]);
				}
			}
			if(key[KEY_P])
			{
				if(mouse_b&1)
				{
					pMap->SetTile(mouse_x/EM_TILE_SIZE, mouse_y/EM_TILE_SIZE, g_pvTileTypes[2]);
				}
				if(mouse_b&2)
				{
					pMap->SetTile(mouse_x/EM_TILE_SIZE, mouse_y/EM_TILE_SIZE, g_pvTileTypes[3]);
				}
			}
			if(key[KEY_I])
			{
				if(mouse_b&1)
				{
					erkTile_p pTile = pMap->GetTile(mouse_x/EM_TILE_SIZE, mouse_y/EM_TILE_SIZE);
					if(pTile)
					{
						erkUnit_p pUnit = new erkUnit();
						pUnit->SetColor(makecol(255, rand()%64, rand()%64));
						pUnit->SetSide(true);
						pUnit->SetType(EU_UT_WORKER);
						pTile->AddUnit(pUnit);
						pMap->AddUnit(pUnit);
					}
				}
				if(mouse_b&2)
				{
					erkTile_p pTile = pMap->GetTile(mouse_x/EM_TILE_SIZE, mouse_y/EM_TILE_SIZE);
					if(pTile)
					{
						erkUnit_p pUnit = new erkUnit();
						pUnit->SetColor(makecol(rand()%64, rand()%64, 255));
						pUnit->SetSide(false);
						pUnit->SetType(EU_UT_WORKER);
						pTile->AddUnit(pUnit);
						pMap->AddUnit(pUnit);
					}
				}
			}*/

			pMap->Update();
		}

		dwFrameCount++;
		clear(pBB);

		pMap->Draw(pBB, 0, 0);

		gbInt dwR = (rand()>>7)&0xFF;
		gbInt dwColor = makecol(255, dwR, dwR);
		rect(pBB,
			dwvRedPos[0]*EM_TILE_SIZE, dwvRedPos[1]*EM_TILE_SIZE,
			(dwvRedPos[0]+1)*EM_TILE_SIZE-1, (dwvRedPos[1]+1)*EM_TILE_SIZE-1,
			dwColor);

		dwR = (rand()>>7)&0xFF;
		dwColor = makecol(dwR, dwR, 255);
		rect(pBB,
			dwvBluePos[0]*EM_TILE_SIZE, dwvBluePos[1]*EM_TILE_SIZE,
			(dwvBluePos[0]+1)*EM_TILE_SIZE-1, (dwvBluePos[1]+1)*EM_TILE_SIZE-1,
			dwColor);

		if(key[KEY_F2])
			textprintf_ex(pBB, font, 4, 4, makecol(255, 255, 0), 0, "FPS: %d", dwFrameRate);
//		textprintf_ex(pBB, font, 4, 14, makecol(255, 255, 0), 0, "Unit Count Red: %d", pMap->GetTeamCount(true));
//		textprintf_ex(pBB, font, 4, 24, makecol(255, 255, 0), 0, "Unit Count Blue: %d", pMap->GetTeamCount(false));

		gbInt dwRedCount = pMap->GetTeamCount(true);
		gbInt dwBlueCount = pMap->GetTeamCount(false);
		if(dwRedCount > 0  &&  dwBlueCount > 0)
		{
			gbInt dwMaxCount = MAX(dwRedCount, dwBlueCount);
			rectfill(pBB, 0, SCREEN_H-12, (SCREEN_W-1)*dwRedCount/dwMaxCount, SCREEN_H-9, makecol(255, 128, 0));
			rectfill(pBB, 0, SCREEN_H-8, (SCREEN_W-1)*dwBlueCount/dwMaxCount, SCREEN_H-5, makecol(0, 128, 255));
		}
		else if(dwGameTime > 1000)
		{
			bQuit = true;
		}

//		show_mouse(pBB);
//		vsync();
		blit(pBB, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
//		show_mouse(NULL);
	}

	gbInt dwRedCount = pMap->GetTeamCount(true);
	gbInt dwBlueCount = pMap->GetTeamCount(false);
	if(dwRedCount > 0  &&  dwBlueCount <= 0)
	{
		blit(g_pRedWins, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
		while(!key[KEY_ESC]);
	}
	else if(dwRedCount <= 0  &&  dwBlueCount > 0)
	{
		blit(g_pBlueWins, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
		while(!key[KEY_ESC]);
	}

	while(key[KEY_ESC]);
}

void DrawSineSprite(BITMAP* pDest, BITMAP* pSprite, gbInt dwX, gbInt dwY)
{
	for(int lx=0; lx<pSprite->w; lx++)
	{
		masked_blit(pSprite, pDest, lx, 0, dwX+lx, dwY+(int)(sin((g_dwMainTime+lx*5)*0.02f)*12), 1, pSprite->h);
	}
}

void DoPlayer2(gbInt dwvBluePos[], erkMap_p pMap, gbInt dwMapW, gbInt dwMapH)
{
	if(key[KEY_LEFT]  &&  dwvBluePos[0] > 0)
	{
		key[KEY_LEFT] = 0;
		dwvBluePos[0]--;
	}
	if(key[KEY_RIGHT]  &&  dwvBluePos[0] < dwMapW-1)
	{
		key[KEY_RIGHT] = 0;
		dwvBluePos[0]++;
	}
	if(key[KEY_UP]  &&  dwvBluePos[1] > 0)
	{
		key[KEY_UP] = 0;
		dwvBluePos[1]--;
	}
	if(key[KEY_DOWN]  &&  dwvBluePos[1] < dwMapH-1)
	{
		key[KEY_DOWN] = 0;
		dwvBluePos[1]++;
	}
	if(key[KEY_8_PAD])
	{
		key[KEY_8_PAD] = 0;
		erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
		if(pTile  &&  !pTile->IsSolid()  &&  !pTile->IsLit()  &&  pTile->GetHealth() > 16)
		{
			erkCommand_p pCmd = new erkCmdNorth();
			pCmd->SetSide(false);
			pTile->SetCommand(false, pCmd);
		}
	}
	if(key[KEY_6_PAD])
	{
		key[KEY_6_PAD] = 0;
		erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
		if(pTile  &&  !pTile->IsSolid()  &&  !pTile->IsLit()  &&  pTile->GetHealth() > 16)
		{
			erkCommand_p pCmd = new erkCmdEast();
			pCmd->SetSide(false);
			pTile->SetCommand(false, pCmd);
		}
	}
	if(key[KEY_5_PAD])
	{
		key[KEY_5_PAD] = 0;
		erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
		if(pTile  &&  !pTile->IsSolid()  &&  !pTile->IsLit()  &&  pTile->GetHealth() > 16)
		{
			erkCommand_p pCmd = new erkCmdSouth();
			pCmd->SetSide(false);
			pTile->SetCommand(false, pCmd);
		}
	}
	if(key[KEY_4_PAD])
	{
		key[KEY_4_PAD] = 0;
		erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
		if(pTile  &&  !pTile->IsSolid()  &&  !pTile->IsLit()  &&  pTile->GetHealth() > 16)
		{
			erkCommand_p pCmd = new erkCmdWest();
			pCmd->SetSide(false);
			pTile->SetCommand(false, pCmd);
		}
	}
	if(key[KEY_7_PAD])
	{
		key[KEY_7_PAD] = 0;
		erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
		if(pTile  &&  pTile->IsSolid())
		{
			erkCmdClear_p pCmd = new erkCmdClear();
			pCmd->SetSide(false);
			pCmd->SetClearType(g_pvTileTypes[1]);
			pTile->SetCommand(false, pCmd);
		}
	}
	if(key[KEY_1_PAD])
	{
		key[KEY_1_PAD] = 0;
		erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
		if(pTile  &&  !pTile->IsSolid()  &&  !pTile->IsLit()  &&  pTile->GetHealth() > 16)
		{
			erkCmdThorns_p pCmd = new erkCmdThorns();
			pCmd->SetSide(false);
			pCmd->SetThornsType(g_pvTileTypes[4]);
			pTile->SetCommand(false, pCmd);
		}
	}
	if(key[KEY_2_PAD])
	{
		key[KEY_2_PAD] = 0;
		erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
		if(pTile  &&  !pTile->IsSolid()  &&  !pTile->IsLit()  &&  pTile->GetHealth() > 16)
		{
			erkCmdTrainer_p pCmd = new erkCmdTrainer();
			pCmd->SetSide(false);
			pCmd->SetTrainerType(g_pvTileTypes[3]);
			pTile->SetCommand(false, pCmd);
		}
	}
	if(key[KEY_3_PAD])
	{
		key[KEY_3_PAD] = 0;
		erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
		if(pTile  &&  !pTile->IsSolid()  &&  !pTile->IsLit()  &&  pTile->GetHealth() > 16)
		{
			erkCmdHive_p pCmd = new erkCmdHive();
			pCmd->SetSide(false);
			pCmd->SetHiveType(g_pvTileTypes[2]);
			pTile->SetCommand(false, pCmd);
		}
	}
	if(key[KEY_9_PAD])
	{
		key[KEY_9_PAD] = 0;
		erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
		if(pTile)
		{
			pTile->SetCommand(false, NULL);
		}
	}
}
