#include "ElementProxyHeaders.hpp"

//
//############################################################################
//#########################    ElementListProxy    ##########################
//############################################################################
//

MemoryBlock*
	ElementListProxy::AllocatedMemory = NULL;
ElementListProxy::ClassData*
	ElementListProxy::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::InitializeClass()
{
	Verify(!AllocatedMemory);
	AllocatedMemory =
		new MemoryBlock(
			sizeof(ElementListProxy),
			10,
			10,
			"ElementListProxy"
		);
	Register_Object(AllocatedMemory);

	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			ElementListProxyClassID,
			"ElementListProxy",
			GroupProxy::DefaultData
		);
	Register_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;

	Unregister_Object(AllocatedMemory);
	delete AllocatedMemory;
	AllocatedMemory = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::Destroy()
{
	//
	//-------------------------------
	// Make sure we are OK to destroy
	//-------------------------------
	//
	Check_Object(this);
	Verify(referenceCount == 1);
	Verify(activeChildProxies.IsEmpty());

	//
	//--------------------------
	// Destroy the group element
	//--------------------------
	//
	Unregister_Object(proxiedList);
	delete proxiedList;
	DetachReference();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementListProxy::ElementListProxy(
	ElementSceneProxy *scene,
	GroupProxy *parent,
	ListElement *list,
	ChainIterator *iterator
):
	GroupProxy(DefaultData, scene, parent),
	proxiedList(list),
	siblingIterator(iterator),
	groupedElements(NULL)
{
	Check_Pointer(this);
	Check_Pointer(proxiedList);

	for (WORD i=0; i<proxiedList->GetActiveCount(); ++i)
	{
		Element *child = proxiedList->GetIndexedElement(i);
		Check_Object(child);
		groupedElements.Add(child);
	}

	Check_Object(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementListProxy::~ElementListProxy()
{
	Check_Object(this);
	Unregister_Object(siblingIterator);
	delete siblingIterator;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
	Check_Object(siblingIterator);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::TransferAndAppendToParentGroup(GroupProxy *parent)
{
	Check_Object(this);

	//
	//--------------------------------------------
	// Delete our attachment to our current parent
	//--------------------------------------------
	//
	Check_Pointer(proxiedList);
	proxiedList->DetachFromParent();
	ElementGroupProxy *old_parent =
		Cast_Object(ElementGroupProxy*, GetParentGroupProxy());
	if (old_parent)
	{
		Check_Object(old_parent);
		old_parent->DetachChildProxy(this);
	}
	else
	{
		Check_Object(GetSceneProxy());
		GetSceneProxy()->DetachChildProxy(this);
	}

	//
	//---------------------------------------------------------------------
	// If a parent is specified, then attach to it, otherwise attach to the
	// scene
	//---------------------------------------------------------------------
	//
	GroupElement *parent_rec;
	parentProxy = parent;
	if (parent)
	{
		ElementGroupProxy *element_parent =
			Cast_Object(ElementGroupProxy*, parent);
		parent_rec = element_parent->GetProxiedGroup();
		parent->AttachChildProxy(this);
	}
	else
	{
		ElementSceneProxy *scene = GetSceneProxy();
		Check_Object(scene);
		parent_rec = scene->GetProxiedScene();
		scene->AttachChildProxy(this);
	}
	Check_Pointer(parent_rec);
	parent_rec->AttachChild(proxiedList);
	proxiedList->Sync();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy*
	ElementListProxy::UseNextSiblingProxy()
{
	Check_Object(this);

	//
	//------------------------------------------------------------------------
	// Clone our iterator, then move it and have the scene figure out the type
	// of proxy to create
	//------------------------------------------------------------------------
	//
	Check_Object(siblingIterator);
	ChainIterator *iterator = siblingIterator->MakeClone();
	Register_Object(iterator);
	iterator->Next();
	return GetSceneProxy()->InterpretElement(GetParentGroupProxy(), iterator);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy*
	ElementListProxy::UsePreviousSiblingProxy()
{
	Check_Object(this);

	//
	//------------------------------------------------------------------------
	// Clone our iterator, then move it and have the scene figure out the type
	// of proxy to create
	//------------------------------------------------------------------------
	//
	Check_Object(siblingIterator);
	ChainIterator *iterator = siblingIterator->MakeClone();
	Register_Object(iterator);
	iterator->Previous();
	return GetSceneProxy()->InterpretElement(GetParentGroupProxy(), iterator);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	ElementListProxy::GetName(MString *name)
{
	Check_Object(this);
	Check_Object(name);
	Check_Object(proxiedList);
	name->AllocateLength(0);
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::SetName(const char* name)
{
	Check_Object(this);
	Check_Object(proxiedList);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	ElementListProxy::GetLocalToParent(LinearMatrix4D *matrix)
{
	Check_Object(this);
	Check_Pointer(matrix);
	Check_Object(proxiedList);
	*matrix = proxiedList->GetLocalToParent();
	return *matrix != LinearMatrix4D::Identity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::SetLocalToParent(const LinearMatrix4D &matrix)
{
	Check_Object(this);
	Check_Object(&matrix);
	Check_Object(proxiedList);
	if (matrix == LinearMatrix4D::Identity)
		proxiedList->SetLocalToParentToIdentity();
	else
		proxiedList->SetLocalToParent(matrix);
	proxiedList->Sync();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::GetCentroid(Point3D *center)
{
	Check_Object(this);
	Check_Pointer(center);
	Check_Object(proxiedList);
	if (proxiedList->m_localOBB.sphereRadius > 0.0f)
		*center = proxiedList->m_localOBB.localToParent;
	else
		GroupProxy::GetCentroid(center);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	ElementListProxy::GetOBB(OBB *obb)
{
	Check_Object(this);
	Check_Pointer(obb);
	Check_Object(proxiedList);

	//
	//-----------------------------------------------
	// Make sure that this proxy thinks it has an OBB
	//-----------------------------------------------
	//
	if (!proxiedList->IsBoundedByOBB())
	{
		return false;
	}

	//
	//------------------------------
	// Copy the data into the sphere
	//------------------------------
	//
	*obb = proxiedList->m_localOBB;
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::SetOBB(const OBB &obb)
{
	Check_Object(this);
	Check_Object(&obb);
	Check_Object(proxiedList);

	//
	//-------------------------------------------------------------------------
	// Set the element into sphere mode, and copy the sphere data into the OBB.
	// Then sync it up so everyone is happy
	//-------------------------------------------------------------------------
	//
	proxiedList->m_localOBB = obb;
	proxiedList->SetOBBMode();
	proxiedList->SetVolumeCullMode();
	proxiedList->Sync();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	ElementListProxy::GetBoundingSphere(Sphere *sphere)
{
	Check_Object(this);
	Check_Pointer(sphere);
	Check_Object(proxiedList);

	//
	//------------------------------
	// Copy the data into the sphere
	//------------------------------
	//
	sphere->center = proxiedList->m_localOBB.localToParent;
	sphere->radius = proxiedList->m_localOBB.sphereRadius;
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementListProxy::SetBoundingSphere(const Sphere &sphere)
{
	Check_Object(this);
	Check_Object(&sphere);
	Check_Object(proxiedList);

	//
	//-------------------------------------------------------------------------
	// Set the element into sphere mode, and copy the sphere data into the OBB.
	// Then sync it up so everyone is happy
	//-------------------------------------------------------------------------
	//
	proxiedList->m_localOBB.localToParent.BuildTranslation(sphere.center);
	proxiedList->m_localOBB.sphereRadius = sphere.radius;
	proxiedList->SetSphereMode();
	proxiedList->SetVolumeCullMode();
	proxiedList->Sync();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned
	ElementListProxy::GetChildCount()
{
	Check_Object(this);
	Check_Object(proxiedList);
	return proxiedList->GetActiveCount();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
PolygonMeshProxy*
	ElementListProxy::AppendNewPolygonMeshProxy()
{
	Check_Object(this);

#if 0
	ShapeElement *new_mesh = new ShapeElement;
	Register_Object(new_mesh);
	Check_Object(proxiedList);
	proxiedList->AttachChild(new_mesh);
	ChainIteratorOf<Element*> *iterator =
		new ChainIteratorOf<Element*>(&proxiedList->groupedElements);
	Register_Object(iterator);
	ElementPolygonMeshProxy *proxy =
		ElementPolygonMeshProxy::MakeProxy(
			GetSceneProxy(),
			this,
			new_mesh,
			iterator
		);
	Register_Object(proxy);
	return proxy;
#else
	STOP(("Not implemented"));
	return NULL;
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
PolygonMeshProxy*
	ElementListProxy::InsertNewPolygonMeshProxy(ChildProxy *before)
{
	Check_Object(this);
	Check_Object(before);
	Verify(before->GetParentGroupProxy() == this);

	STOP(("Not implemented"));
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GroupProxy*
	ElementListProxy::AppendNewGroupProxy()
{
	Check_Object(this);

#if 0
	ListElement *new_hierarchy = new ListElement();
	Register_Object(new_hierarchy);
	Check_Object(proxiedList);
	proxiedList->AttachChild(new_hierarchy);
	ChainIteratorOf<Element*> *iterator =
		new ChainIteratorOf<Element*>(&proxiedList->groupedElements);
	Register_Object(iterator);
	ElementListProxy *proxy =
		ElementListProxy::MakeProxy(
			GetSceneProxy(),
			this,
			new_hierarchy,
			iterator
		);
	Register_Object(proxy);
	return proxy;
#else
	STOP(("Not implemented"));
	return NULL;
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GroupProxy*
	ElementListProxy::InsertNewGroupProxy(ChildProxy *before)
{
	Check_Object(this);
	Check_Object(before);
	Verify(before->GetParentGroupProxy() == this);

	STOP(("Not implemented"));
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy*
	ElementListProxy::UseFirstChildProxy()
{
	Check_Object(this);
	Check_Object(proxiedList);
	ChainIteratorOf<Element*> *elements =
		new ChainIteratorOf<Element*>(&groupedElements);
	Register_Object(elements);
	return GetSceneProxy()->InterpretElement(this, elements);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy*
	ElementListProxy::UseLastChildProxy()
{
	Check_Object(this);
	STOP(("Not implemented"));
	return NULL;
}
