#include "AdeptHeaders.hpp"

#include "GlobalPointerManager.hpp"
#include "VideoHeaders.hpp"
#include "EventStatistics.hpp"
#include "Interface.hpp"
#include "Mission.hpp"
#include "Connection.hpp"
#include "Controls.hpp"
#include "Joystick.hpp"
#include "RendererManager.hpp"
#include "Mission.hpp"
#include "Matcher.hpp"
#include "VideoComponentWeb.hpp"
#include "EntityManager.hpp"
#include "Effect.hpp"
#include "Map.hpp"
#include "Application.hpp"
#include "ApplicationTask.hpp"
#include "AttributeWatcher.hpp"
#include "Driver.hpp"
#include "Player.hpp"
#include "DamageObject.hpp"
#include "DropZone.hpp"
#include "AudioRenderer.hpp"
#include "GUIStatBar.hpp"
#include "NameTable.hpp"
#include "Zone.hpp"
#include "Tile.hpp"
#include "CollisionGrid.hpp"
#include "CollisionVolume.hpp"
#include "LightManager.hpp"
#include "LightComponent.hpp"
#include "SpatializedCommand.hpp"
#include "SpatializedChannel.hpp"
#include "AudioComponentWeb.hpp"
#include "AudioFXComponent.hpp"
#include "EarComponent.hpp"

HGOSHEAP
	Adept::g_Heap = NULL,
	Adept::g_LibraryHeap = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
