#include "PopUpBox.h"
#include "sysutil.h"


#define BORDER_WIDTH	16
#define BORDER_HEIGHT	8
#define TOP_LEFT_CORNER	 0
#define TOP_EDGE			4
#define TOP_RIGHT_CORNER	1
#define SIDE_EDGE			5
#define BOTTOM_LEFT_CORNER	2
#define BOTTOM_EDGE		 4
#define BOTTOM_RIGHT_CORNER 3


BOOLEAN DrawBox( UINT32 uiCounter );
BOOLEAN DrawBoxText( UINT32 uiCounter );

void RemoveCurrentBoxPrimaryText( INT32 hStringHandle );
void RemoveCurrentBoxSecondaryText( INT32 hStringHandle );
void RemoveCurrentBoxText( INT32 hStringHandle, UINT8 column );



void InitPopUpBoxList()
{
	memset( &PopUpBoxList, 0, sizeof( PopUpBoxPt ) );
	return;
}


void InitPopUpBox( INT32 hBoxHandle )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[hBoxHandle] );
	memset( PopUpBoxList[hBoxHandle], 0, sizeof( PopUpBo ) );
}



void SetLineSpace( INT32 hBoxHandle, UINT32 uiLineSpace )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[hBoxHandle] );
	PopUpBoxList[hBoxHandle]->uiLineSpace = uiLineSpace;
	return;
}


UINT32 GetLineSpace( INT32 hBoxHandle )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return(0);

	Assert( PopUpBoxList[hBoxHandle] );
	// return number of pixels between lines for this box
	return(PopUpBoxList[hBoxHandle]->uiLineSpace);
}



void SpecifyBoxMinWidth( INT32 hBoxHandle, INT32 iMinWidth )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	box->uiBoxMinWidth = iMinWidth;

	// check if the box is currently too small
	if ( box->Dimensions.iRight < iMinWidth )
	{
		box->Dimensions.iRight = iMinWidth;
	}

	return;
}


BOOLEAN CreatePopUpBox( INT32 *phBoxHandle, SGPRect Dimensions, SGPPoint Position, UINT32 uiFlags )
{
	INT32 iCounter = 0;
	INT32 iCount = 0;
	PopUpBoxPt pBox = NULL;


	// find first free box
	for ( iCounter = 0; (iCounter < MAX_POPUP_BOX_COUNT) && (PopUpBoxList[iCounter] != NULL); iCounter++ );

	if ( iCounter >= MAX_POPUP_BOX_COUNT )
	{
		// ran out of available popup boxes - probably not freeing them up right!
		Assert( 0 );
		return FALSE;
	}

	iCount = iCounter;
	*phBoxHandle = iCount;

	pBox = (PopUpBoxPt)MemAlloc( sizeof( PopUpBo ) );
	if ( pBox == NULL )
	{
		return FALSE;
	}
	PopUpBoxList[iCount] = pBox;

	InitPopUpBox( iCount );
	SetBoxPosition( iCount, Position );
	SetBoxSize( iCount, Dimensions );
	SetBoxFlags( iCount, uiFlags );

	for ( UINT8 col = 0; col < MAX_POPUP_BOX_COLUMNS; ++col )
	{
		for ( iCounter = 0; iCounter < MAX_POPUP_BOX_STRING_COUNT; ++iCounter )
		{
			PopUpBoxList[iCount]->Text[col][iCounter] = NULL;
		}
	}

	SetCurrentBox( iCount );
	SpecifyBoxMinWidth( iCount, 0 );
	SetBoxSecondColumnMinimumOffset( iCount, 0 );
	SetBoxSecondColumnCurrentOffset( iCount, 0 );

	PopUpBoxList[iCount]->fUpdated = FALSE;

	return TRUE;
}


void SetBoxFlags( INT32 hBoxHandle, UINT32 uiFlags )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	box->uiFlags = uiFlags;
	box->fUpdated = FALSE;

	return;
}


void SetMargins( INT32 hBoxHandle, UINT32 uiLeft, UINT32 uiTop, UINT32 uiBottom, UINT32 uiRight )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	box->uiLeftMargin = uiLeft;
	box->uiRightMargin = uiRight;
	box->uiTopMargin = uiTop;
	box->uiBottomMargin = uiBottom;

	box->fUpdated = FALSE;

	return;
}


UINT32 GetTopMarginSize( INT32 hBoxHandle )
{
	// return size of top margin, for mouse region offsets

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return(0);

	Assert( PopUpBoxList[hBoxHandle] );

	return(PopUpBoxList[hBoxHandle]->uiTopMargin);
}


void ShadeStringInBox( INT32 hBoxHandle, INT32 iLineNumber, UINT8 column )
{
	// shade iLineNumber Line in box indexed by hBoxHandle

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	if ( box->Text[column][iLineNumber] != NULL )
	{
		// set current box
		SetCurrentBox( hBoxHandle );

		// shade line
		box->Text[column][iLineNumber]->fShadeFlag = TRUE;
	}
}

void UnShadeStringInBox( INT32 hBoxHandle, INT32 iLineNumber, UINT8 column )
{
	// unshade iLineNumber in box indexed by hBoxHandle

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	if ( box->Text[column][iLineNumber] != NULL )
	{
		// set current box
		SetCurrentBox( hBoxHandle );

		// shade line
		box->Text[column][iLineNumber]->fShadeFlag = FALSE;
	}
}


void SecondaryShadeStringInBox( INT32 hBoxHandle, INT32 iLineNumber, UINT8 column )
{
	// shade iLineNumber Line in box indexed by hBoxHandle

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	if ( box->Text[column][iLineNumber] != NULL )
	{
		// set current box
		SetCurrentBox( hBoxHandle );

		// shade line
		box->Text[column][iLineNumber]->fSecondaryShadeFlag = TRUE;
	}
}

void UnSecondaryShadeStringInBox( INT32 hBoxHandle, INT32 iLineNumber, UINT8 column )
{
	// unshade iLineNumber in box indexed by hBoxHandle

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	if ( box->Text[column][iLineNumber] != NULL )
	{
		// set current box
		SetCurrentBox( hBoxHandle );

		// shade line
		box->Text[column][iLineNumber]->fSecondaryShadeFlag = FALSE;
	}
}



