#pragma once

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

namespace Proxies {

	class VertexProxy;
	class PolygonProxy;
	class MultiState;

	class Process;
	class CopyProcess;
	class CoalesceTexturesProcess;

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

		static ClassData
			*DefaultData;

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

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Process support
	//
	public:
		bool
			BinSort(BinSortProcess *process);
		void
			BurnLights(BurnLightsProcess *process);
		bool
			CleanHierarchy(CleanHierarchyProcess *process);
		virtual void
			CoalesceTextures(CoalesceTexturesProcess *process);
		virtual void
			Copy(
				CopyProcess *process,
				Proxies::PolygonMeshProxy* mesh
			);
		virtual void
			GetInfo(
				GetInfoProcess *process
			);
		int
			FindErrors(FindErrorsProcess *process);
		bool
			FlattenHierarchy(FlattenHierarchyProcess *process);
		void
			GetCentroid(Stuff::Point3D *center);
		void
			Recenter();
		bool
			SplitByState(SplitByStateProcess *process);
		bool
			MakeSingleSided(MakeSingleSidedProcess *process);
		bool
			OptimizeFlatShading(OptimizeFlatShadingProcess *process);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Polygon Mesh functions
	//
	public:
		unsigned
			UseMultiStateArray(
				Stuff::DynamicArrayOf<MultiState*> *states,
				Stuff::DynamicArrayOf<unsigned> *index,
				Stuff::DynamicArrayOf<unsigned> *count,
				Stuff::DynamicArrayOf<PolygonProxy*> &polygons
			);
		static void
			DetachArrayReferences(Stuff::DynamicArrayOf<MultiState*> *states);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Polygon functions
	//
	public:
		//
		// Get the number of polygons in the mesh
		//
		virtual unsigned
			UsePolygonArray(Stuff::DynamicArrayOf<PolygonProxy*> *polygons) = 0;
		static void
			DetachArrayReferences(Stuff::DynamicArrayOf<PolygonProxy*> *polygons);
		virtual void
			AddPolygons(
				Process *process,
				Stuff::DynamicArrayOf<PolygonProxy*> &polygons
			) = 0;
		virtual void
			SetToMatchMultiState(MultiState* multi_state) = 0;

		void
			AttachPolygonProxy(PolygonProxy *proxy)
				{
					Check_Object(this);
					AttachReference(); activePolygonProxies.Add(proxy);
				}
		void
			DetachPolygonProxy(PolygonProxy* proxy);

	protected:
		Stuff::ChainOf<PolygonProxy*>
			activePolygonProxies;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Vertex functions
	//
	public:
		//
		// Get the number of vertices in the mesh
		//
		virtual unsigned
			UseVertexArray(Stuff::DynamicArrayOf<VertexProxy*> *vertices) = 0;
		static void
			DetachArrayReferences(Stuff::DynamicArrayOf<VertexProxy*> *vertices);

		void
			AttachVertexProxy(VertexProxy *proxy)
				{
					Check_Object(this);
					AttachReference(); activeVertexProxies.Add(proxy);
				}
		void
			DetachVertexProxy(VertexProxy* proxy);

	protected:
		Stuff::ChainOf<VertexProxy*>
			activeVertexProxies;
	};

}
