#include "MW4Headers.hpp"

#include "AI_DebugRenderer.hpp"
#include <Adept\EntityManager.hpp>
#include <Adept\CameraComponent.hpp>
#include <Adept\VideoRenderer.hpp>
#include "CombatAI.hpp"
#include "MWDamageObject.hpp"
#include <MW4\MWMission.hpp>
#include <ElementRenderer\StateChange.hpp>
#include "AIUtils.hpp"
#include "MWPlayer.hpp"
#include "VehicleInterface.hpp"
#include <stdlib.h>
#include "rail_move.hpp"
#include "Flag.hpp"
#include <GameOS\ToolOS.hpp>



using namespace MW4AI;
using namespace MechWarrior4;

extern MW4AI::CPathManager *g_PathManager;

const Stuff::Scalar max_distance_from_camera_to_draw = 500.0f;
const Stuff::Scalar max_distance_from_camera_to_draw_squared = max_distance_from_camera_to_draw * max_distance_from_camera_to_draw;

const int max_line_cloud_points = 500;

const int wheel_move_pixels = 32;
const int max_wheel_move_pixels = 1000;

const unsigned int max_spew_files = 2000;

DebugRenderer* DebugRenderer::m_Instance = 0;




MechWarrior4::CombatAI* GetCombatAI(MechWarrior4::MWObject& v)
{
	Verify(&v != 0);

	if ((v.GetAI() == 0) ||
		(v.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == false))
	{
		return (0);
	}

	CombatAI* combat_ai = Cast_Object(CombatAI*,v.GetAI());
	Check_Object(combat_ai);

	return (combat_ai);
}

MechWarrior4::CombatAI* GetCombatAI()
{
	if (Adept::Player::GetInstance() == 0)
	{
		return (0);
	}

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

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

	return (GetCombatAI(*(p->GetInterface()->vehicle)));
}


DebugRenderer::DebugRenderer()
	: m_AIStatsRendering(STATS_NONE)
	, m_DrawingMovementLines(false)
	, m_DrawingMovementPaths(false)
	, m_DamageInfoRendering(false)
	, m_PointCount(0)
	, m_DeadReckoningRenderTime(0)
	, m_ShowNumPathRequests(false)
	, m_WheelDelta(0)
	, m_LastDiagnosticSpewFileIndex(0)
{
	Verify(m_Instance == 0);
	m_Instance = this;

	gos_PushCurrentHeap(ElementRenderer::g_Heap);
	m_LineCloud = new ElementRenderer::LineCloudElement(max_line_cloud_points);
	gos_PopCurrentHeap();
	m_LineCloud->SetDataPointers(&m_PointCount, m_PointData, m_ColorData);
	m_LineCloud->m_localOBB.localToParent = LinearMatrix4D::Identity;
	m_LineCloud->m_localOBB.sphereRadius = -1;
	Mission::GetInstance()->GetElement()->AttachChild(m_LineCloud);
}

DebugRenderer::~DebugRenderer()
{
	Verify(m_Instance != 0);
	m_Instance = 0;
}

void DebugRenderer::Execute()
{
	#ifdef _ARMOR
	try
	{
	#endif
		ResetLinesToDraw();

		if ((GetAIStatsRendering() != STATS_NONE) ||
			(GetDamageInfoRendering() == true))
		{
			DrawAIStatsAndDamageInfo();
		}

		if ((GetMovementLineRendering() == true) ||
			(GetDeadReckoningRendering() == true))
		{
			DrawLines();
		}

		if (GetMovementPathRendering() == true)
		{
			DrawMovementPaths();
		}

		if (GetShowNumPathRequests() == true)
		{
			DrawNumPathRequests();
		}

		if (GetDiagnosticsRendering() == true)
		{
			DrawDiagnostics();
		}
	#ifdef _ARMOR
	}
	catch (...)
	{
	}
	#endif
}