void SetBoxBuffer( INT32 hBoxHandle, UINT32 uiBuffer )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	box->uiBuffer = uiBuffer;

	box->fUpdated = FALSE;
}


void SetBoxPosition( INT32 hBoxHandle, SGPPoint Position )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	box->Position.iX = Position.iX;
	box->Position.iY = Position.iY;

	box->fUpdated = FALSE;
}


void GetBoxPosition( INT32 hBoxHandle, SGPPoint *Position )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	Position->iX = box->Position.iX;
	Position->iY = box->Position.iY;
}

void SetBoxSize( INT32 hBoxHandle, SGPRect Dimensions )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	box->Dimensions.iLeft = Dimensions.iLeft;
	box->Dimensions.iBottom = Dimensions.iBottom;
	box->Dimensions.iRight = Dimensions.iRight;
	box->Dimensions.iTop = Dimensions.iTop;

	box->fUpdated = FALSE;
}


void GetBoxSize( INT32 hBoxHandle, SGPRect *Dimensions )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box );

	Dimensions->iLeft = box->Dimensions.iLeft;
	Dimensions->iBottom = box->Dimensions.iBottom;
	Dimensions->iRight = box->Dimensions.iRight;
	Dimensions->iTop = box->Dimensions.iTop;
}


void SetBorderType( INT32 hBoxHandle, INT32 iBorderObjectIndex )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[hBoxHandle] );
	PopUpBoxList[hBoxHandle]->iBorderObjectIndex = iBorderObjectIndex;
}

void SetBackGroundSurface( INT32 hBoxHandle, INT32 iBackGroundSurfaceIndex )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[hBoxHandle] );
	PopUpBoxList[hBoxHandle]->iBackGroundSurface = iBackGroundSurfaceIndex;
}


// Adds a string to the first available slot in the column
void AddMonoString( UINT32 *hStringHandle, STR16 pString, UINT8 column )
{
	STR16 pLocalString = NULL;
	POPUPSTRINGPTR pStringSt = NULL;
	INT32 iCounter = 0;


	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );

	// find first free slot in list
	for ( iCounter = 0; (iCounter < MAX_POPUP_BOX_STRING_COUNT) && (box->Text[column][iCounter] != NULL); iCounter++ );

	if ( iCounter >= MAX_POPUP_BOX_STRING_COUNT )
	{
		// using too many text lines, or not freeing them up properly
		Assert( 0 );
		return;
	}

	pStringSt = (POPUPSTRING *)(MemAlloc( sizeof( POPUPSTRING ) ));
	if ( pStringSt == NULL )
		return;

	pLocalString = (STR16)MemAlloc( (wcslen( pString ) + 1) * sizeof( CHAR16 ) );
	if ( pLocalString == NULL )
		return;

	wcscpy( pLocalString, pString );

	RemoveCurrentBoxText( iCounter, column );

	box->Text[column][iCounter] = pStringSt;
	box->Text[column][iCounter]->fColorFlag = FALSE;
	box->Text[column][iCounter]->pString = pLocalString;
	box->Text[column][iCounter]->fShadeFlag = FALSE;
	box->Text[column][iCounter]->fHighLightFlag = FALSE;
	box->Text[column][iCounter]->fSecondaryShadeFlag = FALSE;

	*hStringHandle = iCounter;
	box->fUpdated = FALSE;
	return;
}


// Adds string to the current popup box 2nd column. !!! String's position is the LAST used position in the 1st column !!!
void AddSecondColumnMonoString( UINT32 *hStringHandle, STR16 pString )
{
	STR16 pLocalString = NULL;
	POPUPSTRINGPTR pStringSt = NULL;
	INT32 iCounter = 0;


	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );

	// find the LAST USED text string index
	for ( iCounter = 0; (iCounter + 1 < MAX_POPUP_BOX_STRING_COUNT) && (box->Text[0][iCounter + 1] != NULL); iCounter++ );

	if ( iCounter >= MAX_POPUP_BOX_STRING_COUNT )
	{
		// using too many text lines, or not freeing them up properly
		Assert( 0 );
		return;
	}

	pStringSt = (POPUPSTRING *)(MemAlloc( sizeof( POPUPSTRING ) ));
	if ( pStringSt == NULL )
		return;

	pLocalString = (STR16)MemAlloc( (wcslen( pString ) + 1) * sizeof( CHAR16 ) );
	if ( pLocalString == NULL )
		return;

	wcscpy( pLocalString, pString );

	RemoveCurrentBoxSecondaryText( iCounter );

	box->Text[1][iCounter] = pStringSt;
	box->Text[1][iCounter]->fColorFlag = FALSE;
	box->Text[1][iCounter]->pString = pLocalString;
	box->Text[1][iCounter]->fShadeFlag = FALSE;
	box->Text[1][iCounter]->fHighLightFlag = FALSE;
	box->Text[1][iCounter]->fSecondaryShadeFlag = FALSE;

	*hStringHandle = iCounter;

	return;
}


// Adds a COLORED first column string to the CURRENT box
void AddColorString( INT32 *hStringHandle, STR16 pString, UINT8 column )
{
	STR16 pLocalString;
	POPUPSTRINGPTR pStringSt = NULL;
	INT32 iCounter = 0;


	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );

	// find first free slot in list
	for ( iCounter = 0; (iCounter < MAX_POPUP_BOX_STRING_COUNT) && (box->Text[column][iCounter] != NULL); iCounter++ );

	if ( iCounter >= MAX_POPUP_BOX_STRING_COUNT )
	{
		// using too many text lines, or not freeing them up properly
		Assert( 0 );
		return;
	}

	pStringSt = (POPUPSTRING *)(MemAlloc( sizeof( POPUPSTRING ) ));
	if ( pStringSt == NULL )
		return;

	pLocalString = (STR16)MemAlloc( (wcslen( pString ) + 1) * sizeof( CHAR16 ) );
	if ( pLocalString == NULL )
		return;

	wcscpy( pLocalString, pString );

	RemoveCurrentBoxText( iCounter, column );

	box->Text[column][iCounter] = pStringSt;
	box->Text[column][iCounter]->fColorFlag = TRUE;
	box->Text[column][iCounter]->pString = pLocalString;

	*hStringHandle = iCounter;

	box->fUpdated = FALSE;

	return;
}



