//
// Asura_DebugText.cpp
//
// Created by Kevin Lea - 12/06/2001 11:06:03
// Modified by Andrew Weinkove - 11/11/02 - 
// ********************************************************
//	Re-named from Asura_Text_Output to Asura_DebugText.
//	Hungarianised code.
//	Batched text so code can be called from anywhere for debug text.
//	Added ASURA_USE_DEBUG_TEXT project option.
//	Changed so that it uses static memory allocation.
//  AW - 28/02/03 - Added ability to have multi-frame text blocks.
//  ARC - 01/09/06 - Added ability to reuse specific blocks by ID
// ********************************************************
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "Debugging/Asura_DebugText.h"

#ifdef ASURA_USE_DEBUG_TEXT
// Kevin Lea - 05/10/2001 15:11:28 - hey! I'm being naughty have the stuff below in Independent code
// I guess the primary use of this is debugging text, but eventually we'll need nicer text display stuff
#include <stdio.h> // for vsprintf
#include "Core/Asura_Maths.h"
#include "Core/Asura_Mempool.h"
#include "Core/Asura_TextureManagement.h"
#include "Rendering/Asura_Render.h"

static const Asura_Char* FontFilename = "\\tools\\font.dds";

DEBUGVAR u_int	dbg_uDefaultTextInitialX	= 4;
DEBUGVAR u_int	dbg_uDefaultTextInitialY	= 4;

u_int					Asura_DebugText::s_uDefaultTextX	= dbg_uDefaultTextInitialX;
u_int					Asura_DebugText::s_uDefaultTextY	= dbg_uDefaultTextInitialY;
int						Asura_DebugText::s_iFontTextureIndex;
unsigned				Asura_DebugText::s_uNumTextBlocksUsed;
Asura_DebugTextBlock	Asura_DebugText::s_axDebugTextBlocks[ASURA_DEBUG_TEXT_MAX_BLOCKS];
unsigned				Asura_DebugText::s_uNumCharsUsed;
Asura_Char				Asura_DebugText::s_acTextBuffer[ASURA_DEBUG_TEXT_MAX_CHARS];
Asura_DebugText_PlatformPrint* Asura_DebugText::s_pfnPlatformOverride = NULL;

void Asura_DebugText::Initialise(void)
{
	s_iFontTextureIndex = Asura_Texture_Management::AddTextureWithResetGroup( FontFilename, ASURA_TEXTURE_LOADED_PERMANENT);
	s_uNumTextBlocksUsed = 0;
	s_uNumCharsUsed = 0;
}

void Asura_DebugText::Shutdown(void)
{
	s_uNumTextBlocksUsed = 0;
	s_uNumCharsUsed = 0;
}

void Asura_DebugText::Reset(void)
{
	Shutdown();
	Initialise();
}

