#include "MW4Headers.hpp"

#include "AI_Groups.hpp"

#include <Adept\NameTable.hpp>
#include <Adept\Application.hpp>
#include "MWPlayer.hpp"
#include "MWMission.hpp"
#include "GroupContainer.hpp"
#include "VehicleInterface.hpp"
#include <Adept\Map.hpp>



using namespace MW4AI;

inline MWObject* GetMWObject(Adept::ObjectID object_id)
{
	gosREPORT((NameTable::GetInstance() != 0),"The NameTable object does not exist");

	Adept::Entity* entity = NameTable::GetInstance()->FindData(object_id);

	if ((entity == 0) ||
		(entity->IsDerivedFrom(MechWarrior4::MWObject::DefaultData) == false))
	{
		return (0);
	}

	return (Cast_Object(MechWarrior4::MWObject*,entity));
}

inline MechWarrior4::MWMission& GetMission()
{
	gosREPORT((Adept::Mission::GetInstance() != 0),"The mission object does not exist");
	gosREPORT((Adept::Mission::GetInstance()->IsDerivedFrom(MechWarrior4::MWMission::DefaultData) == true),"The mission object is not the correct type");

	MechWarrior4::MWMission* mission = Cast_Object(MechWarrior4::MWMission*,Adept::Mission::GetInstance());
	Check_Object(mission);
	return (*mission);
}


bool Groups::AllDead(Group::identifier group)
{
	if (Size(group) == 0)
	{
		return (false);
	}

	return (Size(group) == NumDead(group));
}

void Groups::AddObject(Adept::ObjectID object, Group::identifier group)
{
	MWObject* mwobject = GetMWObject(object);

	if (mwobject != 0)
	{
		GetMission().GetGroupContainer().AddObjectToGroup(*mwobject,group);
	}
}

void Groups::RemoveObject(Adept::ObjectID object, Group::identifier group)
{
	MWObject* mwobject = GetMWObject(object);

	if (mwobject != 0)
	{
		GetMission().GetGroupContainer().RemoveObjectFromGroup(*mwobject,group);
	}
}

int Groups::NumDead(Group::identifier group)
{
	gosREPORT((Adept::Application::GetInstance() != 0),"The application object does not exist");
	gosREPORT((NameTable::GetInstance() != 0),"The NameTable object does not exist");
//	gosREPORT((Adept::Application::GetInstance()->networkingFlag == false),"Cannot use group NumDead(), AllDead() functions in multiplayer");

	if (GetMission().GetGroupContainer().GroupExists(group) == false)
	{
		return (0);
	}

	const Group& g = GetMission().GetGroupContainer().GetGroup(group);

	int num_dead = 0;

	{for (Group::element_list::const_iterator i = g.GetElements().begin();
		  i != g.GetElements().end();
		  ++i)
	{
		Adept::Entity* entity = Adept::NameTable::GetInstance()->FindData(*i);

		if ((entity == 0) ||
			(entity->IsDestroyed() == true))
		{
			++num_dead;
		}
	}}
	
	return (num_dead);
}

int Groups::Size(Group::identifier group)
{
	if (GetMission().GetGroupContainer().GroupExists(group) == false)
	{
		return (0);
	}

	const Group& g = GetMission().GetGroupContainer().GetGroup(group);
	return (g.GetElements().size());
}

bool Groups::ContainsObject(Adept::ObjectID object, Group::identifier group)
{
	MWObject* mwobject = GetMWObject(object);

	if (mwobject != 0)
	{
		return (std::find(mwobject->GetGroups().begin(),mwobject->GetGroups().end(),group) != mwobject->GetGroups().end());
	}

	return (false);
}

bool Groups::GetFirstGroup(Adept::ObjectID object, Group::identifier& group_id)
{
	MWObject* v = GetMWObject(object);

	if (v == 0)
	{
		return (false);
	}

	if (v->GetGroups().size() == 0)
	{
		return (false);
	}

	group_id = v->GetGroups()[0];
	return (true);
}

bool Groups::GetFirstObject(Group::identifier group, Adept::ObjectID& object)
{
	if (GetMission().GetGroupContainer().GroupExists(group) == false)
	{
		return (false);
	}

	const Group& g = GetMission().GetGroupContainer().GetGroup(group);
	if (g.GetElements().size() == 0)
	{
		return (false);
	}

	{for (Group::element_list::const_iterator i = g.GetElements().begin();
		  i != g.GetElements().end();
		  ++i)
	{
		MWObject* o = GetMWObject(*i);

		if ((o != 0) &&
			(o->IsDestroyed() == false))
		{
			object = *i;
			return (true);
		}
	}}

	return (false);
}

MechWarrior4::Group& Groups::GetGroup(MechWarrior4::Group::identifier group_id)
{
	Verify(Adept::Mission::GetInstance() != 0);
	Verify(Adept::Mission::GetInstance()->IsDerivedFrom(MechWarrior4::MWMission::DefaultData) == true);
	MechWarrior4::MWMission* mission = Cast_Object(MechWarrior4::MWMission*,Adept::Mission::GetInstance());
	Check_Object(mission);
	Verify(mission->GetGroupContainer().GroupExists(group_id));
	return (mission->GetGroupContainer().GetGroup(group_id));
}

