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

#define AI_JT_NONE				0
#define AI_JT_THORNS			1
#define AI_JT_TRAINER			2
#define AI_JT_HIVE				3
#define AI_JT_FLOOR				4
#define AI_JT_GO_NORTH			5
#define AI_JT_GO_EAST			6
#define AI_JT_GO_SOUTH			7
#define AI_JT_GO_WEST			8
#define AI_JT_CANCEL			9

#define AI_JC_NONE				0
#define AI_JC_CLEAR				1

extern gbList(erkTileType_p) g_pvTileTypes;

typedef struct ai_job_s {
	gbInt						dwType;
	gbInt						dwvPos[2];
	gbInt						dwCondition;
} ai_job_t, *ai_job_p;

gbLinkList(ai_job_t) ai_svJobs;

inline gbBool IsAITile(erkTile_p pTile)
{
	if(!pTile  ||  pTile->IsSolid()  ||  pTile->IsLit())
		return false;

	return true;
}

inline gbBool IsEnemyTile(erkTile_p pTile)
{
	if(!pTile  ||  pTile->IsSolid()  ||  !pTile->IsLit())
		return false;

	return true;
}

inline gbBool IsClearTile(erkTile_p pTile)
{
	if(!pTile  ||  !pTile->IsSolid()  ||  pTile->GetCommand(false))
		return false;

	return true;
}

void AddJob(gbInt dwType, gbInt dwX, gbInt dwY, gbInt dwCond)
{
	for(gbLinkListIter(ai_job_t) iPos=ai_svJobs.begin(); iPos!=ai_svJobs.end(); )
	{
		if(iPos->dwvPos[0] == dwX  &&  iPos->dwvPos[1] == dwY)
			ai_svJobs.erase(iPos++);
		else
			++iPos;
	}

	ai_job_t sJob;
	sJob.dwType = dwType;
	sJob.dwvPos[0] = dwX;
	sJob.dwvPos[1] = dwY;
	sJob.dwCondition = dwCond;
	ai_svJobs.push_back(sJob);
}

void AddJobFront(gbInt dwType, gbInt dwX, gbInt dwY, gbInt dwCond)
{
	for(gbLinkListIter(ai_job_t) iPos=ai_svJobs.begin(); iPos!=ai_svJobs.end(); )
	{
		if(iPos->dwvPos[0] == dwX  &&  iPos->dwvPos[1] == dwY)
			ai_svJobs.erase(iPos++);
		else
			++iPos;
	}

	ai_job_t sJob;
	sJob.dwType = dwType;
	sJob.dwvPos[0] = dwX;
	sJob.dwvPos[1] = dwY;
	sJob.dwCondition = dwCond;
	ai_svJobs.push_front(sJob);
}

void InitAI(erkMap_p pMap, gbInt dwMapW, gbInt dwMapH, gbInt dwHiveX, gbInt dwHiveY)
{
	/*AddJob(AI_JT_TRAINER, dwHiveX-1, dwHiveY-1, AI_JC_NONE);
	AddJob(AI_JT_TRAINER, dwHiveX, dwHiveY-1, AI_JC_NONE);
	AddJob(AI_JT_TRAINER, dwHiveX+1, dwHiveY-1, AI_JC_NONE);
	AddJob(AI_JT_TRAINER, dwHiveX+1, dwHiveY, AI_JC_NONE);
	AddJob(AI_JT_TRAINER, dwHiveX+1, dwHiveY+1, AI_JC_NONE);
	AddJob(AI_JT_TRAINER, dwHiveX, dwHiveY+1, AI_JC_NONE);
	AddJob(AI_JT_TRAINER, dwHiveX-1, dwHiveY+1, AI_JC_NONE);
	AddJob(AI_JT_TRAINER, dwHiveX-1, dwHiveY, AI_JC_NONE);

	AddJob(AI_JT_GO_EAST, dwHiveX-1, dwHiveY-1, AI_JC_CLEAR);
	AddJob(AI_JT_GO_EAST, dwHiveX, dwHiveY-1, AI_JC_CLEAR);
	AddJob(AI_JT_GO_SOUTH, dwHiveX+1, dwHiveY-1, AI_JC_CLEAR);
	AddJob(AI_JT_GO_SOUTH, dwHiveX+1, dwHiveY, AI_JC_CLEAR);
	AddJob(AI_JT_GO_WEST, dwHiveX+1, dwHiveY+1, AI_JC_CLEAR);
	AddJob(AI_JT_GO_WEST, dwHiveX, dwHiveY+1, AI_JC_CLEAR);
	AddJob(AI_JT_GO_NORTH, dwHiveX-1, dwHiveY+1, AI_JC_CLEAR);
	AddJob(AI_JT_GO_NORTH, dwHiveX-1, dwHiveY, AI_JC_CLEAR);*/
}

