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


		#include "script/script_debugger.h"
		#include "metafile/nml.h"

		using namespace GS;
		using namespace GS::Script;


//------------------------------------------------------------------------------
void				IDebugger::DereferenceVarTree(const List <DebuggerVariable *> &tree)
{
	ListForeachPtr(DebuggerVariable *, v, tree)
	{
		DereferenceVarTree(v->member_list);
		v->referenced = false;
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SourceBreakpoint	*IDebugger::FindSourceBreakpoint(const char *source, int line)
{
	ListForeachPtr(SourceBreakpoint *, bp, source_breakpoint_list)
		if	((bp->source == source) && (bp->line == line))
			return bp;
	return NULL;
}
SourceBreakpoint	*IDebugger::AddSourceBreakpoint(const char *source, int line)
{
	SourceBreakpoint *bp = FindSourceBreakpoint(source, line);
	if	(!bp)
		if	((bp = new SourceBreakpoint(source, line)) != NULL)
			source_breakpoint_list.Add(bp);
	return bp;
}
bool				IDebugger::RemoveSourceBreakpoint(SourceBreakpoint *breakpoint)
{	return source_breakpoint_list.Remove(breakpoint);	}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				IDebugger::SetBreakpoints(const NML::Tag &tag)
{
	if	(tag.name != "SetBreakpoints")
		return false;

	source_breakpoint_list.Clear();

	NMLTagForeach(bp, tag)
		if	(bp->name == "Breakpoint")
		{
			NML::Tag *ts = bp->GetTypedTag("Source;", GS::Variant::VariantString),
					 *tl = bp->GetTypedTag("Line", GS::Variant::VariantInteger);
			if	(ts && tl)
				AddSourceBreakpoint(ts->GetString(), tl->GetInteger());
		}

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

//------------------------------------------------------------------------------
String				IDebugger::GetStackFrameLocals()
{
	String data;

	data << "<SetStackFrameLocals=\n";
	ListForeachPtr(DebuggerVariable *, v, local_var_tree)
		VariableToMetatagString(v, data);
	data << ">";

	return data;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				IDebugger::SetDebugStackFrame(int level)
{
	if	(level == -1)
		level = GetStackFrameIndex();

	if	(level != debug_stack_frame)
	{
		debug_stack_frame = level;
		local_var_tree.Clear();
		RefreshStackFrameLocalsCache();
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				IDebugger::Suspend()
{
	is_suspended = true;
}
void				IDebugger::Resume()
{
	is_suspended = false;

	if	(!IsStepping())
		local_var_tree.Clear();
}
void				IDebugger::StepInto()
{
	is_stepping = true;
	step_to_callstack_depth = -1;
	Resume();
}
void				IDebugger::StepOut()
{
	is_stepping = true;
	step_to_callstack_depth = GetCallstackDepth() > 0 ? GetCallstackDepth() - 1 : 0;
	Resume();
}
void				IDebugger::Step()
{
	is_stepping = true;
	step_to_callstack_depth = GetCallstackDepth();
	Resume();
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				IDebugger::CheckSuspendOnBreakpoint(const char *source, int line)
{
	if	(SourceBreakpoint *bp = FindSourceBreakpoint(source, line))
		Suspend();
}
void				IDebugger::CheckSuspendOnStep()
{
	if	((GetCallstackDepth() <= step_to_callstack_depth) || (step_to_callstack_depth == -1))
	{
		Suspend();
		is_stepping = false;
	}
	if	(IsSuspended())
		RefreshStackFrameLocalsCache();
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				IDebugger::Reset()
{
	is_suspended = false;
	is_stepping = false;
	step_to_callstack_depth = -1;
}
//------------------------------------------------------------------------------

IDebugger::IDebugger()
{
	Reset();
}
IDebugger::~IDebugger()
{}
