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


		#include "network_debugger.h"
		#include "network_debugger_thread.h"
		#include "metafile/nml.h"

		using namespace GS;
		using namespace GS::Script;


//------------------------------------------------------------------------------
void		NetworkDebugger::OnControllerPacketReceived(const Array <char> &data)
{
	using namespace NML;

	Tag tag;
	Parser::ParseTag(tag, data.Start(), data.End());

	//----------------------------------------------------------------------
			if	(tag.name == "Start")
		start_signal = true;
	else	if	(tag.name == "StepInto")
		debugger->StepInto();
	else	if	(tag.name == "StepOver")
		debugger->Step();
	else	if	(tag.name == "StepOut")
		debugger->StepOut();
	else	if	(tag.name == "Resume")
		debugger->Resume();
	//----------------------------------------------------------------------

	//----------------------------------------------------------------------
	else	if	(tag.name == "SetDebugStackFrame")
		debugger->SetDebugStackFrame(tag.GetInteger());
	else	if	(tag.name == "SetTopDebugStackFrame")
		debugger->SetDebugStackFrame(-1);

	else	if	(tag.name == "RequestDebugStackFrameSource")
	{
		const char *source; int line;
		debugger->GetStackFrameSource(source, line);

		if	(source)
			BroadcastNetworkCommand(String::Format("<SetDebugSource=<Source=\"%s\"><Line=%d>>", source, line));
	}
	else	if	(tag.name == "RequestDebugCallStack")
		BroadcastNetworkCommand(GetCallstack());
	else	if	(tag.name == "RequestDebugStackFrameLocals")
		BroadcastNetworkCommand(GetDebugStackFrameLocals());
	else	if	(tag.name == "SetBreakpoints")
		debugger->SetBreakpoints(tag);
	//----------------------------------------------------------------------
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
String		NetworkDebugger::GetPeerAddress()
{
	ASync::Future <String> address;
	thread->async.QueueMemberCall(address, thread, &NetworkDebuggerThread::GetControllerAddress);
	return address.Get();
}
bool		NetworkDebugger::IsConnected() const
{	return thread->IsConnected();	}
void		NetworkDebugger::Stop()
{	thread->Stop();	}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void		NetworkDebugger::BroadcastNetworkCommand(const String &cmd)
{
	// Queue an asynchronous call to the controller thread.
	thread->async.QueueMemberCall(thread, &NetworkDebuggerThread::SendToController, cmd);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void		NetworkDebugger::OnSuspendExecution(const char *source, int line)
{
	// Set callstack, stack frame locals and source.
	BroadcastNetworkCommand(GetCallstack());
	BroadcastNetworkCommand(debugger->GetStackFrameLocals());
	BroadcastNetworkCommand(String::Format("<SetDebugSource=<Source=\"%s\"><Line=%d>>", source, line));
}
bool		NetworkDebugger::OnUpdateSuspendedExecution()
{
	async.Execute();	// [EJ] execute calls pushed by the debug thread to us so that we may receive new packets
	return thread->IsConnected();
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void		NetworkDebugger::OnFatalError(const char *reason)
{
	BroadcastNetworkCommand(String::Format("<VMKill=<Description=\"%s\">>", reason));
}
void		NetworkDebugger::OnCompilerError(const char *error, const char *source, int line)
{
	// Make sure the error location is displayed prior to the VM kill event being received.
	BroadcastNetworkCommand(String::Format("<SetDebugSource=<Source=\"%s\"><Line=%d>>", source, line));
	BroadcastNetworkCommand(String::Format("<VMKill=<Description=\"%s\">>", error));
}
void		NetworkDebugger::OnRuntimeException(const char *error)
{
	BroadcastNetworkCommand(String::Format("<VMException=<Description=\"%s\">>", error));

	/*
		...then suspend all execution beside the server inspection communication
		channels. The VM along with the executing program will die when this
		function returns.
	*/
	while ((vm->GetState() == IVM::StateExceptionThrown) && thread->IsConnected())
	{
		async.Execute();
		Threading::Thread::Switch();
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
NetworkDebugger::NetworkDebugger(IVM *vm, IDebugger *debugger, const char *address, int port) : IDebuggerProfiler(vm, debugger)
{
	start_signal = false;

	thread = new NetworkDebuggerThread(*this, address, port);
	thread->Start();
}
NetworkDebugger::~NetworkDebugger()
{
	_safe_delete(thread);
}
//------------------------------------------------------------------------------