void ResizeBoxForSecondStrings( INT32 hBoxHandle )
{
	INT32 iCounter = 0;
	PopUpBoxPt pBox;
	UINT32 uiBaseWidth, uiThisWidth;


	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	pBox = (PopUpBoxList[hBoxHandle]);
	Assert( pBox );

	uiBaseWidth = pBox->uiLeftMargin + pBox->uiSecondColumnMinimunOffset;

	// check string sizes
	for ( iCounter = 0; iCounter < MAX_POPUP_BOX_STRING_COUNT; iCounter++ )
	{
		if ( pBox->Text[0][iCounter] )
		{
			uiThisWidth = uiBaseWidth + StringPixLength( pBox->Text[0][iCounter]->pString, pBox->Text[0][iCounter]->uiFont );

			if ( uiThisWidth > pBox->uiSecondColumnCurrentOffset )
			{
				pBox->uiSecondColumnCurrentOffset = uiThisWidth;
			}
		}
	}
}

static void ResizeStrategicMvtBoxForSecondStrings( INT32 hBoxHandle )
{
	INT32 iCounter = 0;
	PopUpBoxPt pBox;
	UINT32 uiBaseWidth, uiThisWidth;


	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	pBox = (PopUpBoxList[hBoxHandle]);
	Assert( pBox );

	// Determine last line for next loop
	UINT8 last = MAX_POPUP_BOX_STRING_COUNT;
	for ( iCounter = 1; iCounter < MAX_POPUP_BOX_STRING_COUNT; iCounter++ )
	{
		if ( pBox->Text[0][iCounter] == nullptr )
		{
			// Do not consider the last blank, "cancel" & "Plot Travel route" lines
			last = iCounter - 3;
			break;
		}
	}

	uiBaseWidth = pBox->uiLeftMargin + pBox->uiSecondColumnMinimunOffset;

	// check string sizes, skip title line
	for ( iCounter = 1; iCounter < last; iCounter++ )
	{
		if ( pBox->Text[0][iCounter] )
		{
			uiThisWidth = uiBaseWidth + StringPixLength( pBox->Text[0][iCounter]->pString, pBox->Text[0][iCounter]->uiFont );

			if ( uiThisWidth > pBox->uiSecondColumnCurrentOffset )
			{
				// Maintain width if something is selected and the '*' characters have been added
				if ( wcsncmp( pBox->Text[0][iCounter]->pString, L"  *", 3 ) == 0 )
				{
					uiThisWidth -= 10;
				}
				pBox->uiSecondColumnCurrentOffset = uiThisWidth;
			}
		}
	}
}


UINT32 GetNumberOfLinesOfTextInBox( INT32 hBoxHandle, UINT8 column )
{
	INT32 iCounter = 0;

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return(0);

	// count number of lines
	// check string size
	for ( iCounter = 0; iCounter < MAX_POPUP_BOX_STRING_COUNT; iCounter++ )
	{
		if ( PopUpBoxList[hBoxHandle]->Text[column][iCounter] == NULL )
		{
			break;
		}
	}

	return(iCounter);
}


UINT32 GetTotalNumberOfLinesOfTextInBox( INT32 hBoxHandle )
{
	UINT32 lines = 0;
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return(0);

	// count number of lines
	// check string size
	for ( size_t i = 0; i < MAX_POPUP_BOX_COLUMNS; i++ )
	{
		for ( INT32 iCounter = 0; iCounter < MAX_POPUP_BOX_STRING_COUNT; iCounter++ )
		{
			if ( PopUpBoxList[hBoxHandle]->Text[i][iCounter] == NULL )
			{
				break;
			}
			lines += 1;
		}
	}

	return(lines);
}


void SetBoxFont( INT32 hBoxHandle, UINT32 uiFont )
{
	UINT32 uiCounter;

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	for ( size_t i = 0; i < MAX_POPUP_BOX_COLUMNS; i++ )
	{
		for ( uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
		{
			if ( PopUpBoxList[hBoxHandle]->Text[i][uiCounter] != NULL )
			{
				PopUpBoxList[hBoxHandle]->Text[i][uiCounter]->uiFont = uiFont;
			}
		}
	}

	PopUpBoxList[hBoxHandle]->fUpdated = FALSE;

	return;
}

void SetBoxSecondColumnMinimumOffset( INT32 hBoxHandle, UINT32 uiWidth )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	PopUpBoxList[hBoxHandle]->uiSecondColumnMinimunOffset = uiWidth;
	return;
}

void SetBoxSecondColumnCurrentOffset( INT32 hBoxHandle, UINT32 uiCurrentOffset )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	PopUpBoxList[hBoxHandle]->uiSecondColumnCurrentOffset = uiCurrentOffset;
	return;
}


void SetBoxColumnFont( INT32 hBoxHandle, UINT32 uiFont, UINT8 column )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	for ( UINT32 uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( PopUpBoxList[hBoxHandle]->Text[column][uiCounter] != NULL )
		{
			PopUpBoxList[hBoxHandle]->Text[column][uiCounter]->uiFont = uiFont;
		}
	}

	PopUpBoxList[hBoxHandle]->fUpdated = FALSE;
	return;
}



UINT32 GetBoxFont( INT32 hBoxHandle )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return(0);

	Assert( PopUpBoxList[hBoxHandle] );
	Assert( PopUpBoxList[hBoxHandle]->Text[0][0] );

	// return font id of first line of text of box
	return(PopUpBoxList[hBoxHandle]->Text[0][0]->uiFont);
}


