#pragma once

#include "ElementProxies.hpp"

namespace ElementProxies {

	class ElementSceneProxy;
	class MLRStatePoolProxy;

	//
	//#########################################################################
	//########################    MLRStateProxy    ############################# 
	//#########################################################################
	//
	class MLRStateProxy:
		public Proxies::StateProxy
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		static MLRStateProxy*
			MakeProxy(
				MLRStatePoolProxy *library,
				const MidLevelRenderer::MLRState &state
			)
				{return new MLRStateProxy(library, state);}

		void
			Destroy();

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

	protected:
		MLRStateProxy(
			MLRStatePoolProxy *library,
			const MidLevelRenderer::MLRState &state
		);
		~MLRStateProxy();

		static Stuff::MemoryBlock
			*AllocatedMemory;

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State management functions
	//
	public:
		MLRStatePoolProxy*
			GetStateLibrary()
				{
					Check_Object(this);
					return Cast_Pointer(MLRStatePoolProxy*, libraryProxy);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State functions
	//
	public:
		//
		// name functions
		//
		bool
			GetName(Stuff::MString *name);
		void
			SetName(const char* name);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Render state
	//
		bool
			GetAlpha(AlphaMode*);
		void
			SetAlpha(AlphaMode);
		bool
			GetAlphaChildPermission();
		void
			SetAlphaChildPermission(bool override);

		bool
			GetFilter(FilterMode*);
		void
			SetFilter(FilterMode);
		bool
			GetFilterChildPermission();
		void
			SetFilterChildPermission(bool override);

		bool
			GetFog(FogMode*);
		void
			SetFog(FogMode);
		bool
			GetFogChildPermission();
		void
			SetFogChildPermission(bool override);

		bool
			GetDither(bool*);
		void
			SetDither(bool);
		bool
			GetDitherChildPermission();
		void
			SetDitherChildPermission(bool override);

		 bool
			GetSpecular(bool*);
		 void
			SetSpecular(bool);
		 bool
			GetSpecularChildPermission();
		 void
			SetSpecularChildPermission(bool override);

		bool
			GetTextureCorrection(bool*);
		void
			SetTextureCorrection(bool);
		bool
			GetTextureCorrectionChildPermission();
		void
			SetTextureCorrectionChildPermission(bool override);

		 bool
			GetTextureWrap(TextureWrapMode*);
		 void
			SetTextureWrap(TextureWrapMode);
		 bool
			GetTextureWrapChildPermission();
		 void
			SetTextureWrapChildPermission(bool override);

		bool
			GetWireFrame(WireFrameMode*);
		void
			SetWireFrame(WireFrameMode);
		bool
			GetWireFrameChildPermission();
		void
			SetWireFrameChildPermission(bool override);

		bool
			GetZBufferCompare(bool*);
		void
			SetZBufferCompare(bool);
		bool
			GetZBufferCompareChildPermission();
		void
			SetZBufferCompareChildPermission(bool override);

		bool
			GetZBufferWrite(bool*);
		void
			SetZBufferWrite(bool);
		bool
			GetZBufferWriteChildPermission();
		void
			SetZBufferWriteChildPermission(bool override);

		bool
			GetFlatColoring(bool*);
		void
			SetFlatColoring(bool);
		bool
			GetFlatColoringChildPermission();
		void
			SetFlatColoringChildPermission(bool override);


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Process state
	//
		bool
			GetMatTwoSided(bool *onOff);
		void
			SetMatTwoSided(bool onOff);
		bool
			GetMatTwoSidedChildPermission();
		void
			SetMatTwoSidedChildPermission(bool override);

		bool
			GetBackface(bool *onOff);
		void
			SetBackface(bool onOff);
		bool
			GetBackfaceChildPermission();
		void
			SetBackfaceChildPermission(bool override);

		bool
			GetPriority(int*);
		void
			SetPriority(int);
		bool
			GetPriorityChildPermission();
		void
			SetPriorityChildPermission(bool override);

		bool
			GetLighting(int*);
		void
			SetLighting(int);
		bool
			GetLightingChildPermission();
		void
			SetLightingChildPermission(bool override);

		//
		// specular color functions
		//
		bool
			GetSpecularColor(Stuff::RGBColor *color);
		void
			SetSpecularColor(const Stuff::RGBColor &color);
		Stuff::Scalar
			GetSpecularShininess();
		void
			SetSpecularShininess(Stuff::Scalar shininess);

		//
		// texture functions
		//
		Proxies::TextureProxy*
			UseTextureProxy();
		Proxies::TextureProxy*
			SetToMatchTextureProxy(Proxies::TextureProxy *texture);

	protected:
		MidLevelRenderer::MLRState
			mlrState;

	public:
		const MidLevelRenderer::MLRState&
			GetMLRState()
				{Check_Object(this); return mlrState;}
	};

	//
	//#########################################################################
	//######################    MLRStatePoolProxy    ##########################
	//#########################################################################
	//
	class MLRStatePoolProxy:
		public Proxies::StateLibrary
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	protected:
		MLRStatePoolProxy(
			ElementSceneProxy *scene,
			const char *path
		);
		MLRStatePoolProxy(ElementSceneProxy *scene);
		~MLRStatePoolProxy();

	public:
		static MLRStatePoolProxy*
			MakeProxy(
				ElementSceneProxy *scene,
				const char *path
			)
				{return new MLRStatePoolProxy(scene, path);}
		static MLRStatePoolProxy*
			MakeProxy(ElementSceneProxy *scene)
				{return new MLRStatePoolProxy(scene);}

		void
			Destroy();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data Support
	//
	public:
		static ClassData
			*DefaultData;

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State management functions
	//
	public:
		ElementSceneProxy*
			GetSceneProxy()
				{Check_Object(this); return Cast_Pointer(ElementSceneProxy*, sceneProxy);}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State functions
	//
	public:
		//
		// Child creation functions
		//
		Proxies::StateProxy*
			UseMatchingStateProxy(
				Proxies::StateProxy *state,
				Proxies::TextureProxy *texture=NULL
			);
		void
			CalculateMLRState(
				MidLevelRenderer::MLRState *state,
				Proxies::StateProxy *proxy,
				Proxies::TextureProxy *texture
			);
		void
			CloseLibrary();

	protected:
		Stuff::HashOf<MLRStateProxy*, MidLevelRenderer::MLRState>
			proxiedStates;
	};

}
