
#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __TOOLS_TEXTURETILER_EXPORT_H_
#define __TOOLS_TEXTURETILER_EXPORT_H_

#include "Core/Asura_TiledTextureManagement.h"
#include "PC/Rendering/Asura_Direct3D.h"
#include "PSP/Rendering/Asura_PSP_TextureHeader.h"

// Tools
#include "Misc/Tools_Platform.h"

// swaps two instances of Tools_TT_Tile objects held in two positions in an array
template<typename T> void Tools_TT_Swap( T& A, T& B )
{
	T tmp = A;

	A = B;
	B = tmp;
}

// defines a set of common colours, useful for timed_messages etc
struct Tools_TT_Colour
{
	static const int Null;  // black with zero alpha
	static const int Black;
	static const int White;
	static const int Red;
	static const int Green;
	static const int Blue;
	static const int Magenta;
	static const int Yellow;
};

// defines the possible texture file types and their file name extensions
struct Tools_TT_FileType
{
	enum TOOLS_TT_FILE_NAME_EXTENSION
	{
		TOOLS_TT_ALL,
		TOOLS_TT_BMP,
		TOOLS_TT_DDS,
		TOOLS_TT_JPG,
		TOOLS_TT_PNG,
		TOOLS_TT_PSP,
		TOOLS_TT_TGA,
		TOOLS_TT_TM2,
		TOOLS_TT_TPL,
		TOOLS_TT_XPR,
		TOOLS_TT_FILE_NAME_EXTENSION_NUM,
	};

	static const char* s_apcFileExtensionName[TOOLS_TT_FILE_NAME_EXTENSION_NUM];

	// returns the file extension associated with the type passed as argument
	static const char* GetName( const u_int uFileType );

	// returns the file type enum of the texture file normaly associated with the platform supplied as an argument
	static const TOOLS_TT_FILE_NAME_EXTENSION GetTextureFileTypeForPlatform( const Tools_Platform_Type ePlatform );
};

// defines the availble DDS compression formats ( see Tools_TT_SaveDDS() )
struct Tools_TT_DDSCompressionFormat
{
	enum TOOLS_TT_EXPORT_DDS_COMPRESSION_FORMAT
	{
		TOOLS_TT_EXPORT_DDS_COMPRESSION_UNCOMPRESSED,
		TOOLS_TT_EXPORT_DDS_COMPRESSION_DXT1,
		TOOLS_TT_EXPORT_DDS_COMPRESSION_DXT3,
		TOOLS_TT_EXPORT_DDS_COMPRESSION_DXT5,

		TOOLS_TT_EXPORT_DDS_COMPRESSION_FORMAT_NUM,
	};

	static const char* s_apcName[TOOLS_TT_EXPORT_DDS_COMPRESSION_FORMAT_NUM];

	static const char* GetName( const u_int uFormat );
};

// defines the PSP texture pixel formats ( see Tools_TT_SavePSPTx() )
struct Tools_TT_PSPPixelFormat
{
	enum TOOLS_TT_EXPORT_PSP_PIXEL_FORMAT
	{
		//TOOLS_TT_EXPORT_PSP_PIXEL_5650,		// = ASURA_PSP_TEXTUREFORMAT_5650,
		//TOOLS_TT_EXPORT_PSP_PIXEL_5551,		// = ASURA_PSP_TEXTUREFORMAT_5551,
		//TOOLS_TT_EXPORT_PSP_PIXEL_4444,		// = ASURA_PSP_TEXTUREFORMAT_4444,
		//TOOLS_TT_EXPORT_PSP_PIXEL_8888,		// = ASURA_PSP_TEXTUREFORMAT_8888,
		//TOOLS_TT_EXPORT_PSP_PIXEL_IDX4,		// = ASURA_PSP_TEXTUREFORMAT_IDX4,
		//TOOLS_TT_EXPORT_PSP_PIXEL_IDX8,		// = ASURA_PSP_TEXTUREFORMAT_IDX8,
		//TOOLS_TT_EXPORT_PSP_PIXEL_IDX16,	// = ASURA_PSP_TEXTUREFORMAT_IDX16,
		//TOOLS_TT_EXPORT_PSP_PIXEL_IDX32,	// = ASURA_PSP_TEXTUREFORMAT_IDX32,
	
		TOOLS_TT_EXPORT_PSP_PIXEL_4,
		TOOLS_TT_EXPORT_PSP_PIXEL_8,

		TOOLS_TT_EXPORT_PSP_PIXEL_FORMAT_NUM,
	};


	static const char* s_apcName[TOOLS_TT_EXPORT_PSP_PIXEL_FORMAT_NUM];

	static const char* GetName( const u_int uFormat );
	static const int   GetValue( const u_int uFormat );
};

