#include "MW4Headers.hpp"

#include "Objective.hpp"

#include <Adept\EntityClassData.hpp>
#include "ai_userconstants.hpp"
#include "AI_Statistics.hpp"
#include "mwguimanager.hpp"
#include "hudobj.hpp"
#include "hudhelp.hpp"
#include "mwapplication.hpp"

// MSL 5.05 Objective
bool g_bObjMode;

int CountVisibleObjectives (void)
{
	int toret,size,j;
	Objective *obj;
	NameTable *table = NameTable::GetInstance();

	toret = 0;
	Check_Object (table);
	size = table->nameTableArray[NameTable::ObjectiveArray].GetLength ();
	for (j=0;j<size;j++)
	{
		NameTableEntry *data;
		Entity *ent;

		data = &table->nameTableArray [NameTable::ObjectiveArray][j];
		ent = data->dataPointer->GetCurrent ();
		if (ent)
		{
			Verify (ent->IsDerivedFrom (Objective::DefaultData));
			obj = Cast_Object (Objective *,ent);
			if (obj->Visible ())
				toret++;
		}
	}
	return toret;
}

const char* ObjectiveText (int id)
{
	int index,size,j;
	Objective *obj;
	NameTable *table = NameTable::GetInstance();

	index = 0;
	size = table->nameTableArray[NameTable::ObjectiveArray].GetLength ();
	for (j=0;j<size;j++)
	{
		NameTableEntry *data;
		Entity *ent;

		data = &table->nameTableArray [NameTable::ObjectiveArray][j];
		ent = data->dataPointer->GetCurrent ();
		if (ent)
		{
			Verify (ent->IsDerivedFrom (Objective::DefaultData));
			obj = Cast_Object (Objective *,ent);
			if (obj->Visible ())
			{
				if (index == id)
					return obj->CurrentText ();
				index++;
			}
		}
	}
	return NULL;
}


//#############################################################################
//###############################    Objective    #############################
//#############################################################################

