#include "ProxyHeaders.hpp"

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	ChildProxy::FlattenHierarchy(FlattenHierarchyProcess *process)
{
	Check_Object(this);
	Check_Object(process);

	//
	//------------------------------------------------------------
	// Make sure that the process says its OK to check the texture
	//------------------------------------------------------------
	//
	process->FlattenHierarchyCallback(this);

	//
	//-----------------------------------------------
	// Tell whoever called us to detach the reference
	//-----------------------------------------------
	//
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	GroupProxy::FlattenHierarchy(FlattenHierarchyProcess *process)
{
	Check_Object(this);
	Check_Object(process);

	//
	//------------------------------------------------------------
	// Make sure that the process says its OK to check the texture
	//------------------------------------------------------------
	//
	process->FlattenHierarchyCallback(this);
	if (!process->continueProcess)
		return true;

	//
	//---------------------------------------------------------------------
	// If this is not the parent group, move the group's children up to the
	// parent then destroy the proxy
	//---------------------------------------------------------------------
	//
	if (this != process->parentGroup)
	{
		LinearMatrix4D matrix;
		bool push = GetLocalToParent(&matrix);
		ChildProxy *child = UseFirstChildProxy();
		while (child)
		{
			Check_Object(child);
			ChildProxy *next = child->UseNextSiblingProxy();
			if (push)
				child->TransformLocalToParent(matrix);
			if (child->FlattenHierarchy(process))
				child->DetachReference();
			child = next;
			if (!process->continueProcess)
			{
				if (child)
					child->DetachReference();
				break;
			}
		}
		Destroy();
		return false;
	}

	//
	//-------------------------------------------------------------------------
	// This is the parent group, so just call flatten hierarchy on the children
	//-------------------------------------------------------------------------
	//
	unsigned child_count = GetChildCount();
	ChildProxy *child = UseFirstChildProxy();
	for (unsigned i=0; i<child_count; ++i)
	{
		Check_Object(child);
		ChildProxy *next = child->UseNextSiblingProxy();
		if (child->FlattenHierarchy(process))
			child->DetachReference();
		child = next;
		if (!process->continueProcess)
		{
			if (child)
			{
				child->DetachReference();
			}
			break;
		}
	}

	//
	//-------------------------------------------
	// Make sure to discard any remaining proxies
	//-------------------------------------------
	//
	if (child)
		child->DetachReference();
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	PolygonMeshProxy::FlattenHierarchy(FlattenHierarchyProcess *process)
{
	Check_Object(this);
	Check_Object(process);

	//
	//------------------------------------------------------------
	// Make sure that the process says its OK to check the texture
	//------------------------------------------------------------
	//
	process->FlattenHierarchyCallback(this);
	if (!process->continueProcess)
		return true;

	//
	//-------------------------------
	// Transfer the mesh to the scene
	//-------------------------------
	//
	TransferAndAppendToParentGroup(process->parentGroup);

	//
	//----------------------------------------------------------------------
	// Adjust all the vertices so they are correct for an identity transform
	//----------------------------------------------------------------------
	//
	LinearMatrix4D matrix;
	GetLocalToParent(&matrix);
	SetLocalToParent(LinearMatrix4D::Identity);
	DynamicArrayOf<VertexProxy*> vertices;
	unsigned vertex_count = UseVertexArray(&vertices);
	for (unsigned i=0; i<vertex_count; ++i)
	{
		VertexProxy *vertex = vertices[i];
		Check_Object(vertex);
		Point3D old_position;
		vertex->GetPosition(&old_position);
		Point3D new_position;
		new_position.Multiply(old_position, matrix);
		vertex->SetPosition(new_position);
		Normal3D old_normal;
		if(vertex->GetNormal(&old_normal))
		{
			Normal3D new_normal;
			new_normal.Multiply(old_normal, matrix);
			vertex->SetNormal(new_normal);
		}
	}
	DetachArrayReferences(&vertices);

	//
	//-----------------------------------------------
	// Tell whoever called us to detach the reference
	//-----------------------------------------------
	//
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SceneProxy::FlattenHierarchy(FlattenHierarchyProcess *process)
{
	Check_Object(this);
	Check_Object(process);
	Verify(!process->parentGroup);

	//
	//---------------------------------------
	// Make sure that the process says its OK
	//---------------------------------------
	//
	process->FlattenHierarchyCallback(this);
	if (!process->continueProcess)
		return;

	//
	//---------------------
	// Flatten the children
	//---------------------
	//
	unsigned child_count = GetChildCount();
	ChildProxy *child = UseFirstChildProxy();
	for (unsigned i=0; i<child_count; ++i)
	{
		Check_Object(child);
		ChildProxy *next = child->UseNextSiblingProxy();
		if (child->FlattenHierarchy(process))
			child->DetachReference();
		child = next;
		if (!process->continueProcess)
		{
			if (child)
			{
				child->DetachReference();
			}
			break;
		}
	}

	//
	//-------------------------------------------
	// Make sure to discard any remaining proxies
	//-------------------------------------------
	//
	if (child)
		child->DetachReference();
}