// defines the possible number of bits used to describe alpha in tpl textures
struct Tools_TT_TPLAlphaBits
{
	enum TOOLS_TT_EXPORT_TPL_ALPHA_BITS
	{
		TOOLS_TT_EXPORT_TPL_ALPHA_BITS_0,
		TOOLS_TT_EXPORT_TPL_ALPHA_BITS_1,
		TOOLS_TT_EXPORT_TPL_ALPHA_BITS_4,
		TOOLS_TT_EXPORT_TPL_ALPHA_BITS_8,

		TOOLS_TT_EXPORT_TPL_ALPHA_BITS_NUM,
	};

	static const char* s_apcName[TOOLS_TT_EXPORT_TPL_ALPHA_BITS_NUM];

	static const char* GetName( const u_int uFormat );
	static const u_int GetValue( const u_int uFormat );
};

class Tools_TT_Export_Pixel
{
public:
	Tools_TT_Export_Pixel();

	u_char uR;
	u_char uG;
	u_char uB;
	u_char uA;
};

const bool operator==( const Tools_TT_Export_Pixel& xLhs,const Tools_TT_Export_Pixel& xRhs );

// Raw Pixel Data
//
// Stores pixel data from an image as an array of bytes. This is used in most
// image manipulation methods.
//
// Holds a pointer to a dynamically allocated array of unsigned chars along 
// with the maximum size of the array (uSize). The *Begin/*End data members 
// define a rectangular region of the array (a window). Width and Height are
// in pixels but Size is in bytes and the data is stored in bytes.
class Tools_TT_Export_RawPixelData
{
public:
	Tools_TT_Export_RawPixelData();
	Tools_TT_Export_RawPixelData( const u_int uWidth,const u_int uHeight,const u_int uBytesPP );
	Tools_TT_Export_RawPixelData( const u_int uWidth,const u_int uHeight,const u_int uBytesPP, u_char* pcData );
	Tools_TT_Export_RawPixelData( const Tools_TT_Export_RawPixelData& xOther ); // note: makes a deep copy of all pixel data in xOther
	~Tools_TT_Export_RawPixelData();

	// deletes any existing data, creates a new data array just large enough to hold the new dimensions and calls this->Clear()
	void Set( const u_int uWidth,const u_int uHeight,const u_int uBytesPP );

	const Tools_TT_Export_RawPixelData& operator=( const Tools_TT_Export_RawPixelData& xOther );

	// returns the byte reffered to by the index
	u_char& operator[]( const u_int uIndex );

	// set window top left and bottom right corners in pixels
	void SetWindow( const u_int uXBegin,const u_int uYBegin,const u_int uXEnd,const u_int uYEnd )
	{
		m_uWindowXBegin = uXBegin;
		m_uWindowXEnd   = uXEnd;
		m_uWindowYBegin = uYBegin;
		m_uWindowYEnd   = uYEnd;
		
		Asura_Assert( m_uWindowXEnd>m_uWindowXBegin,"window has negative width" );
		Asura_Assert( m_uWindowYEnd>m_uWindowYBegin,"window has negative height" );

		Asura_Assert( m_uWindowXEnd<=GetWidth(),"window width greater than total width" );
		Asura_Assert( m_uWindowYEnd<=GetHeight(),"window height greater than total height" );
		
		m_uWindowSize = GetWindowWidth()*GetWindowHeight()*GetBytesPP();
	}

	void SetWindowToMax()
	{
		m_uWindowXBegin = 0;
		m_uWindowXEnd   = GetWidth();
		m_uWindowYBegin = 0;
		m_uWindowYEnd   = GetHeight();
		
		m_uWindowSize = GetWindowWidth()*GetWindowHeight()*GetBytesPP();	
	}

	const u_int GetBytesPP() const {return m_uBytesPP;}

	const u_int GetWidth() const {return m_uWidth;}
	const u_int GetHeight() const {return m_uHeight;}
	const u_int GetPitch() const {return GetWidth() * GetBytesPP();}
	const u_int GetSize() const {return m_uSize;}
	
	const u_int GetWindowWidth() const {return m_uWindowXEnd - m_uWindowXBegin;}
	const u_int GetWindowHeight() const {return m_uWindowYEnd - m_uWindowYBegin;}
	const u_int GetWindowPitch() const {return GetWindowWidth() * GetBytesPP();}
	const u_int GetWindowSize() const {return m_uWindowSize;}

	// set all pixels in array to null colour, as defined in Tools_TT_Colour struct
	void Clear();

	// not nice to return pointer to private data member but 
	// this is required by the interface to Texture_Writer 
	// clases - NDB
	u_char* GetData() {return m_pcBitData;}

	// copys the data in the window into the array provided as an argument upto the number of bytes specified by uSize
	u_char* GetWindowData( u_char* pcOutput, const u_int uSize );

