#pragma once

#include "ElementProxies.hpp"

namespace ElementProxies {

	class ElementSceneProxy;
	class MLRTexturePoolProxy;
	class MLRStatePoolProxy;

	//
	//#########################################################################
	//######################    MLRTextureProxy    #############################
	//#########################################################################
	//
	class MLRTextureProxy:
		public Proxies::TextureProxy
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		static MLRTextureProxy*
			MakeProxy(
				MLRTexturePoolProxy *library,
				MidLevelRenderer::MLRTexture *texture
			)
				{return new MLRTextureProxy(library, texture);}

		void
			Destroy();

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

	protected:
		MLRTextureProxy(
			MLRTexturePoolProxy *library,
			MidLevelRenderer::MLRTexture *texture
		);
		~MLRTextureProxy();

		static Stuff::MemoryBlock
			*AllocatedMemory;

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Texture management functions
	//
	public:
		MLRTexturePoolProxy*
			GetTextureLibrary()
				{
					Check_Object(this);
					return Cast_Pointer(MLRTexturePoolProxy*, libraryProxy);
				}

		Proxies::TextureProxy*
			UseNextTextureProxyInLibrary();
		
		Proxies::TextureProxy*
			UsePreviousTextureProxyInLibrary();

		bool GetFormat(FormatType*);
		void SetFormat(FormatType);

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

		//
		// Get the bitmap size
		//
		void
			GetImageSize(Stuff::Vector2DOf<int> *size);

		//
		// Get pixel sizes per channel
		//
		void
			GetChannelDepth(
				unsigned *red_depth,
				unsigned *blue_depth,
				unsigned *green_depth,
				unsigned *alpha_depth
			);

		//
		// Get channel values
		//
		void
			GetChannels(
				Stuff::DynamicArrayOf<BYTE> *red,
				Stuff::DynamicArrayOf<BYTE> *green,
				Stuff::DynamicArrayOf<BYTE> *blue,
				Stuff::DynamicArrayOf<BYTE> *alpha
			);
		void
			SetChannels(
				const Stuff::DynamicArrayOf<BYTE> *red,
				const Stuff::DynamicArrayOf<BYTE> *green,
				const Stuff::DynamicArrayOf<BYTE> *blue,
				const Stuff::DynamicArrayOf<BYTE> *alpha
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Helper functions
	//
	public:
		MidLevelRenderer::MLRTexture*
			GetMLRTexture()
				{Check_Object(this); return mlrTexture;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Implementation details
	//
	protected:
		MidLevelRenderer::MLRTexture
			*mlrTexture;

		void
			ReadTexture();
	};

	//
	//#########################################################################
	//######################    MLRTexturePoolProxy    ###########################
	//#########################################################################
	//
	class MLRTexturePoolProxy:
		public Proxies::TextureLibrary
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	protected:
		MLRTexturePoolProxy(
			MLRStatePoolProxy *states,
			const char *path
		);
		MLRTexturePoolProxy(MLRStatePoolProxy *states);
		~MLRTexturePoolProxy();

	public:
		static MLRTexturePoolProxy*
			MakeProxy(
				MLRStatePoolProxy *states,
				const char *path
			)
				{return new MLRTexturePoolProxy(states, path);}
		static MLRTexturePoolProxy*
			MakeProxy(MLRStatePoolProxy *states)
				{return new MLRTexturePoolProxy(states);}
		void
			Destroy();

		virtual void
			GetInfo( Proxies::GetInfoProcess *process );

		static MLRTexturePoolProxy
			*Instance;

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

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Texture functions
	//
	public:
		//
		// Gets the current number of children
		//
		unsigned
			GetTextureCount();

		//
		// Child creation functions
		//
		Proxies::TextureProxy*
			UseNewTextureProxy();
		Proxies::TextureProxy*
			UseMatchingTextureProxy(Proxies::TextureProxy *texture);
		Proxies::TextureProxy*
			UseTextureProxy(const char* texture_name);

		//
		// Child traversal functions
		//
		Proxies::TextureProxy*
			UseFirstTextureProxy();
		Proxies::TextureProxy*
			UseLastTextureProxy();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// ElementRenderer helper functions
	//
	public:
		MLRTextureProxy*
			UseTextureProxy(unsigned handle);

		void
			CloseLibrary(bool flush_mlr=false);
		const char*
			GetTexturePath()
				{Check_Object(this); return texturePath;}
		void SetTexturePath(const char *path)
			{Check_Object(this); texturePath = path;}

	protected:
		Stuff::DynamicArrayOf<MLRTextureProxy*>
			textureProxies;
		unsigned
			textureCount;
		Stuff::MString
			texturePath;
	};

}