// set the foreground color of this string in this pop up box
void SetBoxLineForeground( INT32 iBox, INT32 iStringValue, UINT8 ubColor )
{
	if ( (iBox < 0) || (iBox >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[iBox] );
	Assert( PopUpBoxList[iBox]->Text[0][iStringValue] );

	PopUpBoxList[iBox]->Text[0][iStringValue]->ubForegroundColor = ubColor;
	return;
}

void SetBoxSecondaryShade( INT32 iBox, UINT8 ubColor )
{
	UINT32 uiCounter;

	if ( (iBox < 0) || (iBox >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[iBox] );

	for ( uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( PopUpBoxList[iBox]->Text[0][uiCounter] != NULL )
		{
			PopUpBoxList[iBox]->Text[0][uiCounter]->ubSecondaryShade = ubColor;
		}
	}
	return;
}


// The following functions operate on the CURRENT box
void SetPopUpStringFont( INT32 hStringHandle, UINT32 uiFont )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[0][hStringHandle] );

	box->Text[0][hStringHandle]->uiFont = uiFont;
	return;
}


void SetPopUpSecondColumnStringFont( INT32 hStringHandle, UINT32 uiFont )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[1][hStringHandle] );

	box->Text[1][hStringHandle]->uiFont = uiFont;
	return;
}



void SetStringSecondaryShade( INT32 hStringHandle, UINT8 ubColor )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[0][hStringHandle] );

	box->Text[0][hStringHandle]->ubSecondaryShade = ubColor;
	return;
}

void SetStringForeground( INT32 hStringHandle, UINT8 ubColor )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[0][hStringHandle] );

	box->Text[0][hStringHandle]->ubForegroundColor = ubColor;
	return;
}

void SetStringBackground( INT32 hStringHandle, UINT8 ubColor )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[0][hStringHandle] );

	box->Text[0][hStringHandle]->ubBackgroundColor = ubColor;
	return;
}

void SetStringHighLight( INT32 hStringHandle, UINT8 ubColor )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[0][hStringHandle] );

	box->Text[0][hStringHandle]->ubHighLight = ubColor;
	return;
}


void SetStringShade( INT32 hStringHandle, UINT8 ubShade )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[0][hStringHandle] );

	box->Text[0][hStringHandle]->ubShade = ubShade;
	return;
}

void SetStringSecondColumnForeground( INT32 hStringHandle, UINT8 ubColor )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[1][hStringHandle] );

	box->Text[1][hStringHandle]->ubForegroundColor = ubColor;
	return;
}

void SetStringSecondColumnBackground( INT32 hStringHandle, UINT8 ubColor )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[1][hStringHandle] );

	box->Text[1][hStringHandle]->ubBackgroundColor = ubColor;
	return;
}

void SetStringSecondColumnHighLight( INT32 hStringHandle, UINT8 ubColor )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[1][hStringHandle] );

	box->Text[1][hStringHandle]->ubHighLight = ubColor;
	return;
}


void SetStringSecondColumnShade( INT32 hStringHandle, UINT8 ubShade )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( box->Text[1][hStringHandle] );

	box->Text[1][hStringHandle]->ubShade = ubShade;
	return;
}



void SetBoxForeground( INT32 hBoxHandle, UINT8 ubColor )
{
	UINT32 uiCounter;

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[hBoxHandle] != NULL );

	for ( uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( PopUpBoxList[hBoxHandle]->Text[0][uiCounter] != NULL )
		{
			PopUpBoxList[hBoxHandle]->Text[0][uiCounter]->ubForegroundColor = ubColor;
		}
	}
	return;
}

void SetBoxBackground( INT32 hBoxHandle, UINT8 ubColor )
{
	UINT32 uiCounter;

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[hBoxHandle] != NULL );

	for ( uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( PopUpBoxList[hBoxHandle]->Text[0][uiCounter] != NULL )
		{
			PopUpBoxList[hBoxHandle]->Text[0][uiCounter]->ubBackgroundColor = ubColor;
		}
	}
	return;
}

void SetBoxHighLight( INT32 hBoxHandle, UINT8 ubColor )
{
	UINT32 uiCounter;

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[hBoxHandle] != NULL );

	for ( uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( PopUpBoxList[hBoxHandle]->Text[0][uiCounter] != NULL )
		{
			PopUpBoxList[hBoxHandle]->Text[0][uiCounter]->ubHighLight = ubColor;
		}
	}
	return;
}

void SetBoxShade( INT32 hBoxHandle, UINT8 ubColor )
{
	UINT32 uiCounter;

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	Assert( PopUpBoxList[hBoxHandle] != NULL );

	for ( uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( PopUpBoxList[hBoxHandle]->Text[0][uiCounter] != NULL )
		{
			PopUpBoxList[hBoxHandle]->Text[0][uiCounter]->ubShade = ubColor;
		}
	}
	return;
}




void SetBoxColumnForeground( INT32 hBoxHandle, UINT8 ubColor, UINT8 column )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box != NULL );

	for ( UINT32 uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( box->Text[column][uiCounter] != NULL )
		{
			box->Text[column][uiCounter]->ubForegroundColor = ubColor;
		}
	}
	return;
}

void SetBoxColumnBackground( INT32 hBoxHandle, UINT8 ubColor, UINT8 column )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box != NULL );

	for ( UINT32 uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( box->Text[column][uiCounter] != NULL )
		{
			box->Text[column][uiCounter]->ubBackgroundColor = ubColor;
		}
	}
	return;
}

void SetBoxColumnHighLight( INT32 hBoxHandle, UINT8 ubColor, UINT8 column )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box != NULL );

	for ( UINT32 uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( box->Text[column][uiCounter] != NULL )
		{
			box->Text[column][uiCounter]->ubHighLight = ubColor;
		}
	}
	return;
}

void SetBoxColumnShade( INT32 hBoxHandle, UINT8 ubColor, UINT8 column )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	Assert( box != NULL );

	for ( UINT32 uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
	{
		if ( box->Text[column][uiCounter] != NULL )
		{
			box->Text[column][uiCounter]->ubShade = ubColor;
		}
	}
	return;
}



void HighLightLine( INT32 hStringHandle, UINT8 column )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );

	if ( !box->Text[column][hStringHandle] )
		return;
	box->Text[column][hStringHandle]->fHighLightFlag = TRUE;
	return;
}


