/* -----------------------------------------------------------------------------
 * See the LICENSE file for information on copyright, usage and redistribution
 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
 *
 * lua_fnptr.i
 *
 * SWIG Library file containing the main typemap code to support Lua modules.
 * ----------------------------------------------------------------------------- */

/* -----------------------------------------------------------------------------
 *                          Basic function pointer support
 * ----------------------------------------------------------------------------- */
/*
The structure: SWIGLUA_FN provides a simple (local only) wrappering for a function.

For example if you wanted to have a C/C++ function take a lua function as a parameter.
You could declare it as:
  int my_func(int a, int b, SWIGLUA_FN fn);
note: it should be passed by value, not byref or as a pointer.

The SWIGLUA_FN holds a pointer to the lua_State, and the stack index where the function is held.
The macro SWIGLUA_FN_GET() will put a copy of the lua function at the top of the stack.
After that its fairly simple to write the rest of the code (assuming know how to use lua),
just push the parameters, call the function and return the result.

  int my_func(int a, int b, SWIGLUA_FN fn)
  {
    SWIGLUA_FN_GET(fn);
    lua_pushnumber(fn.L,a);
    lua_pushnumber(fn.L,b);
    lua_call(fn.L,2,1);    // 2 in, 1 out
    return luaL_checknumber(fn.L,-1);
  }

SWIG will automatically performs the wrappering of the arguments in and out.

However: if you wish to store the function between calls, look to the SWIGLUA_REF below.

*/
// this is for the C code only, we don't want SWIG to wrapper it for us.
%{
typedef struct{
  lua_State* L; /* the state */
  int idx;      /* the index on the stack */
}SWIGLUA_FN;

#define SWIGLUA_FN_GET(fn) {lua_pushvalue(fn.L,fn.idx);}
%}

// the actual typemap
%typemap(in,checkfn="lua_isfunction") SWIGLUA_FN
%{  $1.L=L; $1.idx=$input; %}

/* -----------------------------------------------------------------------------
 *                          Storing lua object support
 * ----------------------------------------------------------------------------- */
/*
The structure: SWIGLUA_REF provides a mechanism to store object (usually functions)
between calls to the interpreter.

For example if you wanted to have a C/C++ function take a lua function as a parameter.
Then call it later, You could declare it as:
  SWIGLUA_REF myref;
  void set_func(SWIGLUA_REF ref);
  SWIGLUA_REF get_func();
  void call_func(int val);
note: it should be passed by value, not byref or as a pointer.

The SWIGLUA_REF holds a pointer to the lua_State, and an integer reference to the object.
Because it holds a permenet ref to an object, the SWIGLUA_REF must be handled with a bit more care.
It should be initalised to {0,0}. The function swiglua_ref_set() should be used to set it.
swiglua_ref_clear() should be used to clear it when not in use, and swiglua_ref_get() to get the
data back.

Note: the typemap does not check that the object is in fact a function,
if you need that you must add it yourself.


  int my_func(int a, int b, SWIGLUA_FN fn)
  {
    SWIGLUA_FN_GET(fn);
    lua_pushnumber(fn.L,a);
    lua_pushnumber(fn.L,b);
    lua_call(fn.L,2,1);    // 2 in, 1 out
    return luaL_checknumber(fn.L,-1);
  }

SWIG will automatically performs the wrappering of the arguments in and out.

However: if you wish to store the function between calls, look to the SWIGLUA_REF below.

*/

%{
typedef struct{
  lua_State* L; /* the state */
  int ref;      /* a ref in the lua global index */
}SWIGLUA_REF;


void swiglua_ref_clear(SWIGLUA_REF* pref){
 	if (pref->L!=0 && pref->ref!=LUA_NOREF && pref->ref!=LUA_REFNIL){
		luaL_unref(pref->L,LUA_REGISTRYINDEX,pref->ref);
	}
	pref->L=0; pref->ref=0;
}

void swiglua_ref_set(SWIGLUA_REF* pref,lua_State* L,int idx){
//	swiglua_ref_clear(pref); /* just in case */
	pref->L=L;
	lua_pushvalue(L,idx);                 /* copy obj to top */
	pref->ref=luaL_ref(L,LUA_REGISTRYINDEX); /* remove obj from top & put into registry */
}

void swiglua_ref_get(SWIGLUA_REF* pref){
	if (pref->L!=0)
		lua_rawgeti(pref->L,LUA_REGISTRYINDEX,pref->ref);
}

%}

%typemap(in) SWIGLUA_REF
%{  swiglua_ref_set(&$1,L,$input); %}

%typemap(out) SWIGLUA_REF
%{  if ($1.L!=0)  {swiglua_ref_get(&$1);} else {lua_pushnil(L);}
  SWIG_arg++; %}

