#pragma once

#include "MAXProxies.hpp"

namespace MAXProxies {

	class MAXScene;
	class MAXGroup;

	//
	//#########################################################################
	//########################    MAXPolygonMesh    ############################
	//#########################################################################
	//
	class MAXPolygonMesh:
		public Proxies::PolygonMeshProxy
	{
		friend class MAXVertex;

	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		static MAXPolygonMesh*
			MakeProxy(
				MAXScene *scene,
				MAXGroup *parent,
				INode *mesh,
				TimeValue t,
				int index,
				bool children
			)
				{return new MAXPolygonMesh(
								scene, 
								parent, 
								mesh,
								t,
								index,
								children
				);}

		void
			Destroy();

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

	protected:
		MAXPolygonMesh(
			MAXScene *scene,
			MAXGroup *parent,
			INode *mesh,
			TimeValue t,
			int index,
			bool children

		);
		~MAXPolygonMesh();

		static Stuff::MemoryBlock
			*AllocatedMemory;

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Process support
	//
	public:
		void
			Copy(Proxies::PolygonMeshProxy* mesh);

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

		MAXGroup*
			GetParentGroupProxy()
				{
					Check_Object(this);
					return reinterpret_cast<MAXGroup*>(parentProxy);
				}
		void
			TransferAndAppendToParentGroup(Proxies::GroupProxy *parent);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// polygon mesh 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
		//
		bool
			GetOBB(Stuff::OBB *obb);
		void
			SetOBB(const Stuff::OBB &obb);
		void
			SetBoundingSphere(const Stuff::Sphere &sphere);
		Mtl *
			GetMtl() {return proxiedMesh->GetMtl();}


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Polygon functions
	//
	public:
		//
		// Get the number of polygons in the mesh
		//
		unsigned
			UsePolygonArray(Stuff::DynamicArrayOf<Proxies::PolygonProxy*> *polygons);

		void
			AddPolygons(
				Proxies::Process *process,
				Stuff::DynamicArrayOf<Proxies::PolygonProxy*> &polygons);

//		void
//			SetToMatchStateProxy(Proxies::StateProxy* state);

		void
			SetToMatchMultiState(Proxies::MultiState* multi_state);

	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Vertex functions
	//
	public:
		//
		// Get the number of vertices in the mesh
		//
		unsigned
			UseVertexArray(Stuff::DynamicArrayOf<Proxies::VertexProxy*> *vertices);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Local implementation details
	//
	public:
		INode*
			GetProxiedMesh()
				{Check_Object(this); return proxiedMesh;}
		INode 
			*GetPreviousChild();
		INode 
			*GetNextChild();
		int
			GetNumberTextureMaps(int face_index);

		int
			GetUVTypeOfMap(int texture_index, int face_index);

	protected:
		TriObject 
			*meshData;

//		static INode*
//			AllocateRecord()
//				{return mgNewRec(fltObject);}


	protected:
		bool 
			needToDelete;

		TimeValue
			time;

		int
			childIndex;

		bool
			pseudoChild,bmeshInitialized;

		INode
			*proxiedMesh;

		Stuff::LinearMatrix4D
			meshToPivot;

		Stuff::DynamicArrayOf<DWORD> group_array;
		Stuff::DynamicArrayOf<Face> face_array;
		Stuff::DynamicArrayOf<Point3> vertex_array;
		Stuff::DynamicArrayOf<DWORD> vertex_ref_array;
		Stuff::DynamicArrayOf<DWORD> vertex_revmap;	// reverse map of the new to old vertex index
		Stuff::DynamicArrayOf<Point3> normal_array; // normal for each vertex
		Mesh *newMesh;
	public:
		int InitMesh();

		int GetNumVertices();
		Point3 *GetVertex(DWORD);
		DWORD GetVertexGroup(DWORD);

		TVFace *GetTVFace(int);
		int GetnumTVerts();
		UVVert GetTVert(DWORD);
		void SetTVert(DWORD,UVVert);
		int GetnumCVerts();
		VertColor *GetvertColor(DWORD);
		Point3 GetFaceNormal(DWORD);
		Point3 GetVertexNormal(DWORD);
		void SetNormal(DWORD,Point3);
		int GetNumVertCol();
	};
}