BOOLEAN GetShadeFlag( INT32 hStringHandle )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return(FALSE);

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );

	if ( !box->Text[0][hStringHandle] )
		return(FALSE);

	return(box->Text[0][hStringHandle]->fShadeFlag);
}

BOOLEAN GetSecondaryShadeFlag( INT32 hStringHandle )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return(FALSE);

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );

	if ( !box->Text[0][hStringHandle] )
		return(FALSE);

	return(box->Text[0][hStringHandle]->fSecondaryShadeFlag);
}


void HighLightBoxLine( INT32 hBoxHandle, INT32 iLineNumber, UINT8 column )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	// highlight iLineNumber Line in box indexed by hBoxHandle

	if ( PopUpBoxList[hBoxHandle]->Text[column][iLineNumber] != NULL )
	{
		// set current box
		SetCurrentBox( hBoxHandle );

		// highlight line
		HighLightLine( iLineNumber, column );
	}

	return;
}


BOOLEAN GetBoxShadeFlag( INT32 hBoxHandle, INT32 iLineNumber )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return(FALSE);

	if ( PopUpBoxList[hBoxHandle]->Text[0][iLineNumber] != NULL )
	{
		return(PopUpBoxList[hBoxHandle]->Text[0][iLineNumber]->fShadeFlag);
	}


	return(FALSE);
}

BOOLEAN GetBoxSecondaryShadeFlag( INT32 hBoxHandle, INT32 iLineNumber )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return(FALSE);

	if ( PopUpBoxList[hBoxHandle]->Text[0][iLineNumber] != NULL )
	{
		return(PopUpBoxList[hBoxHandle]->Text[0][iLineNumber]->fSecondaryShadeFlag);
	}


	return(FALSE);
}

void UnHighLightLine( INT32 hStringHandle, UINT8 column )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );

	if ( !box->Text[column][hStringHandle] )
		return;
	box->Text[column][hStringHandle]->fHighLightFlag = FALSE;
	return;
}

void UnHighLightBox( INT32 hBoxHandle )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[hBoxHandle];
	for ( size_t i = 0; i < MAX_POPUP_BOX_COLUMNS; i++ )
	{
		for ( INT32 iCounter = 0; iCounter < MAX_POPUP_BOX_STRING_COUNT; iCounter++ )
		{
			if ( box->Text[i][iCounter] )
				box->Text[i][iCounter]->fHighLightFlag = FALSE;
		}
	}
}

void UnHighLightSecondColumnLine( INT32 hStringHandle )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );

	if ( !box->Text[1][hStringHandle] )
		return;

	box->Text[1][hStringHandle]->fHighLightFlag = FALSE;
	return;
}

void UnHighLightSecondColumnBox( INT32 hBoxHandle )
{
	INT32 iCounter = 0;

	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	for ( iCounter = 0; iCounter < MAX_POPUP_BOX_STRING_COUNT; iCounter++ )
	{
		if ( PopUpBoxList[hBoxHandle]->Text[1][iCounter] )
			PopUpBoxList[hBoxHandle]->Text[1][iCounter]->fHighLightFlag = FALSE;
	}
}

void RemoveOneCurrentBoxString( INT32 hStringHandle, BOOLEAN fFillGaps )
{
	UINT32 uiCounter = 0;

	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( hStringHandle < MAX_POPUP_BOX_STRING_COUNT );

	RemoveCurrentBoxPrimaryText( hStringHandle );
	RemoveCurrentBoxSecondaryText( hStringHandle );

	if ( fFillGaps )
	{
		// shuffle all strings down a slot to fill in the gap
		for ( uiCounter = hStringHandle; uiCounter < (MAX_POPUP_BOX_STRING_COUNT - 1); uiCounter++ )
		{
			box->Text[0][uiCounter] = box->Text[0][uiCounter + 1];
			box->Text[1][uiCounter] = box->Text[1][uiCounter + 1];
		}
	}

	box->fUpdated = FALSE;
}


void RemoveAllCurrentBoxStrings( void )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) || !PopUpBoxList[guiCurrentBox] )
		return;

	for ( size_t i = 0; i < MAX_POPUP_BOX_COLUMNS; i++ )
	{
		for ( UINT32 uiCounter = 0; uiCounter < MAX_POPUP_BOX_STRING_COUNT; uiCounter++ )
		{
			RemoveCurrentBoxText( uiCounter, i );
		}
	}
}


void RemoveBox( INT32 hBoxHandle )
{
	INT32 hOldBoxHandle;


	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	GetCurrentBox( &hOldBoxHandle );
	SetCurrentBox( hBoxHandle );

	RemoveAllCurrentBoxStrings();

	MemFree( PopUpBoxList[hBoxHandle] );
	PopUpBoxList[hBoxHandle] = NULL;

	if ( hOldBoxHandle != hBoxHandle )
		SetCurrentBox( hOldBoxHandle );

	return;
}



void ShowBox( INT32 hBoxHandle )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	if ( PopUpBoxList[hBoxHandle] != NULL )
	{
		if ( PopUpBoxList[hBoxHandle]->fShowBox == FALSE )
		{
			PopUpBoxList[hBoxHandle]->fShowBox = TRUE;
			PopUpBoxList[hBoxHandle]->fUpdated = FALSE;
		}
	}
}

void HideBox( INT32 hBoxHandle )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	if ( PopUpBoxList[hBoxHandle] != NULL )
	{
		if ( PopUpBoxList[hBoxHandle]->fShowBox == TRUE )
		{
			PopUpBoxList[hBoxHandle]->fShowBox = FALSE;
			PopUpBoxList[hBoxHandle]->fUpdated = FALSE;
		}
	}
}



void SetCurrentBox( INT32 hBoxHandle )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	guiCurrentBox = hBoxHandle;
}


void GetCurrentBox( INT32 *hBoxHandle )
{
	*hBoxHandle = guiCurrentBox;
}



void DisplayBoxes( UINT32 uiBuffer )
{
	UINT32 uiCounter;

	for ( uiCounter = 0; uiCounter < MAX_POPUP_BOX_COUNT; uiCounter++ )
	{
		DisplayOnePopupBox( uiCounter, uiBuffer );
	}
	return;
}


