/*
**	Command & Conquer Renegade(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 O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Combat																		  *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Combat/messagewindow.cpp        $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 1/07/02 10:43a                                              $*
 *                                                                                             *
 *                    $Revision:: 19                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


#include "messagewindow.h"
#include "assetmgr.h"
#include "texture.h"
#include "font3d.h"
#include "objectives.h"
#include "translatedb.h"
#include "scene.h"
#include "timemgr.h"
#include "assets.h"
#include "globalsettings.h"
#include "smartgameobj.h"
#include "evasettings.h"
#include "soldier.h"
#include "dynamicspeechanim.h"
#include "combat.h"
#include "camera.h"
#include "scene.h"
#include "ww3d.h"
#include "wwmemlog.h"

////////////////////////////////////////////////////////////////
//	Constants
////////////////////////////////////////////////////////////////
static const char *FONT_NAME						= "FONT6X8.TGA";
static const char *HEADER_FONT_NAME				= "FONT8X8.TGA";



////////////////////////////////////////////////////////////////
//
//	MessageWindowClass
//
////////////////////////////////////////////////////////////////
MessageWindowClass::MessageWindowClass (void) :
	TextWindow (NULL),
	DecayTime (6000),
	Scene (NULL),
	Camera (NULL),
	HeadModel (NULL),
	IsRectangleDirty (true)
{	
	MessageLog.Set_Growth_Step (1000);
	MessageLogColor.Set_Growth_Step (1000);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	~MessageWindowClass
//
////////////////////////////////////////////////////////////////
MessageWindowClass::~MessageWindowClass (void)
{
	REF_PTR_RELEASE (Scene);
	REF_PTR_RELEASE (Camera);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Shutdown
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Shutdown (void)
{
	if (TextWindow != NULL) {
		delete TextWindow;
		TextWindow = NULL;
	}

	if (HeadModel != NULL) {
		HeadModel->Remove ();
	}
	REF_PTR_RELEASE (HeadModel);

	Clear_Log ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Initialize
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Initialize (void)
{
	WWMEMLOG(MEM_GAMEDATA);
	//
	//	Allocate the new text window
	//
	TextWindow = new TextWindowClass;

	EvaSettingsDefClass *settings = EvaSettingsDefClass::Get_Instance ();

	//
	//	Configure the backdrop for the text window
	//
	CurrentRect = settings->Get_Messages_Screen_Rect ();
	CurrentRect.Bottom = CurrentRect.Top + 1;
	TextWindow->Set_Backdrop ("hud_6x4_Messages.tga", CurrentRect,
		settings->Get_Messages_Texture_Size (), settings->Get_Messages_Endcap_Rect (),
		settings->Get_Messages_Fadeout_Rect (), settings->Get_Messages_Background_Rect ());
	
	//
	//	Configure the area where text can be displayed in the window
	//
	RectClass text_rect = settings->Get_Messages_Text_Rect ();
	text_rect.Bottom = text_rect.Top + 1;
	TextWindow->Set_Text_Area (text_rect);

	//
	//	Configure the fonts for the window
	//
	TextWindow->Set_Heading_Font (HEADER_FONT_NAME);
	TextWindow->Set_Text_Font (FONT_NAME);
	
	//
	//	Configure the columns
	//
	TextWindow->Add_Column (L"", 1.0F, Vector3 (1, 1, 1));
	TextWindow->Display_Columns (false);

	//
	//	Configure the icon renderer
	//
	//IconRenderer.Reset ();
	//IconRenderer.Set_Hidden (true);
	//IconRenderer.Set_Coordinate_Range (Render2DClass::Get_Screen_Resolution ());

	//
	//	Create a scene to use for the head model
	//
	Scene = new SimpleSceneClass;
	Scene->Set_Ambient_Light(Vector3(1,1,1));

	//
	//	Create a camera to use in the "head-scene"
	//
	Camera = new CameraClass ();
	Camera->Set_Position (Vector3 (0, 0, 2.0F));	
	Camera->Set_View_Plane (DEG_TO_RADF (107.0), DEG_TO_RADF (74.0));
	Camera->Set_Clip_Planes (0.1F, 100.0F);
	Camera->Set_Projection_Type (CameraClass::ORTHO);

	//
	//	Lookup the head model we'll use for conversations
	//
	//HeadModel = WW3DAssetManager::Get_Instance ()->Create_Render_Obj ("CX_HAVOC_HEAD");
	if (HeadModel != NULL) {
		HeadModel->Set_Hidden (true);

		//
		//	Position the head model
		//
		Matrix3D tm (1);
		tm.Rotate_Z (DEG_TO_RADF (90));
		tm.Rotate_X (DEG_TO_RADF (90));		
		tm.Set_Translation (Vector3 (-1.22F, 0.53F, 0));
		HeadModel->Set_Transform (tm);

		//
		//	Add the head model to the scene
		//
		Scene->Add_Render_Object (HeadModel);
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Render (void)
{
	WWMEMLOG(MEM_GAMEDATA);

	//
	//	Update the window rectangle as necessary
	//
	if (IsRectangleDirty) {
		Update_Window_Rectangle ();
	}

	if (TextWindow != NULL) {
		TextWindow->Render ();
	}
	
	//IconRenderer.Render ();

	WW3D::Render (Scene, Camera);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_Frame_Update
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::On_Frame_Update (void)
{
	WWMEMLOG(MEM_GAMEDATA);
	if (TextWindow == NULL || TextWindow->Is_Displayed () == false) {
		return ;
	}

	if (TextWindow->Get_Item_Count () == 0) {
		TextWindow->Display (false);
		//IconRenderer.Set_Hidden (true);
		if (HeadModel != NULL) {
			HeadModel->Set_Hidden (true);
		}
		Reset_Current_Rect ();
	} else {
		int items_to_remove = TextWindow->Get_Item_Count () - TextWindow->Get_Display_Count ();
		
		//
		//	Remove messages from the top of the list if we have more then we
		// can display
		//
		for (int index = 0; index < items_to_remove; index ++) {
			TextWindow->Delete_Item (0);
		}

		//
		//	Decay the entries
		//
		for (index = TextWindow->Get_Item_Count () - 1; index >= 0; index --) {
			
			//
			//	Decay the time remaining on this message
			//
			int time_left = (int)TextWindow->Get_Item_Data (index);
			time_left -= TimeManager::Get_Frame_Ticks ();
			TextWindow->Set_Item_Data (index, (uint32)time_left);

			//
			//	Should we remove this message?
			//
			if (time_left <= 0) {
				TextWindow->Delete_Item (index);
			}
		}
	}
	
	TextWindow->On_Frame_Update ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Add_Message
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Add_Message
(
	const WideStringClass &	message,
	const Vector3 &			color,
	SmartGameObj *				game_obj,
	float							decay_time
)
{
	WWMEMLOG(MEM_GAMEDATA);
	if (TextWindow == NULL) {
		return ;
	}

	//
	//	Determine how long we should display the message for...
	//
	int decay_time_in_ms = DecayTime;
	if (decay_time != 0) {
		decay_time_in_ms = int(decay_time * 1000);
	}

	//
	//	Add the message to the end of the list
	//
	if (message.Get_Length () > 0) {
		int item_index = TextWindow->Insert_Item (TextWindow->Get_Item_Count (), message);
		if (item_index != -1) {		
			TextWindow->Set_Item_Color (item_index, 0, color);
			TextWindow->Set_Item_Data (item_index, decay_time_in_ms);		
		}
	}

	//
	//	Resize the window as necessary
	//
	Update_Window_Rectangle ();

	//
	//	Make sure the window is displayed
	//
	if (message.Get_Length () > 0) {
		TextWindow->Display (true);
	}

	//
	//	Get the name of the icon file we'll use
	//
	StringClass filename("hud_6x4_icon_default.tga",true);
	if (game_obj != NULL) {
		Strip_Path_From_Filename (filename, game_obj->Get_Info_Icon_Texture_Filename ());

		//
		//	Try to play an animation on the head model
		//
		if (HeadModel != NULL) {
			SoldierGameObj *soldier = game_obj->As_SoldierGameObj ();
			if (soldier != NULL) {
				DynamicSpeechAnimClass *speech_anim = soldier->Get_Facial_Anim ();

				if (speech_anim != NULL) {
					HeadModel->Set_Animation( speech_anim, 0, RenderObjClass::ANIM_MODE_ONCE );			
				}
			}	
		}
	}


	//
	//	Configure the icon renderer
	//
	//IconRenderer.Reset ();
	//IconRenderer.Set_Hidden (false);

	if (HeadModel != NULL) {
		HeadModel->Set_Hidden (false);
	}

	//
	//	Log the message
	//
	MessageLog.Add (message);
	MessageLogColor.Add (color);

	//
	//	Calculate the display rectangle of the icon
	//
	/*const HUDGlobalSettingsDef *hud_settings = HUDGlobalSettingsDef::Get_Instance ();
	RectClass icon_rect (Vector2 (0, 0), hud_settings->TargetIconSize);
	icon_rect += Render2DClass::Get_Screen_Resolution().Upper_Left () + settings->Get_Messages_Icon_Position ();*/

	//
	//	Build the icon mesh
	//
	//IconRenderer.Set_Texture ( filename );
	//IconRenderer.Add_Quad (icon_rect, 0xFFFFFFFF);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Update_Window_Rectangle
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Update_Window_Rectangle (void)
{
	//
	//	Get the dimensions of the text window
	//
	EvaSettingsDefClass *settings		= EvaSettingsDefClass::Get_Instance ();

	if (settings == NULL || TextWindow == NULL) {
		return;
	}

	WWASSERT(settings != NULL);
	RectClass screen_rect				= settings->Get_Messages_Screen_Rect ();
	RectClass text_rect					= settings->Get_Messages_Text_Rect ();
	float top_border						= text_rect.Top - screen_rect.Top;
	float bottom_border					= screen_rect.Bottom - text_rect.Bottom;
	float vert_border						= top_border + bottom_border;

	//
	//	Resize the area (if needs be)
	//
	WWASSERT(TextWindow != NULL);
	float total_height = TextWindow->Get_Total_Display_Height ();
	if (IsRectangleDirty || (total_height > (CurrentRect.Height () - vert_border))) {

		CurrentRect.Bottom = WWMath::Clamp (CurrentRect.Top + total_height + vert_border, 0, screen_rect.Bottom);

		//
		//	Resize the backdrop area
		//
		TextWindow->Set_Backdrop ("hud_6x4_Messages.tga", CurrentRect,
			settings->Get_Messages_Texture_Size (), settings->Get_Messages_Endcap_Rect (),
			settings->Get_Messages_Fadeout_Rect (), settings->Get_Messages_Background_Rect ());

		//
		//	Resize the text area
		//
		text_rect.Top		= CurrentRect.Top + top_border;
		text_rect.Bottom	= CurrentRect.Bottom - bottom_border;
		TextWindow->Set_Text_Area (text_rect);		
	}
	
	IsRectangleDirty = false;
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Clear
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Clear (void)
{
	if (TextWindow != NULL) {
		TextWindow->Delete_All_Items ();
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Force_Display
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Force_Display (bool onoff)
{
	if (TextWindow != NULL) {
		TextWindow->Display (onoff);
	}

	//IconRenderer.Set_Hidden (!onoff);


	if (HeadModel != NULL) {
		HeadModel->Set_Hidden (!onoff);
	}

	Reset_Current_Rect ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Has_Data
//
////////////////////////////////////////////////////////////////
bool
MessageWindowClass::Has_Data (void) const
{
	return (TextWindow != NULL && TextWindow->Get_Item_Count () > 0);
}


////////////////////////////////////////////////////////////////
//
//	Reset_Current_Rect
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Reset_Current_Rect (void)
{
	EvaSettingsDefClass *settings = EvaSettingsDefClass::Get_Instance ();

	//
	//	Shrink the rectangle so its only 1 pixel high (this will force
	// it to grow to the right size later on).
	//
	CurrentRect				= settings->Get_Messages_Screen_Rect ();
	CurrentRect.Bottom	= CurrentRect.Top + 1;	
	return ;
}