#include "munga.h"
#pragma hdrstop

#include "subsystm.h"
#include "fileutil.h"
#include "notation.h"
#include "namelist.h"

Subsystem::SharedData
	Subsystem::DefaultData(
		Subsystem::GetClassDerivations(),
		Subsystem::GetMessageHandlers(),
		Subsystem::GetAttributeIndex(),
		Subsystem::StateCount
	);

Derivation* Subsystem::GetClassDerivations()
{
	static Derivation classDerivations(Simulation::GetClassDerivations(), "Subsystem");
	return &classDerivations;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Subsystem::WriteUpdateRecord(
		UpdateRecord *message,
		int update_model
	)
{
	Check(this);
	Check_Pointer(message);

	Simulation::WriteUpdateRecord(message, update_model);
	message->subsystemID = (Word)(subsystemID+1);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Subsystem::Subsystem(
	Entity *entity,
	int subsystem_ID,
	SubsystemResource *model,
	SharedData &shared_data
):
	Simulation(model->classID, shared_data)
{
	owningEntity = entity;
	subsystemID = subsystem_ID;
	size_t name_size = strlen(model->subsystemName)+1;
	subsystemName = new char[name_size];
	Register_Pointer(subsystemName);
	Str_Copy(subsystemName, model->subsystemName, name_size);
	segmentIndex = model->segmentIndex;
	simulationFlags = model->subsystemFlags;
   damageZone = NULL;
}

Subsystem::Subsystem(
	Entity *entity,
	int subsystem_id,
	const char*  subsystem_name,
	RegisteredClass::ClassID	class_id,
	SharedData &shared_data
):
	Simulation(class_id, shared_data)
{
	owningEntity = entity;
	subsystemID = subsystem_id;
	size_t name_size = strlen(subsystem_name)+1;
	subsystemName = new char[name_size];
	Register_Pointer(subsystemName);
	Str_Copy(subsystemName, subsystem_name, name_size);
	segmentIndex = -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Subsystem::~Subsystem()
{
	Unregister_Pointer(subsystemName);
	delete[] subsystemName;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription::ResourceID
	Subsystem::CreateStreamedSubsystem(
		NotationFile	*model_file,
		const char		*model_name,
		const char *subsystem_name,
		SubsystemResource *subsystem_resource,
		NotationFile *subsystem_file,
		const ResourceDirectories *directories
	)
{
	Check(model_file);
	Check_Pointer(model_name);
	Check_Pointer(subsystem_name);
	Check_Pointer(subsystem_resource);
	Check(subsystem_file);
	Check_Pointer(directories);

	for(int ii=0; ii<(sizeof(subsystem_resource->subsystemName));ii++)
	{
		subsystem_resource->subsystemName[ii] = '\0';
	}
	subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource);

	if (strlen(subsystem_name) > sizeof(subsystem_resource->subsystemName)-1)
	{
		DEBUG_STREAM << subsystem_name << " is too long.  Maximum name size is "
		 << (sizeof(subsystem_resource->subsystemName)-1) << " character!\n";
		return False;
	}
	Str_Copy(
		subsystem_resource->subsystemName,
		subsystem_name,
		sizeof(subsystem_resource->subsystemName)-1
	);

	//
	//------------------------------------------
	// If any flags were specified, read them in
	//------------------------------------------
	//
	const char* flags;
	subsystem_resource->subsystemFlags = 0;
	if(
		subsystem_file->GetEntry(
			subsystem_name,
			"SubsystemFlags",
			&flags
		)
	)
	{
		if (!strcmp(flags,"DontReplicateFlag"))
		{
			subsystem_resource->subsystemFlags |= Subsystem::DontReplicateFlag;
		}
		else
		{
			DEBUG_STREAM << subsystem_name << " has an unknown subsystem flag!\n" << std::flush;
			return False;
		}
	}

	//
	//--------------------------------------------------
	//	Get the Segment Name to locate in the .skl file
	//--------------------------------------------------
	//
	const char* desired_page;
	subsystem_resource->segmentIndex = -1;
	if(
		subsystem_file->GetEntry(
			subsystem_name,
			"SegmentPageName",
			&desired_page
		)
	)
	{
		subsystem_resource->segmentIndex =
			Get_Segment_Index(model_file, model_name, directories, desired_page);
	}
	return True;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	Subsystem::TestInstance() const
{
	return IsDerivedFrom(*GetClassDerivations());
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	Subsystem::GenerateFault(int /*fault_index*/)
{
	Check(this);
	Check_Fpu();
	return False;		// fault not generated
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	Get_Segment_Index(
		NotationFile *model_file,
		const char* model_name,
		const ResourceDirectories *directories,
		const char *desired_page
	)
{
	//------------------------------------------
	// Get the Segment Index from the .skl file
	//------------------------------------------
	//
	const char* skl_entry;
	if (
		!model_file->GetEntry(
			"video",
			"skeleton",
			&skl_entry
			)
		)
	{
		std::cerr << model_name << " is missing .skl file specification!\n";
		return -1;
	}

	char *skl_filename =
		MakePathedFilename(directories->videoDirectory, skl_entry);
	Register_Pointer(skl_filename);

	NotationFile *skl_file = new NotationFile(skl_filename);
	Register_Object(skl_file);
		if (!skl_file->PageCount())
	{
		std::cerr << skl_filename << " is empty or missing!\n";
Dump_And_Die:
		Unregister_Pointer(skl_filename);
		delete[] skl_filename;
		Unregister_Object(skl_file);
		delete skl_file;
		return ResourceDescription::NullResourceID;
	}

	//
	//      Make a pagelist of all the segments
	//
	NameList        *segment_pages  = skl_file->MakePageList();
	Register_Object(segment_pages);

	NameList::Entry *segment_entry = segment_pages->GetFirstEntry();
	 char
		segment_page_name[32];
	 int
		segment_index = -1;
	 int
		current_index = 0;
	while(segment_entry)
	{
	Str_Copy(
			segment_page_name,
			segment_entry->GetName(),
			sizeof(segment_page_name)
		);
		//
		//---------------------------------------
		// skip labonly and damagezones
		//---------------------------------------
		//
		if(
			(strcmp(segment_page_name, "LAB_ONLY") == 0) ||
			(strcmp(segment_page_name,"DamageZones") ==0)
			)
		{
			segment_entry = segment_entry->GetNextEntry();
			continue;
		}
		//
		//-------------------------------------
		// if names match save the index
		//-------------------------------------
		//
		else if(strcmp(segment_page_name,desired_page) ==0)
		{
			segment_index = current_index;
			break;
		}
		++current_index;
		segment_entry = segment_entry->GetNextEntry();
	}
	if(segment_index == -1)
	{
		std::cout<<desired_page <<"  SegmentPageName Not in "<< skl_filename <<std::endl;
		return False;
	}
	Unregister_Pointer(skl_filename);
	delete[] skl_filename;
	Unregister_Object(skl_file);
	delete skl_file;
	Unregister_Object(segment_pages);
	delete segment_pages;

	return segment_index;
}