void DisplayOnePopupBox( UINT32 uiIndex, UINT32 uiBuffer )
{
	if ( (uiIndex < 0) || (uiIndex >= MAX_POPUP_BOX_COUNT) )
		return;

	if ( PopUpBoxList[uiIndex] != NULL )
	{
		if ( (PopUpBoxList[uiIndex]->uiBuffer == uiBuffer) && (PopUpBoxList[uiIndex]->fShowBox) )
		{
			DrawBox( uiIndex );
			DrawBoxText( uiIndex );
		}
	}
}



// force an update of this box
void ForceUpDateOfBox( UINT32 uiIndex )
{
	if ( (uiIndex < 0) || (uiIndex >= MAX_POPUP_BOX_COUNT) )
		return;

	if ( PopUpBoxList[uiIndex] != NULL )
	{
		PopUpBoxList[uiIndex]->fUpdated = FALSE;
	}
}



BOOLEAN DrawBox( UINT32 uiCounter )
{
	// will build pop up box in usTopX, usTopY with dimensions usWidth and usHeight
	UINT32 uiNumTilesWide;
	UINT32 uiNumTilesHigh;
	UINT32 uiCount = 0;
	HVOBJECT hBoxHandle;
	HVSURFACE hSrcVSurface;
	UINT32 uiDestPitchBYTES;
	UINT32 uiSrcPitchBYTES;
	UINT16 *pDestBuf;
	UINT8 *pSrcBuf;
	SGPRect clip;
	UINT16 usTopX, usTopY;
	UINT16 usWidth, usHeight;


	if ( (uiCounter < 0) || (uiCounter >= MAX_POPUP_BOX_COUNT) )
		return(FALSE);

	auto box = PopUpBoxList[uiCounter];
	Assert( box != NULL );

	// only update if we need to

	if ( box->fUpdated == TRUE )
	{
		return(FALSE);
	}

	box->fUpdated = TRUE;

	if ( box->uiFlags & POPUP_BOX_FLAG_RESIZE )
	{
		ResizeBoxToText( uiCounter );
	}

	usTopX = (UINT16)box->Position.iX;
	usTopY = (UINT16)box->Position.iY;
	usWidth = ((UINT16)(box->Dimensions.iRight - box->Dimensions.iLeft));
	usHeight = ((UINT16)(box->Dimensions.iBottom - box->Dimensions.iTop));

	//CHRISL: Adjust position for screen limits
	if ( (usTopX + usWidth) > SCREEN_WIDTH && usTopX > ((usTopX + usWidth) - SCREEN_WIDTH) )
	{
		usTopX -= ((usTopX + usWidth) - SCREEN_WIDTH);
		box->Position.iX -= (box->Position.iX - usTopX);
	}
	if ( (usTopY + usHeight) > SCREEN_HEIGHT && usTopY > ((usTopY + usHeight) - SCREEN_HEIGHT) )
	{
		usTopY -= ((usTopY + usHeight) - SCREEN_HEIGHT);
		box->Position.iY -= (box->Position.iY - usTopY);
	}

	// check if we have a min width, if so then update box for such
	if ( (box->uiBoxMinWidth) && (usWidth < box->uiBoxMinWidth) )
	{
		usWidth = (INT16)(box->uiBoxMinWidth);
	}

	// make sure it will fit on screen!
	Assert( usTopX + usWidth <= SCREEN_WIDTH );
	Assert( usTopY + usHeight <= SCREEN_HEIGHT );

	// subtract 4 because the 2 2-pixel corners are handled separately
	uiNumTilesWide = ((usWidth - 4) / BORDER_WIDTH);
	uiNumTilesHigh = ((usHeight - 4) / BORDER_HEIGHT);

	clip.iLeft = 0;
	clip.iRight = clip.iLeft + usWidth;
	clip.iTop = 0;
	clip.iBottom = clip.iTop + usHeight;

	// blit in texture first, then borders
	// blit in surface
	pDestBuf = (UINT16 *)LockVideoSurface( box->uiBuffer, &uiDestPitchBYTES );
	CHECKF( GetVideoSurface( &hSrcVSurface, box->iBackGroundSurface ) );
	pSrcBuf = LockVideoSurface( box->iBackGroundSurface, &uiSrcPitchBYTES );
	Blt8BPPDataSubTo16BPPBuffer( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf, uiSrcPitchBYTES, usTopX, usTopY, &clip );
	UnLockVideoSurface( box->iBackGroundSurface );
	UnLockVideoSurface( box->uiBuffer );
	GetVideoObject( &hBoxHandle, box->iBorderObjectIndex );

	// blit in 4 corners (they're 2x2 pixels)
	BltVideoObject( box->uiBuffer, hBoxHandle, TOP_LEFT_CORNER, usTopX, usTopY, VO_BLT_SRCTRANSPARENCY, NULL );
	BltVideoObject( box->uiBuffer, hBoxHandle, TOP_RIGHT_CORNER, usTopX + usWidth - 2, usTopY, VO_BLT_SRCTRANSPARENCY, NULL );
	BltVideoObject( box->uiBuffer, hBoxHandle, BOTTOM_RIGHT_CORNER, usTopX + usWidth - 2, usTopY + usHeight - 2, VO_BLT_SRCTRANSPARENCY, NULL );
	BltVideoObject( box->uiBuffer, hBoxHandle, BOTTOM_LEFT_CORNER, usTopX, usTopY + usHeight - 2, VO_BLT_SRCTRANSPARENCY, NULL );

	// blit in edges
	if ( uiNumTilesWide > 0 )
	{
		// full pieces
		for ( uiCount = 0; uiCount < uiNumTilesWide; uiCount++ )
		{
			BltVideoObject( box->uiBuffer, hBoxHandle, TOP_EDGE, usTopX + 2 + (uiCount * BORDER_WIDTH), usTopY, VO_BLT_SRCTRANSPARENCY, NULL );
			BltVideoObject( box->uiBuffer, hBoxHandle, BOTTOM_EDGE, usTopX + 2 + (uiCount * BORDER_WIDTH), usTopY + usHeight - 2, VO_BLT_SRCTRANSPARENCY, NULL );
		}

		// partial pieces
		BltVideoObject( box->uiBuffer, hBoxHandle, TOP_EDGE, usTopX + usWidth - 2 - BORDER_WIDTH, usTopY, VO_BLT_SRCTRANSPARENCY, NULL );
		BltVideoObject( box->uiBuffer, hBoxHandle, BOTTOM_EDGE, usTopX + usWidth - 2 - BORDER_WIDTH, usTopY + usHeight - 2, VO_BLT_SRCTRANSPARENCY, NULL );
	}
	if ( uiNumTilesHigh > 0 )
	{
		// full pieces
		for ( uiCount = 0; uiCount < uiNumTilesHigh; uiCount++ )
		{
			BltVideoObject( box->uiBuffer, hBoxHandle, SIDE_EDGE, usTopX, usTopY + 2 + (uiCount * BORDER_HEIGHT), VO_BLT_SRCTRANSPARENCY, NULL );
			BltVideoObject( box->uiBuffer, hBoxHandle, SIDE_EDGE, usTopX + usWidth - 2, usTopY + 2 + (uiCount * BORDER_HEIGHT), VO_BLT_SRCTRANSPARENCY, NULL );
		}

		// partial pieces
		BltVideoObject( box->uiBuffer, hBoxHandle, SIDE_EDGE, usTopX, usTopY + usHeight - 2 - BORDER_HEIGHT, VO_BLT_SRCTRANSPARENCY, NULL );
		BltVideoObject( box->uiBuffer, hBoxHandle, SIDE_EDGE, usTopX + usWidth - 2, usTopY + usHeight - 2 - BORDER_HEIGHT, VO_BLT_SRCTRANSPARENCY, NULL );
	}

	InvalidateRegion( usTopX, usTopY, usTopX + usWidth, usTopY + usHeight );
	return TRUE;
}



