//===========================================================================//
// File:	MechAI.cpp														 //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 07/13/99  AHF  Created file												 //
//---------------------------------------------------------------------------//
// Copyright (C) 1999, Microsoft										     //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "MW4Headers.hpp"
#include "Adept\AdeptHeaders.hpp"

#include "mw4.hpp"
#include "mech_ai.hpp"
#include "Adept\Interface.hpp"
#include "Adept\Application.hpp"
#include "Vehicle.hpp"
#include "lancemate.hpp"
#include "gameinfo.hpp"
#include "field_base.hpp"
#include "vehicleinterface.hpp"

using namespace MechWarrior4;
using namespace MW4AI;

std::list<MechAI*>* MechAI::m_gShutdownMechAIs = 0;
int MechAI::m_gShutdownMechAIs_RefCount = 0;

//#############################################################################
//###############################    AI      ##################################
//#############################################################################

MechAI::ClassData* MechAI::DefaultData = NULL;

const Receiver::MessageEntry MechAI::MessageEntries[]=
{
	MESSAGE_ENTRY(MechAI, DebugText),
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechAI::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
	new ClassData(
							 MechAIClassID,
							 "MechWarrior4::MechAI",
							 CombatAI::DefaultData,
							 ELEMENTS(MessageEntries), MessageEntries,
							 (Entity::Factory)Make,
							 (Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
							 ExecutionStateEngine::DefaultData,
							 (Entity::GameModel::Factory)GameModel::ConstructGameModel,
							 NULL,
							 (Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
							 (Entity::GameModel::ModelWrite)GameModel::WriteToText,
							 (Entity::GameModel::ModelSave)GameModel::SaveGameModel
							 );
	Register_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechAI::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MechAI* MechAI::Make(CreateMessage *message,ReplicatorID *base_id)
{
	AutoHeap local_heap (g_AIHeap);
	Check_Object(message);
	MechAI *new_entity = new MechAI(DefaultData, message, base_id, NULL);
	Check_Object(new_entity);
	new_entity->SyncMatrices(true);
	return new_entity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MechAI::MechAI(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element)
: CombatAI(class_data, message, base_id, element)
{
	Check_Pointer(this);
	Check_Object(message);

	m_Mech = NULL;

	if (Network::GetInstance()->AmIServer())
	{

		Check_Object(vehicle);
		m_Mech = Cast_Object(Mech *, getEntity ());
		Check_Object (m_Mech);
	}

	if (m_gShutdownMechAIs_RefCount == 0)
	{
		Verify(m_gShutdownMechAIs == 0);
		m_gShutdownMechAIs = new std::list<MechAI*>;
	}

	++m_gShutdownMechAIs_RefCount;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MechAI::~MechAI()
{
	Verify(m_gShutdownMechAIs_RefCount > 0);
	Verify(m_gShutdownMechAIs != 0);

	std::list<MechAI*>::iterator found = std::find(m_gShutdownMechAIs->begin(),m_gShutdownMechAIs->end(),this);
	if (found != m_gShutdownMechAIs->end())
	{
		m_gShutdownMechAIs->erase(found);
	}

	--m_gShutdownMechAIs_RefCount;
	if (m_gShutdownMechAIs_RefCount == 0)
	{
		delete m_gShutdownMechAIs;
		m_gShutdownMechAIs = 0;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechAI::PreCollisionExecute(Time till)
{
  extern int g_nMR;
   if (g_nMR == 2)
       return;
	AI_LOGIC("Pre-Collision::MechAI");
	Check_Object(this);
#if defined(LAB_ONLY)
		if (!instanceName)
			MWGameInfo::g_LastMWObject[0] = '\0';
		else
		{
			strncpy(MWGameInfo::g_LastMWObject, instanceName, sizeof(MWGameInfo::g_LastMWObject)-1);
			MWGameInfo::g_LastMWObject[sizeof(MWGameInfo::g_LastMWObject)-1] = '\0';
		}
		MWGameInfo::g_LastMWObjectPos = GetLocalToWorld();
#endif

	//
	//---------------------------------
	// Verify that this always executes
	//---------------------------------
	//


	Check_Object(executionState);
	Verify(executionState->GetState() != ExecutionStateEngine::NeverExecuteState);
	if (m_StartupRequest)
		Startup ();
	if (m_ShutdownRequest)
		Shutdown ();

	inherited::PreCollisionExecute(till);
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechAI::DebugTextMessageHandler(Adept::ReceiverDataMessageOf<int> *message)
{
	Check_Object(this);
	Check_Object(message);
	Verify(message->messageID == DebugTextMessageID);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool MechAI::ReactToCollision(Stuff::DynamicArrayOf<CollisionData> *collisions,bool& shoulddamage)
{
	int i;

	if (m_EnteringFieldBase != FIELDBASE_NOT_ACTIVE)
	{
		return inherited::ReactToCollision (collisions,shoulddamage);
	}

	for (i=0; i<collisions->GetLength(); ++i)
	{
		CollisionData *data = &(*collisions)[i];

		Check_Object(data);
		Check_Object(data->m_otherEntity);
		Verify(this != data->m_otherEntity);
		Verify(GetInterestLevel() != DormantInterestLevel);
		Check_Object(m_Vehicle);
	
		Vector3D vector_to_target;
		Point3D local_to_world(m_Vehicle->GetLocalToWorld());
		Point3D target_local_to_world(data->m_otherEntity->GetLocalToWorld());
		if (data->m_otherEntity->IsDerivedFrom (FieldBase::DefaultData))
		{
			if (!CreateFieldBasePoints (Cast_Object (FieldBase *,data->m_otherEntity)))
			{
				if (!m_Vehicle->vehicleInterface)
				{
					ClearMoveOrder ();
				}
				shoulddamage = false;
				return inherited::ReactToCollision (collisions,shoulddamage);
			}
			if (m_Vehicle->vehicleInterface)
			{
				m_Vehicle->vehicleInterface->PlayerAIFieldBase (true);
			}
			PrepareEnterFieldBase ();
			shoulddamage = false;
		}
	}
	return inherited::ReactToCollision (collisions,shoulddamage);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechAI::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}

void MechAI::SetOrderSpeed (Stuff::Scalar newvalue)
{
	if (newvalue < 0)
	{
		Mech *mech;
		mech = Cast_Object (Mech *,m_Vehicle);
		if (mech->gimpState != Mech::NotGimpedMode)
			newvalue = -newvalue;
	}
	m_OrderSpeed = newvalue;
}

void MechAI::Shutdown (void)
{
	Check_Object (m_Mech);
	m_StartupRequest = false;
	if (!m_Mech->ShutDownRequest (true))
		m_ShutdownRequest = true;
	else
		m_ShutdownRequest	= false;
	inherited::Shutdown ();

	if (m_gShutdownMechAIs != 0)
	{
		std::list<MechAI*>::iterator found = std::find(m_gShutdownMechAIs->begin(),m_gShutdownMechAIs->end(),this);

		if (found == m_gShutdownMechAIs->end())
		{
			m_gShutdownMechAIs->push_back(this);
		}
	}
}

void MechAI::Startup (void)
{
	Check_Object (m_Mech);
	m_ShutdownRequest = false;
	if (!m_Mech->ShutDownRequest (false))
		m_StartupRequest = true;
	else
		m_StartupRequest = false;
	inherited::Startup ();

	if (m_gShutdownMechAIs != 0)
	{
		std::list<MechAI*>::iterator found = std::find(m_gShutdownMechAIs->begin(),m_gShutdownMechAIs->end(),this);
		if (found != m_gShutdownMechAIs->end())
		{
			m_gShutdownMechAIs->erase(found);
		}
	}
}

void MechAI::Save (MemoryStream *stream)
{
	*stream << m_StartupRequest;
	*stream << m_ShutdownRequest;
	CombatAI::Save (stream);
}

void MechAI::Load (MemoryStream *stream)
{
	*stream >> m_StartupRequest;
	*stream >> m_ShutdownRequest;
	CombatAI::Load (stream);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechAI::NotifyShutDownMechsShotFired(const Adept::Entity::CollisionQuery& query, MWObject& shooter)
{
	if (m_gShutdownMechAIs == 0)
	{
		return;
	}

	{for (std::list<MechAI*>::iterator i = m_gShutdownMechAIs->begin();
		  i != m_gShutdownMechAIs->end();
		  ++i)
	{
		(*i)->NotifyShotFired(query,shooter);
	}}
}

bool MechAI::ShouldRunScript()
{
	if (m_SquadOrders.GetPointer() != 0)
	{
		return (m_SquadOrders->ShouldRunScript());
	}

	return (inherited::ShouldRunScript());
}

bool MechAI::GetLeaderAlignment(int& alignment)
{
	if (m_SquadOrders.GetPointer() != 0)
	{
		return (m_SquadOrders->GetLeaderAlignment(alignment));
	}

	return (inherited::GetLeaderAlignment(alignment));
}
