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


		#include "script_squirrel/cobject/cobject_decl.h"
		#include "script_squirrel/cobject/cobject.h"
		#include "script_squirrel/squirrel_vm.h"
		#include "log/log.h"

		using namespace GS::Script;


//------------------------------------------------------------------------------
bool				CObject::GetBase(HSQUIRRELVM vm, int idx, void **o, CObjectType *types)
{
	// get object type
	CObjectType type;
	if	(!GetType(vm, idx, type))
		return false;

	// cast to target type if compatible
	for (int n = 0; types[n] != typetag_Undefined; ++n)
		if	(type == types[n])
			return Get(vm, idx, (void **)o);

	return false;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
static SQInteger	CObject_release_hook(SQUserPointer p, SQInteger size)
{
	if	(CObject *pv = (CObject *)p)
		delete pv;
	return 0;
}
bool				push_CObject(HSQUIRRELVM vm, const CObject &quat)
{
	CObject *newquat = new CObject((EngineVM *)sq_getforeignptr(vm));
	*newquat = quat;
	if	(!CreateNativeClassInstance(vm, "CObject", newquat, CObject_release_hook))
	{
		delete newquat;
		return false;
	}
	return true;
}
::SquirrelObject	new_CObject(HSQUIRRELVM vm, const CObject &quat)
{
	::SquirrelObject ret(vm);
	if	(push_CObject(vm, quat))
	{
		ret.AttachToStackObject(-1);
		sq_pop(vm, 1);
	}
	return ret;
}
int					construct_CObject(HSQUIRRELVM vm, CObject *p)
{
	sq_setinstanceup(vm, 1, p);
	sq_setreleasehook(vm, 1, CObject_release_hook);
	return 1;
}
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
bool				CObject::Push(HSQUIRRELVM v, void *_ptr, CObjectType _type, bool managed)
{
	CObject *o = new CObject((EngineVM *)sq_getforeignptr(v), _type, _ptr, managed);

	if	(!CreateNativeClassInstance(v, "CObject", o, CObject_release_hook))
	{
		__LOG_E__ << "Could not allocate native reference.\n";
		_safe_delete(o);
		return false;
	}
	return true;
}
bool				CObject::GetType(HSQUIRRELVM v, int idx, CObjectType &type)
{
	StackHandler sa(v);

	CObject *self;
	if	(SQ_FAILED(sq_getinstanceup(v, idx, (SQUserPointer*)&self, (SQUserPointer)&__CObject_decl)))
		return false;

	__ASSERT__(self != NULL);

	type = self->type;
	return true;
}
bool				CObject::Get(HSQUIRRELVM v, int idx, void **p, CObjectType type)
{
	__ASSERT__(p != NULL);

	StackHandler sa(v);

	CObject *self;
	if	(SQ_FAILED(sq_getinstanceup(v, idx, (SQUserPointer*)&self, (SQUserPointer)&__CObject_decl)))
		return false;

	__ASSERT__(self != NULL);

	if	((type != typetag_Undefined) && (self->type != type))
	{
		sq_throwerror(v, String::Format("Native reference to '%s' expected, got '%s'", CObjectTypeToString(type), CObjectTypeToString(self->type)));
		return false;
	}

	p[0] = self->native;
	return true;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
_MEMBER_FUNCTION_IMPL(CObject, constructor)
	return construct_CObject(v, new CObject((EngineVM *)sq_getforeignptr(v)));
_END_IMPL

_MEMBER_FUNCTION_IMPL(CObject, _cmp)
	_GetSelf(CObject, CObject);
	_GetTypedParam(object, 2, CObject, CObject);
	return sa.Return(asbool(self->native == object->native));
_END_IMPL

_MEMBER_FUNCTION_IMPL(CObject, type)
	_GetSelf(CObject, CObject);
	return sa.Return((int)self->type);
_END_IMPL
_MEMBER_FUNCTION_IMPL(CObject, isValid)
	_GetSelf(CObject, CObject);
	return sa.Return(asbool(self->native));
_END_IMPL
_MEMBER_FUNCTION_IMPL(CObject, isNull)
	_GetSelf(CObject, CObject);
	return sa.Return(!asbool(self->native));
_END_IMPL
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
_BEGIN_CLASS(CObject)

_MEMBER_FUNCTION(CObject, constructor, -1, ".")
_MEMBER_FUNCTION(CObject, _cmp, 2, ".xx")

_MEMBER_FUNCTION(CObject, isValid, 1, _SC("."))
_MEMBER_FUNCTION(CObject, isNull, 1, _SC("."))
_MEMBER_FUNCTION(CObject, type, 1, _SC("."))

_END_CLASS(CObject)
//------------------------------------------------------------------------------