BOOLEAN DrawBoxText( UINT32 uiCounter )
{
	UINT32 uiCount = 0;
	INT16 uX, uY;
	CHAR16 sString[100];


	if ( (uiCounter < 0) || (uiCounter >= MAX_POPUP_BOX_COUNT) )
		return(FALSE);

	auto box = PopUpBoxList[uiCounter];
	Assert( box != NULL );

	//clip text?
	if ( box->uiFlags & POPUP_BOX_FLAG_CLIP_TEXT )
	{
		const auto x1 = box->Position.iX + box->uiLeftMargin - 1;
		const auto y1 = box->Position.iY + box->uiTopMargin;
		const auto x2 = box->Position.iX + box->Dimensions.iRight - box->uiRightMargin;
		const auto y2 = box->Position.iY + box->Dimensions.iBottom - box->uiBottomMargin;
		SetFontDestBuffer( box->uiBuffer, x1, y1, x2, y2, FALSE );
	}

	for ( size_t i = 0; i < MAX_POPUP_BOX_COLUMNS; i++ )
	{
		for ( uiCount = 0; uiCount < MAX_POPUP_BOX_STRING_COUNT; uiCount++ )
		{
			auto entry = box->Text[i][uiCount];
			// there is text in this line?
			if ( entry )
			{
				// set font
				SetFont( entry->uiFont );

				// are we highlighting?...shading?..or neither
				if ( (entry->fHighLightFlag == FALSE) && (entry->fShadeFlag == FALSE) && (entry->fSecondaryShadeFlag == FALSE) )
				{
					// neither
					SetFontForeground( entry->ubForegroundColor );
				}
				else if ( (entry->fHighLightFlag == TRUE) )
				{
					// highlight
					SetFontForeground( entry->ubHighLight );
				}
				else if ( (entry->fSecondaryShadeFlag == TRUE) )
				{
					SetFontForeground( entry->ubSecondaryShade );
				}
				else
				{
					//shading
					SetFontForeground( entry->ubShade );
				}

				// set background
				SetFontBackground( entry->ubBackgroundColor );

				// copy string
				wcsncpy( sString, entry->pString, wcslen( entry->pString ) + 1 );

				// centering?
				if ( box->uiFlags & POPUP_BOX_FLAG_CENTER_TEXT )
				{
					INT16 sLeft = box->Position.iX + box->uiLeftMargin;
					INT16 sTop = box->Position.iY + uiCount * GetFontHeight( entry->uiFont ) + box->uiTopMargin + uiCount * box->uiLineSpace;
					INT16 sWidth = box->Dimensions.iRight - (box->uiRightMargin + box->uiLeftMargin + 2);
					INT16 sHeight = GetFontHeight( entry->uiFont );
					FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, (sString), ((INT32)entry->uiFont), &uX, &uY );
				}
				else
				{
					uX = box->Position.iX + box->uiLeftMargin + box->uiSecondColumnCurrentOffset * i;
					uY = ((INT16)(box->Position.iY + uiCount * GetFontHeight( entry->uiFont ) + box->uiTopMargin + uiCount * box->uiLineSpace));
				}

				// print
				mprintf( uX, uY, entry->pString );
			}
		}
	}


	if ( box->uiBuffer != guiSAVEBUFFER )
	{
		InvalidateRegion( box->Position.iX + box->uiLeftMargin - 1, box->Position.iY + box->uiTopMargin, box->Position.iX + box->Dimensions.iRight - box->uiRightMargin, box->Position.iY + box->Dimensions.iBottom - box->uiBottomMargin );
	}

	SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );

	return TRUE;
}