void Asura_DebugText::AddTextBlock(const unsigned int uX, const unsigned int uY, const unsigned int uColour, const int iFormatFlags, const Asura_Char* szString, va_list& xVAList)
{
	// N.B. If a block is being overwritten, there has to be enough space in the character buffer
	// for the old string AND the new string, since the old string will no longer be pointed to.
	// This shouldn't be a problem though as when all the blocks are rendered, the blocks that
	// persist over several frames will be cleaned up (see code at the end of RenderAll())

	if(s_uNumTextBlocksUsed < ASURA_DEBUG_TEXT_MAX_BLOCKS)
	{
		int iNumCharsRemaining = ASURA_DEBUG_TEXT_MAX_CHARS - s_uNumCharsUsed;

		if(iNumCharsRemaining < 0)
		{
			Asura_Assert(iNumCharsRemaining >= 0, "Sanity check");
		}
		else if(iNumCharsRemaining == 0)
		{
			Asura_Assert(false, "Error : Asura_DebugText has exceeded max number of characters (see ASURA_DEBUG_TEXT_MAX_CHARS in Asura_EngineConfiguration.h). You are calling RenderAll() once per frame, right?");
		}
		else
		{
			Asura_PrintfToBfr(&s_acTextBuffer[s_uNumCharsUsed], szString, xVAList, iNumCharsRemaining, true);

			// ARC - 01 September 2006 15:09:01 - Check if an ID has been specified and attempt to find the requested block.
			//                                    If it's not found, a new block will be created (if possible)
			unsigned int uiRequestedID = (iFormatFlags & ASURA_DEBUGTEXT_FORMAT_BLOCKID);
			unsigned int uiBlockToUse = s_uNumTextBlocksUsed;

			if (uiRequestedID != 0)
			{
				for (uiBlockToUse = 0; uiBlockToUse < s_uNumTextBlocksUsed; ++uiBlockToUse)
				{
					unsigned int uiBlockID = (s_axDebugTextBlocks[uiBlockToUse].iFormatFlags &= ASURA_DEBUGTEXT_FORMAT_BLOCKID);
					if (uiBlockID == uiRequestedID)
					{
						break;
					}
				}
			}

			s_axDebugTextBlocks[uiBlockToUse].uX = uX;
			s_axDebugTextBlocks[uiBlockToUse].uY = uY;
			if (iFormatFlags & ASURA_DEBUGTEXT_FORMAT_NOFRAMEDISPLAY)
			{
				s_axDebugTextBlocks[uiBlockToUse].iFormatFlags = iFormatFlags;
			}
			else
			{
				// If they've not set number of frames - set it to 1.
				s_axDebugTextBlocks[uiBlockToUse].iFormatFlags = iFormatFlags | 0x01000000;
			}
			s_axDebugTextBlocks[uiBlockToUse].uColour = uColour;
			Asura_Assert(uColour & 0xff000000, "Did you intend to make a fully alpha'd debug text block?");
			s_axDebugTextBlocks[uiBlockToUse].szText = &s_acTextBuffer[s_uNumCharsUsed];
			s_uNumCharsUsed += strlen(s_axDebugTextBlocks[uiBlockToUse].szText) + 1;

			// Increment text block count if we added a new one
			if (uiBlockToUse == s_uNumTextBlocksUsed)
			{
				s_uNumTextBlocksUsed++;
			}
		}
	}
}

void Asura_DebugText::AddDefaultTextBlock(const unsigned int uColour, const int iFormatFlags, const Asura_Char* szString, ...)
{
	va_list ap;

	// KJL 26/07/00 12:02:01 - format string and place in buffer
	va_start(ap, szString);
	AddTextBlock(s_uDefaultTextX, s_uDefaultTextY++, uColour, iFormatFlags, szString, ap);
	va_end(ap);
}

void Asura_DebugText::AddTextBlock(const unsigned int uX, const unsigned int uY, const unsigned int uColour, const int iFormatFlags, const Asura_Char* szString, ...)
{
	va_list ap;

	// KJL 26/07/00 12:02:01 - format string and place in buffer
	va_start(ap, szString);
	AddTextBlock(uX, uY, uColour, iFormatFlags, szString, ap);
	va_end(ap);
}

