#include "MAXProxyHeaders.hpp"

//
//############################################################################
//##############################    MAXGroup    ###############################
//############################################################################
//

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

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

	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			MAXGroupClassID,
			"MAXGroup",
			GroupProxy::DefaultData
		);
	Register_Object(DefaultData);
}

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MAXGroup::Destroy()
{
	Check_Object(this);
	Verify(referenceCount == 1);
	Verify(activeChildProxies.IsEmpty());
	Check_Pointer(proxiedGroup);
//	mgbool result = mgDelete(proxiedGroup);
//	Verify(result == mgTRUE);
	DetachReference();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MAXGroup::MAXGroup(
	MAXScene *scene,
	MAXGroup *parent,
	INode *group,
	TimeValue t,
	int index,
	bool children
):
	GroupProxy(DefaultData, scene, parent),
	proxiedGroup(group),
	time(t),
	childIndex(index),
	pseudoGroup(children)

{
	Check_Pointer(this);
	Check_Pointer(proxiedGroup);
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MAXGroup::~MAXGroup()
{
	Check_Object(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MAXGroup::TestInstance() const
{
	Check_Pointer(proxiedGroup);
	ObjectState os = proxiedGroup->EvalWorldState(time);
	Verify(	(os.obj->SuperClassID() == HELPER_CLASS_ID) ||
			(os.obj->SuperClassID() == CAMERA_CLASS_ID) ||
			(os.obj->SuperClassID() == SHAPE_CLASS_ID)  ||
			(os.obj->SuperClassID() == GEOMOBJECT_CLASS_ID)  );
	
	Verify(IsDerivedFrom(DefaultData));
}

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

	//
	//--------------------------------------------
	// Delete our attachment to our current parent
	//--------------------------------------------
	//
	Check_Pointer(proxiedGroup);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::ChildProxy*
	MAXGroup::UseNextSiblingProxy()
{
	Check_Object(this);
	Check_Pointer(proxiedGroup);
	int index = GetNextSiblingIndex();
	
	if (index == -1)
		return NULL;

	index += childIndex;
	INode *next = proxiedGroup->GetParentNode()->GetChildNode(index);
	return
		GetSceneProxy()->InterpretRecord(GetParentGroupProxy(), next, index,true);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::ChildProxy*
	MAXGroup::UsePreviousSiblingProxy()
{
	Check_Object(this);
	Check_Pointer(proxiedGroup);

	int index = GetPreviousSiblingIndex();
	if (index > -1)
	{
		INode *prev = proxiedGroup->GetParentNode()->GetChildNode(childIndex-index);
		return
			GetSceneProxy()->InterpretRecord(this, prev, childIndex-index,true);
	}
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MAXGroup::GetNextSiblingIndex()
{
	MAXScene *scene = GetSceneProxy();
	Check_Pointer(scene);
	Check_Pointer(proxiedGroup);
	INode *parent = proxiedGroup->GetParentNode();
	Check_Pointer(parent);

	unsigned children = parent->NumberOfChildren();
	Verify(children>0);

//	DEBUG_STREAM << "MAXGroup::UseNextSiblingProxy parent name " << parent->GetName() << 
//		" index:" << index << " childIndex:" << childIndex << " children:" << children << endl;

	int index = 1;
	while (childIndex+index < children)
	{
		if (scene->ValidElement(parent->GetChildNode(childIndex+index)))
		{
			return index;
		}
		index++;
	}
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int 
	MAXGroup::GetPreviousSiblingIndex()
{
	MAXScene *scene = GetSceneProxy();
	Check_Pointer(scene);
	Check_Pointer(proxiedGroup);
	INode *parent = proxiedGroup->GetParentNode();
	Check_Pointer(parent);
	int index = 1;

//	DEBUG_STREAM << "MAXGroup::UseNextSiblingProxy parent name " << parent->GetName() << endl;
	unsigned children = parent->NumberOfChildren();

	if (!children)
	{
		return NULL;
	}
	while (childIndex-index >= 0)
	{
		if (scene->ValidElement(parent->GetChildNode(childIndex-index)))
		{
			return index;
		}
		index++;
	}
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MAXGroup::GetName(MString *name)
{
	Check_Object(this);
	Check_Object(name);
	Check_Pointer(proxiedGroup);
	//
	//----------------------------------------------
	// Get the scene name and check the length
	//----------------------------------------------
	//
	TCHAR *string = proxiedGroup->GetName();
	int len = strlen(string);
	if (len != 0)
	{
		*name = string;
		return true;
	}
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MAXGroup::SetName(const char* name)
{
	Check_Object(this);
	Check_Pointer(proxiedGroup);
	TCHAR *string = (TCHAR *)name;
	proxiedGroup->SetName(string);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MAXGroup::GetLocalToParent(LinearMatrix4D *matrix)
{
	Check_Object(this);
	Check_Pointer(matrix);
	Check_Pointer(proxiedGroup);
	Matrix3 LocalToWorld = proxiedGroup->GetNodeTM(time,NULL);
	Matrix3 ParentToWorld = proxiedGroup->GetParentTM(time);
	Matrix3 LocalToParent =  LocalToWorld * Inverse(ParentToWorld);
  
	//
	// now decompose the max matrix and make our linear matrix
	//
		AffineParts parts;
		decomp_affine(LocalToParent, &parts);

		Point3D translation;
		translation=ConvertMaxToMW(parts.t);

		UnitQuaternion rotation;
		rotation=ConvertMaxToMW(parts.q);

		matrix->BuildRotation(rotation);
		matrix->BuildTranslation(translation);
	

	return *matrix != LinearMatrix4D::Identity;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MAXGroup::SetLocalToParent(const LinearMatrix4D &matrix)
{
	Check_Object(this);
	Check_Object(&matrix);
//	Matrix3	mat3 = matrix;
	//TODO (jkyle): convert from MW to max here

	//proxiedGroup->SetNodeTM(time, mat3);
//	STOP(("Not implemented"));
}

bool
	MAXGroup::GetOBB(OBB *obb)
{
	Check_Object(this);
	Check_Pointer(&obb);
	STOP(("Not implemented"));
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MAXGroup::SetOBB(const OBB &obb)
{
	Check_Object(this);
	Check_Object(&obb);
	STOP(("Not implemented"));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MAXGroup::GetBoundingSphere(Sphere *sphere)
{
	Check_Object(this);
	Check_Pointer(sphere);
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MAXGroup::SetBoundingSphere(const Sphere &sphere)
{
	Check_Object(this);
	Check_Object(&sphere);
	STOP(("Not implemented"));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned
	MAXGroup::GetChildCount()
{
	Check_Object(this);
	Check_Pointer(proxiedGroup);
	return proxiedGroup->NumberOfChildren();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::PolygonMeshProxy*
	MAXGroup::AppendNewPolygonMeshProxy()
{
	Check_Object(this);
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::PolygonMeshProxy*
	MAXGroup::InsertNewPolygonMeshProxy(Proxies::ChildProxy *before)
{
	Check_Object(this);
	Check_Object(before);
	Verify(before->GetParentGroupProxy() == this);
	STOP(("Not implemented"));
	return NULL;
}

INode *CreateNode(Interface *ip,SClass_ID superID,Class_ID classid);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::GroupProxy*
	MAXGroup::AppendNewGroupProxy()
{
	Check_Object(this);
	int time = 0;
	int index = 0;
	INode *child = CreateNode(GetSceneProxy()->GetInterface(),HELPER_CLASS_ID,Class_ID(DUMMY_CLASS_ID,0));
	MAXGroup *proxy =	MAXGroup::MakeProxy(GetSceneProxy(), this, child, time, index, true);
	Check_Object(proxy);
	return proxy;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::GroupProxy*
	MAXGroup::InsertNewGroupProxy(Proxies::ChildProxy *before)
{
	Check_Object(this);
	Check_Object(before);
	Verify(before->GetParentGroupProxy() == this);
	STOP(("Not implemented"));
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::ChildProxy*
	MAXGroup::AppendMatchingChildProxy(Proxies::ChildProxy *child)
{
	Check_Object(this);
	Check_Object(child);
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::ChildProxy*
	MAXGroup::InsertMatchingChildProxy(
		Proxies::ChildProxy *child,
		Proxies::ChildProxy *before
	)
{
	Check_Object(this);
	Check_Object(child);
	Check_Object(before);
	Verify(before->GetParentGroupProxy() == this);
	STOP(("Not implemented"));
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::ChildProxy*
	MAXGroup::UseFirstChildProxy()
{
	Check_Object(this);
	Check_Pointer(proxiedGroup);
	MAXScene *scene = GetSceneProxy();
	unsigned count = proxiedGroup->NumberOfChildren();
	Proxies::ChildProxy *child = NULL;
	INode *node = NULL;
	int index = 0;
	if ((pseudoGroup)&&(scene->ValidElement(proxiedGroup)))
	{
		child = scene->InterpretRecord(this,proxiedGroup,index,false);
	}
	else
	{
		while ((index < count) && (scene->ValidElement(node) == false))
		{
			node = proxiedGroup->GetChildNode(index);
			if (scene->ValidElement(node))
			{
				child = scene->InterpretRecord(this,node,index,true);
			}
			index++;
		}
	}
	return child;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::ChildProxy*
	MAXGroup::UseLastChildProxy()
{
	Check_Object(this);
	Check_Pointer(proxiedGroup);
	MAXScene *scene = GetSceneProxy();
//	DEBUG_STREAM << "MAXGroup::UseLastChildProxy()" << endl;
	unsigned count = proxiedGroup->NumberOfChildren();
	Proxies::ChildProxy *child = NULL;
	INode *node = NULL;
	int index = count-1;
	while ((index >= 0) && (scene->ValidElement(node) == false))
	{
		node = proxiedGroup->GetChildNode(index);
		if (scene->ValidElement(node))
		{
			child = scene->InterpretRecord(this,node,index,true);
		}
		index--;
	}
	return child;
}
