//
// 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/GAMEDLG.CPP 1     3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
 ***              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 : GAMEDLG.CPP                                                  *
 *                                                                                             *
 *                   Programmer : Maria del Mar McCready Legg, Joe L. Bostic                   *
 *                                                                                             *
 *                   Start Date : Jan 8, 1995                                                  *
 *                                                                                             *
 *                  Last Update : Jan 18, 1995   [MML]                                         *
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 *   OptionsClass::Process -- Handles all the options graphic interface.                       *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include	"function.h"
#include	"gamedlg.h"
#include "sounddlg.h"
#include "visudlg.h"
#define GERMAN_OFFSET_Y   4      //VG

#ifdef WOLAPI_INTEGRATION
#include "WolStrng.h"
#include "WolapiOb.h"
extern WolapiObject* pWolapi;
bool WOL_Options_Dialog( WolapiObject* pWO, bool bCalledFromGame );
#endif


/***********************************************************************************************
 * 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.                                                                 *
 *=============================================================================================*/
void GameControlsClass::Process(void)
{
	/*
	**	Dialog & button dimensions
	*/
	int	d_dialog_w = 232 * RESFACTOR;											// dialog width
	int	d_dialog_h = 141 * RESFACTOR;											// dialog height
	int	d_dialog_x = ((SeenBuff.Get_Width() - d_dialog_w) / 2);				// dialog x-coord
	int	d_dialog_y = ((SeenBuff.Get_Height() - d_dialog_h) / 2);				// centered y-coord
	int	d_dialog_cx = d_dialog_x + (d_dialog_w / 2);		// center x-coord
	int	d_top_margin = 25 * RESFACTOR;

	int	d_txt6_h = (6 * RESFACTOR) + 1;												// ht of 6-pt text
	int	d_margin1 = (5 * RESFACTOR);												// large margin
	int	d_margin2 = (2 * RESFACTOR);												// small margin

	int	d_speed_w = d_dialog_w - (34 * RESFACTOR);
	int	d_speed_h = 6 * RESFACTOR;
	int	d_speed_x = d_dialog_x + (17 * RESFACTOR);
#ifdef GERMAN
	int	d_speed_y = d_dialog_y + d_top_margin + d_margin1 + d_txt6_h - GERMAN_OFFSET_Y;
#else
	int	d_speed_y = d_dialog_y + d_top_margin + d_margin1 + d_txt6_h;
#endif

	int	d_scroll_w = d_dialog_w - (34 * RESFACTOR);
	int	d_scroll_h = 6 * RESFACTOR;
	int	d_scroll_x = d_dialog_x + (17 * RESFACTOR);
#ifdef GERMAN
	int	d_scroll_y = d_speed_y + d_speed_h + d_txt6_h + (d_margin1 * 2) + d_txt6_h - GERMAN_OFFSET_Y;
#else
	int	d_scroll_y = d_speed_y + d_speed_h + d_txt6_h + (d_margin1 * 2) + d_txt6_h;
#endif

	int	d_visual_w = d_dialog_w - (40 * RESFACTOR);
	int	d_visual_h = 9 * RESFACTOR;
	int	d_visual_x = d_dialog_x + (20 * RESFACTOR);
	int	d_visual_y = d_scroll_y + d_scroll_h + d_txt6_h + (d_margin1 * 2);

	int	d_sound_w = d_dialog_w - (40 * RESFACTOR);
	int	d_sound_h = (9 * RESFACTOR);
	int	d_sound_x = d_dialog_x + (20 * RESFACTOR);
	int	d_sound_y = d_visual_y + d_visual_h + d_margin1;

	int	d_ok_w = 20 * RESFACTOR;
	int	d_ok_h = 9 * RESFACTOR;
	int	d_ok_x = d_dialog_cx - (d_ok_w / 2);
	int	d_ok_y = d_dialog_y + d_dialog_h - d_ok_h - d_margin1 - (4 * RESFACTOR);

#ifdef WOLAPI_INTEGRATION
	int d_wol_x = d_sound_x;
	int d_wol_y = d_sound_y + d_sound_h + d_margin1;
	int d_wol_w = d_sound_w;
	int d_wol_h = d_sound_h;

	bool bShowWolapi = ( pWolapi && !pWolapi->bConnectionDown );
	if( bShowWolapi )
	{
		//	Enlarge dialog and shift ok button down.
		d_dialog_h += d_wol_h + d_margin1;
		d_dialog_y = ((SeenBuff.Get_Height() - d_dialog_h) / 2);				// centered y-coord
		//d_ok_y += d_wol_h + d_margin1;
		d_ok_y = d_dialog_y + d_dialog_h - d_ok_h - d_margin1 - (4 * RESFACTOR);
	}
#endif

	/*
	**	Button Enumerations
	*/
#ifdef WOLAPI_INTEGRATION
	enum {
		BUTTON_SPEED = 100,
		BUTTON_SCROLLRATE,
		BUTTON_VISUAL,
		BUTTON_SOUND,
		BUTTON_WOLAPI,
		BUTTON_OK,
		BUTTON_COUNT,
		BUTTON_FIRST = BUTTON_SPEED,
	};
#else
	enum {
		BUTTON_SPEED = 100,
		BUTTON_SCROLLRATE,
		BUTTON_VISUAL,
		BUTTON_SOUND,
		BUTTON_OK,
		BUTTON_COUNT,
		BUTTON_FIRST = BUTTON_SPEED,
	};
#endif

	/*
	**	Dialog variables
	*/
	KeyNumType input;

	int gamespeed = Options.GameSpeed;
	int scrollrate = Options.ScrollRate;
	int selection;
	bool pressed = false;
	int curbutton = 0;
	TextButtonClass *buttons[BUTTON_COUNT - BUTTON_FIRST];
	TextPrintType style;

	RemapControlType * scheme = GadgetClass::Get_Color_Scheme();

	/*
	**	Buttons
	*/
	GadgetClass * commands;										// button list

	SliderClass gspeed_btn(BUTTON_SPEED, d_speed_x, d_speed_y, d_speed_w, d_speed_h, true);
	SliderClass scrate_btn(BUTTON_SCROLLRATE, d_scroll_x, d_scroll_y, d_scroll_w, d_scroll_h, true);
	TextButtonClass visual_btn(BUTTON_VISUAL, TXT_VISUAL_CONTROLS, TPF_BUTTON, d_visual_x, d_visual_y, d_visual_w, d_visual_h);
	TextButtonClass sound_btn(BUTTON_SOUND, TXT_SOUND_CONTROLS, TPF_BUTTON, d_sound_x, d_sound_y, d_sound_w, d_sound_h);
	TextButtonClass okbtn(BUTTON_OK, TXT_OPTIONS_MENU, TPF_BUTTON, d_ok_x, d_ok_y);
	okbtn.X = (SeenBuff.Get_Width()-okbtn.Width)/2;

#ifdef WOLAPI_INTEGRATION
	TextButtonClass wol_btn( BUTTON_WOLAPI, TXT_WOL_OPTTITLE, TPF_BUTTON, d_wol_x, d_wol_y, d_wol_w, d_wol_h );
#endif

	/*
	**	Various Inits.
	*/
	Set_Logic_Page(SeenBuff);

	/*
	**	Build button list
	*/
	commands = &okbtn;
	gspeed_btn.Add_Tail(*commands);
	scrate_btn.Add_Tail(*commands);
	visual_btn.Add_Tail(*commands);
	sound_btn.Add_Tail(*commands);
#ifdef WOLAPI_INTEGRATION
	if( bShowWolapi )
		wol_btn.Add_Tail(*commands);
#endif
	/*
	**	Init button states
	**	For sliders, the thumb ranges from 0 - (maxval-1), so to convert the
	**	thumb value to a real-world value:
	**		val = (MAX - slider.Get_Value()) - 1;
	**	and,
	**		slider.Set_Value(-(val + 1 - MAX));
	*/
	gspeed_btn.Set_Maximum(OptionsClass::MAX_SPEED_SETTING);	// varies from 0 - 7
	gspeed_btn.Set_Thumb_Size(1);
	gspeed_btn.Set_Value((OptionsClass::MAX_SPEED_SETTING-1) - gamespeed);

	scrate_btn.Set_Maximum(OptionsClass::MAX_SCROLL_SETTING);	// varies from 0 - 7
	scrate_btn.Set_Thumb_Size(1);
	scrate_btn.Set_Value((OptionsClass::MAX_SCROLL_SETTING-1) - scrollrate);

	/*
	**	Fill array of button ptrs.
	*/
	buttons[0] = NULL;
	buttons[1] = NULL;
	buttons[2] = &visual_btn;
	buttons[3] = &sound_btn;
#ifdef WOLAPI_INTEGRATION
	buttons[4] = &wol_btn;
	buttons[5] = &okbtn;
#else
	buttons[4] = &okbtn;
#endif
	/*
	**	Processing loop.
	*/
	bool process = true;
	bool display = true;
	bool refresh = true;
	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) {
			Hide_Mouse();

			Map.Flag_To_Redraw(true);
			Map.Render();

			Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h);
			Draw_Caption(TXT_GAME_CONTROLS, d_dialog_x, d_dialog_y, d_dialog_w);
			Show_Mouse();
			display = false;
			refresh = true;
		}

		if (refresh) {
			Hide_Mouse();

			/*
			**	Label the game speed slider
			*/
			style = TPF_TEXT;
			if (curbutton == (BUTTON_SPEED - BUTTON_FIRST)) {
				style = (TextPrintType)(style | TPF_BRIGHT_COLOR);
			}
			Fancy_Text_Print(TXT_SPEED, d_speed_x, d_speed_y - d_txt6_h, scheme, TBLACK, style);

			Fancy_Text_Print(TXT_SLOWER, d_speed_x, d_speed_y + d_speed_h + (1 * RESFACTOR), scheme, TBLACK, TPF_TEXT);
			Fancy_Text_Print(TXT_FASTER, d_speed_x + d_speed_w, d_speed_y + d_speed_h + (1 * RESFACTOR), scheme, TBLACK, TPF_TEXT|TPF_RIGHT);

			/*
			**	Label the scroll rate slider
			*/
			style = TPF_TEXT;
			if (curbutton == (BUTTON_SCROLLRATE - BUTTON_FIRST)) {
				style = (TextPrintType)(style | TPF_BRIGHT_COLOR);
			}
			Fancy_Text_Print(TXT_SCROLLRATE, d_scroll_x, d_scroll_y - d_txt6_h, scheme, TBLACK, style);

			Fancy_Text_Print (TXT_SLOWER, d_scroll_x, d_scroll_y + d_scroll_h + (1 * RESFACTOR), scheme, TBLACK, TPF_TEXT);
			Fancy_Text_Print (TXT_FASTER, d_scroll_x + d_scroll_w, d_scroll_y + d_scroll_h + (1 * RESFACTOR), scheme, TBLACK, TPF_TEXT|TPF_RIGHT);

			commands->Draw_All();

			Show_Mouse();
			refresh = false;
		}

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

		/*
		**	Process input.
		*/
		switch (input) {
			case (BUTTON_SPEED | KN_BUTTON):
				curbutton = (BUTTON_SPEED - BUTTON_FIRST);
				refresh = true;
				break;

			case (BUTTON_SCROLLRATE | KN_BUTTON):
				curbutton = (BUTTON_SCROLLRATE - BUTTON_FIRST);
				refresh = true;
				break;

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

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

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

#ifdef WOLAPI_INTEGRATION
			case (BUTTON_WOLAPI | KN_BUTTON):
				selection = BUTTON_WOLAPI;
				pressed = true;
				break;
#endif

			case (KN_ESC):
				process = false;
				break;

			case (KN_LEFT):
				if (curbutton == (BUTTON_SPEED - BUTTON_FIRST) ) {
					gspeed_btn.Bump(1);
				} else
					if (curbutton == (BUTTON_SCROLLRATE - BUTTON_FIRST) ) {
						scrate_btn.Bump(1);
					}
				break;

			case (KN_RIGHT):
				if (curbutton == (BUTTON_SPEED - BUTTON_FIRST) ) {
					gspeed_btn.Bump(0);
				} else
					if (curbutton == (BUTTON_SCROLLRATE - BUTTON_FIRST) ) {
						scrate_btn.Bump(0);
					}
				break;

			case (KN_UP):
				if (buttons[curbutton]) {
					buttons[curbutton]->Turn_Off();
					buttons[curbutton]->Flag_To_Redraw();
				}

				curbutton--;
#ifdef WOLAPI_INTEGRATION
				if( !bShowWolapi )
				{
					if( curbutton == BUTTON_WOLAPI - BUTTON_FIRST )
						curbutton--;		//	Skip over missing button.
				}
#endif
				if (curbutton < 0) {
					curbutton = (BUTTON_COUNT - BUTTON_FIRST - 1);
				}

				if (buttons[curbutton]) {
					buttons[curbutton]->Turn_On();
					buttons[curbutton]->Flag_To_Redraw();
				}
				refresh = true;
				break;

			case (KN_DOWN):
				if (buttons[curbutton]) {
					buttons[curbutton]->Turn_Off();
					buttons[curbutton]->Flag_To_Redraw();
				}

				curbutton++;
#ifdef WOLAPI_INTEGRATION
				if( !bShowWolapi )
				{
					if( curbutton == BUTTON_WOLAPI - BUTTON_FIRST )
						curbutton++;		//	Skip over missing button.
				}
#endif
				if (curbutton > (BUTTON_COUNT - BUTTON_FIRST - 1) ) {
					curbutton = 0;
				}

				if (buttons[curbutton]) {
					buttons[curbutton]->Turn_On();
					buttons[curbutton]->Flag_To_Redraw();
				}
				refresh = true;
				break;

			case (KN_RETURN):
				selection = curbutton + BUTTON_FIRST;
				pressed = true;
				break;

			default:
				break;
		}

		/*
		**	Perform some action. Either to exit the dialog or bring up another.
		*/
		if (pressed) {

			/*
			**	Record the new options slider settings.
			** The GameSpeed data member MUST NOT BE SET HERE!  It will cause multiplayer
			** games to go out of sync.  It's set by virtue of the event being executed.
			*/
			if (gamespeed != ((OptionsClass::MAX_SPEED_SETTING-1) - gspeed_btn.Get_Value()) ) {
				gamespeed = (OptionsClass::MAX_SPEED_SETTING-1) - gspeed_btn.Get_Value();
				OutList.Add(EventClass(EventClass::GAMESPEED, gamespeed));
			}

			if (scrollrate != ((OptionsClass::MAX_SCROLL_SETTING-1) - scrate_btn.Get_Value()) ) {
				scrollrate = (OptionsClass::MAX_SCROLL_SETTING-1) - scrate_btn.Get_Value();
				Options.ScrollRate = scrollrate;
			}
			process = false;

			/*
			** Save the settings in such a way that the GameSpeed is only set during
			** the save process; restore it when we're done, so multiplayer games don't
			** go out of sync.
			*/
			if (Session.Type == GAME_NORMAL) {
				Options.GameSpeed = gamespeed;
				Options.Save_Settings();			// save new value
			} else {
				int old = Options.GameSpeed;		// save orig value
				Options.GameSpeed = gamespeed;
				Options.Save_Settings();			// save new value
				Options.GameSpeed = old;			// restore old value
			}

			/*
			**	Possibly launch into another dialog if so directed.
			*/
			switch (selection) {
				case (BUTTON_VISUAL):
					VisualControlsClass().Process();
					process = true;
					display = true;
					refresh = true;
					break;

				case (BUTTON_SOUND):
					if (!SoundType) {
						WWMessageBox().Process(Text_String(TXT_NO_SOUND_CARD));
						process = true;
						display = true;
						refresh = true;
					} else {
						SoundControlsClass().Process();
						process = true;
						display = true;
						refresh = true;
					}
					break;

#ifdef WOLAPI_INTEGRATION
				case BUTTON_WOLAPI:
					if( WOL_Options_Dialog( pWolapi, true ) )
					{
						//	The game ended while in this dialog.
						process = false;
					}
					else
					{
						process = true;
						display = true;
						refresh = true;
					}
					break;
#endif

				case (BUTTON_OK):
					break;
			}

			pressed = false;
		}
	}
}