
#include "StdAfx.h"
#include "MemVuff.h"
#include "Settle.h"

#define LOG(X1,X2) DUMMYx

inline void DUMMYx(...) { }

// ->->->
#pragma comment(lib, "dplayx")
#pragma comment(lib, "dxguid")

#define CMDc2s_RequestDungeon 0x00000001
#define CMDc2s_OverwriteDungeon 0x00000002

#define CMDs2c_SendDungeon 0x20000001

// {DA69BC87-84B5-4b29-9644-380F712AB7D0}
static const GUID _DPSPID_SETTLE = 
{ 0xda69bc87, 0x84b5, 0x4b29, { 0x96, 0x44, 0x38, 0xf, 0x71, 0x2a, 0xb7, 0xd0 } };

#define _DP_SESSION_NAME "DOSBOX 0.63x"

#define _DP_SERVER_PLAYER "DOSBOX"
#define _DP_CLIENT_PLAYER "A DMDC2"

// $-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$
// |	Fibres
// $-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$

bool Fibres::serverNow()
{
	HRESULT hr;

	char sessName[256];
	sprintf(sessName, "%s %p", _DP_SESSION_NAME, (void *)GetCurrentProcessId());

	DPSESSIONDESC2 dpsd;
	ZeroMemory(&dpsd, sizeof(dpsd));
	dpsd.dwSize = sizeof(dpsd);
	dpsd.dwFlags = 0 
		|DPSESSION_CLIENTSERVER 
		|DPSESSION_DIRECTPLAYPROTOCOL
		;
	dpsd.guidApplication = _DPSPID_SETTLE;
	dpsd.lpszSessionNameA = sessName;

	if (FAILED(hr = pDP->Open(&dpsd, DPOPEN_CREATE)))
		return false;

	DPNAME dpn;
	dpn.dwSize = sizeof(DPNAME);
	dpn.dwFlags = 0;
	dpn.lpszLongNameA = dpn.lpszShortNameA = _DP_SERVER_PLAYER;

	if (FAILED(hr = pDP->CreatePlayer(&dpidMe, &dpn, NULL, NULL, 0, DPPLAYER_SERVERPLAYER)))
		return false;

	return true;
}

bool Fibres::fn(LPCDPSESSIONDESC2 pdpsd, LPDWORD lpdwTimeOut, DWORD dwFlags)
{
	if (pdpsd != NULL) {
		guidInst = pdpsd->guidInstance;
	}
	if (dwFlags & DPESC_TIMEDOUT) {
		return false;
	}
	return true;
}

bool Fibres::connectNow()
{
	HRESULT hr;

	try {
		DPSESSIONDESC2 dpsd;
		ZeroMemory(&dpsd, sizeof(dpsd));
		dpsd.dwSize = sizeof(dpsd);
		dpsd.guidApplication = _DPSPID_SETTLE;

		guidInst = GUID_NULL;

		if (FAILED(hr = pDP->EnumSessions(&dpsd, 0, fn, this, 0 |DPENUMSESSIONS_AVAILABLE)))
			throw int();

		if (IsEqualGUID(guidInst, GUID_NULL))
			throw int();

		dpsd.guidInstance = guidInst;

		if (FAILED(hr = pDP->Open(&dpsd, DPOPEN_JOIN)))
			throw int();

		DPNAME dpn;
		dpn.dwSize = sizeof(DPNAME);
		dpn.dwFlags = 0;
		dpn.lpszLongNameA = dpn.lpszShortNameA = _DP_CLIENT_PLAYER;

		if (FAILED(hr = pDP->CreatePlayer(&dpidMe, &dpn, NULL, NULL, 0, 0)))
			throw int();

		return true;
	}
	catch (int) {
		close();
		return false;
	}
}

bool Fibres::construct(bool server)
{
	HRESULT hr;

	if (FAILED(hr = CoInitialize(NULL)))
		return false;
	if (FAILED(hr = CoCreateInstance(CLSID_DirectPlay, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay4A, (void **)&pDP)))
		return false;
	if (FAILED(hr = CoCreateInstance(CLSID_DirectPlayLobby, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlayLobby3A, (void **)&pDPL)))
		return false;

	BYTE addr[1000];
	if (!createInetAddr("127.0.0.1", addr, 1000))
		return false;

	if (FAILED(hr = pDP->InitializeConnection(addr, 0)))
		return false;

	if (server) {
		if (!serverNow())
			return false;
	}
	else {
		if (!connectNow())
			return false;
	}

	return true;
}

static BYTE settlebuff[60000];

