#pragma warning (disable:4786)
#include "ai.hpp"

FixedHeap<CommandEntry> CommandEntry::m_EmptyCommand(100);

void InitAI (bool firstpass)
{
	if (firstpass)
	{
		return;
	}
}

void KillAI (void)
{
}


AI::AI (void)
{
	UINT i;

	m_Name.Empty ();
	m_Awareness = NULL;
	m_Combat = NULL;
	m_Converse = NULL;
	m_Comm = NULL;

	m_Location.x = 1;
	m_Location.y = 1;
	m_LastSort[0] = SORT_PRIORITY;
	for (i=1;i<SORT_DEPTH;i++)
	{
		m_LastSort[i] = SORT_NULL;
	}
}

AI::~AI (void)
{
	if (m_Awareness)
		delete m_Awareness;
	if (m_Combat)
		delete m_Combat;
	if (m_Converse)
		delete m_Converse;
	if (m_Comm)
		delete m_Comm;
	if (m_Move)
		delete m_Move;
}

bool AI::Think (double value)
{
	CommandEntry *temp;
	if (m_Awareness)
	{
		temp = m_Awareness->Think (value,m_AreaLastCommand[AWARE_AREA]);
		if (temp)
		{
			m_AreaLastCommand[AWARE_AREA] = temp;
			InsertCommand (temp);
		}
	}
	if (m_Combat)
	{
		temp = m_Combat->Think (value,m_AreaLastCommand[COMBAT_AREA]);
		if (temp)
		{
			m_AreaLastCommand[COMBAT_AREA] = temp;
			InsertCommand (temp);
		}
	}
	if (m_Converse)
	{
		temp = m_Converse->Think (value,m_AreaLastCommand[CONVERSATION_AREA]);
		if (temp)
		{
			m_AreaLastCommand[CONVERSATION_AREA] = temp;
			InsertCommand (temp);
		}
	}
	if (m_Comm)
	{
		temp = m_Comm->Think (value,m_AreaLastCommand[COMMUNICATION_AREA]);
		if (temp)
		{
			m_AreaLastCommand[COMMUNICATION_AREA] = temp;
			InsertCommand (temp);
		}
	}
	if (m_Move)
	{
		temp = m_Move->Think (value,m_AreaLastCommand[MOVE_AREA]);
		if (temp)
		{
			m_AreaLastCommand[MOVE_AREA] = temp;
			InsertCommand (temp);
		}
	}
	
	ExecuteCommand (GetTopCommand (true));

	return true;
}

void AI::SetAreaOrder (const UINT neworder[MAX_AIAREA],bool resort)
{
	memcpy (&(m_AreaOrder[0]),&(neworder[0]),sizeof (AIAREA)*MAX_AIAREA);
	if (resort)
		SortCommandList (m_LastSort);
}

void AI::SortCommandList (const SORTTYPE on[SORT_DEPTH])
{
	CommandEntry *temp,*cur;

	assert (on[0] != SORT_NULL);
	assert (on[SORT_DEPTH-1] == SORT_NULL);

	memcpy (&(m_LastSort[0]),&(on[0]),sizeof (SORTTYPE)*SORT_DEPTH);

	cur = m_RootCommand;
	m_RootCommand = NULL;
	m_SortRoot = NULL;
	while (cur)
	{
		temp = cur;
		cur = cur->next;
		InsertCommand (temp);
	}
}

