//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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.

// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
// in the hope that it will be useful, but with permitted additional restrictions 
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
// distributed with this program. You should have received a copy of the 
// GNU General Public License along with permitted additional restrictions 
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection

/* $Header: /counterstrike/GOPTIONS.CPP 6     3/15/97 7:18p Steve_tall $ */
/***********************************************************************************************
 ***              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 : Command & Conquer                                            *
 *                                                                                             *
 *                    File Name : OPTIONS.CPP                                                  *
 *                                                                                             *
 *                   Programmer : Joe L. Bostic                                                *
 *                                                                                             *
 *                   Start Date : June 8, 1994                                                 *
 *                                                                                             *
 *                  Last Update : July 27, 1995 [JLB]                                          *
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 *   OptionsClass::Process -- Handles all the options graphic interface.                       *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "function.h"

#include "goptions.h"
#include "loaddlg.h"
#include "sounddlg.h"
#include "visudlg.h"
#include "gamedlg.h"
#include "textbtn.h"
#include "descdlg.h"

#ifdef FIXIT_VERSION_3		//	Stalemate games.
#include "WolStrng.h"
#endif

bool RedrawOptionsMenu;

/***********************************************************************************************
 * OptionsClass::Process -- Handles all the options graphic interface.                         *
 *                                                                                             *
 *    This routine is the main control for the visual representation of the options            *
 *    screen. It handles the visual overlay and the player input.                              *
 *                                                                                             *
 * INPUT:      none                                                                            *
 *                                                                                             *
 * OUTPUT:     none                                                                            *
 *                                                                                             *
 * WARNINGS:      none                                                                         *
 *                                                                                             *
 * HISTORY:     12/31/1994 MML : Created.                                                      *
 *   06/23/1995 JLB : Handles restating the mission objective.                                 *
 *   07/27/1995 JLB : Adjusts menu for multiplay mode.                                         *
 *=============================================================================================*/