void Asura_DebugText::RenderAll(void)
{
	// Note : It is convenient to render in reverse order, hopefully this should 
	// cause no problems.aw.
	Asura_Render::AllowFullScreenRendering();
	Asura_Render::Overlay.m_bNonRotated = true;

	unsigned uNumTextBlocks = s_uNumTextBlocksUsed;
	while (s_uNumTextBlocksUsed)
	{
		Asura_DebugTextBlock *pxTextBlock = &s_axDebugTextBlocks[--s_uNumTextBlocksUsed];
		if(s_pfnPlatformOverride)
		{
			s_pfnPlatformOverride(pxTextBlock);
			continue;
		}
		// Render.
		float fX = pxTextBlock->uX * ASURA_DEBUGTEXT_OUTPUT_FONT_WIDTH;
		float fY = pxTextBlock->uY * ASURA_DEBUGTEXT_OUTPUT_FONT_HEIGHT;
		if (pxTextBlock->iFormatFlags)
		{
			int iLengthOfString=strlen(pxTextBlock->szText);

			if (pxTextBlock->iFormatFlags & ASURA_DEBUGTEXT_FORMAT_RIGHTJUSTIFIED)
			{
				fX -= ASURA_DEBUGTEXT_OUTPUT_FONT_WIDTH*iLengthOfString;
			}
			else if (pxTextBlock->iFormatFlags & ASURA_DEBUGTEXT_FORMAT_CENTREJUSTIFIED)
			{
				fX -= (ASURA_DEBUGTEXT_OUTPUT_FONT_WIDTH*iLengthOfString)/2;
			}
		}

		// KJL 26/05/00 12:25:29 - each letter is drawn as a series of quads
		Asura_Render::Overlay.Colour = pxTextBlock->uColour;
		Asura_Render::Overlay.TextureIndex = s_iFontTextureIndex;
		Asura_Render::Overlay.TranslucencyMode = ASURA_TRANSLUCENCY_NORMAL;

		fX=Asura_Maths::FloatToInt(fX)-0.5f;
		fY=Asura_Maths::FloatToInt(fY)-0.5f;

		Asura_Render::Overlay.Y[0] = fY;
		Asura_Render::Overlay.Y[1] = fY;
		Asura_Render::Overlay.Y[2] = fY + ASURA_DEBUGTEXT_OUTPUT_FONT_HEIGHT;
		Asura_Render::Overlay.Y[3] = fY + ASURA_DEBUGTEXT_OUTPUT_FONT_HEIGHT;

		Asura_Char *pcStringPtr = pxTextBlock->szText;
		while( *pcStringPtr )
		{
			Asura_Char cChar = *pcStringPtr++; 
			
			if (cChar!=' ')
			{
				float fTopLeftU = (float)(1+((cChar)&15)*16)/256.0f;
				float fTopLeftV = (float)(1+((cChar)>>4)*16)/256.0f;
				float fDelta = 0.0f;//1.0f/256.0f;
				float fDeltaWidth = ASURA_DEBUGTEXT_OUTPUT_FONT_WIDTH/256.0f+fDelta;
				float fDeltaHeight =ASURA_DEBUGTEXT_OUTPUT_FONT_HEIGHT/256.0f+fDelta;

				Asura_Render::Overlay.U[0] = fTopLeftU + fDelta;
				Asura_Render::Overlay.V[0] = fTopLeftV + fDelta;
				Asura_Render::Overlay.U[1] = fTopLeftU + fDeltaWidth;
				Asura_Render::Overlay.V[1] = fTopLeftV + fDelta;
				Asura_Render::Overlay.U[2] = fTopLeftU + fDeltaWidth;
				Asura_Render::Overlay.V[2] = fTopLeftV + fDeltaHeight;
				Asura_Render::Overlay.U[3] = fTopLeftU + fDelta;
				Asura_Render::Overlay.V[3] = fTopLeftV + fDeltaHeight;
				
				Asura_Render::Overlay.X[0] = fX ;
				Asura_Render::Overlay.X[3] = fX ;
				Asura_Render::Overlay.X[1] = fX + ASURA_DEBUGTEXT_OUTPUT_FONT_WIDTH ;
				Asura_Render::Overlay.X[2] = fX + ASURA_DEBUGTEXT_OUTPUT_FONT_WIDTH ;
					
				Asura_Render::Overlay.Render(false);
			}
			fX += ASURA_DEBUGTEXT_OUTPUT_FONT_WIDTH;
		}
	}
	Asura_Render::FlushDisplay();
	s_uNumCharsUsed = 0;
	// AW - 28/02/03 - Add any text blocks that are multi-frame
	// Must iterate forwards as we will fill from the start.
	for (unsigned u=0;u<uNumTextBlocks;u++)
	{
		Asura_DebugTextBlock *pxTextBlock = &s_axDebugTextBlocks[u];
		int iFramesRemaining = pxTextBlock->iFormatFlags >> ASURA_DEBUGTEXT_NOFRAMEDISPLAYBITSHIFT;
		iFramesRemaining--;
		if (iFramesRemaining)
		{
			pxTextBlock->iFormatFlags &= ~ASURA_DEBUGTEXT_FORMAT_NOFRAMEDISPLAY;
			pxTextBlock->iFormatFlags |= iFramesRemaining << ASURA_DEBUGTEXT_NOFRAMEDISPLAYBITSHIFT;
			AddTextBlock(pxTextBlock->uX, pxTextBlock->uY, pxTextBlock->uColour, pxTextBlock->iFormatFlags, pxTextBlock->szText);
		}
	}

	// Reset the fixed-text positions...
	s_uDefaultTextX	= dbg_uDefaultTextInitialX;
	s_uDefaultTextY	= dbg_uDefaultTextInitialY;
}

#endif //ASURA_USE_DEBUG_TEXT
