/* $Id: xpilotsDlg.cpp,v 5.3 2002/06/14 02:16:28 dik Exp $
 *
 * XPilot, a multiplayer gravity war game.  Copyright (C) 1991-2001 by
 *
 *      Bjørn Stabell        <bjoern@xpilot.org>
 *      Ken Ronny Schouten   <ken@xpilot.org>
 *      Bert Gijsbers        <bert@xpilot.org>
 *      Dick Balaska         <dick@xpilot.org>
 *
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/***************************************************************************\
*  xpilotsDlg.cpp - The main dialog wrapper for xpilots						*
*																			*
*  $Id: xpilotsDlg.cpp,v 5.3 2002/06/14 02:16:28 dik Exp $				*
\***************************************************************************/

#include "stdafx.h"
#include "xpilots.h"
#include "xpilotsDlg.h"
#include "ConfigDlg.h"
//#include "ConfigDialog.h"
#include "winServer.h"
#include "ExitXpilots.h"
#include "ReallyShutdown.h"
#include "../../common/version.h"
#include "../../common/NT/winNet.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// extern "C" int	framesPerSecond;
extern "C" int	winTimer;
extern "C" HWND alarmWnd;

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	afx_msg void OnButtonWwwXpilotOrg();
	afx_msg void OnButtonWwwBuckosoftCom();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
	SendDlgItemMessage(IDC_VERSION, WM_SETTEXT, 0, (LPARAM)(TITLE));
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
	ON_BN_CLICKED(IDC_BUTTON_WWW_XPILOT_ORG, OnButtonWwwXpilotOrg)
	ON_BN_CLICKED(IDC_BUTTON_WWW_BUCKOSOFT_COM, OnButtonWwwBuckosoftCom)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


void CAboutDlg::OnButtonWwwXpilotOrg() 
{
	ShellExecute(NULL, "open", "http://www.xpilot.org/", NULL, NULL, SW_SHOWDEFAULT);
}

void CAboutDlg::OnButtonWwwBuckosoftCom() 
{
	CString	cs;
	cs.Format("http://www.buckosoft.com/xpilot/0.%s.html", VERSION_WINDOWS);
	//ShellExecute(NULL, "open", "http://www.buckosoft.com/xpilot/0.9.html", NULL, NULL, SW_SHOWDEFAULT);
	ShellExecute(NULL, "open", (LPCTSTR)cs, NULL, NULL, SW_SHOWDEFAULT);
}

/////////////////////////////////////////////////////////////////////////////
// CXpilotsDlg dialog

CXpilotsDlg::CXpilotsDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CXpilotsDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CXpilotsDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	m_hEventStartGame = CreateEvent(NULL, FALSE, FALSE, NULL); // auto reset, initially reset
	m_hEventGameTerminated = CreateEvent(NULL, TRUE, TRUE, NULL); // manual reset, initially set
	m_hEventKillServerThread = CreateEvent(NULL, FALSE, FALSE, NULL); // auto reset, initially reset
	m_hEventServerThreadKilled = CreateEvent(NULL, FALSE, FALSE, NULL); // auto reset, initially reset

	m_ServerThreadInfo.m_hEventStartGame = m_hEventStartGame;
	m_ServerThreadInfo.m_hEventGameTerminated = m_hEventGameTerminated;
	m_ServerThreadInfo.m_hEventKillServerThread = m_hEventKillServerThread;
	m_ServerThreadInfo.m_hEventServerThreadKilled = m_hEventServerThreadKilled;

	m_pServerWorkerThread = NULL;

	virgin = TRUE;
#ifdef	_BETAEXPIRE
	extern void CheckBetaExpire();
	CheckBetaExpire();
#endif

}

void CXpilotsDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CXpilotsDlg)
	DDX_Control(pDX, IDC_START_SERVER, m_start_server);
	DDX_Control(pDX, IDC_CONNECT_CLIENT, m_connectClient);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CXpilotsDlg, CDialog)
	//{{AFX_MSG_MAP(CXpilotsDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_CONFIGURE, OnConfigure)
	ON_BN_CLICKED(IDC_START_SERVER, OnStartServer)
	ON_BN_CLICKED(IDC_CONNECT_CLIENT, OnConnectClient)
	ON_WM_SIZE()
	ON_WM_CLOSE()
	ON_WM_HELPINFO()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_MSGAVAILABLE, OnMsgAvailable)
	ON_MESSAGE(WM_UPDATESCORES, OnUpdateScores)
	ON_MESSAGE(WM_STARTTIMER, OnStartTimer)
	ON_MESSAGE(WM_SERVERKILLED, OnServerKilled)
	ON_MESSAGE(WM_GETHOSTNAME, OnGetHostName)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CXpilotsDlg message handlers
