//
// 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

#ifdef WOLAPI_INTEGRATION

//	Wol_Main.cpp - Bottom level wolapi-stuff function.
//	ajw 07/16/98

#include "function.h"
#include "WolapiOb.h"
#include "wol_gsup.h"
#include "WolStrng.h"

int WOL_Login_Dialog( WolapiObject* pWolapi );
int WOL_Chat_Dialog( WolapiObject* pWolapi );
const char* Game_Registry_Key();

bool ReregisterWolapiDLL();
void HandleDLLFail();

WolapiObject* pWolapi = NULL;

#include "WolDebug.h"

//***********************************************************************************************
//	The first time through, pWolapi is NULL thus wolapi gets set up. WOL_Login_Dialog presents the user
//	with the login dialog and attempts to log us on to the server. If the user continues on all the
//	way to a game start, we will drop out of here with pWolapi still pointing to a valid WolapiObject,
//	and with pWolapi's iLobbyReturnAfterGame set to the number of the lobby to return to automatically 
//	after the game ends.
//	Init() automatically brings us here if pWolapi is non-null.
//***********************************************************************************************
int WOL_Main()
{
	//	Return values:
	//		0 = cancel
	//		1 = start game
	//		-1 = patch downloaded, shut down app
	int iReturn = 0;

	if( pWolapi )
	{
		//	We have returned from a game started through ww online.
		
		//	Start theme up again.
		Theme.Play_Song( THEME_INTRO );

		//	Verify that we are still connected. If we aren't, kill WolapiObject and start over.
		//	(This will likely occur during the game, if connection is lost. Ensure that it is done here.)
		pWolapi->pChat->PumpMessages();			//	Causes OnNetStatus() call if no longer connected.
		if( pWolapi->bConnectionDown )
		{
//debugprint( "Re-entering WOL_Main(), pWolapi->bConnectionDown is true. Deleting old WolapiObject...\n" );
			WWMessageBox().Process( TXT_WOL_WOLAPIREINIT );
			//	Kill wolapi.
			pWolapi->UnsetupCOMStuff();
			delete pWolapi;
			pWolapi = NULL;
		}
	}

	if( !pWolapi )
	{
		//	Start up wolapi.
		pWolapi = new WolapiObject;
		if( !pWolapi->bSetupCOMStuff() )
		{
			//	Things are really bad if this happens. A COM call failed.
			
			//	We first assume that their wolapi.dll failed to register during wolsetup.exe, part of the patch process.
			//	This happens if they have an outdated oleaut32.dll, such as the one that comes with original
			//	version of Windows 95.

//			debugprint( "bSetupCOMStuff failed. Attemping to reregister wolapi.dll...\n" );
			//	Attempt to re-register wolapi.dll...
			if( ReregisterWolapiDLL() )
			{
				if( !pWolapi->bSetupCOMStuff() )
				{
					//	Still failed after reregistering seemed to work.
					HandleDLLFail();
					return 0;
				}
			}
			else
			{
				HandleDLLFail();
				return 0;
			}
		}
		pWolapi->PrepareButtonsAndIcons();
		//	Undocumented hack needed for patch downloading, per Neal.
		pWolapi->pChat->SetAttributeValue( "RegPath", Game_Registry_Key() );
		//	(Not that anything's really "documented".)
	}

	pWolapi->bInGame = false;

	int iLoginResult = WOL_Login_Dialog( pWolapi );
	if( iLoginResult == 1 )
	{
		pWolapi->SetOptionDefaults();
		bool bKeepGoing = true;
		while( bKeepGoing )
		{
			bool bCreator;
			switch( WOL_Chat_Dialog( pWolapi ) )
			{
			case -1:
				bKeepGoing = false;
				break;
			case 1:
				//	User created game channel.
				bCreator = true;
				break;
			case 2:
				//	User joined game channel.
				bCreator = false;
				break;
			}
			if( bKeepGoing )
			{
				WOL_GameSetupDialog GSupDlg( pWolapi, bCreator );
				switch( GSupDlg.Run() )
				{
				case RESULT_WOLGSUP_LOGOUT:
					//	User logged out.
					bKeepGoing = false;
					break;
				case RESULT_WOLGSUP_BACKTOCHAT:
				case RESULT_WOLGSUP_HOSTLEFT:
				case RESULT_WOLGSUP_RULESMISMATCH:
					//	Return to chat.
					break;
				case RESULT_WOLGSUP_STARTGAMEHOST:
					//	Proceed with game.
					bKeepGoing = false;
					iReturn = 1;
					pWolapi->bGameServer = true;
					break;
				case RESULT_WOLGSUP_STARTGAME:
					//	Proceed with game.
					bKeepGoing = false;
					iReturn = 1;
					pWolapi->bGameServer = false;
					break;
				case RESULT_WOLGSUP_FATALERROR:
//					debugprint( "RESULT_WOLGSUP_FATALERROR from game setup dialog.\n" );
//					Fatal( "RESULT_WOLGSUP_FATALERROR from game setup dialog.\n" );
					if( pWolapi->pChatSink->bConnected )
						pWolapi->Logout();
					bKeepGoing = false;
					break;
				}
			}
		}
	}

	if( iReturn != 1 )
	{
		//	Kill wolapi.
		pWolapi->UnsetupCOMStuff();
		delete pWolapi;
		pWolapi = NULL;
	}
	else
	{
		pWolapi->bInGame = true;
		pWolapi->bConnectionDown = false;
	}

	if( iLoginResult == -1 )
	{
		WWMessageBox().Process( TXT_WOL_DOWNLOADEXITWARNING );
		iReturn = -1;
	}

	return iReturn;
}