bool Fibres::receiver()
{
	HRESULT hr;

	while (true) {
		DPID dpidFrom, dpidTo;
		DWORD buffSize = sizeof(settlebuff);
		hr = pDP->Receive(
			&dpidFrom,
			&dpidTo,
			0 |DPRECEIVE_ALL,
			settlebuff,
			&buffSize
			);
		if (hr == DPERR_NOMESSAGES)
			return true;
		if (FAILED(hr)) {
			break;
		}
		if (dpidFrom == DPID_SYSMSG) {
			DPMSG_GENERIC *gm = (DPMSG_GENERIC *)settlebuff;
			printf("");
		}
		else if (dpidMe == DPID_SERVERPLAYER) {
			CMemVuff mv;
			mv.pData = settlebuff;
			mv.iData = 0;
			mv.nData = buffSize;
			mv.fLE = true;

			DWORD order = mv.ReadDWord();
			switch (order) {
			case (CMDc2s_RequestDungeon):
#ifdef __DOSBOX_H
				///
				mv.iData = 0;
				mv.nData = sizeof(settlebuff);

				mv.WriteDWord(CMDs2c_SendDungeon);
				mv.WriteDWord(0);
				if (fibre2.collect(mv)) {

				}
				else {
					mv.iData = 0;
					mv.WriteDWord(CMDs2c_SendDungeon);
					mv.WriteDWord(-1);
				}
				hr = pDP->Send(dpidMe, dpidFrom, DPSEND_GUARANTEED, mv.pData, mv.iData);
				printf("");
				///
#endif
				break;
			case (CMDc2s_OverwriteDungeon):
				{
#ifdef __DOSBOX_H
					///
					DWORD length = mv.ReadDWord();
					fibre2.forceLoadDungeon(mv);
					///
#endif
				}
				break;
			}
		}
		else {
			CMemVuff mv;
			mv.pData = settlebuff;
			mv.iData = 0;
			mv.nData = buffSize;
			mv.fLE = true;

			RES &res = *(reses.insert(reses.end(), RES()));

			DWORD order = mv.ReadDWord();
			switch (order) {
			case (CMDs2c_SendDungeon):
				{
					res.resi = resiTransit;

					DWORD r = mv.ReadDWord();
					if (r != 0)
						break;
					res.buff.assign((const char *)&mv.pData[mv.iData], mv.nData - mv.iData);
					res.ok = true;
					break;
				}
			}
		}
	}

	return false;
}

bool Fibres::exec()
{
	switch (state) {
	case stateNo:
		{
			LOG(LOG_MISC,LOG_NORMAL)("Settlement interface initializing");
			try {
				if (!construct())
					throw int();

				state = stateListen;
				LOG(LOG_MISC,LOG_NORMAL)("Settlement interface is Ready!");
				return true;
			}
			catch (int) {
				state = stategone;
				LOG(LOG_MISC,LOG_NORMAL)("Settlement interface failed");
			}
		}
	case stateListen:
		{
			receiver();
			return false;
		}
	case stategone:
		{
			return false;
		}
	}
	return false;
}

bool Fibres::simpleOrder(DWORD order)
{
	BYTE buff[10];
	CMemVuff mv;
	mv.pData = buff;
	mv.iData = 0;
	mv.nData = sizeof(buff);
	mv.fLE = true;

	mv.WriteDWord(order);

	HRESULT hr;
	if (FAILED(hr = pDP->Send(dpidMe, DPID_SERVERPLAYER, DPSEND_GUARANTEED, mv.pData, mv.iData)))
		return false;

	return true;
}

void Fibres::close()
{
	if (pDP != NULL) {
		pDP->Close();
	}

	pDP = NULL;
	pDPL = NULL;
}

bool Fibres::sendSettleSave(BYTE *buff, DWORD buffSize)
{
	CMemVuff mv;
	mv.pData = settlebuff;
	mv.iData = 0;
	mv.nData = sizeof(settlebuff);

	mv.WriteDWord(CMDc2s_OverwriteDungeon);
	mv.WriteDWord(buffSize);
	mv.WriteBytes(buff, buffSize);

	HRESULT hr;
	if (FAILED(hr = pDP->Send(dpidMe, DPID_SERVERPLAYER, DPSEND_GUARANTEED, mv.pData, mv.iData)))
		return false;

	return true;
}

// $-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$
// |	Settle intermediation
// $-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$-#-$

Fibres fibres;

static BYTE timing = 0;

void SETTLE_Loop()
{
	if ((timing & 255) == 0) {
		while (fibres.exec());
	}

	timing++;
}

