#pragma once

#include "ElementProxies.hpp"

namespace ElementProxies {

	class ElementSceneProxy;

	//
	//#########################################################################
	//######################    ElementListProxy    ##########################
	//#########################################################################
	//
	class ElementListProxy:
		public Proxies::GroupProxy
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		static ElementListProxy*
			MakeProxy(
				ElementSceneProxy *scene,
				Proxies::GroupProxy *parent,
				ElementRenderer::ListElement *list,
				Stuff::ChainIterator *iterator
			)
				{return new ElementListProxy(scene, parent, list, iterator);}

		void
			Destroy();

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

	protected:
		ElementListProxy(
			ElementSceneProxy *scene,
			Proxies::GroupProxy *parent,
			ElementRenderer::ListElement *list,
			Stuff::ChainIterator *iterator
		);
		~ElementListProxy();

		static Stuff::MemoryBlock
			*AllocatedMemory;

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

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

		void
			TransferAndAppendToParentGroup(Proxies::GroupProxy *parent);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Hierarchy 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
		//
		void
			GetCentroid(Stuff::Point3D *center);
		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);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Local implementation details
	//
	public:
		ElementRenderer::ListElement*
			GetProxiedList()
				{Check_Object(this); return proxiedList;}

	protected:
		ElementRenderer::ListElement
			*proxiedList;
		Stuff::ChainIterator
			*siblingIterator;
		Stuff::ChainOf<ElementRenderer::Element*>
			groupedElements;
	};

}
