// Emacs style mode select   -*- C++ -*- 
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
//	Main program, simply calls D_DoomMain high level loop.
//
//-----------------------------------------------------------------------------

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <eh.h>

#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include <new.h>

#include "errors.h"

#include "doomtype.h"
#include "m_argv.h"
#include "d_main.h"
#include "i_system.h"
#include "c_console.h"
#include "z_zone.h"
#include "version.h"
#include "sv_main.h"

#include "stats.h"
#include "resource.h" // added

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

// Will this work with something besides VC++?
//extern int __argc;
//extern char **__argv;

DArgs Args;

const char WinClassName[] = "ZDOOM WndClass";

HINSTANCE		g_hInst;
WNDCLASS		WndClass;
HWND			Window;
HINSTANCE		hInstance;

extern float mb_used;
extern UINT TimerPeriod;

#define MAX_TERMS	256
void (STACK_ARGS *TermFuncs[MAX_TERMS])(void);
static int NumTerms;

void atterm (void (STACK_ARGS *func)(void))
{
	if (NumTerms == MAX_TERMS)
		I_FatalError ("Too many exit functions registered.\nIncrease MAX_TERMS in i_main.cpp");
	TermFuncs[NumTerms++] = func;
}

void popterm ()
{
	if (NumTerms)
		NumTerms--;
}

static void STACK_ARGS call_terms (void)
{
	while (NumTerms > 0)
	{
		TermFuncs[--NumTerms]();
	}
}

static int STACK_ARGS NewFailure (size_t size)
{
	I_FatalError ("Failed to allocate %d bytes from system heap\n(Try using a smaller -heapsize)");
	return 0;
}

int STACK_ARGS main (int argc, char **argv)
{
	LONG WinWidth, WinHeight;
	TIMECAPS tc;

	_set_new_handler (NewFailure);
	Printf(PRINT_HIGH, "========== STARTING csDoom [1.3] Thread ==========");

	try
	{
		g_hInst = hInstance;
		//Args.SetArgs (argc, argv);//changed

		// Set the timer to be as accurate as possible
		if (timeGetDevCaps (&tc, sizeof(tc) != TIMERR_NOERROR))
			TimerPeriod = 1;	// Assume minimum resolution of 1 ms
		else
			TimerPeriod = tc.wPeriodMin;

		timeBeginPeriod (TimerPeriod);

		/*
		 killough 1/98:

		 This fixes some problems with exit handling
		 during abnormal situations.

		 The old code called I_Quit() to end program,
		 while now I_Quit() is installed as an exit
		 handler and exit() is called to exit, either
		 normally or abnormally.
		*/

		atexit (call_terms);

		Z_Init ();					// 1/18/98 killough: start up memory stuff first
		atterm (I_Quit);

		// Figure out what directory the program resides in.
		GetModuleFileName (NULL, progdir, 1024);
		*(strrchr (progdir, '\\') + 1) = 0;
		FixPathSeperator (progdir);

		WinWidth = 320;
		WinHeight = 240;

		C_InitConsole (((WinWidth / 8) + 2) * 8, (WinHeight / 12) * 8, false);

		Printf (PRINT_HIGH, "Heapsize: %g megabytes\n", mb_used);

		D_DoomMain ();
	}
	catch (CDoomError &error)
	{
		SetWindowPos (Window, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW);
		if (error.GetMessage ())
			MessageBox (Window, error.GetMessage(),
				"ZDOOM Fatal Error", MB_OK|MB_ICONSTOP|MB_TASKMODAL);
		exit (-1);
	}
#ifndef _DEBUG
	catch (...)
	{
		// If an exception is thrown, be sure to do a proper shutdown.
		// This is especially important if we are in fullscreen mode,
		// because the OS will only show the alert box if we are in
		// windowed mode. Graphics gets shut down first in case something
		// goes wrong calling the cleanup functions.
		call_terms ();
		// Now let somebody who understands the exception deal with it.
		throw;
	}
#endif
	return 0;
}

////////////////////// WIN32 CODE /////////////////////////

#ifdef WIN32

BOOL CALLBACK	Dlg(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
DLGPROC			dlgprc = MakeProcInstance(Dlg, hInstance);
HANDLE TheMainThread;
DWORD TheMainThreadID;
HWND hWnd;

int WINAPI WinMain (HINSTANCE Instance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
#ifndef WIN32_NO_UI

	if(strlen(lpCmdLine))
		MessageBox(0, "To run this server with parameters, use the restart command on the console:\nrestart <parameters>\neg. restart -file dwango5 -port 1234", "Parameter Warning", MB_OK | MB_ICONINFORMATION);
	
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC)dlgprc);

#else

	main(__argc, __argv);

#endif

return(nShowCmd);
}

DWORD WINAPI MainThread(LPVOID Data)
{
main(0,0);
return((DWORD)Data);
}

void AddCommandString (char *cmd);

#define WM_REBOOT		(WM_USER + 1)
#define WM_SHUTDOWN		(WM_USER + 2)

///////////////////////////////////////////////////

