#pragma once

#include "Proxies.hpp"

namespace Proxies {

	class IndexProxy;
	class LightProxy;

	struct TransformedLight {
		Stuff::LinearMatrix4D
			lightToLocal;
		LightProxy
			*lightProxy;
	};

	//
	//#########################################################################
	//########################    VertexProxy    ##############################
	//#########################################################################
	//
	class VertexProxy:
		public GenericProxy
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	protected:
		VertexProxy(
			ClassData *class_data,
			PolygonMeshProxy *mesh
		);
		VertexProxy();
		~VertexProxy();

		static Stuff::MemoryBlock
			*AllocatedMemory;

	public:
		static VertexProxy*
			MakeProxy()
				{return new VertexProxy();}

		//
		// Copies the elements of the given vertex pointer into this vertex
		// pointer
		//
		void
			Destroy();

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

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Process support
	//
	public:
		virtual void
			BurnLights(
				BurnLightsProcess *process,
				Stuff::DynamicArrayOf<TransformedLight> &lights
			);
		virtual void
			Copy(
				CopyProcess *process,
				VertexProxy *vertex
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Vertex management functions
	//
	public:
		//
		// Copies the elements of a polygon into this polygon
		//
		PolygonMeshProxy*
			GetPolygonMeshProxy()
				{Check_Object(this); return polygonMeshProxy;}

		virtual bool
			IsEqualTo(
				VertexProxy* vertex,
				Stuff::Scalar threshold
			);
		virtual bool
			IsAllButNormalEqual(
				VertexProxy* vertex,
				Stuff::Scalar threshold
			);

		static unsigned
			AddUniqueVertex(
				Stuff::DynamicArrayOf<VertexProxy*> &vertices,
				unsigned *vertex_count,
				VertexProxy *new_vertex,
				Stuff::Scalar threshold
			);

		//
		// Vertices don't get names
		//
		bool
			GetName(class Stuff::MString *name)
				{Check_Object(this); Check_Object(name); return false;}
		void
			SetName(const char* name)
				{Check_Object(this); Check_Pointer(name);}

	protected:
		PolygonMeshProxy
			*polygonMeshProxy;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Vertex instance functions
	//
	public:
		void
			AttachIndexProxy(IndexProxy *proxy)
				{
					Check_Object(this);
					AttachReference(); activeIndexProxies.Add(proxy);
				}
		void
			DetachIndexProxy(IndexProxy* proxy);

	protected:
		Stuff::ChainOf<IndexProxy*>
			activeIndexProxies;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Vertex functions
	//
	public:
		//
		// position functions
		//
		virtual void
			GetPosition(Stuff::Point3D *point);
		virtual void
			SetPosition(const Stuff::Point3D &point);

		//
		// color functions
		//
		virtual bool
			GetColor(Stuff::RGBAColor *color);
		virtual void
			SetColor(const Stuff::RGBAColor& color);

		//
		// normal functions
		//
		virtual bool
			GetNormal(Stuff::Normal3D *normal);
		virtual void
			SetNormal(const Stuff::Normal3D &normal);

		//
		// UV functions
		//
		virtual bool
			GetUVs(Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > *vector);
		virtual void
			SetUVs(Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &vector);

	protected:
		Stuff::Point3D
			vertexPosition;
		Stuff::Normal3D
			vertexNormal;
		Stuff::RGBAColor
			vertexColor;
		Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> >
			vertexUVs;

		bool
			hasNormal,
			hasColor,
			hasUV;
	};

}