static void __stdcall
	Save_Scene()
{
	//
	//----------------------
	// Get the scene pointer
	//----------------------
	//
	Check_Object(VideoRenderer::Instance);
	Element *root = VideoRenderer::Instance->GetSceneRoot();
	Check_Object(root);

	//
	//--------------------------
	// Open the file and save it
	//--------------------------
	//
	gos_PushCurrentHeap(ElementRenderer::g_Heap);
	Check_Object(Stuff::FileStreamManager::Instance);
	Stuff::FileStream element_stream("Capture.erf", Stuff::FileStream::WriteOnly);
	ElementRenderer::WriteERFVersion(&element_stream);
	root->Save(&element_stream);
	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
static void __stdcall
	Spew_Resources()
{
	//
	//----------------------
	// Get the scene pointer
	//----------------------
	//
	extern volatile bool SpewSilence;
	bool old_silence = SpewSilence;
	SpewSilence = false;
	Check_Object(ResourceManager::Instance);
	ResourceManager::Instance->SpewLoadedResources();
	SpewSilence = old_silence;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Adept::InitializeClasses(NotationFile *startup_ini)
{
	Verify(FirstFreeAdeptClassID <= LastAdeptClassID);

	Verify(!g_LibraryHeap);
	g_LibraryHeap = gos_CreateMemoryHeap("Adept(All)");
	Check_Pointer(g_LibraryHeap);

	Verify(!g_Heap);
	g_Heap = gos_CreateMemoryHeap("Adept", 0, g_LibraryHeap);
	Check_Pointer(g_Heap);

	gos_PushCurrentHeap(g_Heap);

	if (startup_ini)
	{
		Check_Object(startup_ini);
		Page *page = startup_ini->FindPage("Graphics Options");
		if (page)
		{
			Check_Object(page);
			page->GetEntry("ScreenWidth", &Application::s_ScreenWidth);
			page->GetEntry("ScreenHeight", &Application::s_ScreenHeight);
		}
	}
	
#if !(defined(NO_STATS) && defined(NO_TIMERS))
	StatisticFormat("");
	StatisticFormat("Adept");
	StatisticFormat("=====");
	StatisticFormat("");
#endif

	GlobalPointers::InitializeClass();

	//
	//-------------------------------------------------
	// First, Initialize all the non registered classes
	//-------------------------------------------------
	//
	CollisionVolume::InitializeClass();

	//
	//----------------------------------------------
	// Now, initialize all of the registered classes
	//----------------------------------------------
	//
	StateEngine::InitializeClass();
	Receiver::InitializeClass();
	Event::InitializeClass();
	NetworkEvent::InitializeClass();
	GeneralEventQueue::InitializeClass();
	EventQueue::InitializeClass();
	EventStatisticsManager::InitializeClass();
	NameTable::InitializeClass();
	//
	//---------------
	// basic entities
	//---------------
	//
	Replicator::InitializeClass();
	Entity::ExecutionStateEngine::InitializeClass();
	Entity::InitializeClass();
	Mover::ExecutionStateEngine::InitializeClass();
	Mover::InitializeClass();

	Map::InitializeClass(startup_ini);
	Interface::InitializeClass();
	Mission::InitializeClass();
	Effect::ExecutionStateEngine::InitializeClass();
	Effect::InitializeClass();
	Driver::InitializeClass();
	Player::InitializeClass();
	DamageObject::InitializeClass();
	DropZone::InitializeClass();

	//
	//---------------
	// basic managers
	//---------------
	//

	InBox::InitializeClass();
	Connection::InitializeClass();
	Network::InitializeClass();
	

	EntityManager::InitializeClass();

	ControlsInstance::InitializeClass();
	DirectControlsInstance::InitializeClass();
	EventControlsInstance::InitializeClass();
	ControlsMappingGroup::InitializeClass();
	ControlsManager::InitializeClass();

	Renderer::InitializeClass();
	RendererManager::InitializeClass();
	VideoRenderer::InitializeClass(startup_ini);
	AudioRenderer::InitializeClass();

	Application::InitializeClass();
	ApplicationStateEngine::InitializeClass();
	ApplicationTask::InitializeClass();

	//
	//-----------
	// components
	//-----------
	//
	Component::InitializeClass();
	ComponentWeb::InitializeClass();
	EntityComponentWeb::InitializeClass();
	RendererComponentWeb::InitializeClass();
	VideoComponentWeb::InitializeClass();

	Channel::InitializeClass();
	ChannelOf<int>::InitializeClass();
	AttributeWatcherOf<int, IntClassID>::InitializeClass();
	MatcherOf<int>::InitializeClass();

	VideoComponent::InitializeClass();
	GroupComponent::InitializeClass();
	ShapeComponent::InitializeClass();
	CameraComponent::InitializeClass();
	LightComponent::InitializeClass();
	LODComponent::InitializeClass();
	SwitchComponent::InitializeClass();
	ScalableShapeComponent::InitializeClass();
	gosFXComponent::InitializeClass();
	BeamComponent::InitializeClass();
	ConeComponent::InitializeClass();

	GUIObject::InitializeClass();
	GUITextObject::InitializeClass();
	GUITextManager::InitializeClass();
	GUIStatBar::InitializeClass();

	//
	//-----------------
	// Audio components
	//-----------------
	//
	AudioSample::InitializeClass();
	AudioChannel::InitializeClass();
	AudioCommand::InitializeClass();
	SpatializedChannel::InitializeClass();
	SpatializedCommand::InitializeClass();
	AudioComponentWeb::InitializeClass();
	EarComponent::InitializeClass();
	AudioFXComponent::InitializeClass(startup_ini);

	//
	//------------------------
	// Setup collision classes
	//------------------------
	//
	Zone::InitializeClass();
	Tile::InitializeClass();
	CollisionGrid::InitializeClass();

	InternalDamageObject::InitializeClass();
	TiledLightManager::InitializeClass(startup_ini);

	SlidingShapeComponent::InitializeClass();
	MultiLODComponent::InitializeClass();

	//
	//---------------
	// Setup the menu
	//---------------
	//
	AddDebuggerMenuItem("Libraries\\Adept\\Save Scene", 0, Save_Scene, 0 );
	AddDebuggerMenuItem("Libraries\\Adept\\Spew Loaded Resources", 0, Spew_Resources, 0);

	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Adept::TerminateClasses(NotationFile *startup_ini)
{

	if (startup_ini)
	{
		Check_Object(startup_ini);
		Page *page = startup_ini->SetPage("Graphics Options");
		Check_Object(page);

		page->SetEntry("ScreenWidth", Application::s_ScreenWidth);
		page->SetEntry("ScreenHeight", Application::s_ScreenHeight);
	}

	MultiLODComponent::TerminateClass();
	SlidingShapeComponent::TerminateClass();

	TiledLightManager::TerminateClass(startup_ini);

	InternalDamageObject::TerminateClass();

	CollisionGrid::TerminateClass();
	Tile::TerminateClass();
	Zone::TerminateClass();

	//
	//-----------------
	// Audio components
	//-----------------
	//
	AudioFXComponent::TerminateClass(startup_ini);
	EarComponent::TerminateClass();
	AudioComponentWeb::TerminateClass();
	SpatializedCommand::TerminateClass();
	SpatializedChannel::TerminateClass();
	AudioCommand::TerminateClass();
	AudioChannel::TerminateClass();
	AudioSample::TerminateClass();

	//
	//-----------
	// components
	//-----------
	//
	GUIStatBar::TerminateClass();
	GUITextManager::TerminateClass();
	GUITextObject::TerminateClass();
	GUIObject::TerminateClass();

	ConeComponent::TerminateClass();
	BeamComponent::TerminateClass();
	gosFXComponent::TerminateClass();

	ScalableShapeComponent::TerminateClass();
	SwitchComponent::TerminateClass();
	LODComponent::TerminateClass();
	LightComponent::TerminateClass();
	CameraComponent::TerminateClass();
	ShapeComponent::TerminateClass();
	GroupComponent::TerminateClass();
	VideoComponent::TerminateClass();

	MatcherOf<int>::TerminateClass();
	AttributeWatcherOf<int, IntClassID>::TerminateClass();
	ChannelOf<int>::TerminateClass();
	Channel::TerminateClass();

	VideoComponentWeb::TerminateClass();
	RendererComponentWeb::TerminateClass();
	EntityComponentWeb::TerminateClass();
	ComponentWeb::TerminateClass();
	Component::TerminateClass();

	//
	//---------------
	// basic managers
	//---------------
	//

	ApplicationTask::TerminateClass();
	ApplicationStateEngine::TerminateClass();
	Application::TerminateClass();

	AudioRenderer::TerminateClass();
	VideoRenderer::TerminateClass(startup_ini);
	RendererManager::TerminateClass();
	Renderer::TerminateClass();

	ControlsManager::TerminateClass();
	ControlsMappingGroup::TerminateClass();
	EventControlsInstance::TerminateClass();
	DirectControlsInstance::TerminateClass();
	ControlsInstance::TerminateClass();

	EntityManager::TerminateClass();

	
	Network::TerminateClass();
	Connection::TerminateClass();
	InBox::TerminateClass();

	//
	//---------------
	// basic entities
	//---------------
	//
	DropZone::TerminateClass();
	DamageObject::TerminateClass();
	Player::TerminateClass();
	Driver::TerminateClass();
	Effect::TerminateClass();
	Effect::ExecutionStateEngine::TerminateClass();
	Mission::TerminateClass();

	Interface::TerminateClass();
	Map::TerminateClass(startup_ini);
	
	Mover::TerminateClass();
	Mover::ExecutionStateEngine::TerminateClass();
	Entity::TerminateClass();
	Entity::ExecutionStateEngine::TerminateClass();
	Replicator::TerminateClass();

	NameTable::TerminateClass();
	EventStatisticsManager::TerminateClass();
	EventQueue::TerminateClass();
	GeneralEventQueue::TerminateClass();
	NetworkEvent::TerminateClass();
	Event::TerminateClass();
	Receiver::TerminateClass();
	StateEngine::TerminateClass();

	//
	//-----------------------------------------------
	// Then, terminate all the non registered classes
	//-----------------------------------------------
	//
	CollisionVolume::TerminateClass();


	GlobalPointers::TerminateClass();

	Check_Pointer(g_Heap);
	gos_DestroyMemoryHeap(g_Heap);
	g_Heap = NULL;

	Check_Pointer(g_LibraryHeap);
	gos_DestroyMemoryHeap(g_LibraryHeap);
	g_LibraryHeap = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	Adept::MaterialTypeTextToAscii(const char *mode_name)
{
	if(!_stricmp(mode_name, "None"))
		return NoMaterial;
	else if(!_stricmp(mode_name, "Grass"))
		return GrassMaterial;
	else if(!_stricmp(mode_name, "Water"))
		return WaterMaterial;
	else if(!_stricmp(mode_name, "Concrete"))
		return ConcreteMaterial;
	else if(!_stricmp(mode_name, "GreyDirt"))
		return GreyDirtMaterial;
	else if(!_stricmp(mode_name, "BrownDirt"))
		return BrownDirtMaterial;
	else if(!_stricmp(mode_name, "Rock"))
		return RockMaterial;
	else if(!_stricmp(mode_name, "DarkConcrete"))
		return DarkConcreteMaterial;
	else if(!_stricmp(mode_name, "DarkGreyDirt"))
		return DarkGreyDirtMaterial;
	else if(!_stricmp(mode_name, "DarkBrownDirt"))
		return DarkBrownDirtMaterial;
	else if(!_stricmp(mode_name, "DarkRock"))
		return DarkRockMaterial;
	else if(!_stricmp(mode_name, "Blacktop"))
		return BlacktopMaterial;
	else if(!_stricmp(mode_name, "Snow"))
		return SnowMaterial;
	else if(!_stricmp(mode_name, "Wood"))
		return WoodMaterial;
	else if(!_stricmp(mode_name, "Lava"))
		return LavaMaterial;
	else if(!_stricmp(mode_name, "Glass"))
		return GlassMaterial;
	else if(!_stricmp(mode_name, "Steel"))
		return SteelMaterial;
	else if(!_stricmp(mode_name, "Us"))
		return UsMaterial;
	else if(!_stricmp(mode_name, "Them"))
		return ThemMaterial;
// MSL 5.03 Lava
	else if (!_stricmp(mode_name, "LightMineral"))
		return LightMineralMaterial;
	else if (!_stricmp(mode_name, "DarkMineral"))
		return DarkMineralMaterial;
	else if (!_stricmp(mode_name,"Ash"))
		return AshMaterial;
	else if (!_stricmp(mode_name,"CrackedLava"))
		return CrackedLavaMaterial;
	else if (!_stricmp(mode_name,"OpenLava"))
		return OpenLavaMaterial;

	//
	// These are obsolete names, still parsed for compatability
	//
	else if(!_stricmp(mode_name, "Dirt"))
		return BrownDirtMaterial;
	else if(!_stricmp(mode_name, "Vehicle"))
		return SteelMaterial;
	else if(!_stricmp(mode_name, "Brick"))
		return ConcreteMaterial;
	else if(!_stricmp(mode_name, "Tree"))
		return WoodMaterial;
	else if(!_stricmp(mode_name, "Swamp"))
		return GrassMaterial;
	else if(!_stricmp(mode_name, "Rough"))
		return GrassMaterial;
	else if(!_stricmp(mode_name, "Snow"))
		return SnowMaterial;
	else if(!_stricmp(mode_name, "Underbrush"))
		return GrassMaterial;
	else if(!_stricmp(mode_name, "ShallowWater"))
		return WaterMaterial;
	else if(!_stricmp(mode_name, "MidWater"))
		return WaterMaterial;
	else if(!_stricmp(mode_name, "Desert"))
		return BrownDirtMaterial;
	else if(!_stricmp(mode_name, "FlatSwamp"))
		return GrassMaterial;
	else if(!_stricmp(mode_name, "ThickSwamp"))
		return GrassMaterial;
	else if(!_stricmp(mode_name, "RedRock"))
		return RockMaterial;
	else if(!_stricmp(mode_name, "DarkDirt"))
		return DarkBrownDirtMaterial;
	else if(!_stricmp(mode_name, "DarkDesert"))
		return DarkBrownDirtMaterial;
	else if(!_stricmp(mode_name, "DarkRedRock"))
		return DarkRockMaterial;
	else 
	{
		STOP(("Unknown Material Type: %s ", mode_name));
		return 0;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char *
	Adept::MaterialTypeAsciiToText(int material)
{
	switch(material)
	{
	case NoMaterial:
		return "None";
	case GrassMaterial:
		return "Grass";
	case WaterMaterial:
		return "Water";
	case ConcreteMaterial:
		return "Concrete";
	case GreyDirtMaterial:
		return "GreyDirt";
	case BrownDirtMaterial:
		return "BrownDirt";
	case RockMaterial:
		return "Rock";
	case DarkConcreteMaterial:
		return "DarkConcrete";
	case DarkGreyDirtMaterial:
		return "DarkGreyDirt";
	case DarkBrownDirtMaterial:
		return "DarkBrownDirt";
	case DarkRockMaterial:
		return "DarkRock";
	case BlacktopMaterial:
		return "Blacktop";
	case SnowMaterial:
		return "Snow";
	case WoodMaterial:
		return "Wood";
	case LavaMaterial:
		return "Lava";
	case GlassMaterial:
		return "Glass";
	case SteelMaterial:
		return "Steel";
	case UsMaterial:
		return "Us";
	case ThemMaterial:
		return "Them";
// MSL 5.03 Lava
	case LightMineralMaterial:
		return "LightMineral";
	case DarkMineralMaterial:
		return "DarkMineral";
	case AshMaterial:
		return "Ash";
	case CrackedLavaMaterial:
		return "CrackedLava";
	case OpenLavaMaterial:
		return "OpenLava";
	}

	return "Bad Value";
}