#ifdef _WIN32
#ifdef _DEBUG

#include <crtdbg.h> // For SetDebugMemoryLeakDetection and debug output

void SetMemoryLeakTracking(bool bSet)
{

	int iFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Get current flag 

	if(bSet)
		iFlag |= _CRTDBG_LEAK_CHECK_DF; // Turn on leak-checking bit 
	else
		iFlag &= ~ _CRTDBG_LEAK_CHECK_DF; // Turn on leak-checking bit 

	_CrtSetDbgFlag(iFlag); // Set flag to the new value

	return;

#endif

}

#else

void SetMemoryLeakTracking(bool bSet){}

#endif

///////////////////////////////////////////////////

BOOL CALLBACK	Dlg(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	SetMemoryLeakTracking(true);

char szBuffer[2048], szTemp[2048];int i, x;
switch(msg)
	{
	case WM_INITDIALOG:
		hWnd = GetDlgItem(hwnd, IDC_LISTLOG);
		SetTimer(hwnd, 0, 500, 0);
		// Start thread
		TheMainThread = CreateThread(NULL, 0, MainThread, (LPVOID)1, 0, &TheMainThreadID);
		break;
	case WM_TIMER:
		x = SendMessage(GetDlgItem(hwnd, IDC_LISTPLAYERS), LB_GETCURSEL, false, false);
		SendMessage(GetDlgItem(hwnd, IDC_LISTPLAYERS), LB_RESETCONTENT, false, false);
		for(i = 0; i < maxclients; i++)
			{
			if(i > maxclients)
				{
				SendMessage(GetDlgItem(hwnd, IDC_LISTPLAYERS), LB_INSERTSTRING, -1, (LPARAM)(LPSTR)"[closed]");
				continue;
				}
			if(clients[i].cls < cs_spawned)
				{
				SendMessage(GetDlgItem(hwnd, IDC_LISTPLAYERS), LB_INSERTSTRING, -1, (LPARAM)(LPSTR)"[open]");
				continue;
				}
			sprintf(szBuffer, "%s (%d frags) [%s]",
				players[i].userinfo.netname,
				players[i].fragcount,
				NET_AdrToString(clients[i].address));
			SendMessage(GetDlgItem(hwnd, IDC_LISTPLAYERS), LB_INSERTSTRING, -1, (LPARAM)(LPSTR)szBuffer);
			}
		SendMessage(GetDlgItem(hwnd, IDC_LISTPLAYERS), LB_SETCURSEL, x, false);
		break;
	case WM_DESTROY:
		break;
	case WM_CLOSE:
		TerminateThread(TheMainThread, NULL);
		CloseHandle(TheMainThread);
		KillTimer(hwnd, 0);
		EndDialog(hwnd, 0);
		break;
	case WM_REBOOT:
		TerminateThread(TheMainThread, NULL);
		CloseHandle(TheMainThread);
		KillTimer(hwnd, 0);
		Sleep(20);
		// Killed, start again
		SetTimer(hwnd, 0, 500, 0);
		// Start thread
		TheMainThread = CreateThread(NULL, 0, MainThread, (LPVOID)1, 0, &TheMainThreadID);
		break;
	case WM_SHUTDOWN:
		TerminateThread(TheMainThread, NULL);
		CloseHandle(TheMainThread);
		KillTimer(hwnd, 0);
	case WM_COMMAND:
		switch(wParam)
			{
			case IDC_EXIT:
				SendMessage(hwnd, WM_CLOSE, 0, 0);
				break;
			case IDC_GO:
				SendMessage(GetDlgItem(hwnd, IDC_EDIT_COMMAND), WM_GETTEXT, sizeof(szBuffer), (LPARAM)(LPSTR)&szBuffer);
				SendMessage(GetDlgItem(hwnd, IDC_EDIT_COMMAND), WM_SETTEXT, 0, (LPARAM)(LPSTR)"");
				AddCommandString(szBuffer);
				break;
			case IDC_CLEAR:
				SendMessage(hWnd, LB_RESETCONTENT, 0, 0);
				Printf(PRINT_HIGH, "Onscreen log erased (file kept)...");
				break;
			case IDC_REBOOT:
				SendMessage(GetDlgItem(hwnd, IDC_EDIT_COMMAND), WM_GETTEXT, sizeof(szTemp), (LPARAM)(LPSTR)&szTemp);
				SendMessage(GetDlgItem(hwnd, IDC_EDIT_COMMAND), WM_SETTEXT, 0, (LPARAM)(LPSTR)"");
				sprintf(szBuffer, "restart %s", szTemp);
				AddCommandString(szBuffer);
				break;
			case IDC_KICK:
				x = SendMessage(GetDlgItem(hwnd, IDC_LISTPLAYERS), LB_GETCURSEL, false, false);
				if(x > maxclients)break;
				if(clients[x].cls == cs_free)break;
				sprintf(szBuffer, "kick %s", players[x].userinfo.netname);
				AddCommandString(szBuffer);
				break;
			default:
				break;
			}
		break;
	}
return(0);
}

#endif