void DebugRenderer::DrawAIStatsAndDamageInfo()
{
	Verify((GetAIStatsRendering() != STATS_NONE) || (GetDamageInfoRendering() == true));

	#ifdef LAB_ONLY
	if ((Adept::EntityManager::GetInstance() == 0) ||
		(Adept::VideoRenderer::Instance == 0))
	{
		return;
	}
	Check_Object(Adept::EntityManager::GetInstance());
	Check_Object(Adept::VideoRenderer::Instance);

	CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera();
	if ((camera == 0) ||
		(camera->GetElement() == 0))
	{
		return;
	}
	Check_Object(camera);

	Point3D camera_pos = (Point3D)camera->GetElement()->GetLocalToWorld();

	HGOSFONT3D font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0);

	gos_TextSetAttributes(font,0x8FFF0000,1.0f,false,true,false,false);

	std::vector<Adept::Entity*> entities_to_consider;

	NameTable *table = NameTable::GetInstance();
	int size(table->nameTableArray[NameTable::VehicleArray].GetLength());

	{for (int i = 0;
		  i < size;
		  ++i)
	{
		NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
		Adept::Entity* ent = data->dataPointer->GetCurrent ();

		if ((ent != 0) &&
			(ent->IsDerivedFrom(MWObject::DefaultData) == true))
		{
			entities_to_consider.push_back(Cast_Object(MWObject*,ent));
		}
	}}

	if (Adept::NameTable::GetInstance() != 0)
	{
		{
			int last = Adept::NameTable::GetInstance()->GetLength(Adept::NameTable::BuildingArray);

			{for (int i = 0;
				  i < last;
				  ++i)
			{
				NameTableEntry* entry = Adept::NameTable::GetInstance()->FindEntry(Adept::NameTable::BuildingArray,i);
				if ((entry != 0) &&
					(entry->dataPointer->GetCurrent() != 0))
				{
					Adept::Entity* entity = entry->dataPointer->GetCurrent();

					if (entity->IsDerivedFrom(MWObject::DefaultData) == true)
					{
						MWObject* mwobject = Cast_Object(MWObject*,entity);

						if (mwobject->GetAI() != 0)
						{
							entities_to_consider.push_back(mwobject);
						}
					}
				}
			}}
		}

		{
			int last = Adept::NameTable::GetInstance()->GetLength(Adept::NameTable::TurretArray);

			{for (int i = 0;
				  i < last;
				  ++i)
			{
				NameTableEntry* entry = Adept::NameTable::GetInstance()->FindEntry(Adept::NameTable::TurretArray,i);
				if ((entry != 0) &&
					(entry->dataPointer->GetCurrent() != 0))
				{
					Adept::Entity* entity = entry->dataPointer->GetCurrent();

					if (entity->IsDerivedFrom(MWObject::DefaultData) == true)
					{
						entities_to_consider.push_back(entity);
					}
				}
			}}
		}
	}

	{
		int size(Adept::NameTable::GetInstance()->nameTableArray[NameTable::FlagArray].GetLength());

		{for (int i = 0;
			  i < size;
			  ++i)
		{
			NameTableEntry *data = &Adept::NameTable::GetInstance()->nameTableArray [NameTable::FlagArray][i];
			Adept::Entity* ent = data->dataPointer->GetCurrent();

			if ((ent != 0) &&
				(ent->IsDerivedFrom(Flag::DefaultData) == true))
			{
				entities_to_consider.push_back(ent);
			}
		}}
	}

	{for (std::vector<Adept::Entity*>::const_iterator i = entities_to_consider.begin();
		  i != entities_to_consider.end();
		  ++i)
	{
		Point3D pos = (Point3D)(*i)->GetLocalToWorld();

		Vector3D delta_from_camera;
		delta_from_camera.Subtract(pos,camera_pos);
		delta_from_camera.y = 0;

		if (delta_from_camera.GetLengthSquared() > max_distance_from_camera_to_draw_squared)
		{
			continue;
		}

		Stuff::Vector2DOf<Stuff::Scalar> screen_pos;
		if (WorldToScreenCoords(pos,screen_pos) == false)
		{
			continue;
		}

		screen_pos.x *= Environment.screenWidth;
		screen_pos.y *= Environment.screenHeight;

		if ((screen_pos.x >= Environment.screenWidth) ||
			(screen_pos.y >= Environment.screenHeight))
		{
			continue;
		}

		if (PositionIsInFrontOfCamera(pos) == false)
		{
			continue;
		}

		int alpha = 0xFF000000 - ((int)((DistanceFromCamera(pos) * 200.0f) / max_distance_from_camera_to_draw) << 24);
		int color = 0;
		switch ((*i)->objectID & 0x00000007)
		{
			case 1:  color = 0x008F8F8F;  break;
			case 2:  color = 0x0000008F;  break;
			case 3:  color = 0x00008F00;  break;
			case 4:  color = 0x008F0000;  break;
			case 5:  color = 0x008F008F;  break;
			case 6:  color = 0x00008F8F;  break;
			case 7:  color = 0x008F8F00;  break;
		}
		gos_TextSetAttributes(font,alpha + color,1.0f,false,true,false,false);

		gos_TextSetRegion((int)screen_pos.x,(int)screen_pos.y,Environment.screenWidth,Environment.screenHeight);
		gos_TextSetPosition((int)screen_pos.x,(int)screen_pos.y);

		std::string s;

		if ((*i)->IsDerivedFrom(MWObject::DefaultData) == true)
		{
			MWObject* mwobject = Cast_Object(MWObject*,*i);
			if ((GetAIStatsRendering() == STATS_ALL) ||
				((GetAIStatsRendering() == STATS_CURRENT_VEHICLE) && (mwobject->GetAI() == GetCombatAI())))
			{
				mwobject->AddStatsToString(s);

				if (mwobject->GetAI() != 0)
				{
					mwobject->GetAI()->AddStatsToString(s);
				}
			}

			if (GetDamageInfoRendering() == true)
			{
				mwobject->AddDamageInfoToString(s);
			}
		}
		else
		{
			if ((*i)->IsDerivedFrom(Flag::DefaultData) == true)
			{
				Flag* flag = Cast_Object(Flag*,*i);
				flag->AddStatsToString(s);
			}
		}

		gos_TextDraw(s.c_str());
		gos_TextSetAttributes(font,0xFFFF0000,1.0f,false,true,false,false);
	}}

	gos_DeleteFont(font);
	#endif
}

