#import "JubGtkChatUI.h"
#import "JubGtkHelper.h"

struct call_send_block_params {
	jub_send_block_t block;
	JubGtkChatUI *chat;
};

static gboolean call_send_block(GtkEntry *entry, GdkEventKey *event,
    gpointer data)
{
	struct call_send_block_params *params = data;
	if (event->keyval != GDK_KEY_Return &&
	    event->keyval != GDK_KEY_KP_Enter) return TRUE;

	OFString *text =
	    [[OFString alloc] initWithUTF8String: gtk_entry_get_text(entry)];
	gtk_entry_set_text(entry, "");
	params->block(text);
	[params->chat addMessage: text
			  sender: @"You"];
	[text release];

	return TRUE;
}

static gboolean call_close_block(GtkWidget *object, gpointer data)
{
	jub_close_block_t block = data;
	block();

	return FALSE;
}

@implementation JubGtkChatUI
- initWithTitle: (OFString*)title
     closeBlock: (jub_close_block_t)closeBlock_
      sendBlock: (jub_send_block_t)sendBlock_
{
	self = [super init];

	@try {
		__block volatile BOOL initialized = NO;
		__block GtkWidget *chat_window_;
		__block GtkTextBuffer *chat_buffer_;

		closeBlock = [closeBlock_ copy];
		sendBlock = [sendBlock_ copy];
		bufferEmpty = YES;

		g_idle_add_block(^{
			GtkTextView *chat_view;
			GtkEntry *chat_entry;

			GtkBuilder *builder = gtk_builder_new();
			gtk_builder_add_from_file(builder, "data/gtk/chat.ui",
			    NULL);

			chat_window_ = GTK_WIDGET(
			    gtk_builder_get_object(builder, "ChatWindow"));
			g_signal_connect(chat_window_, "destroy",
			    G_CALLBACK(call_close_block), closeBlock);

			chat_view = GTK_TEXT_VIEW(
			    gtk_builder_get_object(builder, "ChatTextView"));
			chat_buffer_ = gtk_text_view_get_buffer(chat_view);
			gtk_text_buffer_create_tag(chat_buffer_, "bold",
			    "weight", PANGO_WEIGHT_BOLD, NULL);

			chat_entry = GTK_ENTRY(
			    gtk_builder_get_object(builder, "ChatEntry"));
			struct call_send_block_params *send_params =
			    [self allocMemoryWithSize: sizeof(*send_params)];
			send_params->block = sendBlock;
			send_params->chat = self;
			g_signal_connect(chat_entry, "key_release_event",
			    G_CALLBACK(call_send_block), send_params);

			gtk_window_set_title(GTK_WINDOW(chat_window_),
			    [title UTF8String]);
			gtk_widget_show(chat_window_);

			initialized = YES;

			g_object_unref(builder);
		});

		while (!initialized);

		chat_buffer = chat_buffer_;
		chat_window = chat_window_;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	gtk_widget_destroy(chat_window);
	[sendBlock release];
	[closeBlock release];

	[super dealloc];
}

- (void)addMessage: (OFString*)text
	    sender: (OFString*)sender
{
	BOOL first = bufferEmpty;
	if (OF_UNLIKELY(bufferEmpty)) bufferEmpty = NO;

	g_object_ref(chat_buffer);
	g_idle_add_block(^{
		GtkTextIter endIter;
		if (OF_LIKELY(!first))
			gtk_text_buffer_insert_at_cursor(chat_buffer, "\n", 1);

		gtk_text_buffer_get_end_iter(chat_buffer, &endIter);
		gtk_text_buffer_insert_with_tags_by_name(chat_buffer, &endIter,
		    [sender UTF8String], [sender UTF8StringLength], "bold",
		    NULL);
		gtk_text_buffer_get_end_iter(chat_buffer, &endIter);
		gtk_text_buffer_insert_with_tags_by_name(chat_buffer, &endIter,
		    ": ", 2, "bold", NULL);

		gtk_text_buffer_insert_at_cursor(chat_buffer, [text UTF8String],
		    [text UTF8StringLength]);
		g_object_unref(chat_buffer);
	});
}
@end