	// texture flags
	void SetTextureFlags( const int iFlags ) { m_iTextureFlags = iFlags; };
	void SetTextureFlag( const int iFlag,const bool bState = true );
	const int GetTextureFlags() const { return m_iTextureFlags; }

private:
	int   m_iTextureFlags; // Asura texture flags applied when exporting texture

	u_int m_uWidth;   // width in pixels
	u_int m_uHeight;  // height in pixels
	u_int m_uBytesPP; // number of bytes per pixel
	u_int m_uSize;    // total size of data buffer in bytes (width*height*BytesPP)

	// location of window top-left and bottom-right corners in buffer in pixels (not bytes)
	u_int m_uWindowXBegin;
	u_int m_uWindowXEnd;
	u_int m_uWindowYBegin;
	u_int m_uWindowYEnd;
	u_int m_uWindowSize;

	u_char* m_pcBitData;
};

// defines a file header for targa files (TGA)
struct Tools_TT_TargaHeader
{
    BYTE IDLength;
    BYTE ColormapType;
    BYTE ImageType;
    BYTE ColormapSpecification[5];
    WORD XOrigin;
    WORD YOrigin;
    WORD ImageWidth;
    WORD ImageHeight;
    BYTE PixelDepth;
    BYTE ImageDescriptor;
};

// loads a texture image file into a D3D texture. The D3D texture and image info arguments are cleared and filled with data from this operation
const bool Tools_TextureTiler_Export_LoadD3DTextureFromFile( const char* szInputName,Direct3D_Texture** pxDxTexture,D3DXIMAGE_INFO& xImageInfo );

// extract all pixels from the image stored in the file, then resize the rawPixelData object and fill it with all the pixels
const bool Tools_TextureTiler_Export_RipBitsFromARGBTexture( const char* szInputName,Tools_TT_Export_RawPixelData& xOutput );

// extract all pixels from the image stored at the current postion in the file refferenced by iFileHandle, then resize the rawPixelData object and fill it with all the pixels
const bool Tools_TextureTiler_Export_RipAllARGBBitsFromFileInMemory( const Asura_Handle iFileHandle,const int iFileSize,Tools_TT_Export_RawPixelData& xOutput );

// determines texture type from file name and calls the appropriate save method
const bool Tools_TT_Export_SaveTextureAs( Tools_TT_Export_RawPixelData& xBitData,const Asura_String& xOutputFileName );

// determines texture type required for the specified platform and calls the appropriate save method
const bool Tools_TT_Export_SaveTextureForPlatform( Tools_TT_Export_RawPixelData& xBitData,Asura_String xOutputFileName,const Tools_Platform_Type eTargetPlatform );

// methods to create texture files of various formats from raw pixel data
const bool Tools_TT_Export_SaveBMP( Tools_TT_Export_RawPixelData& xBitData,const Asura_String& xOutputFileName );
const bool Tools_TT_Export_SaveTM2( Tools_TT_Export_RawPixelData& xBitData,const Asura_String& xOutputFileName );
const bool Tools_TT_Export_SaveTGA( Tools_TT_Export_RawPixelData& xBitData,const Asura_String& xOutputFileName,const bool bUseRLE = true );
const bool Tools_TT_Export_SaveTPL( Tools_TT_Export_RawPixelData& xBitData,const Asura_String& xOutputFileName,const Tools_TT_TPLAlphaBits::TOOLS_TT_EXPORT_TPL_ALPHA_BITS eAlphaBits = Tools_TT_TPLAlphaBits::TOOLS_TT_EXPORT_TPL_ALPHA_BITS_8 );
const bool Tools_TT_Export_SaveDDS( Tools_TT_Export_RawPixelData& xBitData,const Asura_String& xOutputFileName,const Tools_TT_DDSCompressionFormat::TOOLS_TT_EXPORT_DDS_COMPRESSION_FORMAT eCompresionFormat = Tools_TT_DDSCompressionFormat::TOOLS_TT_EXPORT_DDS_COMPRESSION_UNCOMPRESSED );
const bool Tools_TT_Export_SavePSPTx( Tools_TT_Export_RawPixelData& xBitData,const Asura_String& xOutputFileName );
const bool Tools_TT_Export_SavePS3Tx( Tools_TT_Export_RawPixelData& xBitData,const Asura_String& xOutputFileName );
const bool Tools_TT_Export_SaveXPR( Tools_TT_Export_RawPixelData& xBitData,const Asura_String& xOutputFileName,const Tools_TT_DDSCompressionFormat::TOOLS_TT_EXPORT_DDS_COMPRESSION_FORMAT eCompressionFormat = Tools_TT_DDSCompressionFormat::TOOLS_TT_EXPORT_DDS_COMPRESSION_UNCOMPRESSED );