char	s_WindowMet[] = "Window Metrics";
char	s_Commline[] = "Command Line";
char	s_L[] = "Left";
char	s_T[] = "Top";
char	s_R[] = "Right";
char	s_B[] = "Bottom";


BOOL CXpilotsDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	CString strAboutMenu;
	strAboutMenu.LoadString(IDS_ABOUTBOX);
	if (!strAboutMenu.IsEmpty())
	{
		pSysMenu->AppendMenu(MF_SEPARATOR);
		pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here

	//CWnd* pWnd = GetParent();
	CRect rect;
//	GetParentOwner()->GetParentOwner()->GetWindowRect(&rect);
	GetWindowRect(&rect);
	LONG	width = rect.right - rect.left;
	LONG	height = rect.bottom - rect.top;
	//rect.right = theApp.GetProfileInt(s_WindowMet, s_R, 0);
	//rect.bottom = theApp.GetProfileInt(s_WindowMet, s_B, 0);
	//	pWnd->MoveWindow(rect);
	
	GetDlgItem(IDC_EDIT1)->GetWindowRect(&editRect);
	editRect.left -= (rect.left + GetSystemMetrics(SM_CXFRAME));
	editRect.top -= (rect.top + GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION));
	editRect.right -= rect.left;
	editRect.bottom -= rect.top;
	editAdj.x = width - editRect.right;
	editAdj.y = height- editRect.bottom;
	rect.left = theApp.GetProfileInt(s_WindowMet, s_L, -1);
	rect.top = theApp.GetProfileInt(s_WindowMet, s_T, -1);
	m_commandline = theApp.GetProfileString(s_Commline, s_Commline, NULL);
	if (!(rect.left = rect.right == -1))	// only move window to valid coordinates
		MoveWindow(rect.left, rect.top, width, height);

	m_connectClient.EnableWindow(FALSE);		// can't connect until we start the server
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CXpilotsDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CXpilotsDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		if (virgin)
		{/*
			CRect rect;
			GetWindowRect(&rect);

			LONG	width = rect.right - rect.left;
			LONG	height = rect.bottom - rect.top;

			GetDlgItem(IDC_EDIT1)->GetWindowRect(&editRect);
			editAdj.x = rect.right - editRect.right;
			editAdj.y = rect.bottom - editRect.bottom;
		
	CRect rect;
	GetParentOwner()->GetParentOwner()->GetWindowRect(&rect);
	LONG	width = rect.right - rect.left;
	LONG	height = rect.bottom - rect.top;
	//rect.right = theApp.GetProfileInt(s_WindowMet, s_R, 0);
	//rect.bottom = theApp.GetProfileInt(s_WindowMet, s_B, 0);
	//	pWnd->MoveWindow(rect);
	
	GetDlgItem(IDC_EDIT1)->GetWindowRect(&editRect);
	editRect.left -= rect.left;
	editRect.top -= rect.top;
	editRect.right -= rect.left;
	editRect.bottom -= rect.top;
	editAdj.x = width - editRect.right;
	editAdj.y = height- editRect.bottom; */
			virgin = FALSE;
		}

		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CXpilotsDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CXpilotsDlg::OnConfigure() 
{
	// TODO: Add your control notification handler code here
//#if 0
#if 1
	CConfigDlg	cfg;
	cfg.m_commandline = m_commandline;
	int ret = cfg.DoModal();
	if (ret == IDOK)
	{
		m_commandline = cfg.m_commandline;
	}
#else
	CConfigDialog	cfg;
	cfg.m_commandline = m_commandline;
	int ret = cfg.DoModal();
	if (ret == IDOK)
	{
		m_commandline = cfg.m_commandline;
	}
#endif
//#endif
}