void GameOptionsClass::Process(void)
{
	static struct {
		int ID;				// Button ID to use.
		int Text;			// Text number to use for this button.
		bool Multiplay;	// Allowed in multiplayer version?
	} _constants[] = {
		{BUTTON_LOAD,  	TXT_LOAD_MISSION,    false},
#ifdef FIXIT_MULTI_SAVE
		{BUTTON_SAVE,  	TXT_SAVE_MISSION,    true},
#else
		{BUTTON_SAVE,  	TXT_SAVE_MISSION,    false},
#endif
		{BUTTON_DELETE,	TXT_DELETE_MISSION,  true},
		{BUTTON_GAME,  	TXT_GAME_CONTROLS,   true},
		{BUTTON_QUIT,  	TXT_QUIT_MISSION,    true},
#ifdef FIXIT_VERSION_3		//	Stalemate games.
		{BUTTON_DRAW,  	TXT_OK,    true},
#endif
		{BUTTON_RESUME,	TXT_RESUME_MISSION,  true},
		{BUTTON_RESTATE,	TXT_RESTATE_MISSION, false},
	};

	/*
	**	Variables.
	*/
	TextButtonClass * buttons = 0;
	int selection;
	bool pressed;
#ifdef FIXIT_VERSION_3		//	Stalemate games.
	int curbutton = 7;
#else
	int curbutton = 6;
#endif
	int y;
	TextButtonClass * buttonsel[ARRAY_SIZE(_constants)];
	static int num_buttons = sizeof(_constants)/sizeof(_constants[0]);


	int num_players = 0;
	int i;

	//
	// Compute the number of real players in the game; only allow saves
	// if there are more than 1.
	//
	for (i = 0; i < Session.Players.Count(); i++) {
		if (!(HouseClass::As_Pointer(Session.Players[i]->Player.ID)->IsDefeated)) {
			num_players++;
		}
	}


	Set_Logic_Page(SeenBuff);

	/*
	**	Build the button list for all of the buttons for this dialog.
	*/
	int maxwidth = 0;

	for (int index = 0; index < num_buttons ; index++ ) {
		int text = _constants[index].Text;
		buttonsel[index] = NULL;

		if (Session.Type != GAME_NORMAL && !_constants[index].Multiplay) {
			continue;
		}

		if ( (Session.Type == GAME_SKIRMISH ||
					Session.Type == GAME_INTERNET) && text == TXT_SAVE_MISSION) {
			continue;
		}

#ifdef FIXIT_VERSION_3
		if (Session.Type != GAME_NORMAL && ( num_players < 2 ) &&
					text == TXT_SAVE_MISSION) {
			continue;
		}
#else
#ifdef FIXIT_MULTI_SAVE
		if (Session.Type != GAME_NORMAL && (num_players < 2 || PlayingAgainstVersion == VERSION_RED_ALERT_104) &&
					text == TXT_SAVE_MISSION) {
			continue;
		}
#endif	//FIXIT_MULTI_SAVE
#endif

		if (Session.Type == GAME_SKIRMISH && text == TXT_DELETE_MISSION) {
			continue;
		}

		if (Session.Type != GAME_NORMAL && text == TXT_DELETE_MISSION) {
			text = TXT_RESIGN;
		}

#ifdef FIXIT_VERSION_3		//	Stalemate games.
		if (index < 6) {
#else
		if (index < 5) {
#endif
			y = (SeenBuff.Get_Height() - OptionHeight)/2 + ButtonY + ((OButtonHeight+2) * index);
		} else {
			y = OptionY + ButtonResumeY;
		}

#ifdef FIXIT_VERSION_3		//	Stalemate games.
		TextButtonClass* g;
		if( _constants[index].ID == BUTTON_DRAW )
		{
			if( Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH && Session.Players.Count() == 2 )
			{
				if( Scen.bLocalProposesDraw )
				{
					if( !Scen.bOtherProposesDraw )
						g = new TextButtonClass( BUTTON_DRAW, TXT_WOL_RETRACT_DRAW, TPF_BUTTON, 0, y );
					else
						continue;		//	Game will end now anyway.
				}
				else
				{
					if( !Scen.bOtherProposesDraw )
						g = new TextButtonClass( BUTTON_DRAW, TXT_WOL_PROPOSE_DRAW, TPF_BUTTON, 0, y );
					else
						g = new TextButtonClass( BUTTON_DRAW, TXT_WOL_ACCEPT_DRAW, TPF_BUTTON, 0, y );
				}
			}
			else
				continue;
		}
		else
			g = new TextButtonClass(_constants[index].ID, text, TPF_BUTTON, 0, y);
#else
		TextButtonClass * g = new TextButtonClass(_constants[index].ID, text, TPF_BUTTON, 0, y);
#endif

		if (g->Width > maxwidth) {
			maxwidth = g->Width;
		}
		if (buttons == NULL) {
			buttons = g;
		} else {
			g->Add_Tail(*buttons);
		}

		buttonsel[index] = g;
	}

	/*
	** BG: In skirmish mode, there is no 'restate' button, so we have to
	**     backtrack through the list to find the last valid button.
	*/
	while(!buttonsel[curbutton-1]) curbutton--;

	buttonsel[curbutton-1]->Turn_On();

	/*
	**	Force all button lengths to match the maximum length of the widest button.
	*/
	GadgetClass * g = buttons;
	while (g != NULL) {
		g->Width = max(maxwidth, 90 * RESFACTOR);
		g->X = OptionX+(OptionWidth-g->Width)/2;
		g = g->Get_Next();
	}
//#ifdef FRENCH
//	buttonsel[BUTTON_RESUME-1]->Width = 110 * RESFACTOR;
//	buttonsel[BUTTON_RESUME-1]->X = OptionX + (17 * RESFACTOR) - 5;
//#else
	buttonsel[BUTTON_RESUME-1]->Width = 90 * RESFACTOR;
	buttonsel[BUTTON_RESUME-1]->X = OptionX + (17 * RESFACTOR);
//#endif

	if (Session.Type == GAME_NORMAL) {
		buttonsel[BUTTON_RESTATE-1]->Width = 90 * RESFACTOR;
		buttonsel[BUTTON_RESTATE-1]->X = OptionX+OptionWidth-(buttonsel[BUTTON_RESTATE-1]->Width+(17 * RESFACTOR));
	}

	/*
	**	This causes left mouse button clicking within the confines of the dialog to
	**	be ignored if it wasn't recognized by any other button or slider.
	*/
	(new GadgetClass(OptionX, OptionY, OptionWidth, OptionHeight, GadgetClass::LEFTPRESS))->Add_Tail(*buttons);

	/*
	**	This cause a right click anywhere or a left click outside the dialog region
	**	to be equivalent to clicking on the return to game button.
	*/
	(new ControlClass(BUTTON_RESUME, 0, 0, SeenBuff.Get_Width(), SeenBuff.Get_Height(), GadgetClass::LEFTPRESS|GadgetClass::RIGHTPRESS))->Add_Tail(*buttons);

	Keyboard->Clear();

	Fancy_Text_Print(TXT_NONE, 0, 0, GadgetClass::Get_Color_Scheme(), TBLACK, TPF_CENTER|TPF_TEXT);

	/*
	**	Main Processing Loop.
	*/
	bool display = true;
	bool process = true;
	pressed = false;
	while (process) {

		/*
		**	Invoke game callback.
		*/
		if (Session.Type == GAME_NORMAL || Session.Type == GAME_SKIRMISH) {
			Call_Back();
		} else {
			if (Main_Loop()) {
				process = false;
			}
		}

		#ifdef WIN32
		/*
		** If we have just received input focus again after running in the background then
		** we need to redraw.
		*/
		if (AllSurfaces.SurfacesRestored) {
			AllSurfaces.SurfacesRestored = false;
			display = true;
		}
		#endif

		/*
		**	Refresh display if needed.
		*/
		if (display || RedrawOptionsMenu) {

			/*
			**	Redraw the map.
			*/
			HidPage.Clear();
			Map.Flag_To_Redraw(true);
			Map.Render();

			/*
			**	Reset up the window.  Window x-coords are in bytes not pixels.
			*/
			Set_Window(WINDOW_EDITOR, OptionX, OptionY, OptionWidth, OptionHeight);
			Hide_Mouse();

			/*
			**	Draw the background.
			*/
			Dialog_Box(OptionX, OptionY, OptionWidth, OptionHeight);

			/*
			**	Draw the arrows border if requested.
			*/
 			Draw_Caption(TXT_OPTIONS, OptionX, OptionY, OptionWidth);

			/*
			**	Display the version number at the bottom of the dialog box.
			*/
#ifndef WIN32
			Fancy_Text_Print("%s\rV%s",
					(OptionX+OptionWidth)-(17 * RESFACTOR),
					OptionY+OptionHeight-((Session.Type == GAME_NORMAL) ? (32 * RESFACTOR) : (24 * RESFACTOR)),
					GadgetClass::Get_Color_Scheme(), TBLACK,
					TPF_EFNT|TPF_NOSHADOW|TPF_RIGHT,
					Scen.ScenarioName,
					Version_Name());

#else
#if (0)//PG
			Fancy_Text_Print("%s\rV%s",
					(OptionX+OptionWidth)-(25 * RESFACTOR),
					OptionY+OptionHeight-((Session.Type == GAME_NORMAL) ? (32 * RESFACTOR) : (24 * RESFACTOR)),
					GadgetClass::Get_Color_Scheme(), TBLACK,
					TPF_EFNT|TPF_NOSHADOW|TPF_RIGHT,
					Scen.ScenarioName,
					Version_Name());
#endif
#endif

			buttons->Draw_All();
			TabClass::Hilite_Tab(0);
			Show_Mouse();
			display = false;
			RedrawOptionsMenu = false;
		}

		/*
		**	Get user input.
		*/
		KeyNumType input = buttons->Input();

		/*
		**	Process Input.
		*/
		switch (input) {
			case (BUTTON_RESTATE | KN_BUTTON):
				selection = BUTTON_RESTATE;
				pressed = true;
				break;

			case (BUTTON_LOAD | KN_BUTTON):
				selection = BUTTON_LOAD;
				pressed = true;
				break;

			case (BUTTON_SAVE | KN_BUTTON):
				selection = BUTTON_SAVE;
				pressed = true;
				break;

			case (BUTTON_DELETE | KN_BUTTON):
				selection = BUTTON_DELETE;
				pressed = true;
				break;

			case (BUTTON_QUIT | KN_BUTTON):
				selection = BUTTON_QUIT;
				pressed = true;
				break;

			case (BUTTON_GAME | KN_BUTTON):
				selection = BUTTON_GAME;
				pressed = true;
				break;

#ifdef FIXIT_VERSION_3		//	Stalemate games.
			case (BUTTON_DRAW | KN_BUTTON):
				selection = BUTTON_DRAW;
				pressed = true;
				break;
#endif

			case (KN_ESC):
			case (BUTTON_RESUME | KN_BUTTON):
				selection = BUTTON_RESUME;
				pressed = true;
				break;

			case (KN_UP):
				buttonsel[curbutton-1]->Turn_Off();
				buttonsel[curbutton-1]->Flag_To_Redraw();
				do {
					curbutton--;
					if (curbutton < 1) curbutton = num_buttons;
				} while (!buttonsel[curbutton-1]);

				buttonsel[curbutton-1]->Turn_On();
				buttonsel[curbutton-1]->Flag_To_Redraw();
				break;

			case (KN_DOWN):
				buttonsel[curbutton-1]->Turn_Off();
				buttonsel[curbutton-1]->Flag_To_Redraw();
				do {
					curbutton++;
					if ( curbutton > num_buttons ) curbutton = 1;
				} while (!buttonsel[curbutton-1]);

				buttonsel[curbutton-1]->Turn_On();
				buttonsel[curbutton-1]->Flag_To_Redraw();
				break;

			case (KN_RETURN):
				buttonsel[curbutton-1]->IsPressed = true;
				buttonsel[curbutton-1]->Draw_Me(true);
				selection = curbutton;
				pressed = true;
				Keyboard->Clear();
				break;

			default:
				break;
		}

		if (pressed) {

			buttonsel[curbutton-1]->Turn_Off();
			buttonsel[curbutton-1]->Flag_To_Redraw();
			curbutton = selection;
			buttonsel[curbutton-1]->Turn_On();
			buttonsel[curbutton-1]->Flag_To_Redraw();

			switch (selection) {
				case BUTTON_RESTATE:
					display = true;
					if (!Restate_Mission(Scen.ScenarioName, TXT_VIDEO, TXT_RESUME_MISSION/*KOTXT_OPTIONS*/)) {
						BreakoutAllowed = true;
						Play_Movie(Scen.BriefMovie);
						BlackPalette.Adjust(0x08, WhitePalette);
						BlackPalette.Set();
						BlackPalette.Adjust(0xFF);
						BlackPalette.Set();
						GamePalette.Set();

						Map.Flag_To_Redraw(true);
						Theme.Queue_Song(THEME_PICK_ANOTHER);
						process = false;
					} else {
						BlackPalette.Adjust(0x08, WhitePalette);
						BlackPalette.Set();
						BlackPalette.Adjust(0xFF);
						BlackPalette.Set();
						GamePalette.Set();
						Map.Flag_To_Redraw(true);
						process = false;
					}
					break;

				case (BUTTON_LOAD):
					display = true;
					if (LoadOptionsClass(LoadOptionsClass::LOAD).Process()) {
						process = false;
					}
					break;

				case (BUTTON_SAVE):
					display = true;
					if (Session.Type == GAME_NORMAL) {
						LoadOptionsClass(LoadOptionsClass::SAVE).Process();

					} else {
						OutList.Add(EventClass(EventClass::SAVEGAME));
						process = false;
					}
					break;

				case (BUTTON_DELETE):
					display = true;
					if (Session.Type != GAME_NORMAL) {
						if (Surrender_Dialog(TXT_SURRENDER)) {
							OutList.Add(EventClass(EventClass::DESTRUCT));
						}
						process = false;
					} else {
						LoadOptionsClass(LoadOptionsClass::WWDELETE).Process();
					}
					break;

				case (BUTTON_QUIT):
					if (Session.Type == GAME_NORMAL) {
						switch (WWMessageBox().Process(TXT_CONFIRM_EXIT, TXT_ABORT, TXT_CANCEL, TXT_RESTART)) {
							case 1:
								display = true;
								break;

							case 0:
								process = false;
								Queue_Exit();
								break;

							case 2:
								PlayerRestarts = true;
								process = false;
								break;
						}
					} else {
						if (Surrender_Dialog(TXT_CONFIRM_EXIT)) {
							process = false;
							Queue_Exit();
						} else {
							display = true;
						}
						//if (WWMessageBox().Process(TXT_CONFIRM_EXIT, TXT_YES, TXT_NO) == 0) {
							//process = false;
							//Queue_Exit();
						//} else {
							//display = true;
						//}
					}
					break;

#ifdef FIXIT_VERSION_3		//	Stalemate games.
				case BUTTON_DRAW:
					if( Scen.bLocalProposesDraw )
					{
						//	Retract draw offer.
						OutList.Add(EventClass(EventClass::RETRACT_DRAW));
						process = false;
					}
					else
					{
						if( !Scen.bOtherProposesDraw )
						{
							//	Propose a draw?
							if( Surrender_Dialog( TXT_WOL_PROPOSE_DRAW_CONFIRM ) )
							{
								OutList.Add(EventClass(EventClass::PROPOSE_DRAW));
								process = false;
							}
							else
								display = true;
						}
						else
						{
							//	Accept a draw?
							if( Surrender_Dialog( TXT_WOL_ACCEPT_DRAW_CONFIRM ) )
							{
								OutList.Add(EventClass(EventClass::PROPOSE_DRAW));
								process = false;
							}
							else
								display = true;
						}
					}
					break;
#endif

				case (BUTTON_GAME):
					display = true;
					GameControlsClass().Process();
					break;

				case (BUTTON_RESUME):
					Save_Settings();
					process = false;
					display = true;
					break;
			}

			pressed = false;
			buttonsel[curbutton-1]->IsPressed = false;
			buttonsel[curbutton-1]->Turn_Off();
			buttonsel[curbutton-1]->Flag_To_Redraw();
		}
	}

	/*
	**	Clean up and re-enter the game.
	*/
	buttons->Delete_List();

	/*
	**	Redraw the map.
	*/
	Keyboard->Clear();
	HidPage.Clear();
	Map.Flag_To_Redraw(true);
	Map.Render();
}


void GameOptionsClass::Adjust_Variables_For_Resolution(void)
{
	OptionWidth		=	(216+8) * RESFACTOR;
#ifdef FIXIT_VERSION_3		//	Stalemate games.
	OptionHeight	=	111 * RESFACTOR;
#else
	OptionHeight	=	100 * RESFACTOR;
#endif
	OptionX			=	((SeenBuff.Get_Width() - OptionWidth) / 2);
	OptionY			=	((SeenBuff.Get_Height() - OptionHeight) / 2);
	ButtonWidth		=	130 * RESFACTOR;
	OButtonHeight	=	9 * RESFACTOR;
	CaptionYPos		=	5 * RESFACTOR;
	ButtonY			=	21 * RESFACTOR;
	Border1Len		=	72 * RESFACTOR;
	Border2Len		=	16 * RESFACTOR;
	ButtonResumeY	=	(OptionHeight - (19 * RESFACTOR));
}