// A window in xBitData coresponding to the uv coordinates of each element in the TextureInfoCollection is saved as a seperate texture file with the name of that element
const bool Tools_TT_Export_ExtractTexturesFromTTL( Tools_TT_Export_RawPixelData& xBitData,const Asura_TiledTextureInfo* pxTextureInfoCollection,const int iSize,const Tools_TT_FileType::TOOLS_TT_FILE_NAME_EXTENSION eFileType = Tools_TT_FileType::TOOLS_TT_TGA );

// filles the the texture and image dimensions passed as args by reading in the specified file 
const bool Tools_TT_Export_FindTextureAndImageSize( const char* szFileName,int& iTextureWidth,int& iTextureHeight,int& iImageWidth,int& iImageHeight );


// returns the fully qualified path to the graphics directory, including final backslash - NDB
const Asura_String Tools_TT_GetGraphicsPath();

// prefixes the fully qualified path of the graphics directory to the argument. Compenstates correctly for arguments with a preceeding '\'
const Asura_String& Tools_TT_PrefixWithGraphicsPath( Asura_String& xPath );

// remove file extension (including the preceeding '.') and replace it with the string provided as the 2nd arg
const Asura_String& Tools_TT_ReplaceFileExtension( Asura_String& xPath,const Asura_String& xReplacement );

const Asura_String Tools_TT_CreateExportPathForPlatform( const Asura_String& xPath,const int iPlatformType );

// exports a copy of the specifed tiled texture for the specified platform 
void Tools_TT_CreateTiledTextureForPlatform( const Asura_String& xFileName, const int iPlatformType );

// transforms the full path to a tile file into the full path to its associated tga texture file
const Asura_String Tools_TT_CreateTextureFileName( const Asura_String& xTileFileName );

// returns true if the argument is a power of two.
inline const bool Tools_TT_IsPowerOf2( const int iArg )
{
	return (iArg) && !( iArg&(iArg-1) );
}

// find the first power of two which is greater than or equal to the number provided as an arguement
const int Tools_TT_FindNextLargerPowerOfTwo( const int iArg );

inline const int Tools_TT_FindNextSmallerPowerOfTwo( const int iArg )
{
	return (Tools_TT_IsPowerOf2(iArg))? iArg:Tools_TT_FindNextLargerPowerOfTwo(iArg)>>1;
}

// shift elements to the end of the collection if the predicate returns the bool specified in the last argument 
template< typename iterator,typename predicate > iterator const Tools_TT_ShiftElementsToEnd( iterator const pxBegin, iterator const pxEnd, const predicate& xPredicate, const bool bPredicateReturn = true )
{
	iterator pxItr(pxBegin);
	iterator pxFirstShiftedElement(pxEnd);

	Asura_Assert( pxEnd > pxBegin,"The end of the collection comes before the begining" );

	// skip any elements which are already at the end of the collection and are supposed to be there
	--pxFirstShiftedElement; // decrement iterator, temporarily using it as 'last element' iterator

	while( (pxFirstShiftedElement!=pxBegin) && (xPredicate( *pxFirstShiftedElement ) == bPredicateReturn) )
	{
		--pxFirstShiftedElement;
	}

	++pxFirstShiftedElement; // increment iterator to compenstate for decrementing it earlier

	// move elements to end of collection
	while( pxItr!=pxFirstShiftedElement )
	{
		if( xPredicate( *pxItr ) == bPredicateReturn )
		{
			--pxFirstShiftedElement;
			Tools_TT_Swap( *pxItr,*pxFirstShiftedElement );
		}
		else
		{
			++pxItr;
		}
	}

	return pxFirstShiftedElement;
}

class GraphicsFileExists
{
public:
	const bool operator()( const char* szFileName ) const;
	const bool operator()( const Asura_TiledTextureInfo& xInfo ) const;
};

// for each element in collection, checks whether file exists in graphics path on disk. If a file does not exist 
// it's TextureInfo is moved toward the end of the collection. The return value is a pointer to the first file 
// that was not found on disk.
inline Asura_TiledTextureInfo* const Tools_TT_ShiftNonExistantFilesToEnd( Asura_TiledTextureInfo* const pxTextureInfoBegin,Asura_TiledTextureInfo* const pxTextureInfoEnd )
{
	return Tools_TT_ShiftElementsToEnd( pxTextureInfoBegin,pxTextureInfoEnd,GraphicsFileExists(),false ); 
}


// if file name ends with a number then increment that number, else append "_0" to the end of the file name
const Asura_String&	Tools_TT_IncrementFileName( Asura_String& xNextOutputFileName );

#endif // __TOOLS_TEXTURETILER_EXPORT_H_