void CXpilotsDlg::OnStartServer() 
{
	// TODO: Add your control notification handler code here
	if (!server_running)
	{
//		int		ret;
		char	cs[1024];
		char	ct[1024];
		alarmWnd = GetSafeHwnd();
		if (m_pServerWorkerThread == NULL)
		{
			// Begin the worker thread.  It is ok to fill in the CThreadInfo
			// structure after the thread has started, because the thread
			// waits for the "start recalc" event before referring to the structure.
			m_pServerWorkerThread =
				AfxBeginThread(ServerThreadProc, &m_ServerThreadInfo);
		}

//		POSITION pos = GetFirstViewPosition();
//		ASSERT(pos != NULL);
//		CView* pView = GetNextView(pos);
//		ASSERT(pView != NULL);
//		m_ServerThreadInfo.m_hwndNotifyRecalcDone = m_hWnd;
//		m_ServerThreadInfo.m_hwndNotifyProgress = AfxGetMainWnd()->m_hWnd;
		m_ServerThreadInfo.m_hwndNotifyProgress = m_hWnd;

		// The events are initially set or reset in the CreateEvent call;
		// but they may be left in an improperly initialized state if
		// a worker thread has been previously started and then prematurely
		// killed.  Set/reset the events to the proper initial state.
		// Set the "start recalc" event last, since it is the event the
		// triggers the starting of the worker thread recalculation.
		SetEvent(m_hEventGameTerminated);
		ResetEvent(m_hEventKillServerThread);
		ResetEvent(m_hEventServerThreadKilled);
		// GameTerminated() will be called by the view when the thread sends a
		// WM_USER_GAME_TERMINATED message.
			m_start_server.SetWindowText("&Stop Server");
			server_running = TRUE;
			strcpy(cs, theApp.m_lpCmdLine);
			m_ServerThreadInfo.argv[0] = "xpilots";
			m_ServerThreadInfo.argc = 1;

			m_ServerThreadInfo.argv[1] = strtok(cs, " \t\n\r\0");
			if (m_ServerThreadInfo.argv[1])
			{
				m_ServerThreadInfo.argc++;
				while ((m_ServerThreadInfo.argv[m_ServerThreadInfo.argc] = strtok(NULL, "\t\n\r\0")) != (char*)NULL)
					m_ServerThreadInfo.argc++;
			}
			strcpy(ct, m_commandline);

			m_ServerThreadInfo.argv[m_ServerThreadInfo.argc] = strtok(ct, " \t\n\r\0");
			if (m_ServerThreadInfo.argv[m_ServerThreadInfo.argc])
			{
				m_ServerThreadInfo.argc++;
				while ((m_ServerThreadInfo.argv[m_ServerThreadInfo.argc] = strtok(NULL, " \t\n\r\0")) != (char*)NULL)
					m_ServerThreadInfo.argc++;
			}
		TRACE("Eat Me\n");
		SetEvent(m_hEventStartGame);
//		main(m_ServerThreadInfo.argc, m_ServerThreadInfo.argv);

	}
	else
	{
		CReallyShutdown	crs;
		if (crs.DoModal() != IDOK)
			return;
		::KillTimer(NULL, gTimer);
		SetEvent(m_hEventKillServerThread);
		SetEvent(m_hEventStartGame);

		WaitForSingleObject(m_hEventServerThreadKilled, INFINITE);

		m_pServerWorkerThread = NULL;
		m_start_server.SetWindowText("&Start Server");
		m_start_server.EnableWindow(FALSE);				/* can't restart yet... */
		m_connectClient.EnableWindow(FALSE);		// can't connect to this server anymore
		server_running = FALSE;

	}

}

void CXpilotsDlg::OnConnectClient() 
{
	STARTUPINFO			si;
	PROCESS_INFORMATION	pi;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));

	char	cline[] = "XPilot.exe 127.0.0.1";
	if (!CreateProcess(NULL, cline, NULL, NULL, false,
		NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
	{
		AfxMessageBox("Failed to create process for XPilot.exe");
	}
}

BOOL CXpilotsDlg::DestroyWindow() 
{
	// TODO: Add your specialized code here and/or call the base class
	//CWnd* pWnd = GetParent();
	CRect rect;
	GetWindowRect(rect);
	theApp.WriteProfileInt(s_WindowMet, s_L, rect.left);
	theApp.WriteProfileInt(s_WindowMet, s_T, rect.top);
	theApp.WriteProfileInt(s_WindowMet, s_R, rect.right);
	theApp.WriteProfileInt(s_WindowMet, s_B, rect.bottom);
	theApp.WriteProfileString(s_Commline, s_Commline, m_commandline);
	return CDialog::DestroyWindow();
}

BOOL CXpilotsDlg::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class
	
	if (pMsg->message == WM_SYSCOMMAND && pMsg->wParam == SC_CLOSE)
	{
		// from ~mtrecalc() sample.  Make sure worker thread is dead 
		DWORD dwExitCode;
		if (m_pServerWorkerThread != NULL &&
			GetExitCodeThread(m_pServerWorkerThread->m_hThread, &dwExitCode) &&
			dwExitCode == STILL_ACTIVE)
		{
			// Kill the worker thread by setting the "kill thread" event.
			// See comment in OnKillWorkerThread for explanation of the sequence
			// of the "kill thread" and "start recalc" events.
			ExitXpilots	ex;
			int ret = ex.DoModal();
			if (ret == IDCANCEL)
				return(1);
		//	SetEvent(m_hEventKillServerThread);
		//	SetEvent(m_hEventStartGame);
		//	WaitForSingleObject(m_hEventServerThreadKilled, 5*1000);
			return(0);
		}
	}
	return CDialog::PreTranslateMessage(pMsg);
}

