#include <iostream>
#include "ruby.h"

#include "Font.h"
#include "GLProgram.h"
#include "GLShader.h"
#include "Widget.h"
#include "Window.h"

using namespace std;

RUBY_GLOBAL_SETUP

static const char * ruby_string(VALUE obj)
{
    VALUE s = rb_funcall(obj, rb_intern("to_s"), 0);
    return StringValueCStr(s);
}

static void print_exception(VALUE e)
{
    VALUE c = rb_funcall(e, rb_intern("class"), 0);
    VALUE m = rb_funcall(e, rb_intern("message"), 0);
    VALUE bt = rb_funcall(e, rb_intern("backtrace"), 0);
    if ((TYPE(bt) == T_ARRAY) && (RARRAY_LEN(bt) > 0))
    {
        fprintf(stderr,
                "%s: %s (%s)\n",
                ruby_string(rb_ary_entry(bt, 0)),
                ruby_string(m),
                ruby_string(c));
        for (int i = 1; i < RARRAY_LEN(bt); i++)
        {
            fprintf(stderr,
                    "        from %s\n",
                    ruby_string(rb_ary_entry(bt, i)));
        }
    }
    else
    {
        fprintf(stderr, "%s (%s)\n", ruby_string(m), ruby_string(c));
    }
}

static void handle_bootstrap_error()
{
    print_exception(rb_errinfo());
    rb_set_errinfo(Qnil);
}

static int bootstrap()
{
    int rv = 0;
    int err_state = 0;

    Font_Init();
    GLProgram_Init();
    GLShader_Init();
    Widget_Init();
    Window_Init();

    rb_eval_string_protect(
      "load File.expand_path('../../runtime/main.rb', $0)",
      &err_state);
    if (err_state != 0)
    {
        handle_bootstrap_error();
        rv = 1;
    }
    return rv;
}

extern "C" int main(int argc, char *argv[])
{
    int rv = 0;
    int ruby_argc = 1;
    char prog_name[] = "main";
    char * ruby_argv[] = {&prog_name[0]};
    char ** ruby_argv_p = &ruby_argv[0];
    ruby_sysinit(&ruby_argc, &ruby_argv_p);
    {
        RUBY_INIT_STACK;
        ruby_init();
        ruby_init_loadpath();
        ruby_script(argv[0]);
        ruby_set_argv(argc, argv);
        rv = bootstrap();
        ruby_finalize();
    }
    return rv;
}