void DebugRenderer::DrawNumPathRequests()
{
	#ifdef LAB_ONLY
	Verify(GetShowNumPathRequests() == true);

	HGOSFONT3D font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0);
	gos_TextSetAttributes(font,0xFFFFFFFF,1.0f,false,true,false,false);

	gos_TextSetRegion(0,0,Environment.screenWidth,Environment.screenHeight);
	gos_TextSetPosition(10,2);

	std::string s = "Path Requests: ";
	s += IntToString(MW4AI::g_PathManager->GetNumPathRequests());
	gos_TextDraw(s.c_str());

	gos_DeleteFont(font);
	#endif
}

bool DebugRenderer::PositionIsInFrontOfCamera(const Stuff::Point3D& pos) const
{
	if (Adept::VideoRenderer::Instance == 0)
	{
		return (false);
	}

	CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera();
	if ((camera == 0) ||
		(camera->GetElement() == 0))
	{
		return (false);
	}
	Check_Object(camera);

	Stuff::LinearMatrix4D matrix = camera->GetElement()->GetLocalToWorld();

	if (pos == (Stuff::Point3D)matrix)
	{
		return (true);
	}

	return (GetSquaredDistToMatrixForward(pos,matrix) < GetSquaredDistToMatrixBackward(pos,matrix));	
}

Stuff::Scalar DebugRenderer::DistanceFromCamera(const Stuff::Point3D& pos) const
{
	if (Adept::VideoRenderer::Instance == 0)
	{
		return (false);
	}

	CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera();
	if ((camera == 0) ||
		(camera->GetElement() == 0))
	{
		return (false);
	}
	Check_Object(camera);

	Stuff::Vector3D delta;
	delta.Subtract((Stuff::Point3D)camera->GetElement()->GetLocalToWorld(),pos);

	return (delta.GetApproximateLength());
}

