/*
**	Command & Conquer Generals Zero Hour(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

////////////////////////////////////////////////////////////////////////////////
//																																						//
//  (c) 2001-2003 Electronic Arts Inc.																				//
//																																						//
////////////////////////////////////////////////////////////////////////////////

// FILE: W3DTextEntry.cpp /////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//                                                                          
//                       Westwood Studios Pacific.                          
//                                                                          
//                       Confidential Information                           
//                Copyright (C) 2001 - All Rights Reserved                  
//                                                                          
//-----------------------------------------------------------------------------
//
// Project:   RTS3
//
// File name: W3DTextEntry.cpp
//
// Created:   Colin Day, June 2001
//
// Desc:      W3D implementation for the text entry gadget
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include <stdlib.h>

// USER INCLUDES //////////////////////////////////////////////////////////////
#include "GameClient/GameWindowGlobal.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/IMEManager.h"
#include "W3DDevice/GameClient/W3DGadget.h"
#include "W3DDevice/GameClient/W3DDisplay.h"

#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif

// DEFINES ////////////////////////////////////////////////////////////////////

// PRIVATE TYPES //////////////////////////////////////////////////////////////

// PRIVATE DATA ///////////////////////////////////////////////////////////////

// PUBLIC DATA ////////////////////////////////////////////////////////////////

// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

// drawTextEntryText ==========================================================
//=============================================================================
static void drawTextEntryText( GameWindow *window, WinInstanceData *instData,	
															 Color textColor, Color textDropColor,
															 Color compositeColor, Color compositeDropColor,
															 Int x, Int y, Int width, Int fontHeight )
{
	static Byte drawCnt = 0;
	EntryData *e = (EntryData *)window->winGetUserData();
//	Int charPos = e->charPos;
	Int cursorPos;

//	WideChar buffer[ ENTRY_TEXT_LEN + 1 ];
//	WideChar *bufptr = buffer;
//	Color constructColor = TheWindowManager->winMakeColor( 192, 0, 192, 255 );
	DisplayString *text = e->text;
	IRegion2D clipRegion;
	ICoord2D origin, size;
	Int compositeCursorPos = 0;

	// Check to see if the IME manager is composing text
	e->constructText->setText(UnicodeString::TheEmptyString);
	if ( TheIMEManager && TheIMEManager->isAttachedTo( window) && TheIMEManager->isComposing())
	{
		// The user is composing a string.
		// Show the composition in the text gadget.
		UnicodeString composition;

		TheIMEManager->getCompositionString( composition );

		if ( e->secretText )
		{
			e->sText->setText( UnicodeString::TheEmptyString );
			Int len = composition.getLength() + e->text->getTextLength();
			for ( int i = 0; i < len; i++ )
			{
				e->sText->appendChar( '*' );
			}
		}
		else
		{
			e->constructText->setText( composition );
			compositeCursorPos = TheIMEManager->getCompositionCursorPosition();
		}

	}


	// get out of here if no text color to show up
	if( textColor == WIN_COLOR_UNDEFINED )
		return;

	// if our text is "secret" we will print only '*' characters
	if( e->secretText )
		text = e->sText;

	// make sure our font is the same as our parents
	if( text->getFont() != window->winGetFont() )
		text->setFont( window->winGetFont() );
	if( e->constructText->getFont() != window->winGetFont() )
		e->constructText->setFont( window->winGetFont() );

	// get the size of our text, and construct text
	Int textWidth = text->getWidth();

	if (!e->drawTextFromStart)
	{
		// clip the text to the edit window size
		window->winGetScreenPosition( &origin.x, &origin.y );
		window->winGetSize( &size.x, &size.y );
		clipRegion.lo.x = x;
		clipRegion.hi.x = x + width ;
		clipRegion.lo.y = y;
		clipRegion.hi.y = y + fontHeight;
		text->setClipRegion( &clipRegion );
		e->constructText->setClipRegion( &clipRegion );

		// set construct window position if needed
		//if( e->constructList && e->constructText->getTextLength() )
		//	e->constructList->winSetPosition( (x + textWidth1), (y + fontHeight) );

		x+= 2;
		// draw the text
		if(textWidth < width)
		{
			text->draw( x, y, textColor, textDropColor );
			cursorPos = textWidth + x;
		}
		else
		{	
			Int div = textWidth / (width / 2) - 1;
			text->draw(x - (div * (width/2)), y, textColor, textDropColor);
			cursorPos = textWidth - (div * (width/2)) + x;
		}

		//cursorPos = x + textWidth;
	}
	else
	{
		window->winGetScreenPosition( &origin.x, &origin.y );
		window->winGetSize( &size.x, &size.y );
		clipRegion.lo.x = origin.x;
		clipRegion.hi.x = origin.x + size.x;
		clipRegion.lo.y = origin.y;
		clipRegion.hi.y = origin.y + size.y;
		text->setClipRegion( &clipRegion );
		e->constructText->setClipRegion( &clipRegion );

		// set construct window position if needed
		//if( e->constructList && e->constructText->getTextLength() )
		//	e->constructList->winSetPosition( (x + textWidth1), (y + fontHeight) );

		x+= 5;
		// draw the text
		text->draw( x, y, textColor, textDropColor );
		cursorPos = textWidth + x;
	}

	if (e->constructText->getTextLength() > 0 )
	{
		e->constructText->draw( x + textWidth, y, compositeColor, compositeDropColor );
		cursorPos += e->constructText->getWidth( compositeCursorPos );
	}

	// draw blinking cursor
	GameWindow *parent;
	parent = window->winGetParent();
	if(parent && !BitTest(parent->winGetStyle(), GWS_COMBO_BOX))
		parent = NULL;

	if( (window == TheWindowManager->winGetFocus() || (parent && parent == TheWindowManager->winGetFocus())) && ((drawCnt++ >> 3) & 0x1) )
		TheWindowManager->winFillRect( textColor, WIN_DRAW_LINE_WIDTH, 
																	 cursorPos, origin.y + 3, 
																	 cursorPos + 2, origin.y + size.y - 3 );
	window->winSetCursorPosition( cursorPos + 2 - origin.x, 0 ); 

}  // end drawTextEntryText

///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

// W3DGadgetTextEntryDraw =====================================================
/** Draw colored entry field using standard graphics */
//=============================================================================
void W3DGadgetTextEntryDraw( GameWindow *window, WinInstanceData *instData )
{
	EntryData *e = (EntryData *)window->winGetUserData();
	ICoord2D origin, size, start, end;
	Color backBorder, backColor, textColor, textBorder, 
			compositeColor, compositeBorder;

	// cancel unichar flag
	e->receivedUnichar = FALSE;

	// get size and position of window
	window->winGetScreenPosition( &origin.x, &origin.y );
	window->winGetSize( &size.x, &size.y );

	// get the right colors
	if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
	{

		compositeColor	= window->winGetDisabledTextColor();
		compositeBorder	= window->winGetDisabledTextBorderColor();
		textColor		= window->winGetDisabledTextColor();
		textBorder	= window->winGetDisabledTextBorderColor();
		backColor		= GadgetTextEntryGetDisabledColor( window );
		backBorder	= GadgetTextEntryGetDisabledBorderColor( window );

	}  // end if, disabled
	else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
	{

		compositeColor	= window->winGetIMECompositeTextColor();
		compositeBorder	= window->winGetIMECompositeBorderColor();
		textColor		= window->winGetHiliteTextColor();
		textBorder	= window->winGetHiliteTextBorderColor();
		backColor		= GadgetTextEntryGetHiliteColor( window );
		backBorder	= GadgetTextEntryGetHiliteBorderColor( window );

	}  // end else if, hilited
	else
	{

		compositeColor	= window->winGetIMECompositeTextColor();
		compositeBorder	= window->winGetIMECompositeBorderColor();
		textColor		= window->winGetEnabledTextColor();
		textBorder	= window->winGetEnabledTextBorderColor();
		backColor		= GadgetTextEntryGetEnabledColor( window );
		backBorder	= GadgetTextEntryGetEnabledBorderColor( window );

	}  // end else, just enabled

	// draw the back border
	if( backBorder != WIN_COLOR_UNDEFINED )
	{

		start.x = origin.x;
		start.y = origin.y;
		end.x = start.x + size.x;
		end.y = start.y + size.y;
		TheWindowManager->winOpenRect( backBorder, WIN_DRAW_LINE_WIDTH,
																	 start.x, start.y, end.x, end.y );

	}  // end if

	// draw the filled back
	if( backColor != WIN_COLOR_UNDEFINED )
	{

		start.x = origin.x + 1;
		start.y = origin.y + 1;
		end.x = start.x + size.x - 2;
		end.y = start.y + size.y - 2;
		TheWindowManager->winFillRect( backColor, WIN_DRAW_LINE_WIDTH,
																	 start.x, start.y, end.x, end.y );

	}  // end if

	// draw the text
	Int fontHeight = TheWindowManager->winFontHeight( instData->getFont() );
	Int startOffset = 5;
	Int width;

	width = size.x - (2 * startOffset);
	start.x = origin.x + startOffset;  // offset a little bit into the entry
	if( BitTest( window->winGetStatus(), WIN_STATUS_ONE_LINE ) )
		start.y = size.y / 2 - fontHeight / 2;
	else
		start.y = origin.y + startOffset;  // offset a little bit into the entry

	// draw the edit text
	drawTextEntryText( window, instData, textColor, textBorder, compositeColor, compositeBorder,
										 start.x, start.y, width, fontHeight );

	

}  // end W3DGadgetTextEntryDraw

