#pragma once

#include "Proxies.hpp"
#include "GenericProxy.hpp"

namespace Proxies {

	class StateLibrary;
	class TextureLibrary;
	class BuildMegatexturesProcess;
	class GetInfoProcess;
	class ArrangeMegatexturesProcess;

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

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	protected:
		TextureProxy(
			ClassData *class_data,
			TextureLibrary *library
		);
		TextureProxy(
			const char* name,
			const Stuff::Vector2DOf<int> &size,
			TextureLibrary *library
		);
		~TextureProxy();

		static Stuff::MemoryBlock
			*AllocatedMemory;

	public:
		static TextureProxy*
			MakeProxy(
				const char* name,
				const Stuff::Vector2DOf<int> &size,
				TextureLibrary *library
			)
				{return new TextureProxy(name, size, library);}

		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 int
			FindErrors(FindErrorsProcess *process);
		virtual void
			Copy(
				CopyProcess *process,
				TextureProxy *texture
			);
		virtual void
			GetInfo(
				GetInfoProcess *process
			);
		virtual void
			BuildMegatextures(BuildMegatexturesProcess *process);
		virtual void
			ArrangeMegatextures(ArrangeMegatexturesProcess *process);

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

		virtual bool
			IsEqualTo(TextureProxy *texture);

		virtual TextureProxy*
			UseNextTextureProxyInLibrary();

		virtual TextureProxy*
			UsePreviousTextureProxyInLibrary();

		enum FormatType {
			AlphaTexture = 0,
			KeyedTexture
		};
		virtual bool 
			GetFormat(FormatType*);
		virtual void
			SetFormat(FormatType);

	protected:
		TextureLibrary
			*libraryProxy;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Texture functions
	//
	public:
		enum {
			RedChannel,
			GreenChannel,
			BlueChannel,
			AlphaChannel
		};

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

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

		//
		// Get channel data
		//
		virtual void
			GetChannelDepth(
				unsigned *red_depth,
				unsigned *blue_depth,
				unsigned *green_depth,
				unsigned *alpha_depth
			);
		virtual void
			GetChannels(
				Stuff::DynamicArrayOf<BYTE> *red,
				Stuff::DynamicArrayOf<BYTE> *green,
				Stuff::DynamicArrayOf<BYTE> *blue,
				Stuff::DynamicArrayOf<BYTE> *alpha
			);

		virtual void
			SetChannels(
				const Stuff::DynamicArrayOf<BYTE> *red,
				const Stuff::DynamicArrayOf<BYTE> *green,
				const Stuff::DynamicArrayOf<BYTE> *blue,
				const Stuff::DynamicArrayOf<BYTE> *alpha
			);

		//
		// Get pixel index
		//
		unsigned
			GetPixelIndex(const Stuff::Vector2DOf<int> &location)
				{Check_Object(this); return location.y*textureSize.x + location.x;}

		//
		// Texture saving
		//
		void
			SaveAsTarga(const char* filename);
		void
			ReadTarga(
				const char* filename,
				unsigned *red_depth,
				unsigned *green_depth,
				unsigned *blue_depth,
				unsigned *alpha_depth,
				Stuff::Vector2DOf<int> *size,
				Stuff::DynamicArrayOf<BYTE> *red,
				Stuff::DynamicArrayOf<BYTE> *green,
				Stuff::DynamicArrayOf<BYTE> *blue,
				Stuff::DynamicArrayOf<BYTE> *alpha
			);
		void
			ReadPNG(
				const char* filename,
				unsigned *red_depth,
				unsigned *green_depth,
				unsigned *blue_depth,
				unsigned *alpha_depth,
				Stuff::Vector2DOf<int> *size,
				Stuff::DynamicArrayOf<BYTE> *red,
				Stuff::DynamicArrayOf<BYTE> *green,
				Stuff::DynamicArrayOf<BYTE> *blue,
				Stuff::DynamicArrayOf<BYTE> *alpha
			);
		void SaveAsPng(const char* filename);

	protected:
		Stuff::Vector2DOf<int>
			textureSize;
		Stuff::MString
			textureName;
		unsigned
			redDepth,
			greenDepth,
			blueDepth,
			alphaDepth;
		Stuff::DynamicArrayOf<BYTE>
			redChannel,
			greenChannel,
			blueChannel,
			alphaChannel;
	};

	//
	//#########################################################################
	//####################    TextureLibrary    ##########################
	//#########################################################################
	//
	class _declspec(novtable) TextureLibrary:
		public GenericProxy
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	protected:
		TextureLibrary(
			ClassData *class_data,
			StateLibrary *state_library
		);

	public:
		~TextureLibrary();

		//
		// Copies the elements of the given material into this material
		//

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Process support
	//
	public:
		virtual int
			FindErrors(FindErrorsProcess *process);
		virtual void
			Copy(
				CopyProcess *process,
				TextureLibrary *texture
			);
		virtual void
			GetInfo(
				GetInfoProcess *process
			);
		virtual void
			BuildMegatextures(BuildMegatexturesProcess *process);
		virtual void
			ArrangeMegatextures(ArrangeMegatexturesProcess *process);

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

	protected:
		StateLibrary
			*stateLibrary;

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

		//
		// Gets the current number of children
		//
		virtual unsigned
			GetTextureCount() = 0;

		//
		// Child creation functions
		//
		virtual TextureProxy*
			UseNewTextureProxy() = 0;
		virtual TextureProxy*
			UseMatchingTextureProxy(TextureProxy *texture) = 0;
		virtual TextureProxy*
			UseTextureProxy(const char* texture_name) = 0;

		//
		// Child traversal functions
		//
		virtual TextureProxy*
			UseFirstTextureProxy() = 0;
		virtual TextureProxy*
			UseLastTextureProxy() = 0;
		void
			AttachTextureProxy(TextureProxy *proxy)
				{
					Check_Object(this);
					AttachReference(); activeTextureProxies.Add(proxy);
				}
		void
			DetachTextureProxy(TextureProxy* proxy);

	protected:
		Stuff::ChainOf<TextureProxy*>
			activeTextureProxies;
	};

}