extern "C" int MsgAvail0;
extern "C" int MsgAvail1;
extern "C" int NumPlayers;
extern "C" int NumRobots;
extern "C" int NumPseudoPlayers;
afx_msg LONG CXpilotsDlg::OnMsgAvailable(UINT which, LONG s)
{
	int		l;

	l = SendDlgItemMessage(IDC_EDIT1, WM_GETTEXTLENGTH, 0, 0);
	//AfxMessageBox((LPCSTR)s);
	SendDlgItemMessage(IDC_EDIT1, EM_SETSEL, (WPARAM)l, (LPARAM)l);
//	SendDlgItemMessage(IDC_EDIT1, EM_SETSEL, (WPARAM)-1, (LPARAM)1000000);
	SendDlgItemMessage(IDC_EDIT1, EM_REPLACESEL, FALSE, (LPARAM)s);
#if 0
	if (which)
		MsgAvail1 = FALSE;
	else
		MsgAvail0 = FALSE;
#endif
	l = SendDlgItemMessage(IDC_EDIT1, WM_GETTEXTLENGTH, 0, 0);
	SendDlgItemMessage(IDC_EDIT1, EM_SETSEL, (WPARAM)l, (LPARAM)l);
//	SendDlgItemMessage(IDC_EDIT1, EM_SETSEL, (WPARAM)-1, (LPARAM)1000000);
	SendDlgItemMessage(IDC_EDIT1, EM_SCROLLCARET, 0, 0);
//	sprintf(st, "%d", NumPlayers - NumRobots - NumPseudoPlayers);
//	SendDlgItemMessage(IDC_PLAYERCOUNT, WM_SETTEXT, 0, (LPARAM)st);
//	OnUpdateScores();
	return(0);
}

afx_msg LONG CXpilotsDlg::OnUpdateScores(UINT unused, LONG unused1)
{
	char	st[10];
	sprintf(st, "%d", NumPlayers - NumRobots - NumPseudoPlayers);
	//TRACE("OnUpdateScores <%s>\n", st);
	SendDlgItemMessage(IDC_PLAYERCOUNT, WM_SETTEXT, 0, (LPARAM)st);
	return(0);

}
afx_msg LRESULT CXpilotsDlg::OnGetHostName(WPARAM wParam, LPARAM lParam)
{
	m_pServerWorkerThread->PostThreadMessage(WM_GETHOSTNAME, wParam, lParam);
	return(0);
}

afx_msg LONG CXpilotsDlg::OnStartTimer(UINT unused, LONG fps)
{
	gTimer= ::SetTimer(NULL, 0, 1000/fps, (TIMERPROC)ServerThreadTimerProc);
	m_connectClient.EnableWindow(TRUE);
	return(0);
}

afx_msg LONG CXpilotsDlg::OnServerKilled(UINT, LONG)
{
	m_start_server.SetWindowText("&Start Server");
	m_start_server.EnableWindow(FALSE);				/* can't restart yet... */
	server_running = FALSE;
	return(0);
}

void CXpilotsDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
	CRect	wrect;
	CRect	erect;
	CWnd* cw = GetDlgItem(IDC_EDIT1);
	GetWindowRect(&wrect);
	if (cw) cw->GetWindowRect(&erect);
	CRect	rect;
	rect.left = editRect.left;
	rect.top  = editRect.top;
	rect.right = cx - editAdj.x;
	rect.bottom = cy - editAdj.y;

	if (!virgin)
	{
		if (cw)
			cw->MoveWindow(rect);
	}
}

void CXpilotsDlg::OnClose() 
{
	// TODO: Add your message handler code here and/or call default

	if (server_running)
	{
		int ret = AfxMessageBox("Server is running.  Exit Anyway?",	MB_YESNO);
		if (ret != IDYES)
			return;
	}
	CDialog::OnClose();
}

BOOL CXpilotsDlg::OnHelpInfo(HELPINFO* pHelpInfo) 
{
	// TODO: Add your message handler code here and/or call default
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	
	// return CDialog::OnHelpInfo(pHelpInfo);
		return(TRUE);
}
