//
// 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:   F:\projects\c&c\vcs\code\goptions.cpv   2.17   16 Oct 1995 16:50:26   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 : 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.                       *
 *   Draw_Caption -- Draws a caption on a dialog box.                                          *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "function.h"

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

void GameOptionsClass::Adjust_Variables_For_Resolution(void)
{
	int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2;

	OptionWidth		=	(216+8) * factor;
	OptionHeight	=	100 * factor;
	OptionX			=	((SeenBuff.Get_Width() - OptionWidth) / 2);
	OptionY			=	((SeenBuff.Get_Height() - OptionHeight) / 2);
	ButtonWidth		=	130 * factor;
	OButtonHeight	=	9 * factor;
	CaptionYPos		=	5 * factor;
	ButtonY			=	21 * factor;
	Border1Len		=	72 * factor;
	Border2Len		=	16 * factor;
	ButtonResumeY	=	(OptionHeight - (15 * factor));
}
/***********************************************************************************************
 * 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},
		{BUTTON_SAVE,  	TXT_SAVE_MISSION,    	false},
		{BUTTON_DELETE,	TXT_DELETE_MISSION,  	true},
		{BUTTON_GAME,  	TXT_GAME_CONTROLS,   	true},
		{BUTTON_QUIT,  	TXT_QUIT_MISSION,    	true},
		{BUTTON_RESUME,	TXT_RESUME_MISSION,  	true},
		{BUTTON_RESTATE,	TXT_RESTATE_MISSION,		false},
	};

	/*
	**	Variables.
	*/
	TextButtonClass * buttons = 0;
	int selection;
	bool pressed;
	int curbutton = 6;
	int y;
	TextButtonClass *buttonsel[sizeof(_constants)/sizeof(_constants[0])];

	Set_Logic_Page(SeenBuff);

	/*
	**	Build the button list for all of the buttons for this dialog.
	*/
	int maxwidth = 0;
	int resfactor = (SeenBuff.Get_Width() == 320) ? 1 : 2;

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

		if (GameToPlay != GAME_NORMAL && !_constants[index].Multiplay) {
			buttonsel[index] = 0;
			continue;
		}

		if (GameToPlay != GAME_NORMAL && text == TXT_DELETE_MISSION) {
			text = TXT_RESIGN;
		}

		if (index < 5) {
			y = (SeenBuff.Get_Height() - OptionHeight)/2 + ButtonY + ((OButtonHeight+2) * index);
		} else {
			y = OptionY + ButtonResumeY;
		}

		TextButtonClass * g = new TextButtonClass(_constants[index].ID,
			text, TPF_6PT_GRAD|TPF_NOSHADOW, 0, y);

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

		buttonsel[index] = g;
	}

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

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

	if (GameToPlay == GAME_NORMAL) {
		buttonsel[BUTTON_RESTATE-1]->Width = 90 * resfactor;
		buttonsel[BUTTON_RESTATE-1]->X = OptionX+OptionWidth-(buttonsel[BUTTON_RESTATE-1]->Width+(5 * 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, CC_GREEN, TBLACK, TPF_CENTER|TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_NOSHADOW);

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

		/*
		** 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;
		}

		/*
		**	Invoke game callback.
		*/
		if (GameToPlay == GAME_NORMAL) {
			Call_Back();
		} else {
			if (Main_Loop()) {
				process = false;
			}
		}

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

			/*
			**	Redraw the map.
			*/
			HiddenPage.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.
			*/
			Window_Box (WINDOW_EDITOR, BOXSTYLE_GREEN_BORDER); // has border, raised up

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

			/*
			**	Display the version number at the bottom of the dialog box.
			*/
#ifdef DEMO
			Version_Number();
			Fancy_Text_Print("DEMO%s",
					((WindowList[WINDOW_EDITOR][WINDOWX]+WindowList[WINDOW_EDITOR][WINDOWWIDTH])<<3)-3*resfactor,
					WindowList[WINDOW_EDITOR][WINDOWY]+WindowList[WINDOW_EDITOR][WINDOWHEIGHT]-((GameToPlay == GAME_NORMAL) ? (32*resfactor) : (24*resfactor)),
					DKGREY, TBLACK,
					TPF_6POINT|TPF_NOSHADOW|TPF_RIGHT,
					ScenarioName,
					VersionText);
#else
			Fancy_Text_Print("%s\rV.%d%s",
					((WindowList[WINDOW_EDITOR][WINDOWX]+WindowList[WINDOW_EDITOR][WINDOWWIDTH])<<3)-3*resfactor,
					WindowList[WINDOW_EDITOR][WINDOWY]+WindowList[WINDOW_EDITOR][WINDOWHEIGHT]-((GameToPlay == GAME_NORMAL) ? (32*resfactor) : (24*resfactor)),
					DKGREY, TBLACK,
					TPF_6POINT|TPF_NOSHADOW|TPF_RIGHT,
					ScenarioName,
					Version_Number(),
					VersionText);
#endif

			buttons->Draw_All();
			TabClass::Hilite_Tab(0);
			Show_Mouse();
			display = 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;

			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();
				curbutton--;
				if (GameToPlay == GAME_NORMAL) {
					if (curbutton < BUTTON_LOAD) {
						curbutton = (BUTTON_COUNT - 1);
					}
				} else {
					if (curbutton < BUTTON_DELETE) {
						curbutton = BUTTON_RESUME;
//						curbutton = (BUTTON_COUNT-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();
				curbutton++;
				if (GameToPlay == GAME_NORMAL) {
					if (curbutton >= BUTTON_COUNT) {
						curbutton = BUTTON_LOAD;
					}
				} else {
					if (curbutton > BUTTON_RESUME) {
						curbutton = BUTTON_DELETE;
					}
				}
				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;
				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;
#ifdef JAPANESE
					if (!Restate_Mission(ScenarioName, TXT_VIDEO, TXT_TAB_BUTTON_CONTROLS)) {
#else
					if (!Restate_Mission(ScenarioName, TXT_VIDEO, TXT_OPTIONS)) {
#endif
						BreakoutAllowed = true;
						char buffer[25];
						sprintf(buffer, "%s.VQA", BriefMovie);
						if (CCFileClass(buffer).Is_Available()) {
							Play_Movie(BriefMovie);
						} else {
							Play_Movie(ActionMovie);
						}
						//BreakoutAllowed = false;
						memset(BlackPalette, 0x01, 768);
						Set_Palette(BlackPalette);
						memset(BlackPalette, 0x00, 768);
						Set_Palette(BlackPalette);
						Map.Flag_To_Redraw(true);
						Theme.Queue_Song(THEME_PICK_ANOTHER);
						process = false;
					}
					break;

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

				case (BUTTON_SAVE):
					display = true;
					LoadOptionsClass(LoadOptionsClass::SAVE).Process();
					break;

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

				case (BUTTON_QUIT):
					if (GameToPlay == GAME_NORMAL) {
#ifdef JAPANESE
						switch (CCMessageBox().Process(TXT_CONFIRM_EXIT, TXT_YES, TXT_NO, TXT_RESTART)) {
#else
						switch (CCMessageBox().Process(TXT_CONFIRM_EXIT, TXT_ABORT, TXT_CANCEL, TXT_RESTART)) {
#endif
							case 2:
								display = true;
								break;

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

							case 1:
								PlayerRestarts = true;
								process = false;
								break;
						}
					} else {
						if (ConfirmationClass().Process(TXT_CONFIRM_EXIT)) {
							process = false;
							Queue_Exit();
						} else {
							display = true;
						}
					}
					break;

				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]->Turn_On();
			buttonsel[curbutton-1]->Flag_To_Redraw();
		}
	}

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

	/*
	**	Redraw the map.
	*/
	Keyboard::Clear();
	Call_Back();
	HiddenPage.Clear();
	Call_Back();
	Map.Flag_To_Redraw(true);
	Map.Render();
}


/***********************************************************************************************
 * Draw_Caption -- Draws a caption on a dialog box.                                            *
 *                                                                                             *
 *    This routine draws the caption text and any fancy filigree that the dialog may require.  *
 *                                                                                             *
 * INPUT:   text  -- The text of the caption. This is the text number.                         *
 *                                                                                             *
 *          x,y   -- The dialog box X and Y pixel coordinate of the upper left corner.         *
 *                                                                                             *
 *          w     -- The width of the dialog box (in pixels).                                  *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/23/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void Draw_Caption(int text, int x, int y, int w)
{
	OptionControlType option = OPTION_NONE;
	int factor			= (SeenBuff.Get_Width() == 320) ? 1 : 2;


	/*
	**	Determine the filigree to use depending on the text of the caption.
	*/
	switch (text) {
		case TXT_GAME_CONTROLS:
		case TXT_OPTIONS:
			option = OPTION_CONTROLS;
			break;

		case TXT_LOAD_MISSION:
		case TXT_SAVE_MISSION:
		case TXT_DELETE_MISSION:
			option = OPTION_DELETE;
			break;

		case TXT_NONE:
		case TXT_MODEM_SERIAL:
		case TXT_SELECT_MPLAYER_GAME:
		case TXT_SELECT_SERIAL_GAME:
			option = OPTION_DIALOG;
			break;

		case TXT_HOST_SERIAL_GAME:
		case TXT_JOIN_SERIAL_GAME:
			option = OPTION_SERIAL;
			break;

		case TXT_SETTINGS:
		case TXT_PHONE_LIST:
		case TXT_PHONE_LISTING:
			option = OPTION_PHONE;
			break;

		case TXT_JOIN_NETWORK_GAME:
			option = OPTION_JOIN_NETWORK;
			break;

		case TXT_NETGAME_SETUP:
			option = OPTION_NETWORK;
			break;

		case TXT_VISUAL_CONTROLS:
			option = OPTION_VISUAL;
			break;

		case TXT_SOUND_CONTROLS:
			option = OPTION_SOUND;
			break;

		default:
			option = OPTION_DIALOG;
			break;
	}

	/*
	**	Draw the filigree at the corners of the dialog.
	*/
	if (option != OPTION_NONE) {
		CC_Draw_Shape(MixFileClass::Retrieve("OPTIONS.SHP"), (int)option, x+12, y+11, WINDOW_MAIN, SHAPE_CENTER);
		CC_Draw_Shape(MixFileClass::Retrieve("OPTIONS.SHP"), (int)option+1, x+w-14, y+11, WINDOW_MAIN, SHAPE_CENTER);
	}

	/*
	**	Draw the caption.
	*/
	if (text != TXT_NONE) {
		Fancy_Text_Print(text, w/2 + x, 5*factor + y, CC_GREEN, TBLACK, TPF_CENTER|TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_NOSHADOW);

		int length = String_Pixel_Width(Text_String(text));
		LogicPage->Draw_Line((x+(w/2))-(length/2), y+FontHeight+FontYSpacing + 5*factor, (x+(w/2))+(length/2), y+FontHeight+FontYSpacing + 5*factor, CC_GREEN);
	}
}