#pragma once

#include "Proxies.hpp"
#include "GenericProxy.hpp"

namespace Proxies {

	class PolygonMeshProxy;
	class GroupProxy;
	class ChildProxy;
	class TextureLibrary;
	class StateLibrary;
	class CoalesceTexturesProcess;

	//
	//#########################################################################
	//#########################    SceneProxy    ##############################
	//#########################################################################
	//
	class _declspec(novtable) SceneProxy:
		public GenericProxy
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	protected:
		SceneProxy(ClassData *class_data);
		~SceneProxy();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Process support
	//
	public:
		virtual void
			BinSort(BinSortProcess *process);
		virtual void
			BurnLights(BurnLightsProcess *process);
		virtual bool
			CleanHierarchy(CleanHierarchyProcess *process);
		virtual void
			CoalesceTextures(CoalesceTexturesProcess *process);
		virtual void
			Copy(
				CopyProcess *process,
				SceneProxy *scene
			);
		virtual void
			GetInfo(
				GetInfoProcess *process
			);
		virtual int
			FindErrors(FindErrorsProcess *process);
		virtual void
			FindLights(BurnLightsProcess *process);
		virtual void
			FlattenHierarchy(FlattenHierarchyProcess *process);
		virtual void
			SplitByState(SplitByStateProcess *process);
		virtual void
			MakeSingleSided(MakeSingleSidedProcess *process);
		virtual void
			OptimizeFlatShading(OptimizeFlatShadingProcess *process);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Library functions
	//
	public:
		virtual StateLibrary*
			GetStateLibrary() = 0;

	protected:
		StateLibrary*
			stateLibrary;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Bounding functions
	//
	// GetBoundingSphere should be used only after GetOBB has returned a false
	//
	public:
		virtual bool
			GetOBB(Stuff::OBB *obb) = 0;
		virtual void
			SetOBB(const Stuff::OBB &obb) = 0;
		virtual bool
			GetBoundingSphere(Stuff::Sphere *sphere);
		virtual void
			SetBoundingSphere(const Stuff::Sphere &sphere) = 0;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Polygon functions
	//
	public:
		virtual void
			GetCentroid(Stuff::Point3D *center);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Child 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* proxy)
				{
					Check_Object(this);
					AttachReference(); activeChildProxies.Add(proxy);
				}
		void
			DetachChildProxy(ChildProxy* proxy);

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

}
