#pragma once

#include "Proxies.hpp"
#include "ChildProxy.hpp"

namespace Proxies {

	class PolygonMeshProxy;
	class PolygonProxy;
	class StateProxy;
	class Process;
	class GetInfoProcess;

	//
	//#########################################################################
	//#######################    GroupProxy    ############################
	//#########################################################################
	//
	class _declspec(novtable) GroupProxy:
		public ChildProxy
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	protected:
		GroupProxy(
			ClassData *class_data,
			SceneProxy *scene,
			GroupProxy *parent
		);
		~GroupProxy();

	public:
		//
		// Copies the elements of a hierarchy into this hierarchy
		//
		virtual void
			Copy(
				CopyProcess *process,
				GroupProxy *hierarchy
			);
		//
		// gives informations about the group
		//
		virtual void
			GetInfo(
				GetInfoProcess *process
			);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Process support
	//
	public:
		bool
			BinSort(BinSortProcess *process);
		void
			BurnLights(BurnLightsProcess *process);
		bool
			CleanHierarchy(CleanHierarchyProcess *process);
		int
			FindErrors(FindErrorsProcess *process);
		void
			FindLights(BurnLightsProcess *process);
		bool
			FlattenHierarchy(FlattenHierarchyProcess *process);
		bool
			SplitByState(SplitByStateProcess *process);
		bool
			MakeSingleSided(MakeSingleSidedProcess *process);
		bool
			OptimizeFlatShading(OptimizeFlatShadingProcess *process);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Polygon functions
	//
	public:
		void
			GetCentroid(Stuff::Point3D *center);
		void
			Recenter();
		void
			SortAndAddPolygons(
				BinSortProcess *process,
				Stuff::DynamicArrayOf<PolygonProxy*> &polygons
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Bounding functions
	//
	// GetBoundingSphere should be used only after GetOBB has returned a false
	//
	public:
		bool
			GetBoundingSphere(Stuff::Sphere *sphere);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Hierarchy functions
	//
	public:
		//
		// Gets the current number of children
		//
		virtual unsigned
			GetChildCount() = 0;

		//
		// Child creation functions
		//
		virtual GroupProxy*
			AppendNewGroupProxy() = 0;
		virtual GroupProxy*
			InsertNewGroupProxy(ChildProxy *before) = 0;

		virtual PolygonMeshProxy*
			AppendNewPolygonMeshProxy() = 0;
		virtual PolygonMeshProxy*
			InsertNewPolygonMeshProxy(ChildProxy *before) = 0;

		ChildProxy*
			AppendMatchingChildProxy(
				CopyProcess *process,
				ChildProxy *child
			);
		ChildProxy*
			InsertMatchingChildProxy(
				CopyProcess *process,
				ChildProxy *child,
				ChildProxy *before
			);

		//
		// Child traversal functions
		//
		virtual ChildProxy*
			UseFirstChildProxy() = 0;
		virtual ChildProxy*
			UseLastChildProxy() = 0;
		virtual void
			FindNamedChildren(
				Stuff::DynamicArrayOf<ChildProxy*> *children,
				const char* prefix,
				bool matching = true
			);

		void
			AttachChildProxy(ChildProxy *child)
				{
					Check_Object(this);
					AttachReference(); activeChildProxies.Add(child);
				}
		void
			DetachChildProxy(ChildProxy* proxy);

	protected:
		Stuff::ChainOf<ChildProxy*>
			activeChildProxies;
	};

}
