#pragma once

#include "MAXProxies.hpp"

namespace MAXProxies {

	class MAXScene;

	//
	//#########################################################################
	//###########################    MAXGroup    ###############################
	//#########################################################################
	//
	class MAXGroup:
		public Proxies::GroupProxy
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		static MAXGroup*
			MakeProxy(
				MAXScene *scene,
				MAXGroup *parent,
				INode *group,
				TimeValue t,
				int index,
				bool children
			)
				{return new MAXGroup(scene, parent, group, t, index, children);}

		void
			Destroy();

		void*
			operator new(size_t)
				{return AllocatedMemory->New();}
		void
			operator delete(void *where)
				{AllocatedMemory->Delete(where);}

	protected:
		MAXGroup(
			MAXScene *scene,
			MAXGroup *parent,
			INode *group,
			TimeValue t,
			int index,
			bool children
		);
		~MAXGroup();

		static Stuff::MemoryBlock
			*AllocatedMemory;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data Support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Testing
	//
	public:
		void
			TestInstance() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Group management functions
	//
	public:
		//
		// Position traversal functions
		//
		MAXScene*
			GetSceneProxy()
				{Check_Object(this); return Cast_Pointer(MAXScene*, sceneProxy);}

		MAXGroup*
			GetParentGroupProxy()
				{
					Check_Object(this);
					return reinterpret_cast<MAXGroup*>(parentProxy);
				}
		void
			TransferAndAppendToParentGroup(Proxies::GroupProxy *parent);

		Proxies::ChildProxy*
			UseNextSiblingProxy();
		Proxies::ChildProxy*
			UsePreviousSiblingProxy();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Group functions
	//
	public:
		//
		// name functions
		//
		bool
			GetName(Stuff::MString *name);
		void
			SetName(const char* name);

		//
		// Position functions
		//
		bool
			GetLocalToParent(Stuff::LinearMatrix4D *matrix);
		void
			SetLocalToParent(const Stuff::LinearMatrix4D &matrix);

		//
		// Bounding functions
		//
		bool
			GetOBB(Stuff::OBB *obb);
		void
			SetOBB(const Stuff::OBB &obb);
		bool
			GetBoundingSphere(Stuff::Sphere *sphere);
		void
			SetBoundingSphere(const Stuff::Sphere &sphere);

		//
		// Gets the current number of children
		//
		unsigned
			GetChildCount();

		//
		// Polygon mesh child creation functions
		//
		Proxies::GroupProxy*
			AppendNewGroupProxy();
		Proxies::GroupProxy*
			InsertNewGroupProxy(Proxies::ChildProxy *before);

		Proxies::PolygonMeshProxy*
			AppendNewPolygonMeshProxy();
		Proxies::PolygonMeshProxy*
			InsertNewPolygonMeshProxy(Proxies::ChildProxy *before);

		Proxies::ChildProxy*
			AppendMatchingChildProxy(Proxies::ChildProxy *child);
		Proxies::ChildProxy*
			InsertMatchingChildProxy(
				Proxies::ChildProxy *child,
				Proxies::ChildProxy *before
			);

		//
		// Child traversal functions
		//
		Proxies::ChildProxy*
			UseFirstChildProxy();
		Proxies::ChildProxy*
			UseLastChildProxy();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Local implementation details
	//
	public:
		INode*
			GetProxiedGroup()
				{Check_Object(this); return proxiedGroup;}
		INode
			*proxiedGroup;

//		static INode*
//			AllocateRecord()
//				{return mgNewRec(fltGroup);}

	protected:
		int 
			GetPreviousSiblingIndex();
		int
			GetNextSiblingIndex();
		int
			childIndex;

		bool
			pseudoGroup;

		TimeValue
			time;
	};
}