void DoAI(gbInt dwvBluePos[], erkMap_p pMap, gbInt dwMapW, gbInt dwMapH)
{
	static gbInt dwMoveTicker = 0;
	static gbInt dwRefresh = 0;
	dwMoveTicker = (dwMoveTicker+1)%10;
	if(!dwMoveTicker)
	{
		ai_job_t sJob = ai_svJobs.front();
		if(sJob.dwCondition == AI_JC_CLEAR  &&  pMap->GetTile(sJob.dwvPos[0], sJob.dwvPos[1])->GetCommand(false))
		{
			ai_svJobs.push_back(ai_svJobs.front());
			ai_svJobs.pop_front();
		}
		else if(sJob.dwType)
		{
			if(dwvBluePos[0] > sJob.dwvPos[0])
			{
				dwvBluePos[0]--;
			}
			else if(dwvBluePos[0] < sJob.dwvPos[0])
			{
				dwvBluePos[0]++;
			}
			else if(dwvBluePos[1] > sJob.dwvPos[1])
			{
				dwvBluePos[1]--;
			}
			else if(dwvBluePos[1] < sJob.dwvPos[1])
			{
				dwvBluePos[1]++;
			}
			else
			{
				switch(sJob.dwType)
				{
				case AI_JT_THORNS:
					{
						erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
						if(pTile)
						{
							erkCmdThorns_p pCmd = new erkCmdThorns();
							pCmd->SetSide(false);
							pCmd->SetThornsType(g_pvTileTypes[4]);
							pTile->SetCommand(false, pCmd);
						}
						break;
					}
				case AI_JT_TRAINER:
					{
						erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
						if(pTile)
						{
							erkCmdTrainer_p pCmd = new erkCmdTrainer();
							pCmd->SetSide(false);
							pCmd->SetTrainerType(g_pvTileTypes[3]);
							pTile->SetCommand(false, pCmd);
						}
						break;
					}
				case AI_JT_HIVE:
					{
						erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
						if(pTile)
						{
							erkCmdHive_p pCmd = new erkCmdHive();
							pCmd->SetSide(false);
							pCmd->SetHiveType(g_pvTileTypes[2]);
							pTile->SetCommand(false, pCmd);
						}
						break;
					}
				case AI_JT_FLOOR:
					{
						erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
						if(pTile)
						{
							erkCmdClear_p pCmd = new erkCmdClear();
							pCmd->SetSide(false);
							pCmd->SetClearType(g_pvTileTypes[1]);
							pTile->SetCommand(false, pCmd);
						}
						break;
					}
				case AI_JT_GO_NORTH:
					{
						erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
						if(pTile)
						{
							erkCommand_p pCmd = new erkCmdNorth();
							pCmd->SetSide(false);
							pTile->SetCommand(false, pCmd);
						}
						break;
					}
				case AI_JT_GO_EAST:
					{
						erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
						if(pTile)
						{
							erkCommand_p pCmd = new erkCmdEast();
							pCmd->SetSide(false);
							pTile->SetCommand(false, pCmd);
						}
						break;
					}
				case AI_JT_GO_SOUTH:
					{
						erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
						if(pTile)
						{
							erkCommand_p pCmd = new erkCmdSouth();
							pCmd->SetSide(false);
							pTile->SetCommand(false, pCmd);
						}
						break;
					}
				case AI_JT_GO_WEST:
					{
						erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
						if(pTile)
						{
							erkCommand_p pCmd = new erkCmdWest();
							pCmd->SetSide(false);
							pTile->SetCommand(false, pCmd);
						}
						break;
					}
				case AI_JT_CANCEL:
					{
						erkTile_p pTile = pMap->GetTile(dwvBluePos[0], dwvBluePos[1]);
						if(pTile)
						{
							pTile->SetCommand(false, NULL);
						}
						break;
					}
				}

				ai_svJobs.pop_front();
			}
		}
		else if(++dwRefresh > 10)
		{
			dwRefresh = 0;

			gbInt dwX = 0;
			gbInt dwY = 0;
			for(gbListIter(erkTile_p) iPos=pMap->TilesBegin(); iPos!=pMap->TilesEnd(); ++iPos)
			{
				erkTile_p pTile = *iPos;
				gbInt dwOldDir = -1;
				gbInt dwDir = -1;
				if(IsAITile(pTile))
				{
					erkCommand_p pCmd = pTile->GetCommand(false);
					if(pCmd)
					{
						if(typeid(*pCmd) == typeid(erkCmdNorth))
						{
							dwOldDir = 0;
						}
						else if(typeid(*pCmd) == typeid(erkCmdEast))
						{
							dwOldDir = 1;
						}
						else if(typeid(*pCmd) == typeid(erkCmdSouth))
						{
							dwOldDir = 2;
						}
						else if(typeid(*pCmd) == typeid(erkCmdWest))
						{
							dwOldDir = 3;
						}
					}

					if(IsEnemyTile(pTile->GetNeighbour(ET_N_NORTH)))
					{
						dwDir = 0;
					}
					else if(IsEnemyTile(pTile->GetNeighbour(ET_N_EAST)))
					{
						dwDir = 1;
					}
					else if(IsEnemyTile(pTile->GetNeighbour(ET_N_SOUTH)))
					{
						dwDir = 2;
					}
					else if(IsEnemyTile(pTile->GetNeighbour(ET_N_WEST)))
					{
						dwDir = 3;
					}
				}

				if(dwOldDir != dwDir)
				{
					if(dwDir >= 0)
						AddJobFront(AI_JT_GO_NORTH+dwDir, dwX, dwY, AI_JC_NONE);
					else if((rand()%5) == 0)
						AddJob(AI_JT_CANCEL, dwX, dwY, AI_JC_NONE);
				}

				dwX++;
				if(dwX >= dwMapW)
				{
					dwX = 0;
					dwY++;
				}
			}
		}
		else
		{
			gbInt dwvDesPos[2] = { rand()%dwMapW, rand()%dwMapH };
			erkTile_p pTile = pMap->GetTile(dwvDesPos[0], dwvDesPos[1]);
			if(pTile  &&  !pTile->IsLit())
			{
				erkTileType_p pType = pTile->GetType();
				if(pType == g_pvTileTypes[0])
				{
					gbBool bNorth, bEast, bSouth, bWest;
					bNorth = IsAITile(pTile->GetNeighbour(ET_N_NORTH));
					bEast = IsAITile(pTile->GetNeighbour(ET_N_EAST));
					bSouth = IsAITile(pTile->GetNeighbour(ET_N_SOUTH));
					bWest = IsAITile(pTile->GetNeighbour(ET_N_WEST));
					if(!pTile->GetCommand(false)  &&  (bNorth  ||  bEast  ||  bSouth  ||  bWest))
					{
						gbInt dwX = dwvDesPos[0];
						gbInt dwY = dwvDesPos[1];
						gbInt dwXD = 0;
						gbInt dwYD = 0;
						if(bSouth  &&  !bNorth)
						{
							dwYD = -1;
						}
						else if(!bSouth  &&  bNorth)
						{
							dwYD = 1;
						}
						else if(bEast  &&  !bWest)
						{
							dwXD = -1;
						}
						else if(!bEast  &&  bWest)
						{
							dwXD = 1;
						}
						if(dwXD  ||  dwYD)
						{
							gbInt dwR = (rand()%5)+1;
							for(int lp=0; lp<dwR; lp++)
							{
								pTile = pMap->GetTile(dwX, dwY);
								if(!IsClearTile(pTile))
									break;
	
								AddJob(AI_JT_FLOOR, dwX, dwY, AI_JC_NONE);
	
								dwX += dwXD;
								dwY += dwYD;
							}
						}
					}
				}
				else if(pType == g_pvTileTypes[1]  &&  IsAITile(pTile)  &&  !pTile->GetCommand(false))
				{
					switch(rand()%15)
					{
					case 0:
					case 1:
					case 2:
						{
							AddJob(AI_JT_TRAINER, dwvDesPos[0], dwvDesPos[1], AI_JC_NONE);
							break;
						}	
					case 3:
						{
							AddJob(AI_JT_HIVE, dwvDesPos[0], dwvDesPos[1], AI_JC_NONE);
							break;
						}	
					}
				}
			}
		}
	}
}