void DebugRenderer::DrawLines()
{
	Verify(GetMovementLineRendering() == true);

	#ifdef LAB_ONLY
	NameTable *table = NameTable::GetInstance();
	int size(table->nameTableArray[NameTable::VehicleArray].GetLength());

	{for (int i = 0;
		  i < size;
		  ++i)
	{
		NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
		Adept::Entity* ent = data->dataPointer->GetCurrent ();

		if ((ent != 0) &&
			(ent->IsDestroyed() == false) &&
			(ent->IsDerivedFrom(MWObject::DefaultData) == true))
		{
			MWObject* v = Cast_Object(MWObject*,ent);
			Verify(v != 0);
			Check_Object(v);

			if ((GetMovementLineRendering() == true) &&
				(GetCombatAI(*v) != 0))
			{
				std::vector<Stuff::Point3D> points;
				GetCombatAI(*v)->GetDirectPath(points);

				if (points.size() > 0)
				{
//					points[0].y += 8.0f;
//					points[1].y += 8.0f;
					AddPointsToLinesToDraw(points,Stuff::RGBAColor(0xFF,0,0,0));
				}
			}

			if (GetDeadReckoningRendering() == true)
			{
				std::vector<Stuff::Point3D> points;
				points.push_back((Stuff::Point3D)v->GetLocalToWorld());
				Stuff::Point3D temp;
				points.push_back(v->EstimateFuturePosition(&temp, (Scalar)m_DeadReckoningRenderTime));
				points[0].y += 6.0f;
				points[1].y += 6.0f;
				AddPointsToLinesToDraw(points,Stuff::RGBAColor(0,0,0xFF,0));
			}
		}
	}}

	DrawLineCloud();
	#endif
}

void DebugRenderer::DrawLineCloud()
{
	#ifdef LAB_ONLY
	gos_PushCurrentHeap(ElementRenderer::g_Heap);

	if (m_PointCount > 0)
	{
		{for (int i = 0;
			  i < m_PointCount;
			  ++i)
		{
			Scalar length = m_PointData[i].GetLengthSquared();

			if (length > m_LineCloud->m_localOBB.sphereRadius)
			{
				m_LineCloud->m_localOBB.sphereRadius = length;
			}

		}}

		m_LineCloud->NeedNewBounds();
		m_LineCloud->NeedMatrixSync();

		ElementRenderer::StateChange *state = new ElementRenderer::StateChange();
		Check_Object(state);

		state->DisableZBufferCompare();

		m_LineCloud->AdoptStateChange(state);
		m_LineCloud->Sync();
	}

	gos_PopCurrentHeap();
	#endif
}

void DebugRenderer::DrawMovementPaths()
{
	Verify(GetMovementPathRendering() == true);

	#ifdef LAB_ONLY
	NameTable *table = NameTable::GetInstance();
	int size(table->nameTableArray[NameTable::VehicleArray].GetLength());

	{for (int i = 0;
		  i < size;
		  ++i)
	{
		NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
		Adept::Entity* ent = data->dataPointer->GetCurrent ();

		if ((ent != 0) &&
			(ent->IsDerivedFrom(Vehicle::DefaultData) == true))
		{
			Check_Object(ent);
			Vehicle* v = Cast_Object(Vehicle*,ent);
			Verify(v != 0);
			Check_Object(v);

			if (GetCombatAI(*v) != 0)
			{
				MW4AI::CRailPath* cur_path = GetCombatAI(*v)->getCurPath();

				if (cur_path != 0)
				{
					Stuff::Point3D my_pos(v->GetLocalToWorld());

					std::vector<Stuff::Point3D> path;
					cur_path->PointList(path);
					if (path.size () == 0)
						continue;

					path.insert(path.begin(),my_pos);

					{for (int i = 1;
						  i < path.size();
						  ++i)
					{
						std::vector<Stuff::Point3D> path2;
						path2.push_back(path[i-1]);
						path2.push_back(path[i]);

						path2[0].y = my_pos.y + 7.0f;
						path2[1].y = my_pos.y + 7.0f;

						AddPointsToLinesToDraw(path2,Stuff::RGBAColor(0,0xFF,0,0));
					}}
				}
			}
		}
	}}

	DrawLineCloud();
	#endif
}

DebugRenderer::STATS_RENDERING DebugRenderer::GetAIStatsRendering() const
{
	return (m_AIStatsRendering);
}

void DebugRenderer::SetAIStatsRendering(DebugRenderer::STATS_RENDERING fDrawStats)
{
	m_AIStatsRendering = fDrawStats;
}

bool DebugRenderer::GetDamageInfoRendering() const
{
	return (m_DamageInfoRendering);
}

void DebugRenderer::SetDamageInfoRendering(bool fDrawDamageInfo)
{
	m_DamageInfoRendering = fDrawDamageInfo;
}

bool DebugRenderer::GetMovementLineRendering() const
{
	return (m_DrawingMovementLines);
}

void DebugRenderer::SetMovementLineRendering(bool fDrawMovementLines)
{
	m_DrawingMovementLines = fDrawMovementLines;
}

