/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


		#include "network_debugger_thread.h"
		#include "network_debugger.h"
		#include "core/engine.h"
		#include "metafile/nml.h"
		#include "log/log.h"

		using namespace GS::Script;


//------------------------------------------------------------------------------
void		NetworkDebuggerThread::OnPacketReceived(void *peer, const void *data, size_t size)
{
	using namespace NML;

	Tag tag;
	Parser::ParseTag(tag, (char *)data, (char *)data + size);

	if	(ctl_peer == NULL)
	{
		if	(tag.name == "HelloMonitor")
		{
			Tag *client_version = tag.GetTag("Version;");

			if	(client_version->GetInteger() == 1)
			{
				ctl_peer = peer;
				SendString(peer, String::Format("<Welcome=<Platform=\"%s\"><Version=\"%s\">>", Platform::Get().GetName().c_str(), Core::Version));

				ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::OnControllerConnected);

				connected.Set(1);
			}
		}
		else
			Disconnect(peer);
	}
	else	if	(ctl_peer == peer)
		ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::OnControllerPacketReceived, Array <char> ((uint)size, (const char *)data));
	else
		Disconnect(peer);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void		NetworkDebuggerThread::OnPeerConnection(void *peer)
{
	if	(ctl_peer == NULL)
	{
		SetPeerTimeout(peer, TimeoutVeryLong);
		SendString(peer, "<Ident>");
	}
	else
		Disconnect(peer);
}
void		NetworkDebuggerThread::OnConnectionClosed(void *peer)
{
	if	(peer == ctl_peer)
	{
		ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::OnControllerDisconnected);
		ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::Kill);
		ctl_peer = NULL;
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void		NetworkDebuggerThread::SendToController(const GS::String &p)
{
	if	(ctl_peer)
		SendString(ctl_peer, p.c_str());
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool		NetworkDebuggerThread::OpenServer(const char *address, int port)
{
	if	(!Network::Enet::OpenServer(address, port))
		return false;

	String host_address;
	GetHostAddress(host_address);
	ctl.async.QueueMemberCall(&ctl, &NetworkDebugger::OnNetworkReady, host_address, port);

	return true;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
GS::String	NetworkDebuggerThread::GetControllerAddress()
{
	String address;
	if	(ctl_peer)
		GetPeerAddress(ctl_peer, address);
	return address;
}
void		NetworkDebuggerThread::DisconnectController()
{
	if	(ctl_peer)
	{
		SendString(ctl_peer, "<EndSession>");
		connected.Set(0);
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void		NetworkDebuggerThread::Execute()
{
	Thread::SetName("NetworkDebuggerThread");

	if	(!OpenServer(address, port))
		return;

	for (state.Set(StateWaitingController); state.Get() != StateStop; )
	{
		switch (state.Get())
		{
			case StateWaitingController: if (ctl_peer) state.Set(StateControllerConnected); break;
			case StateControllerConnected: if (ctl_peer == NULL) state.Set(StateStop); break;	// if controller lost, stop debugger
		}

		UpdateHost();

		while (async.Execute());

		Platform::Get().Sleep(1);
	}

	DisconnectController();
	Close();

	connected.Set(0);

	state.Set(StateStopped);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void		NetworkDebuggerThread::Stop()
{
	if (state.Get() != StateStopped)
	{
		state.Set(StateStop);
		while (state.Get() != StateStopped);	// spinlock
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
NetworkDebuggerThread::NetworkDebuggerThread(NetworkDebugger &h, const char *a, int p) : ctl(h)
{
	address = a;
	port = p;

	ctl_peer = NULL;
}
NetworkDebuggerThread::~NetworkDebuggerThread()
{
	Stop();
}
//------------------------------------------------------------------------------
