
extern "C" {
#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
}

#include "FL/Fl_Widget.H"
#include "FL/Fl_Menu_Item.H"
#include "FL/Fl.H"


extern lua_State *L;

static void generic_callback(Fl_Widget *widget, void *data)
{
  lua_getglobal(L, "fltk_dispatch");
  if (!lua_isfunction(L, -1))
    {
      fprintf(stderr, "missing fltk_dispatch function in callback; no Lua action taken");
    }

  lua_pushusertag(L, widget, (int)data);
  lua_call(L, 1, 0);
}

int register_callback(lua_State *L) {
  Fl_Widget *w = (Fl_Widget *)lua_touserdata(L, 1);
  
  long tag = lua_tag(L, 1);

  w->callback(generic_callback, (void *)tag);
  
  return 0;
}

int register_menu_item_callback(lua_State *L) {
  Fl_Menu_Item *w = (Fl_Menu_Item *)lua_touserdata(L, 1);
  
  long tag = lua_tag(L, 1);

  w->callback(generic_callback, (void *)tag);
  
  return 0;
}


static int ldo (int (*f)(lua_State *l, const char *), const char *name) {
  int res;
  // handler h = lreset();
  int top = lua_gettop(L);
  res = f(L, name);  /* dostring | dofile */
  lua_settop(L, top);  /* remove eventual results */
  // signal(SIGINT, h);  /* restore old action */
  /* Lua gives no message in such cases, so lua.c provides one */
  if (res == LUA_ERRMEM) {
    fprintf(stderr, "lua: memory allocation error\n");
  }
  else if (res == LUA_ERRERR)
    fprintf(stderr, "lua: error in error message\n");
  return res;
}

static void stdin_callback(int fd, void *data)
{
    char buf[2000];
    if (feof(stdin) || !fgets(buf, 2000, stdin)) {
	fprintf(stderr, "[eof]\n");
	Fl::remove_fd(0);
	return;
    }	
    // fprintf(stderr, "got input: %s", buf);
    ldo(lua_dostring, buf);
    fprintf(stderr, "> ");
}
    


int prepare_stdin(lua_State *L) 
{
  Fl::add_fd(0, stdin_callback);
  fprintf(stderr, "> ");
  return 0;
}

static const struct luaL_reg attach_funcs[] = {
  {"fl_cb", register_callback},
  // {"rmicb", register_menu_item_callback},
  {"prepare_stdin", prepare_stdin}
};

void lua_attachopen(lua_State *L) {
  luaL_openl(L, attach_funcs);
}
  