bool DebugRenderer::GetMovementPathRendering() const
{
	return (m_DrawingMovementPaths);
}

void DebugRenderer::SetMovementPathRendering(bool fDrawMovementPaths)
{
	m_DrawingMovementPaths = fDrawMovementPaths;
}

DebugRenderer* DebugRenderer::GetInstance()
{
	return (m_Instance);
}

bool DebugRenderer::WorldToScreenCoords(const Stuff::Point3D& world_coords,
											   Stuff::Vector2DOf<Stuff::Scalar>& screen_coords) const
{
	if (Adept::VideoRenderer::Instance == 0)
	{
		return (false);
	}

	CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera();
	if ((camera == 0) ||
		(camera->GetElement() == 0))
	{
		return (false);
	}
	Check_Object(camera);

	camera->ComputeCursor(&screen_coords,world_coords);

	return (true);
}

void DebugRenderer::ResetLinesToDraw()
{
	m_PointCount = 0;
}

void DebugRenderer::AddPointsToLinesToDraw(const std::vector<Stuff::Point3D>& points, const Stuff::RGBAColor& color)
{
	if (m_PointCount >= max_line_cloud_points)
	{
		return;
	}

	{for (std::vector<Stuff::Point3D>::const_iterator i = points.begin();
		  i != points.end();
		  ++i)
	{
		m_PointData[m_PointCount] = *i;
//		m_PointData[m_PointCount].y += 8.0f;
		m_ColorData[m_PointCount] = color;
		++m_PointCount;

		if (m_PointCount >= max_line_cloud_points)
		{
			return;
		}
	}}
}

void DebugRenderer::SetDeadReckoningRenderTime(Stuff::Time time)
{
	m_DeadReckoningRenderTime = time;
}

Stuff::Time DebugRenderer::GetDeadReckoningRenderTime() const
{
	return (m_DeadReckoningRenderTime);
}

bool DebugRenderer::GetDeadReckoningRendering() const
{
	return (m_DeadReckoningRenderTime > 0);
}

bool DebugRenderer::GetShowNumPathRequests() const
{
	return (m_ShowNumPathRequests);
}

void DebugRenderer::SetShowNumPathRequests(bool fShow)
{
	m_ShowNumPathRequests = fShow;
}

bool DebugRenderer::GetDiagnosticsRendering() const
{
	if ((MWMission::GetInstance() == 0) ||
		(MWMission::GetInstance()->IsDerivedFrom(MWMission::DefaultData) == false))
	{
		return (false);
	}

	Check_Object(MWMission::GetInstance());
	MWMission *mission = Cast_Object(MWMission*,MWMission::GetInstance());

	return (mission->GetDiagnosticsInterface().GetEnabled());
}

bool EraseSpewFile(unsigned int index)
{
	std::string s = "AISpew\\spew.";
	std::string suffix = IntToString(index);
	while (suffix.size() < 4)
	{
		suffix = "0" + suffix;
	}
	s += suffix;

	if (gos_DoesFileExist(s.c_str()) == true)
	{
		gos_DeleteFile(s.c_str());
		return (true);
	}

	return (false);
}

void EraseExistingSpewFiles()
{
	bool erased0 = EraseSpewFile(0);
	bool erasedmax = EraseSpewFile(max_spew_files);

	if ((erased0 == false) &&
		(erasedmax == false))
	{
		return;
	}

	unsigned int i = 1;

	bool previous = false;
	while (i < max_spew_files)
	{
		previous = EraseSpewFile(i);
		++i;
	}

	if (erasedmax == true)
	{
		++i;
	}

	if (previous == true)
	{
		while (EraseSpewFile(i) == true)
		{
			++i;
		}
	}
}

void SpewEntityInfo(Adept::Entity& entity, std::string& string, bool include_geometry_info = false)
{
	string += "ObjectID: ";
	string += IntToString(entity.objectID);
	string += "; Name: ";
	string += entity.instanceName;

	if (include_geometry_info == true)
	{
		string += "\n  Position: (";
		Stuff::Point3D pos(entity.GetLocalToWorld());
		string += ScalarToString(pos.x);
		string += ",";
		string += ScalarToString(pos.y);
		string += ",";
		string += ScalarToString(pos.z);
		string += ")";

		if (entity.IsDerivedFrom(MechWarrior4::Vehicle::DefaultData) == true)
		{
			MechWarrior4::Vehicle* v = Cast_Object(MechWarrior4::Vehicle*,&entity);
			Check_Object(v);

			string += "; Velocity: ";
			string += ScalarToString(v->currentSpeedMPS);
			string += " mps";
		}
		else
		{
			string += "; [not a vehicle]";
		}
	}
}