/*			gbInt dwvDesPos[2] = { rand()%dwMapW, rand()%dwMapH };
			erkTile_p pTile = pMap->GetTile(dwvDesPos[0], dwvDesPos[1]);
			if(pTile  &&  !pTile->IsLit())
			{
				erkTileType_p pType = pTile->GetType();
				if(pType == g_pvTileTypes[0])
				{
					if(!pTile->GetCommand(false) &&
						(IsAITile(pTile->GetNeighbour(ET_N_NORTH))  ||
						IsAITile(pTile->GetNeighbour(ET_N_EAST))  ||
						IsAITile(pTile->GetNeighbour(ET_N_SOUTH))  ||
						IsAITile(pTile->GetNeighbour(ET_N_WEST))))
					{
						ai_job_t sJob;
						sJob.dwType = AI_JT_FLOOR;
						sJob.dwvPos[0] = dwvDesPos[0];
						sJob.dwvPos[1] = dwvDesPos[1];
						sJob.dwCondition = 0;
						ai_svJobs.push_back(sJob);
					}
				}
				else if(pType == g_pvTileTypes[1])
				{
					ai_job_t sJob;
					sJob.dwType = AI_JT_GO_NORTH+(rand()%4);
					sJob.dwvPos[0] = dwvDesPos[0];
					sJob.dwvPos[1] = dwvDesPos[1];
					sJob.dwCondition = 0;
					ai_svJobs.push_back(sJob);
				}
				else if(pType == g_pvTileTypes[2])
				{
				}
				else if(pType == g_pvTileTypes[3])
				{
				}
				else if(pType == g_pvTileTypes[4])
				{
				}
			}
*/
