/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

%{
#include <haka/lua/object.h>
#include <haka/config.h>

extern bool lua_object_push(lua_State *L, void *ptr, struct lua_object *obj, swig_type_info *type_info, int owner);
%}

%define _LUA_OBJECT(typeptr, casttype, name)

%typemap(in, checkfn="SWIG_isptrtype") typeptr* %{
	if (!lua_isnil(L, $input)) {
		swig_lua_userdata *usr = (swig_lua_userdata*)lua_touserdata(L, $input);
		/* check that the object is still valid */
		if (!usr) {
			lua_pushstring(L,"$symname: object has been destroyed");
			SWIG_fail;
		}

#ifdef HAKA_DEBUG
		if ($disown) {
			assert(!$disown || usr->own == 1);
		}
#endif
	}

	if (!SWIG_IsOK(SWIG_ConvertPtr(L, $input, (void**)&$1, $descriptor, $disown))){
		SWIG_fail_ptr("$symname", $argnum, $descriptor);
	}
%}

%typemap(in, checkfn="SWIG_isptrtype") typeptr* DISOWN %{
	if (!lua_isnil(L, $input)) {
		swig_lua_userdata *usr = (swig_lua_userdata*)lua_touserdata(L, $input);
		/* check that the object is still valid */
		if (!usr) {
			lua_pushstring(L,"$symname: object has been destroyed");
			SWIG_fail;
		}

#ifdef HAKA_DEBUG
		if ($disown) {
			assert(!$disown || usr->own == 1);
		}
#endif
	}

	if (!SWIG_IsOK(SWIG_ConvertPtr(L, $input, (void**)&$1, $descriptor, SWIG_POINTER_DISOWN))){
		SWIG_fail_ptr("$symname", $argnum, $descriptor);
	}
%}

%apply typeptr* DISOWN { typeptr* DISOWN_SUCCESS_ONLY };

%typemap(out) typeptr* {
	if (!lua_object_push(L, $1, &((casttype*)$1)->name, $descriptor, $owner)) {
		SWIG_execfail;
	}
	else {
		SWIG_arg++;
	}
}

%typemap(freearg) typeptr* DISOWN {
	if (SWIG_arg == -1 && $1) {
		if (lua_object_push(L, $1, &((casttype*)$1)->name, $descriptor, 1)) {
			lua_pop(L, 1);
		}
	}
}

%typemap(freearg) typeptr* DISOWN_SUCCESS_ONLY {
	if (SWIG_arg == -2 && $1) {
		if (lua_object_push(L, $1, &((casttype*)$1)->name, $descriptor, 1)) {
			lua_pop(L, 1);
		}
	}
}

%typemap(in,numinputs=0) typeptr** OUTPUT_DISOWN ($*ltype temp)
%{ temp = ($*ltype)0; $1 = &temp; %}

%typemap(argout) typeptr** OUTPUT_DISOWN {
	if ($1) {
		if (!lua_object_push(L, *$1, &(*(casttype**)$1)->name, $*descriptor, 0)) {
			SWIG_execfail;
		}
		else {
			SWIG_arg++;
		}
	}
	else {
		lua_pushnil(L);
		SWIG_arg++;
	}
}

%typemap(in,numinputs=0) typeptr** OUTPUT ($*ltype temp)
%{ temp = ($*ltype)0; $1 = &temp; %}

%typemap(argout) typeptr** OUTPUT {
	if ($1) {
		if (!lua_object_push(L, *$1, &(*(casttype**)$1)->name, $*descriptor, 1)) {
			SWIG_execfail;
		}
		else {
			SWIG_arg++;
		}
	}
	else {
		lua_pushnil(L);
		SWIG_arg++;
	}
}

%enddef


%define LUA_OBJECT_CAST(typeptr, casttype)
	_LUA_OBJECT(typeptr, casttype, lua_object)
%enddef

%define LUA_OBJECT(typeptr)
	_LUA_OBJECT(typeptr, typeptr, lua_object)
%enddef

%define LUA_OBJECT_EX(typeptr, name)
	_LUA_OBJECT(typeptr, typeptr, name)
%enddef