void SpewToDiagnosticFile(const std::string& spew_output, unsigned int index)
{
	std::string text_to_spew = "Last Compile Date/Time: ";
	text_to_spew += __DATE__;
	text_to_spew += ", ";
	text_to_spew += __TIME__;
	text_to_spew += "\nSpewed at gos_GetElapsedTime() = ";
	text_to_spew += ScalarToString((Stuff::Scalar)gos_GetElapsedTime());
	text_to_spew += "\n";
	CombatAI* combat_ai = GetCombatAI();
	if (combat_ai != 0)
	{
		text_to_spew += "Vehicle AI ";
		SpewEntityInfo(*combat_ai,text_to_spew);

		text_to_spew += "\n\nVehicle ";
		SpewEntityInfo(combat_ai->GetSelf(),text_to_spew,true);

		text_to_spew += "\n\n";
		combat_ai->AddStatsToString(text_to_spew);

		if (combat_ai->Target() != 0)
		{
			text_to_spew += "\n\nTarget ";
			SpewEntityInfo(*(combat_ai->Target()),text_to_spew,true);
		}
		else
		{
			text_to_spew += "\nNo target.";
		}
	}

	text_to_spew += "\n\n";
	text_to_spew += spew_output;

	std::string s = "AISpew\\spew.";
	std::string suffix = IntToString(index);
	while (suffix.size() < 4)
	{
		suffix = "0" + suffix;
	}
	s += suffix;

	HGOSFILE hGOSfile;
	gos_OpenFile(&hGOSfile,s.c_str(),READWRITE);
	gos_WriteFile(hGOSfile,text_to_spew.c_str(),text_to_spew.size());
	gos_CloseFile(hGOSfile);
}

void DebugRenderer::DrawDiagnostics()
{
	#ifdef LAB_ONLY
	if ((MWMission::GetInstance() == 0) ||
		(MWMission::GetInstance()->IsDerivedFrom(MWMission::DefaultData) == false))
	{
		return;
	}

	int wheelDelta = 0;
	gos_GetMouseInfo(0,0,0,0,&wheelDelta,0);

	if (wheelDelta != 0)
	{
		if (wheelDelta < 0)
		{
			m_WheelDelta += wheel_move_pixels;
			if (m_WheelDelta > max_wheel_move_pixels)
			{
				m_WheelDelta = max_wheel_move_pixels;
			}
		}
		else
		{
			m_WheelDelta -= wheel_move_pixels;
			if (m_WheelDelta < 0)
			{
				m_WheelDelta = 0;
			}
		}
	}

	Check_Object(MWMission::GetInstance());
	MWMission *mission = Cast_Object(MWMission*,MWMission::GetInstance());

	std::string s;
	mission->GetDiagnosticsInterface().GetSpew(s);

	if (s.size() == 0)
	{
		return;
	}

	if (DiagnosticsInterface::GetInstance().GetFileSpewing() == true)
	{
		if (m_LastDiagnosticSpewFileIndex == 0)
		{
			EraseExistingSpewFiles();

			gos_CreateDirectory("AISpew");
		}

		if (m_LastDiagnosticSpewFileIndex >= max_spew_files)
		{
			EraseSpewFile(m_LastDiagnosticSpewFileIndex - max_spew_files);
		}

		if (s != m_LastDiagnosticSpew)
		{
			SpewToDiagnosticFile(s,m_LastDiagnosticSpewFileIndex);
			++m_LastDiagnosticSpewFileIndex;
		}
	}

	HGOSFONT3D font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0);

	gos_TextSetAttributes(font,0xFF000000,1.0f,false,true,false,false);

	gos_TextSetRegion(10,10,Environment.screenWidth,Environment.screenHeight);
	gos_TextSetPosition(10,10 - m_WheelDelta);

	gos_TextDraw(s.c_str());

	gos_DeleteFont(font);

	m_LastDiagnosticSpew = s;
	#endif
}