// W3DGadgetTextEntryImageDraw ================================================
/** Draw horizontal slider with user supplied images */
//=============================================================================
void W3DGadgetTextEntryImageDraw( GameWindow *window, WinInstanceData *instData )
{
	EntryData *e = (EntryData *)window->winGetUserData();
	ICoord2D origin, size, start, end;
	Color textColor, textBorder;
	Color compositeColor, compositeBorder;
	const Image *leftImage, *rightImage, *centerImage, *smallCenterImage;
	Int xOffset, yOffset;
	Int i;

	// cancel unichar flag
	e->receivedUnichar = FALSE;

	// get size and position of window
	window->winGetScreenPosition( &origin.x, &origin.y );
	window->winGetSize( &size.x, &size.y );

	// get image offset
	xOffset = instData->m_imageOffset.x;
	yOffset = instData->m_imageOffset.y;

	// get the right colors
	if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
	{

		textColor					= window->winGetDisabledTextColor();
		textBorder				= window->winGetDisabledTextBorderColor();
		compositeColor		= window->winGetDisabledTextColor();
		compositeBorder		= window->winGetDisabledTextBorderColor();
		leftImage					= GadgetTextEntryGetDisabledImageLeft( window );
		rightImage				= GadgetTextEntryGetDisabledImageRight( window );
		centerImage				= GadgetTextEntryGetDisabledImageCenter( window );
		smallCenterImage	= GadgetTextEntryGetDisabledImageSmallCenter( window );

	}  // end if, disabled
	else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
	{

		textColor					= window->winGetHiliteTextColor();
		textBorder				= window->winGetHiliteTextBorderColor();
		compositeColor		= window->winGetIMECompositeTextColor();
		compositeBorder		= window->winGetIMECompositeBorderColor();
		leftImage					= GadgetTextEntryGetHiliteImageLeft( window );
		rightImage				= GadgetTextEntryGetHiliteImageRight( window );
		centerImage				= GadgetTextEntryGetHiliteImageCenter( window );
		smallCenterImage	= GadgetTextEntryGetHiliteImageSmallCenter( window );

	}  // end else if, hilited
	else
	{

		textColor					= window->winGetEnabledTextColor();
		textBorder				= window->winGetEnabledTextBorderColor();
		compositeColor		= window->winGetIMECompositeTextColor();
		compositeBorder		= window->winGetIMECompositeBorderColor();
		leftImage					= GadgetTextEntryGetEnabledImageLeft( window );
		rightImage				= GadgetTextEntryGetEnabledImageRight( window );
		centerImage				= GadgetTextEntryGetEnabledImageCenter( window );
		smallCenterImage	= GadgetTextEntryGetEnabledImageSmallCenter( window );

	}  // end else, just enabled

	// get image sizes for the ends
	ICoord2D leftSize, rightSize;
	leftSize.x = leftImage->getImageWidth();
	leftSize.y = leftImage->getImageHeight();
	rightSize.x = rightImage->getImageWidth();
	rightSize.y = rightImage->getImageHeight();

	// get two key points used in the end drawing
	ICoord2D leftEnd, rightStart;
	leftEnd.x = origin.x + leftSize.x + xOffset;
	leftEnd.y = origin.y + size.y + yOffset;
	rightStart.x = origin.x + size.x - rightSize.x + xOffset;
	rightStart.y = origin.y + yOffset;

	// draw the center repeating bar
	Int centerWidth, pieces;

	// get width we have to draw our repeating center in
	centerWidth = rightStart.x - leftEnd.x;

	// how many whole repeating pieces will fit in that width
	pieces = centerWidth / centerImage->getImageWidth();

	// draw the pieces
	start.x = leftEnd.x;
	start.y = origin.y + yOffset;
	end.y = start.y + size.y;
	for( i = 0; i < pieces; i++ )
	{

		end.x = start.x + centerImage->getImageWidth();
		TheWindowManager->winDrawImage( centerImage, 
																		start.x, start.y,
																		end.x, end.y );
		start.x += centerImage->getImageWidth();

	}  // end for i

	//
	// how many small repeating pieces will fit in the gap from where the
	// center repeating bar stopped and the right image, draw them
	// and overlapping underneath where the right end will go
	//
	centerWidth = rightStart.x - start.x;
	pieces = centerWidth / smallCenterImage->getImageWidth() + 1;
	end.y = start.y + size.y;
	for( i = 0; i < pieces; i++ )
	{

		end.x = start.x + smallCenterImage->getImageWidth();
		TheWindowManager->winDrawImage( smallCenterImage,
																		start.x, start.y,
																		end.x, end.y );
		start.x += smallCenterImage->getImageWidth();

	}  // end for i

	// draw left end
	start.x = origin.x + xOffset;
	start.y = origin.y + yOffset;
	end = leftEnd;
	TheWindowManager->winDrawImage(leftImage, start.x, start.y, end.x, end.y);

	// draw right end
	start = rightStart;
	end.x = start.x + rightSize.x;
	end.y = start.y + size.y;
	TheWindowManager->winDrawImage(rightImage, start.x, start.y, end.x, end.y);

	// draw the text
	Int fontHeight = TheWindowManager->winFontHeight( instData->getFont() );
	Int startOffset = 5;
	Int width;

	width = size.x - (2 * startOffset);
	start.x = origin.x + startOffset;  // offset a little bit into the entry
		if( BitTest( window->winGetStatus(), WIN_STATUS_ONE_LINE ) )
		start.y = size.y / 2 - fontHeight / 2;
	else
		start.y = origin.y + startOffset;  // offset a little bit into the entry

	// draw the edit text
	drawTextEntryText( window, instData, textColor, textBorder, compositeColor, compositeBorder,
										 start.x, start.y, width, fontHeight );

	

}  // end W3DGadgetTextEntryImageDraw