void AI::InsertCommand (CommandEntry *cmd)
{
	CommandEntry *level[SORT_DEPTH];
	UINT i,here;
	bool done;

	if (!cmd)
		return;
	assert (CheckCommandValid (cmd));
	assert (m_LastSort[0] != SORT_NULL);
	assert (m_LastSort[SORT_DEPTH-1] == SORT_NULL);

	cmd->next = m_RootCommand;
	cmd->prev = NULL;
	if (m_RootCommand)
		m_RootCommand->prev = cmd;
	m_RootCommand = cmd;

	if (m_SortRoot != NULL)
	{

		level[0] = m_SortRoot;
		done = false;
		here = 0;

		for (i=0;(i<SORT_DEPTH) && (!done);i++)
		{
			while ((level[i]) && (here != 1) && (!done))
			{
				here = 0;
				if (i != 0)
				{
					switch (m_LastSort[i-1])
					{
					case SORT_NULL:
						assert (false);   // should not continue searching if just did a null sort
						break;
					case SORT_PRIORITY:
						if (level[i]->priority != cmd->priority)
							here = 2;
						break;
					case SORT_VALID:
						if (level[i]->validFor != cmd->validFor)
							here = 2;
						break;
					case SORT_AREA:
						if (CompareArea (level[i]->from,cmd->from) != 0)
							here = 2;
						break;
					}
				}
				if ((here != 2) && (level[i]->sort_next == NULL))
					here = 2;
				else if (here != 2)
				{
					switch (m_LastSort[i])
					{
						case SORT_NULL:
							here = 2;
						case SORT_PRIORITY:
							if (level[i]->priority == cmd->priority)
								here = 1;
							if (level[i]->priority > cmd->priority)
								here = 2;
							break;
						case SORT_VALID:
							if (level[i]->validFor == cmd->validFor)
								here = 1;
							if (level[i]->validFor > cmd->validFor)
								here = 2;
							break;
						case SORT_AREA:
							if (CompareArea(level[i]->from,cmd->from) == 0)
								here = 1;
							if (CompareArea(level[i]->from,cmd->from) > 0)
								here = 2;
							break;
					}
				}
				switch (here)
				{
				case 0:
					level[i] = level[i]->sort_next;
					break;
				case 1:
					level[i+1] = level[i];
					break;
				case 2:
					if (level[i]->sort_prev)
						level[i]->sort_prev->sort_next = cmd;
					cmd->sort_prev = level[i]->sort_prev;
					cmd->sort_next = level[i];
					level[i]->sort_prev = cmd;
					if (m_SortRoot = level[i])
						m_SortRoot = cmd;
					done = true;
					break;
				}
			}
		}
	}
	else
	{
		m_SortRoot = cmd;
	}
}

void AI::RemoveCommand (CommandEntry *cmd)
{

	if (!cmd)
		return;

	if (cmd->next)
		cmd->next->prev = cmd->prev;
	if (cmd->prev)
		cmd->prev->next = cmd->next;
	if (m_RootCommand == cmd)
		m_RootCommand = cmd->next;
	cmd->next = NULL;
	cmd->prev = NULL;


	if (cmd->sort_next)
		cmd->sort_next->sort_prev = cmd->sort_prev;
	if (cmd->sort_prev)
		cmd->sort_prev->sort_next = cmd->sort_next;
	if (m_SortRoot == cmd)
		m_SortRoot = cmd->sort_next;
	cmd->sort_next = NULL;
	cmd->sort_prev = NULL;

	for (int i=0;i<MAX_AIAREA;i++)
	{
		if (m_AreaLastCommand[i] == cmd)
			m_AreaLastCommand[i] = NULL;
	}

}

void AI::ExecuteCommand (CommandEntry *command)
{
	if (!command)
		return;
	switch (command->commandType)
	{
	case MOVE_CMD:
		m_Location.x = command->commandData.moveData.dx;
		m_Location.y = command->commandData.moveData.dy;
		break;
	case SAY_CMD:
		break;
	case STANCE_CMD:
		break;
	case TURN_CMD:
		break;
	case SEND_CMD:
		break;
	case PLACEMENT_CMD:
		break;
	case ATTACK_CMD:
		break;
	case TRADE_CMD:
		break;
	case SPECIAL_CMD:
		break;
	case ADJUST_CMD:
		break;
	case REMOVE_CMD:
		break;
	}
	RemoveCommand (command);
	delete command;
}

#ifdef _DEBUG
bool AI::CheckCommandValid (CommandEntry *cmd)
{
	return true;
}
#endif