void ResizeBoxToText( INT32 hBoxHandle )
{
	// run through lines of text in box and size box width to longest line plus margins
	// height is sum of getfontheight of each line+ spacing
	INT32 iWidth = 0;
	INT32 iHeight = 0;
	INT32 iCurrString = 0;
	INT32 iColumnLength = 0;


	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return;

	if ( !PopUpBoxList[hBoxHandle] )
		return;

	if ( hBoxHandle == ghMoveBox )
	{
		ResizeStrategicMvtBoxForSecondStrings( hBoxHandle );
	}
	else
	{
		ResizeBoxForSecondStrings( hBoxHandle );
	}

	auto box = PopUpBoxList[hBoxHandle];
	const UINT32 margins = box->uiLeftMargin + box->uiRightMargin;
	iHeight = box->uiTopMargin + box->uiBottomMargin;
	const auto columnOffset = box->uiSecondColumnCurrentOffset;

	for ( iCurrString = 0; iCurrString < MAX_POPUP_BOX_STRING_COUNT; iCurrString++ )
	{
		if ( box->Text[0][iCurrString] != NULL )
		{

			if ( box->Text[3][iCurrString] != NULL && wcscmp( box->Text[3][iCurrString]->pString, L"" ) != 0 )
			{
				iColumnLength = StringPixLength( box->Text[3][iCurrString]->pString, box->Text[3][iCurrString]->uiFont );
				if ( 3 * columnOffset + iColumnLength + margins > iWidth )
				{
					iWidth = 3 * columnOffset + iColumnLength + margins;
				}
			}
			else if ( box->Text[2][iCurrString] != NULL && wcscmp( box->Text[2][iCurrString]->pString, L"" ) != 0 )
			{
				iColumnLength = StringPixLength( box->Text[2][iCurrString]->pString, box->Text[2][iCurrString]->uiFont );
				if ( 2 * columnOffset + iColumnLength + margins > iWidth )
				{
					iWidth = 2 * columnOffset + iColumnLength + margins;
				}
			}
			else if ( box->Text[1][iCurrString] != NULL && wcscmp( box->Text[1][iCurrString]->pString, L"" ) != 0 )
			{
				iColumnLength = StringPixLength( box->Text[1][iCurrString]->pString, box->Text[1][iCurrString]->uiFont );
				if ( columnOffset + iColumnLength + margins > iWidth )
				{
					iWidth = columnOffset + iColumnLength + margins;
				}
			}


			INT32 iFirstColumnLength = StringPixLength( box->Text[0][iCurrString]->pString, box->Text[0][iCurrString]->uiFont ) + margins;
			if ( iFirstColumnLength > iWidth )
				iWidth = iFirstColumnLength;

			//vertical
			iHeight += GetFontHeight( box->Text[0][iCurrString]->uiFont ) + box->uiLineSpace;
		}
		else
		{
			// doesn't support gaps in text array...
			break;
		}
	}

	// Flugente we shouldn't have added more popup options than we can display anyway, but I have no idea where to stop that, so at least we can fix this
	box->Dimensions.iBottom = min( iHeight, SCREEN_HEIGHT - box->Position.iY );
	box->Dimensions.iRight = min( iWidth, SCREEN_WIDTH - box->Position.iX );

	// Constrain popup box height to background graphics max height. Otherwise we get blue graphics glitches
	const auto popupBoxHeight = box->Dimensions.iBottom - box->Dimensions.iTop;
	if ( popupBoxHeight > 480 )
	{
		box->Dimensions.iBottom = box->Dimensions.iTop + 480;
	}
}


BOOLEAN IsBoxShown( UINT32 uiHandle )
{
	if ( (uiHandle < 0) || (uiHandle >= MAX_POPUP_BOX_COUNT) )
		return(FALSE);

	if ( PopUpBoxList[uiHandle] == NULL )
	{
		return (FALSE);
	}

	return(PopUpBoxList[uiHandle]->fShowBox);
}


void MarkAllBoxesAsAltered( void )
{
	INT32 iCounter = 0;

	// mark all boxes as altered
	for ( iCounter = 0; iCounter < MAX_POPUP_BOX_COUNT; iCounter++ )
	{
		ForceUpDateOfBox( iCounter );
	}

	return;
}


void HideAllBoxes( void )
{
	INT32 iCounter = 0;

	// hide all the boxes that are shown
	for ( iCounter = 0; iCounter < MAX_POPUP_BOX_COUNT; iCounter++ )
	{
		HideBox( iCounter );
	}
}


void RemoveCurrentBoxPrimaryText( INT32 hStringHandle )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( hStringHandle < MAX_POPUP_BOX_STRING_COUNT );

	// remove & release primary text
	if ( box->Text[0][hStringHandle] != NULL )
	{
		if ( box->Text[0][hStringHandle]->pString )
		{
			MemFree( box->Text[0][hStringHandle]->pString );
		}

		MemFree( box->Text[0][hStringHandle] );
		box->Text[0][hStringHandle] = NULL;
	}
}

void RemoveCurrentBoxSecondaryText( INT32 hStringHandle )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( hStringHandle < MAX_POPUP_BOX_STRING_COUNT );

	// remove & release secondary strings
	if ( box->Text[1][hStringHandle] != NULL )
	{
		if ( box->Text[1][hStringHandle]->pString )
		{
			MemFree( box->Text[1][hStringHandle]->pString );
		}

		MemFree( box->Text[1][hStringHandle] );
		box->Text[1][hStringHandle] = NULL;
	}
}

void RemoveCurrentBoxText( INT32 hStringHandle, UINT8 column )
{
	if ( (guiCurrentBox < 0) || (guiCurrentBox >= MAX_POPUP_BOX_COUNT) || column >= MAX_POPUP_BOX_COLUMNS )
		return;

	auto box = PopUpBoxList[guiCurrentBox];
	Assert( box != NULL );
	Assert( hStringHandle < MAX_POPUP_BOX_STRING_COUNT );

	// remove & release text
	auto textColumn = box->Text[column];

	if ( textColumn[hStringHandle] != NULL )
	{
		if ( textColumn[hStringHandle]->pString )
		{
			MemFree( textColumn[hStringHandle]->pString );
		}

		MemFree( textColumn[hStringHandle] );
		textColumn[hStringHandle] = NULL;
	}
}

UINT32 GetBoxSecondColumnCurrentOffset( INT32 hBoxHandle )
{
	if ( (hBoxHandle < 0) || (hBoxHandle >= MAX_POPUP_BOX_COUNT) )
		return 0;

	return PopUpBoxList[hBoxHandle]->uiSecondColumnCurrentOffset;
}