bool IsLancemateGroup(Group::identifier group)
{
	if (GetMission().GetGroupContainer().GroupExists(group) == false)
	{
		return (false);
	}

	const Group& g = GetMission().GetGroupContainer().GetGroup(group);
	if (g.GetElements().size() == 0)
	{
		return (false);
	}

	if (g.HasAI() == false)
	{
		return (false);
	}

	const MW4AI::Squad::AI* group_ai = g.GetAI();

	if (group_ai->GetID() != MW4AI::Squad::GROUPAI_LANCEMATE)
	{
		return (false);
	}

	Adept::Entity* entity = NameTable::GetInstance()->FindData(g.GetElements()[0]);

	if ((entity != 0) &&
		(entity->IsPlayerVehicle() == true))
	{
		return (true);
	}

	return (false);
}

bool Groups::GetLancemateGroup(const std::vector<Group::identifier>& groups, Group::identifier& group_id)
{
	{for (std::vector<Group::identifier>::const_iterator i = groups.begin();
		  i != groups.end();
		  ++i)
	{
		if ((Size(*i) > 0) &&
			(IsLancemateGroup(*i) == true))
		{
			group_id = *i;
			return (true);
		}
	}}

	return (false);
}

bool Groups::GetMember(Group::identifier group, unsigned int index, Adept::ObjectID& object)
{
	if (GetMission().GetGroupContainer().GroupExists(group) == false)
	{
		return (false);
	}

	const Group& g = GetMission().GetGroupContainer().GetGroup(group);
	if (index >= g.GetElements().size())
	{
		return (false);
	}

	object = g.GetElements()[index];
	return (true);
}

void Groups::GetLancemates(std::vector<MWObject*>& lancemates, bool include_player)
{
	if (Adept::Player::GetInstance() == 0)
	{
		return;
	}

	MechWarrior4::MWPlayer* p = Cast_Object(MechWarrior4::MWPlayer*,Adept::Player::GetInstance());
	if (p == 0)
	{
		return;
	}

	Check_Object(p);
	if ((p->GetInterface() == 0) ||
		(p->GetInterface()->vehicle == 0))
	{
		return;
	}

	if (include_player == true)
	{
		lancemates.push_back(p->GetInterface()->vehicle);
	}

	{for (std::vector<Group::identifier>::const_iterator i = p->GetInterface()->vehicle->GetGroups().begin();
		  i != p->GetInterface()->vehicle->GetGroups().end();
		  ++i)
	{
		if ((Size(*i) > 0) &&
			(IsLancemateGroup(*i) == true))
		{
			const Group& g = GetMission().GetGroupContainer().GetGroup(*i);

			{for (int index = 1;
				  index < g.GetElements().size();
				  ++index)
			{
				Adept::Entity* entity = Adept::NameTable::GetInstance()->FindData(g.GetElements()[index]);
				if ((entity != 0) &&
					(entity->IsDerivedFrom(MWObject::DefaultData) == true))
				{
					MWObject* mwobject = Cast_Object(MWObject*,entity);
					lancemates.push_back(mwobject);
				}
			}}

			return;
		}
	}}
}

void Groups::GetGroupmates(const Adept::ObjectID& of_who, std::vector<MWObject*>& groupmates)
{
	Adept::Entity* entity = Adept::NameTable::GetInstance()->FindData(of_who);
	if ((entity == 0) ||
		(entity->IsDerivedFrom(MWObject::DefaultData) == false))
	{
		return;
	}

	const GroupContainer& gc = GetMission().GetGroupContainer();

	MWObject* mwobject = Cast_Object(MWObject*,entity);
	{for (MWObject::GroupList::const_iterator i = mwobject->GetGroups().begin();
		  i != mwobject->GetGroups().end();
		  ++i)
	{
		std::vector<MWObject*> group_members;
		gc.GetGroup(*i).GetMembers(group_members);

		{for (std::vector<MWObject*>::const_iterator i_members = group_members.begin();
			  i_members != group_members.end();
			  ++i_members)
		{
			if (((*i_members)->objectID != of_who) &&
				(std::find(groupmates.begin(),groupmates.end(),*i_members) == groupmates.end()))
			{
				groupmates.push_back(*i_members);
			}
		}}
	}}
}

void Groups::NotifyPlayerFocusedOnEntity(MechWarrior4::MWObject& player_vehicle, Adept::Entity& entity)
{
	if ((entity.IsDestroyed() == true) ||
		(player_vehicle.IsDestroyed() == true) ||
		(entity.GetAlignment() == player_vehicle.GetAlignment()) ||
		(&entity == Adept::Map::GetInstance()))
	{
		return;
	}

	GroupContainer& gc = GetMission().GetGroupContainer();

	{for (MWObject::GroupList::const_iterator i = player_vehicle.GetGroups().begin();
		  i != player_vehicle.GetGroups().end();
		  ++i)
	{
		MW4AI::Squad::AI* squad_ai = gc.GetGroup(*i).GetAI();
		if (squad_ai != 0)
		{
			squad_ai->SetEntityToIgnore(entity.objectID);
		}
	}}
}
