#define PERL_NO_GET_CONTEXT
#include "module.h"

static GHashTable *perl_sbar_defs;

static int check_sbar_destroy(char *key, char *value, char *script)
{
	if (strncmp(value, script, strlen(script)) == 0 &&
	    value[strlen(script)] == ':') {
                statusbar_item_unregister(key);
		g_free(key);
                g_free(value);
		return TRUE;
	}

        return FALSE;
}

static void script_unregister_statusbars(PERL_SCRIPT_REC *script)
{
	g_hash_table_foreach_remove(perl_sbar_defs,
				    (GHRFunc) check_sbar_destroy,
				    script->package);
}

void perl_statusbar_init(void)
{
	perl_sbar_defs = g_hash_table_new((GHashFunc) g_str_hash,
					  (GCompareFunc) g_str_equal);
	signal_add("script destroyed", (SIGNAL_FUNC) script_unregister_statusbars);
}

static void statusbar_item_def_destroy(void *key, void *value)
{
	statusbar_item_unregister(key);
	g_free(key);
        g_free(value);
}

void perl_statusbar_deinit(void)
{
	signal_remove("script destroyed", (SIGNAL_FUNC) script_unregister_statusbars);

	g_hash_table_foreach(perl_sbar_defs,
			     (GHFunc) statusbar_item_def_destroy, NULL);
	g_hash_table_destroy(perl_sbar_defs);
}

static void perl_statusbar_event(char *function, SBAR_ITEM_REC *item,
				 int get_size_only)
{
	dSP;
	SV *item_sv, **sv;
        HV *hv;

	ENTER;
	SAVETMPS;

	PUSHMARK(SP);
        item_sv = plain_bless(item, "Irssi::TextUI::StatusbarItem");
	XPUSHs(sv_2mortal(item_sv));
	XPUSHs(sv_2mortal(newSViv(get_size_only)));
	PUTBACK;

	perl_call_pv(function, G_EVAL|G_DISCARD);
	SPAGAIN;

	if (SvTRUE(ERRSV)) {
                PERL_SCRIPT_REC *script;
                char *package, *error;

                package = perl_function_get_package(function);
                script = perl_script_find_package(package);
                g_free(package);

		if (script != NULL) {
                        /* make sure we don't get back here */
			script_unregister_statusbars(script);
		}

		error = g_strdup(SvPV_nolen(ERRSV));
		signal_emit("script error", 2, script, error);
		g_free(error);
	} else {
		/* min_size and max_size can be changed, move them to SBAR_ITEM_REC */
		hv = hvref(item_sv);
		if (hv != NULL) {
			sv = hv_fetch(hv, "min_size", 8, 0);
			if (sv != NULL) item->min_size = SvIV(*sv);
			sv = hv_fetch(hv, "max_size", 8, 0);
			if (sv != NULL) item->max_size = SvIV(*sv);
		}
	}

	FREETMPS;
	LEAVE;
}


static void sig_perl_statusbar(SBAR_ITEM_REC *item, int get_size_only)
{
	char *function;

	function = g_hash_table_lookup(perl_sbar_defs, item->config->name);
	if (function != NULL)
		perl_statusbar_event(function, item, get_size_only);
	else {
		/* use default function - this shouldn't actually happen.. */
		statusbar_item_default_handler(item, get_size_only, NULL, "", TRUE);
	}
}

MODULE = Irssi::TextUI::Statusbar  PACKAGE = Irssi
PROTOTYPES: ENABLE

void
statusbar_item_register(name, value, func = NULL)
	char *name
	char *value
	char *func
CODE:
	statusbar_item_register(name, value, func == NULL || *func == '\0' ? NULL : sig_perl_statusbar);
	if (func != NULL) {
		g_hash_table_insert(perl_sbar_defs, g_strdup(name),
				    g_strdup_printf("%s::%s", perl_get_package(), func));
	}

void
statusbar_item_unregister(name)
	char *name
PREINIT:
        gpointer key, value;
CODE:
	if (g_hash_table_lookup_extended(perl_sbar_defs, name, &key, &value)) {
                g_hash_table_remove(perl_sbar_defs, name);
		g_free(key);
                g_free(value);
	}
	statusbar_item_unregister(name);

void
statusbar_items_redraw(name)
	char *name

void
statusbars_recreate_items()

#*******************************
MODULE = Irssi::TextUI::Statusbar  PACKAGE = Irssi::TextUI::StatusbarItem  PREFIX = statusbar_item_
#*******************************

void
statusbar_item_default_handler(item, get_size_only, str, data, escape_vars = TRUE)
	Irssi::TextUI::StatusbarItem item
	int get_size_only
	char *str
	char *data
	int escape_vars
PREINIT:
	HV *hv;
CODE:
	statusbar_item_default_handler(item, get_size_only,
				       *str == '\0' ? NULL : str,
				       data, escape_vars);
	hv = hvref(ST(0));
	(void) hv_store(hv, "min_size", 8, newSViv(item->min_size), 0);
	(void) hv_store(hv, "max_size", 8, newSViv(item->max_size), 0);
