#include "AdeptHeaders.hpp"

#include "DropZone.hpp"
#include "Tool.hpp"

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	DropZone__CreateMessage::ConstructCreateMessage(Script *script)
{
	Check_Object(script);
	#if defined(_ARMOR)
		int stack_level = Tool::Instance->GetStackLevel();
	#endif
	//
	//--------------
	// Set up stream
	//--------------
	//
	MemoryStream *message_stream = script->messageStream;
	Check_Object(message_stream);
	message_stream->AllocateBytes(sizeof(DropZone__CreateMessage));
	Entity__CreateMessage::ConstructCreateMessage(script);
	DropZone__CreateMessage *message =
		Cast_Pointer(
			DropZone__CreateMessage*,
			message_stream->GetPointer()
		);
	message->messageLength = sizeof(*message);

	//
	//---------------------------
	// Point at the notation file
	//---------------------------
	//
	Page *page = script->instancePage;
	Check_Object(page);
	Check_Object(Tool::Instance);
	NotationFile *instance_file = page->GetNotationFile();
	Check_Object(instance_file);
	Tool::Instance->PushFilePath(instance_file);

	message->dropPointsResourceID = ResourceID::Null;
	NotationFile drop_file;
	if (page->GetEntry("DropPoints", &drop_file))
	{
		const char* drop_points_filename = drop_file.GetFileName();

		//
		//---------------------------------------------------------------
		// Look for the damage stream resource to see if it is up to date
		//---------------------------------------------------------------
		//
		Resource drop_resource(drop_points_filename);
		if (
			drop_resource.DoesResourceExist() &&
			drop_resource.IsResourceUpToDate()
		)
		{
			Check_Object(Resource::ParentFileDependencies);
			if (!drop_resource.IsRegistered())
				drop_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			message->dropPointsResourceID = drop_resource.GetResourceID();
		}	
		else
		{

			//
			//----------------------------------------
			// For each page, an Point3D will be added
			//----------------------------------------
			//
			Tool::Instance->PushFilePath(&drop_file);
			DynamicMemoryStream drop_stream;
			Page *drop_page = drop_file.GetPage("DropPoints");
			Page *rot_page = drop_file.GetPage("DropRots");
			Check_Object(drop_page);
			Check_Object(rot_page);
			Page::NoteIterator *drop_entries = drop_page->MakeNoteIterator();
			Page::NoteIterator *rot_entries = rot_page->MakeNoteIterator();
			Check_Object(drop_entries);
			Check_Object(rot_entries);
			Note *point_instance;
			Note *rot_instance;
			drop_stream << drop_entries->GetSize();

			//
			//---------------------------------------
			// Create the damage Object for this page
			//---------------------------------------
			//
			while ((point_instance = drop_entries->ReadAndNext()) != NULL)
			{
				Check_Object(point_instance);
				rot_instance = rot_entries->ReadAndNext ();
				Check_Object (rot_instance);						// rotation should match one for one with points
				LinearMatrix4D mat;
				YawPitchRoll rot;
				Point3D point;
				point_instance->GetEntry(&point);
				rot_instance->GetEntry (&rot);
				mat.BuildRotation (rot);
				mat.BuildTranslation (point);
				drop_stream << mat;
			}

			//
			//-----------------------------------------
			// Only save out the stream if there is one
			//-----------------------------------------
			//
			if (drop_stream.GetBytesUsed())
			{
				drop_resource.Save(
					&drop_stream, 
					drop_file.GetFileDependencies()
				);
				Check_Object(&drop_resource);
				message->dropPointsResourceID = drop_resource.GetResourceID();
				Check_Object(Resource::ParentFileDependencies);
				if (!drop_resource.IsRegistered())
					drop_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
			}
			else
				message->dropPointsResourceID = ResourceID::Null;
		
			//------------------------
			// Clean up the tool stack
			//------------------------
			//
			delete rot_entries;

			Check_Object(drop_entries);
			delete drop_entries;
			Tool::Instance->PopFilePath();
		}
	}
	Tool::Instance->PopFilePath();
	Verify(stack_level == Tool::Instance->GetStackLevel());
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	
void
	DropZone::SaveInstanceText(Page *instance_page)
{
	Check_Object(this);
	Check_Object(instance_page);

	Entity::SaveInstanceText(instance_page);

	if(dropPointsResourceID != ResourceID::Null)
	{
		Resource drop_resource(dropPointsResourceID);
		Verify(drop_resource.DoesResourceExist());
		instance_page->SetEntry("DropPoints", drop_resource.GetName());
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	DropZone::SavePointsFile(const char *file_name)
{
	Check_Object(this);
	Point3D loc;
	YawPitchRoll rot;
	if(dropPointsResourceID != ResourceID::Null)
	{
		Resource drop_point_resource(dropPointsResourceID);
		
		NotationFile point_notation_file;
		Page *drop_page = point_notation_file.AddPage("DropPoints");

		char entry_name[256];
		strcpy(entry_name, "Point");
		ChainIteratorOf<MatrixPlug *> iterator(&dropMats);
		MatrixPlug *drop_point;
		int count = 1;
		while((drop_point = iterator.ReadAndNext()) != NULL)
		{	
			Check_Object(drop_point);
			sprintf(entry_name, "Point%d", count);
			LinearMatrix4D mat = drop_point->GetItem();
			loc = (Point3D) mat;
			drop_page->AppendEntry(entry_name, loc);
			count++;
		}
		drop_page = point_notation_file.AddPage("DropRots");

		strcpy(entry_name, "Rot");
		ChainIteratorOf<MatrixPlug *> iterator2(&dropMats);
		count = 1;
		while((drop_point = iterator2.ReadAndNext()) != NULL)
		{	
			Check_Object(drop_point);
			sprintf(entry_name, "Rot%d", count);
			LinearMatrix4D mat = drop_point->GetItem();
			rot = (YawPitchRoll) mat;
			drop_page->AppendEntry(entry_name, rot);
			count++;
		}
		point_notation_file.SaveAs(file_name);
	}
}