//***********************************************************************************************
bool ReregisterWolapiDLL()
{
	//	Attempt to reregister wolapi.dll.
	//	Returns true if we think we succeeded.
	HKEY hKey;
	char szInstallPath[ _MAX_PATH ];
	if( ::RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\Westwood\\WOLAPI", 0, KEY_READ, &hKey ) == ERROR_SUCCESS )
	{
		DWORD dwBufSize = _MAX_PATH;
		if( ::RegQueryValueEx( hKey, "InstallPath", 0, NULL, (LPBYTE)szInstallPath, &dwBufSize ) == ERROR_SUCCESS )
		{
			WIN32_FIND_DATA wfd;
			HANDLE handle = FindFirstFile( szInstallPath, &wfd );
			if( handle == INVALID_HANDLE_VALUE )
			{
				//	File is not there.
				FindClose( handle );
				::RegCloseKey( hKey );
				return false;
			}
//			debugprint( "Found dll -> %s\n", szInstallPath );
			//	Get the DLL to register itself.
			HINSTANCE hLib = LoadLibrary( szInstallPath );
			if( !hLib )
			{
//				debugprint( "LoadLibrary failed, GetLastError is %i\n", GetLastError() );
				::RegCloseKey( hKey );
				return false;
			}
			FARPROC lpDllRegisterFunction = GetProcAddress( hLib, "DllRegisterServer" );
			if( !lpDllRegisterFunction )
			{
				::RegCloseKey( hKey );
				return false;
			}
			if( lpDllRegisterFunction() != S_OK )
			{
				::RegCloseKey( hKey );
				return false;
			}
			//	There is a bug in wolapi.dll that makes the following delay necessary.
			//	Something about Neal's extra threads only getting half-way set up before they get deleted.
			//	(The extra threads shouldn't really be created in this case, anyway...)
			::Sleep( 1000 );
			FreeLibrary( hLib );
			FindClose( handle );
		}
		else
		{
			::RegCloseKey( hKey );
			return false;
		}
		::RegCloseKey( hKey );
	}
	else
	{
		return false;
	}
	return true;
}

//***********************************************************************************************
void HandleDLLFail()
{
	//	The DLL failed to load. Either we failed to reregister it, or we think we succeeded at this but it
	//	still is not working. Show an error message and delete pWolapi.
	//	We show either "call tech support" or "download IE3", depending on whether oleaut32.dll looks out of date.

	char szPath[ _MAX_PATH + 1 ];
	::GetSystemDirectory( szPath, _MAX_PATH );
	if( *szPath && szPath[ strlen( szPath ) - 1 ] != '\\' )
		strcat( szPath, "\\" );

	strcat( szPath, "oleaut32.dll" );

	WIN32_FIND_DATA wfd;
	HANDLE handle = FindFirstFile( szPath, &wfd );

//	debugprint( "HandleDLLFail(): filesize of oleaut32 is %i\n", wfd.nFileSizeLow );
	if( handle != INVALID_HANDLE_VALUE && wfd.nFileSizeLow <= 232720 )
		WWMessageBox().Process( TXT_WOL_DLLERROR_GETIE3 );
	else
		WWMessageBox().Process( TXT_WOL_DLLERROR_CALLUS );

	FindClose( handle );

	delete pWolapi;
	pWolapi = NULL;
}

#endif