Objective::ClassData* Objective::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Objective::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
	new ClassData(
							 ObjectiveClassID,
							 "MechWarrior4::Objective",
							 Entity::DefaultData,
							 0, NULL,
							 (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 Objective::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Objective* Objective::Make(CreateMessage *message,ReplicatorID *base_id)
{
	Check_Object(message);
	gos_PushCurrentHeap(Heap);
	Objective *new_entity = new Objective(DefaultData, message, base_id, NULL);
	gos_PopCurrentHeap();
	Check_Object(new_entity);
	return new_entity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Objective::Objective(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element) :
Entity(class_data, message, base_id, element)
{
	Check_Pointer(this);
	Check_Object(message);
	m_ObjectiveID = message->objectiveID;
	m_Primary = message->primaryObjective;

	m_FailText[0] = 0;
	m_SucceedText[0] = 0;
	m_NeutralText[0] = 0;
	m_DescriptionText[0] = 0;
	MWApplication *app;
	
	m_FailTextID = message->failtextID;
	m_SucceedTextID = message->succeedtextID;
	m_NeutralTextID = message->neutraltextID;
	m_DescriptionTextID = message->descriptiontextID;
	
	char *text;
	app = MWApplication::GetInstance ();

	Str_Copy (m_LoadedFailText,message->failtext,sizeof (m_LoadedFailText));
	Str_Copy (m_LoadedSucceedText,message->succeedtext,sizeof (m_LoadedSucceedText));
	Str_Copy (m_LoadedNeutralText,message->neutraltext,sizeof (m_LoadedNeutralText));
	Str_Copy (m_LoadedDescriptionText,message->descriptiontext,sizeof (m_LoadedDescriptionText));

	text = app->GetLocString (m_FailTextID);
	if (m_FailTextID>0 && ((text) || (text[0] == 0)))
		Str_Copy (m_FailText,text,sizeof (m_FailText));
	else
		Str_Copy (m_FailText,message->failtext,sizeof (m_FailText));

	text = app->GetLocString (m_SucceedTextID);
	if (m_SucceedTextID>0 && ( (text) || (text[0] == 0)))
		Str_Copy (m_SucceedText,text,sizeof (m_SucceedText));
	else
		Str_Copy (m_SucceedText,message->succeedtext,sizeof (m_SucceedText));

	text = app->GetLocString (m_NeutralTextID);
	if (m_NeutralTextID>0 && ( (text) || (text[0] == 0)))
		Str_Copy (m_NeutralText,text,sizeof (m_NeutralText));
	else
		Str_Copy (m_NeutralText,message->neutraltext,sizeof (m_NeutralText));
	text = app->GetLocString (m_DescriptionTextID);
	if (m_DescriptionTextID>0 && ( (text) || (text[0] == 0)))
		Str_Copy (m_DescriptionText,text,sizeof (m_DescriptionText));
	else
		Str_Copy (m_DescriptionText,message->descriptiontext,sizeof (m_DescriptionText));

	m_VisibleObjective = message->visibleObjective;
	m_ObjectiveState = message->objectiveState;
	m_Primary = message->primaryObjective;
	m_HelpMessage = message->helpMessage;


//	font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0);
	if (m_VisibleObjective)
	{
		m_VisibleObjective = false;
		Reveal();

	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Objective::~Objective()
{
}

void Objective::SetName (const char *name,bool resettext)
{
	m_FailText[0] = 0;
	m_SucceedText[0] = 0;
	m_NeutralText[0] = 0;
	m_DescriptionText[0] = 0;

	if (m_HelpMessage)
	{
		sprintf (m_FailText,"%s",name);
		sprintf (m_SucceedText,"%s",name);
		sprintf (m_NeutralText,"%s",name);
		sprintf (m_DescriptionText,"%s",name);
	}
	else
	{
		sprintf (m_FailText,"Failed: %s",name);
		sprintf (m_SucceedText,"Succeeded: %s",name);
		sprintf (m_NeutralText,"Incomplete: %s",name);
		sprintf (m_DescriptionText,"Description: %s",name);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage* Objective::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
	Check_Object(this);
	Check_Object(stream);

	//
	//---------------------------------------------------------------------
	// Make sure there is enough room for the factory request on the stream
	//---------------------------------------------------------------------
	//
	stream->AllocateBytes(sizeof(CreateMessage));
	Entity::SaveMakeMessage(stream, res_file);
	CreateMessage *message = Cast_Pointer(CreateMessage*, stream->GetPointer());

	message->objectiveID = m_ObjectiveID;

	message->messageLength = sizeof(*message);

	return message;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Objective::PreCollisionExecute(Time till)
{
	Check_Object(this);
	Check_Object(executionState);
	Check_Object(ObjectiveRenderer::Instance);
	PRECOLLISION_LOGIC("Objective");

	executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void Objective::DrawObjective(Scalar x_loc, Scalar y_loc)
{
	Check_Object(this);
	int x_location = (int)(x_loc * Environment.screenWidth);
	int y_location = (int)(y_loc * Environment.screenHeight);

	DisplayText(CurrentText (), x_location, y_location);
}


bool Objective::HelpMessage (void)
{
	return m_HelpMessage;
}

void Objective::Succeed (void)
{
	if (m_ObjectiveState == Objective_Succeeded)
		return;
	m_ObjectiveState = Objective_Succeeded;
	if (!m_VisibleObjective)
		return;

	ObjectiveRenderer::Instance->ResetTime ();

	#ifdef LAB_ONLY
	if (MW4AI::Statistics::Enabled() == true)
	{
		MW4AI::Statistics::NotifyObjective(m_DescriptionText,true);
	}
	#endif
}

void Objective::Fail (void)
{
	if (m_ObjectiveState == Objective_Failed)
		return;
	m_ObjectiveState = Objective_Failed;
	if (!m_VisibleObjective)
		return;

	ObjectiveRenderer::Instance->ResetTime ();

	#ifdef LAB_ONLY
	if (MW4AI::Statistics::Enabled() == true)
	{
		MW4AI::Statistics::NotifyObjective(m_DescriptionText,false);
	}
	#endif
}

void Objective::Reveal (void)
{
	if (m_VisibleObjective)
		return;

	Check_Object(ObjectiveRenderer::Instance);
	m_VisibleObjective = true;
	ObjectiveRenderer::Instance->ResetTime ();
}

void Objective::Hide (void)
{
	if (!m_VisibleObjective)
		return;

	Check_Object(executionState);
	Check_Object(ObjectiveRenderer::Instance);

	m_VisibleObjective = false;
}

int Objective::Status (void)
{
	return m_ObjectiveState;
}

bool Objective::Visible (void)
{
	return m_VisibleObjective;
}
const char *Objective::CurrentText (bool ignorevisual)
{
	if (m_HelpMessage)
		return m_SucceedText;

	if (!m_VisibleObjective && !ignorevisual)
		return NULL;

	switch (m_ObjectiveState)
	{
		case Objective_Failed:
			return m_FailText;
			break;
		case Objective_Succeeded:
			return m_SucceedText;
			break;
		case Objective_Neutral:
			return m_NeutralText;
			break;
	}
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Objective::ShowHelp (Stuff::Time time)
{
	Check_Object(ObjectiveRenderer::Instance);
	ObjectiveRenderer::Instance->Help (this,time);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Objective::DisplayText(const char *text_string, int x_loc, int y_loc)
{
#if 0
	if (!text_string)
		return;

	Check_Object(this);
	Check_Pointer(text_string);

	gos_TextSetRegion(0, 0, Environment.screenWidth, Environment.screenHeight);
	gos_TextSetAttributes(font,0xFFFFFFFF,1.0f,false,true,false,false);
	gos_TextSetPosition(x_loc, y_loc);
	gos_TextDraw(text_string);

#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Objective::DrawTextWindow()
{
	Check_Object(this);

#if 0
	gos_SetRenderState( gos_State_Texture, 0 );
	gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha );
	gos_SetRenderState( gos_State_Clipping, 0 );
	gos_SetRenderState( gos_State_ZWrite, 0 );
	gos_SetRenderState( gos_State_Filter, gos_FilterNone );
	gos_SetRenderState( gos_State_ZCompare, 0 );
	gos_SetRenderState( gos_State_WireframeMode, 0 );
	gos_SetRenderState( gos_State_Specular, 0 );
	gos_SetRenderState( gos_State_Dither, 0 );
	gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat );
	gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
	gos_SetRenderState( gos_State_AlphaTest, 0 );
	gos_SetRenderState( gos_State_Fog, 0 );
#endif

	//First we need to Draw the Quad for the Window
	gos_VERTEX quad_verticies[4];
	memset(quad_verticies, 0, sizeof(quad_verticies));

	quad_verticies[0].rhw = 1.0;
	quad_verticies[1].rhw = 1.0;
	quad_verticies[2].rhw = 1.0;
	quad_verticies[3].rhw = 1.0;

	quad_verticies[0].x   = (0.02f * Environment.screenWidth);
	quad_verticies[0].y   = (0.02f * Environment.screenHeight);
	quad_verticies[0].z   = 0.9f;
	quad_verticies[0].argb  = 0x77aaaaaa;

	quad_verticies[1].x   = (0.25f * Environment.screenWidth);
	quad_verticies[1].y   = (0.02f * Environment.screenHeight);
	quad_verticies[1].z   = 0.9f;
	quad_verticies[1].argb  = 0x77aaaaaa;

	quad_verticies[2].x   = (0.25f * Environment.screenWidth);
	quad_verticies[2].y   = (0.12f * Environment.screenHeight);
	quad_verticies[2].z   = 0.9f;
	quad_verticies[2].argb  = 0x77aaaaaa;

	quad_verticies[3].x   = (0.02f * Environment.screenWidth);
	quad_verticies[3].y   = (0.12f * Environment.screenHeight);
	quad_verticies[3].z   = 0.9f;
	quad_verticies[3].argb  = 0x77aaaaaa;

	gos_DrawQuads(quad_verticies, 4);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Objective::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}

int CountObjectives (void);
const char* ObjectiveText (int id);


//#############################################################################
//##########################    ObjectiveRenderer       #######################
//#############################################################################

ObjectiveRenderer *ObjectiveRenderer::Instance = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ObjectiveRenderer::ObjectiveRenderer() :
Plug(Plug::DefaultData)
{
	m_HelpStartTime = gos_GetElapsedTime ();
	m_StartTime = gos_GetElapsedTime ();
	MW4AI::UserConstants *data;
	data = MW4AI::UserConstants::Instance ();
	m_ShowHelp = false;
	if (!data)
	{
		m_DelayTime = 10;
		m_HelpDelayTime = 0;
	}
	else
	{
		m_DelayTime	= data->Get (MW4AI::UserConstants::objective_display_time);
		m_HelpDelayTime	= 0;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ObjectiveRenderer::~ObjectiveRenderer()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void ObjectiveRenderer::Help (Objective *helpmessage,Stuff::Time delay)
{
	m_HelpStartTime = gos_GetElapsedTime ();
	if (helpmessage == NULL)
	{
		m_HelpDelayTime = 0;
		m_ShowHelp = false;
		MWGUIManager::GetInstance ()->HideHudComponent (MWGUIManager::HUD_HELP);
		return;
	}
	if (delay > 0)
	{
		m_HelpDelayTime = delay;
//		m_DelayTime = delay;
	}
	m_ShowHelp = true;
	HUDComponent *hud = MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_HELP);
	HUDHelp *help = Cast_Object (HUDHelp *,hud);
	help->NewMessage (helpmessage);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void ObjectiveRenderer::ToggleObjective (void)
{
	g_bObjMode = !g_bObjMode;

/*	if ((gos_GetElapsedTime () - m_StartTime) >= m_DelayTime)
	{
		ResetTime ();
	}
	else
	{
		m_StartTime = gos_GetElapsedTime () - m_DelayTime - 1.0;
	}
*/
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void ObjectiveRenderer::ResetTime (void)
{
	m_StartTime = gos_GetElapsedTime ();
	MW4AI::UserConstants *data;
	data = MW4AI::UserConstants::Instance ();
	if (!data)
	{
		m_DelayTime = 10;
	}
	else
	{
		m_DelayTime	= data->Get (MW4AI::UserConstants::objective_display_time);
	}
}

void ObjectiveRenderer::Execute()
{
	Check_Object(this);

	if (g_bObjMode == true)
	{
		MWGUIManager::GetInstance ()->HideHudComponent (MWGUIManager::HUD_OBJECTIVE);
//		MW4AI::UserConstants *data;
//		data = MW4AI::UserConstants::Instance ();
//		if (!data)
//			m_DelayTime = 10;
//		else
//			m_DelayTime	= data->Get (MW4AI::UserConstants::objective_display_time);
		return;
	}
	else
	{
		MWGUIManager::GetInstance ()->ShowHudComponent (MWGUIManager::HUD_OBJECTIVE);
	}
/*
	if ((gos_GetElapsedTime () - m_StartTime) >= m_DelayTime)
	{
		MWGUIManager::GetInstance ()->HideHudComponent (MWGUIManager::HUD_OBJECTIVE);
		MW4AI::UserConstants *data;
		data = MW4AI::UserConstants::Instance ();
		if (!data)
			m_DelayTime = 10;
		else
			m_DelayTime	= data->Get (MW4AI::UserConstants::objective_display_time);
		return;
	}
	else
	{
		MWGUIManager::GetInstance ()->ShowHudComponent (MWGUIManager::HUD_OBJECTIVE);
	}
*/	
	if (((gos_GetElapsedTime () - m_HelpStartTime) >= m_HelpDelayTime) || (!m_ShowHelp))
	{
		m_ShowHelp = false;
		MWGUIManager::GetInstance ()->HideHudComponent (MWGUIManager::HUD_HELP);
		MW4AI::UserConstants *data;
		data = MW4AI::UserConstants::Instance ();
		if (!data)
			m_HelpDelayTime = 10;
		else
			m_HelpDelayTime	= data->Get (MW4AI::UserConstants::objective_display_time);
		return;
	}
	else
	{
		MWGUIManager::GetInstance ()->ShowHudComponent (MWGUIManager::HUD_HELP);
	}
}


//#############################################################################
//##########################    ExecutionStateEngine    #######################
//#############################################################################

Objective::ExecutionStateEngine::ClassData*
Objective::ExecutionStateEngine::DefaultData = NULL;

const StateEngine::StateEntry
Objective::ExecutionStateEngine::StateEntries[]=
{
	STATE_ENTRY(Objective__ExecutionStateEngine, Revealed)
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Objective::ExecutionStateEngine::InitializeClass()
{
	Check_Object(StateEngine::DefaultData);
	Verify(!DefaultData);
	DefaultData =
	new ClassData(
							 Objective__ExecutionStateEngineClassID,
							 "Objective::ExecutionStateEngine",
							 Entity::ExecutionStateEngine::DefaultData,
							 ELEMENTS(StateEntries), StateEntries,
							 (Entity::ExecutionStateEngine::Factory)Make,
							 (Entity::ExecutionStateEngine::FactoryRequest::Factory)
							 &FactoryRequest::ConstructFactoryRequest
							 );
	Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Objective::ExecutionStateEngine::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Objective::ExecutionStateEngine*
Objective::ExecutionStateEngine::Make(
																		 Objective *objective,
																		 FactoryRequest *request
																		 )
{
	Check_Object(objective);
	Check_Object(request);
	gos_PushCurrentHeap(Heap);
	Objective::ExecutionStateEngine *engine =
	new Objective::ExecutionStateEngine(DefaultData, objective, request);
	gos_PopCurrentHeap();
	return engine;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Objective::ExecutionStateEngine::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}
