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


		#include "script_squirrel/engine_vm.h"
		#include "script_squirrel/cobject/cobject.h"
		#include "script_squirrel/cobject/cobject_decl.h"
		#include "script_squirrel/legacy/squirrel_binding.h"
		#include "script/scripted_object.h"
		#include "script/script_variant.h"
		#include "log/log.h"

		using namespace GS::Script;


//------------------------------------------------------------------------------
bool				EngineVM::Open()
{
	if	(!SquirrelVM::Open())
		return false;

	#define	__SQ_REGISTERINT(__NAME__, __V__) sq_pushstring(vm, __NAME__, -1); sq_pushinteger(vm, __V__); sq_newslot(vm, -3, true);

	sq_pushroottable(vm);

	__SQ_REGISTERINT("objectTypeUndefined", typetag_Undefined)
	__SQ_REGISTERINT("objectTypeDeleted", typetag_Deleted)

	__SQ_REGISTERINT("objectTypeEngine", typetag_Engine)
	__SQ_REGISTERINT("objectTypeResourceCache", typetag_ResourceSet)
	__SQ_REGISTERINT("objectTypeProject", typetag_Project)
	__SQ_REGISTERINT("objectTypeRenderer", typetag_Renderer)
	__SQ_REGISTERINT("objectTypeRaytracer", typetag_Raytracer)
	__SQ_REGISTERINT("objectTypeMixer", typetag_Mixer)
	__SQ_REGISTERINT("objectTypeScene", typetag_Scene3d)
	__SQ_REGISTERINT("objectTypeClock", typetag_Clock)

	__SQ_REGISTERINT("objectTypeFont", typetag_Font)
	__SQ_REGISTERINT("objectTypeRasterFont", typetag_RasterFont)
	__SQ_REGISTERINT("objectTypeUI", typetag_Scene2d)
	__SQ_REGISTERINT("objectTypeUICursor", typetag_UICursor)
	__SQ_REGISTERINT("objectTypeWindow", typetag_Window)
	__SQ_REGISTERINT("objectTypeWidget", typetag_Widget)
	__SQ_REGISTERINT("objectTypeSizerWidget", typetag_SizerWidget)
	__SQ_REGISTERINT("objectTypeContainerWidget", typetag_ContainerWidget)
	__SQ_REGISTERINT("objectTypeSpacerWidget", typetag_SpacerWidget)
	__SQ_REGISTERINT("objectTypeCanvasWidget", typetag_CanvasWidget)
	__SQ_REGISTERINT("objectTypeTextWidget", typetag_TextWidget)
	__SQ_REGISTERINT("objectTypeBitmapWidget", typetag_BitmapWidget)
	__SQ_REGISTERINT("objectTypeCheckWidget", typetag_CheckWidget)
	__SQ_REGISTERINT("objectTypePicture", typetag_Picture)

	__SQ_REGISTERINT("objectTypeGroup", typetag_Group)
	__SQ_REGISTERINT("objectTypeItem", typetag_Item)
	__SQ_REGISTERINT("objectTypeCamera", typetag_Camera)
	__SQ_REGISTERINT("objectTypeObject", typetag_Object)
	__SQ_REGISTERINT("objectTypeLight", typetag_Light)
	__SQ_REGISTERINT("objectTypeInstance", typetag_Instance)
	__SQ_REGISTERINT("objectTypeMotion", typetag_Motion)
	__SQ_REGISTERINT("objectTypeTrigger", typetag_Trigger)
	__SQ_REGISTERINT("objectTypePath", typetag_Path)

	__SQ_REGISTERINT("objectTypeSound", typetag_Sound)
	__SQ_REGISTERINT("objectTypeTexture", typetag_Texture)
	__SQ_REGISTERINT("objectTypeGeometry", typetag_Geometry)
	__SQ_REGISTERINT("objectTypeMaterial", typetag_Material)
	__SQ_REGISTERINT("objectTypeColShape", typetag_ColShape)
	__SQ_REGISTERINT("objectTypeConstraint", typetag_Constraint)

	__SQ_REGISTERINT("objectTypeMetafile", typetag_Metafile)
	__SQ_REGISTERINT("objectTypeMetatag", typetag_Metatag)

	__SQ_REGISTERINT("objectTypeHidDevice", typetag_InputDevice)

	__SQ_REGISTERINT("objectTypeEditorPlugin", typetag_EditorPlugin)

	__SQ_REGISTERINT("objectTypeProjectScene", typetag_ProjectScene)
	__SQ_REGISTERINT("objectTypeProjectLayer", typetag_ProjectLayer)

	__SQ_REGISTERINT("objectTypeAnimationSource", typetag_AutomationSource)
	__SQ_REGISTERINT("objectTypeAnimationSourceGroup", typetag_AutomationSourceGroup)

	sq_pop(vm, 1);

	_INIT_CLASS(vm, CObject);

	RegisterAllSquirrelBinding(vm);
	return true;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				EngineVM::PushVariant(const Variant &v)
{
	if	(v.type == Variant::Type_UserObject)
		return CObject::Push(vm, v.ptr, (CObjectType)v.typetag);
	return SquirrelVM::PushVariant(v);
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
int					EngineVM::InvalidateNativeReference(void *ptr)
{
	uint invalidated_count = 0;
	ListForeachPtr(CObject *, o, cobjects)
		if	(o->native == ptr)
		{
			cobjects.Remove(o);

			o->list_item = NULL;
			o->type = typetag_Deleted;
			o->native = NULL;

			++invalidated_count;
		}

//	__LOG_E__ << "Invalidate native object " << nString::Format("0x%x", ptr) << " - reference found: " << count << ", CObject left: " << safe_ptr_list.GetCount() << ".\n";
	return invalidated_count;
}
void				EngineVM::ReleaseAllNativeReferences()
{
	ListForeachPtr(CObject *, o, cobjects)
		o->Release();
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void				EngineVM::Close()
{
	/*
		[EJ] We have to drop all native object references now. If we don't,
		native objects holding a reference to a script object will crash the VM
		when they try to release it from their destructor (hence making a
		reentrant call into the VM).
	*/
	ReleaseAllNativeReferences();

	SquirrelVM::Close();
}
//------------------------------------------------------------------------------
