/*
 * gui.c
 * 
 * Copyright (C) 2006-2007  Josef Kufner <jk@myserver.cz>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <ctype.h>

#include "gui.h"
#include "gui_callbacks.h"
#include "gui_opt_callbacks.h"
#include "glade_interface.h"
#include "glade_support.h"
#include "backend.h"
#include "connection.h"
#include "session.h"
#include "options.h"
#include "playerlist.h"
#include "roles.h"
#include "backend.h"
#include "record.h"

#define DEBUG 		3
#include "debug.h"

extern BACKEND *backend_network;
extern BACKEND *backend_game;

GtkWidget *dialog_connect = NULL;
GtkWidget *dialog_about = NULL;
GtkWidget *dialog_game_select = NULL;
GtkWidget *dialog_network_profiles = NULL;
GtkWidget *dialog_option_browser = NULL;
GtkWidget *dialog_send_message = NULL;


/* from interfaces.c */
#define GLADE_HOOKUP_OBJECT(component,widget,name) \
  g_object_set_data_full (G_OBJECT (component), name, \
    gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)


struct s_gui_page gui_page[GUI_PAGE_MAX] = {
	/* GUI_PAGE_BOARD */ { 
		"detached_board", NULL, NULL, "board", NULL,
		"board_alignment", "board_vbox", NULL, "board_label_image",
		NULL, NULL, NULL, NULL, NULL
	},
	/* GUI_PAGE_CHAT */ {
		"detached_chat", NULL, NULL, "chat", NULL,
		"chat_vpaned", "chat_vbox", NULL, "chat_label_image",
		NULL, NULL, NULL, NULL, NULL
	},
	/* GUI_PAGE_STATUS */ {
		"detached_status", "show_status_tab", NULL, "status", NULL,
		"status_scrolledwindow", "status_vbox", NULL, NULL,
		NULL, NULL, NULL, NULL, NULL
	},
	/* GUI_PAGE_RECORD */ {
		"detached_record", "show_record_tab", NULL, "record", NULL,
		"record_scrolledwindow", "record_vbox", NULL, NULL,
		NULL, NULL, NULL, NULL, NULL
	},
	/* GUI_PAGE_GAMELOG */ {
		"detached_gamelog", "show_logs", NULL, "gamelog", NULL,
		"gamelog_scrolledwindow", "gamelog_vbox", NULL, NULL,
		NULL, NULL, NULL, NULL, NULL
	},
	/* GUI_PAGE_NETLOG */ {
		"detached_netlog", "show_logs", NULL, "netlog", NULL,
		"netlog_scrolledwindow", "netlog_vbox", NULL, NULL,
		NULL, NULL, NULL, NULL, NULL
	}
};

static char *gui_connect_icon[S_C_MAX] = {
	/* NONE			*/ "gtk-dialog-question",
	/* OFFLINE		*/ "gtk-disconnect",
	/* CONNECTING		*/ "gtk-execute",
	/* CONNECTED		*/ "gtk-connect",
	/* DISCONNECTING	*/ "gtk-delete",
	/* EXITING		*/ "gtk-quit",
	/* RECONNECT		*/ "gtk-refresh"
};

static char *gui_session_icon[S_S_MAX] = {
	/* NONE			*/  "gtk-dialog-question",
	/* IDLE			*/  "gtk-close",
	/* LOADING		*/  "gtk-execute",
	/* LOADED		*/  "gtk-index",
	/* LOAD_ABORT		*/  "gtk-delete",
	/* LOAD_ERROR		*/  "gtk-dialog-error",
	/* ROLE_SELECT		*/  "gtk-execute",
	/* READY		*/  "gtk-jump-to",
	/* START_CHECK		*/  "gtk-execute",
	/* GAME_PLAYING		*/  "gtk-media-play",
	/* GAME_OVER		*/  "gtk-quit",
	/* GAME_ERROR		*/  "gtk-dialog-error",
	/* KILL			*/  "gtk-stop",
	/* SYNCING		*/  "gtk-refresh"
};

static struct {
	char *widget_name;
	enum { 
		connection, session
	} st;
	enum {
		sens, vis
	} type;
	int sens[S_C_MAX > S_S_MAX ? S_C_MAX:S_S_MAX];
	GtkWidget *widget;
} gui_sensitivity[] = {
	/*							state:	  N  O  C   C   D  E  R  *
	 *								  O  F  G   D   I  X  E  */
	{ "network_connect",			connection,	sens,	{ 0, 1, 0,  0,  0, 0, 0 },	NULL },
	{ "network_disconnect",			connection,	sens,	{ 0, 0, 1,  1,  0, 0, 0 },	NULL },
	{ "network_reconnect",			connection,	sens,	{ 0, 1, 1,  1,  0, 0, 0 },	NULL },
	{ "chat_entry",				connection,	sens,	{ 0, 0, 1,  1,  0, 0, 0 },	NULL },
	{ "players_hbox",			connection,	sens,	{ 0, 0, 1,  1,  0, 0, 0 },	NULL },
	{ "game_synchronize",			connection,	sens,	{ 0, 0, 0,  1,  0, 0, 0 },	NULL },
	{ "connection_connect_button",		connection,	sens,	{ 0, 1, 0,  0,  0, 0, 0 },	NULL },
	{ "connection_backend_value_label",	connection,	vis,	{ 0, 0, 1,  1,  1, 1, 1 },	NULL },
	{ "connection_address_value_label",	connection,	vis,	{ 0, 0, 1,  1,  1, 1, 1 },	NULL },
	{ "connection_backend_label",		connection,	sens,	{ 0, 0, 1,  1,  1, 1, 1 },	NULL },
	{ "connection_address_label",		connection,	sens,	{ 0, 0, 1,  1,  1, 1, 1 },	NULL },

	/*							state:	  N  I   L  L   L  L   R  R  S   G  G  G   K  S  *
	 *								  O  D   G  D   A  E   S  D  C   P  O  E   L  Y  */
	{ "board_drawingarea",			session,	sens,	{ 0, 0,  0, 0,  0, 0,  0, 0, 0,  1, 0, 0,  0, 0 },	NULL },
	{ "game_name_button",			session,	sens,	{ 0, 1,  0, 0,  0, 0,  0, 0, 0,  0, 0, 0,  0, 0 },	NULL },
	{ "game_name_label",			session,	sens,	{ 0, 1,  0, 0,  0, 0,  0, 0, 0,  0, 0, 0,  0, 0 },	NULL },
	{ "game_role_combobox",			session,	sens,	{ 0, 0,  0, 1,  0, 0,  0, 1, 0,  0, 0, 0,  0, 0 },	NULL },
	{ "game_role_label",			session,	sens,	{ 0, 0,  0, 1,  0, 0,  0, 1, 0,  0, 0, 0,  0, 0 },	NULL },
	{ "game_start_button",			session,	sens,	{ 0, 0,  0, 1,  0, 0,  0, 0, 0,  0, 0, 0,  0, 0 },	NULL },
	{ "game_select",			session,	sens,	{ 0, 1,  0, 0,  0, 0,  0, 0, 0,  0, 0, 0,  0, 0 },	NULL },
	{ "game_start",				session,	sens,	{ 0, 0,  0, 1,  0, 0,  1, 0, 0,  0, 0, 0,  0, 0 },	NULL },
	{ "game_load_abort",			session,	sens,	{ 0, 0,  1, 1,  0, 1,  1, 1, 1,  0, 0, 0,  0, 0 },	NULL },
	{ "game_surrender",			session,	sens,	{ 0, 0,  0, 0,  0, 0,  0, 0, 0,  1, 0, 1,  0, 0 },	NULL },
	{ "game_pause",				session,	sens,	{ 0, 0,  0, 0,  0, 0,  0, 0, 0,  1, 0, 0,  0, 0 },	NULL },
	{ "game_terminate",			session,	sens,	{ 0, 0,  1, 1,  1, 0,  1, 1, 1,  1, 1, 0,  0, 0 },	NULL },
	{ "debug_draw",				session,	sens,	{ 0, 1,  0, 0,  0, 1,  0, 0, 0,  0, 0, 0,  0, 0 },	NULL },
	{ "debug_clean",			session,	sens,	{ 0, 1,  0, 0,  0, 1,  0, 0, 0,  0, 0, 0,  0, 0 },	NULL },
	{ NULL }
};

static struct {
	char *name;
	GtkWidget *widget;
} gui_expander[] = {
	/* 0x01 */ { "connection_expander",	NULL },
	/* 0x02 */ { "game_expander",		NULL },
	/* 0x04 */ { "players_expander",	NULL },
	{ NULL, NULL }
};

static const unsigned char gui_expand[S_S_MAX][S_C_MAX] = {
	/* 	   	\ conn.	       N     O     C     C     D     E  *
	 * session st.	 \  st.	       O     F     G     D     G     X  */
	/* NONE			*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
	/* IDLE			*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
	/* LOADING		*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
	/* LOADED		*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
	/* LOAD_ABORT		*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
	/* LOAD_ERROR		*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
	/* ROLE_SELECT		*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
	/* GAME_STARTING	*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
	/* GAME_CHECK		*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
	/* GAME_PLAYING		*/{ 0x06, 0x01, 0x01, 0x04, 0x01, 0x01 },
	/* GAME_ENDING		*/{ 0x06, 0x01, 0x01, 0x04, 0x01, 0x01 },
	/* GAME_ERROR		*/{ 0x06, 0x01, 0x01, 0x04, 0x01, 0x01 },
	/* KILL			*/{ 0x06, 0x01, 0x01, 0x04, 0x01, 0x01 },
	/* SYNCING		*/{ 0x06, 0x01, 0x01, 0x06, 0x01, 0x01 },
};

/*****************************************************************************
 * 	GUI Functions
 ****************************************************************************/

void gui_update_main_window(void) {
	char *tt;
	int i;
	GtkWidget *tooltips;

	STATUS *sens_st[] = { connection_status, session_status };

	/* Citlivost widgetu */
	for (i = 0; gui_sensitivity[i].widget_name; i++) {
		int val = gui_sensitivity[i].sens[status_get(sens_st[gui_sensitivity[i].st])];
		if (!gui_sensitivity[i].widget)
			gui_sensitivity[i].widget = lookup_widget(main_window, gui_sensitivity[i].widget_name);
		switch (gui_sensitivity[i].type) {
			case sens:
				gtk_widget_set_sensitive(gui_sensitivity[i].widget, val);
				break;

			case vis:
				if (val)
					gtk_widget_show(gui_sensitivity[i].widget);
				else
					gtk_widget_hide(gui_sensitivity[i].widget);
				break;
		}
	}


	tooltips = lookup_widget(main_window, "tooltips");

	/* connection state icon */
	gtk_image_set_from_stock(GTK_IMAGE(lookup_widget(main_window, "statusbar_connect")),
			gui_connect_icon[status_get(connection_status)],
			GTK_ICON_SIZE_MENU);
	tt = g_strdup_printf(_("Stav spojení: %s"), status_get_name(connection_status));
	gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), lookup_widget(main_window, "statusbar_connect_eventbox"), tt, NULL);
	g_free(tt);

	/* global game state icon */
	gtk_image_set_from_stock(GTK_IMAGE(lookup_widget(main_window, "statusbar_game_global")),
			gui_session_icon[session_global_st.status],
			GTK_ICON_SIZE_MENU);
	tt = g_strdup_printf(_("Globální stav hry: %s"), status_get_name_by_id(session_status, session_global_st.status));
	gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), lookup_widget(main_window, "statusbar_game_global_eventbox"), tt, NULL);
	g_free(tt);

	/* local game state icon */
	gtk_image_set_from_stock(GTK_IMAGE(lookup_widget(main_window, "statusbar_game_local")),
			gui_session_icon[status_get(session_status)],
			GTK_ICON_SIZE_MENU);
	tt = g_strdup_printf(_("Lokální stav hry: %s"), status_get_name(session_status));
	gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), lookup_widget(main_window, "statusbar_game_local_eventbox"), tt, NULL);
	g_free(tt);

	/* connection status */
	gtk_label_set_text(GTK_LABEL(lookup_widget(main_window, "connection_status_value_label")), status_get_name(connection_status));
	
	/* sync icon */
	gui_show_syncing(!session_is_synced());

	/* update pages */
	gui_update_main_window_tabbar();

	/* update status tab */
	gui_update_status_tab();
}


static int gui_update_status_tab_timeout(gpointer data)
{
	if (data) {
		*(int *)data = 1;
		gui_update_status_tab();
		*(int *)data = 0;
	}
	return FALSE;
}

void gui_update_status_tab(void)
{
	static int is_timeout = 0, have_timeout = 0, timed_update = 0;
	static GtkTextView *ta = NULL;
	static GtkTextBuffer*tb = NULL;
	static GtkTextTag *tt_hd = NULL;
	GtkTextIter iter;
	gchar *str = NULL;
	
	if (!ta) {
		ta = GTK_TEXT_VIEW(lookup_widget(main_window, "status_textview"));
		tb = gtk_text_view_get_buffer(ta);

		tt_hd = gtk_text_buffer_create_tag(tb, "hd", "weight", PANGO_WEIGHT_BOLD, NULL);
	}
	
	if (!GTK_WIDGET_VISIBLE(ta)) {
		is_timeout = 0;
		have_timeout = 0;
		timed_update = 0;
		return;
	}

	if (is_timeout) {
		have_timeout = 0;
		if (timed_update) {
			DBG_MSG(3, "timeout");
			timed_update = 0;
		} else {
			DBG_MSG(3, "timeout ignored");
			return;
		}
	} else {
		if (have_timeout) {
			timed_update = 1;
			DBG_MSG(3, "delayed");
			return;
		} else {
			have_timeout = 1;
			timed_update = 0;
			g_timeout_add(600, gui_update_status_tab_timeout, &is_timeout);
			DBG_MSG(3, "now");
		}
	}
	
	/* clear text and set iter to start */
	gtk_text_buffer_set_text(tb, "", -1);
	gtk_text_buffer_get_iter_at_offset(tb, &iter, 0);

	/* add text */
	gtk_text_buffer_insert(tb, &iter, "\n", -1);
	gtk_text_buffer_insert_with_tags(tb, &iter, _("Stav spojení"), -1, tt_hd, NULL);
	gtk_text_buffer_insert(tb, &iter, _("\n\tStav:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, status_get_name(connection_status), -1);
	gtk_text_buffer_insert(tb, &iter, _("\n\tModul:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, option_get_string("main", "net", "backend") ? :"", -1);
	gtk_text_buffer_insert(tb, &iter, _("\n\tAdresa:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, option_get_string("main", "net", "address") ? :"", -1);
	gtk_text_buffer_insert(tb, &iter, "\n\n", -1);

	gtk_text_buffer_insert_with_tags(tb, &iter, _("Globální stav hry"), -1, tt_hd, NULL);
	gtk_text_buffer_insert(tb, &iter, _("\n\tČas:  \t"), -1);
	str = g_strdup_printf("%ld", session_global_st.time);
	gtk_text_buffer_insert(tb, &iter, str, -1);
	g_free(str);
	gtk_text_buffer_insert(tb, &iter, _("\n\tStav:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, status_get_name_by_id(session_status, session_global_st.status), -1);
	gtk_text_buffer_insert(tb, &iter, _("\n\tModul:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, session_global_st.game ? :"", -1);
	gtk_text_buffer_insert(tb, &iter, _("\n\tMoje role:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, session_global_st.my_role ? :"", -1);
	gtk_text_buffer_insert(tb, &iter, "\n\n", -1);

	gtk_text_buffer_insert_with_tags(tb, &iter, _("Lokální stav hry"), -1, tt_hd, NULL);
	gtk_text_buffer_insert(tb, &iter, _("\n\tČas:  \t"), -1);
	str = g_strdup_printf("%ld", session_status->time);
	gtk_text_buffer_insert(tb, &iter, str, -1);
	g_free(str);
	gtk_text_buffer_insert(tb, &iter, _("\n\tStav:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, status_get_name(session_status), -1);
	gtk_text_buffer_insert(tb, &iter, _("\n\tModul:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, option_get_string("main", "game", "backend") ? :"", -1);
	gtk_text_buffer_insert(tb, &iter, _("\n\tRole:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, option_get_string("main", "game", "my_role") ? :"", -1);
	gtk_text_buffer_insert(tb, &iter, _("\n\tSync.:\t"), -1);
	gtk_text_buffer_insert(tb, &iter, "\n\n", -1);

	gtk_text_buffer_insert_with_tags(tb, &iter, _("Statistiky"), -1, tt_hd, NULL);
	{
		static long net_bytes_sent = 0, net_bytes_received = 0;
		static long game_bytes_sent = 0, game_bytes_received = 0;
	
		if (backend_network)
			backend_get_stats(backend_network, &net_bytes_sent, &net_bytes_received);
		
		gtk_text_buffer_insert(tb, &iter, _("\n\tSíťový modul:"), -1);
		gtk_text_buffer_insert(tb, &iter, _("\n\t\tOdesláno:\t"), -1);
		str = g_strdup_printf("%ld B", net_bytes_sent);
		gtk_text_buffer_insert(tb, &iter, str, -1);
		g_free(str);
		gtk_text_buffer_insert(tb, &iter, _("\n\t\tPřijato:\t\t"), -1);
		str = g_strdup_printf("%ld B", net_bytes_received);
		gtk_text_buffer_insert(tb, &iter, str, -1);
		g_free(str);

		if (backend_game)
			backend_get_stats(backend_game, &game_bytes_sent, &game_bytes_received);
		
		gtk_text_buffer_insert(tb, &iter, _("\n\tHerní modul:"), -1);
		gtk_text_buffer_insert(tb, &iter, _("\n\t\tOdesláno:\t"), -1);
		str = g_strdup_printf("%ld B", game_bytes_sent);
		gtk_text_buffer_insert(tb, &iter, str, -1);
		g_free(str);
		gtk_text_buffer_insert(tb, &iter, _("\n\t\tPřijato:\t\t"), -1);
		str = g_strdup_printf("%ld B", game_bytes_received);
		gtk_text_buffer_insert(tb, &iter, str, -1);
		g_free(str);
	}
	gtk_text_buffer_insert(tb, &iter, "\n", -1);
}


void gui_set_semaphore(int x)
{
	/* semafor */
	gtk_widget_set_sensitive(lookup_widget(main_window, "statusbar_turn_no"), x & 1);
	gtk_widget_set_sensitive(lookup_widget(main_window, "statusbar_turn_yes"), x & 2);
}


GtkWidget *gui_create_main_window(void)
{
	GtkWidget *wid;
	GtkSizeGroup *size_group;
	GtkWidget *mnu;
	//GtkWidget *mnu_item;
	int g, i;
	//, icon_width, icon_height;

	//GtkCellRenderer *renderer;
	//GtkTreeViewColumn *column;
	//GtkTreeView *treeview;

	gchar *size_group_labels[] = {
		"connection_status_label",
		"connection_backend_label",
		"connection_address_label",
		"game_name_label",
		"game_role_label",
		NULL
	};
	gchar *size_group_buttons[] = {
		"connection_connect_button",
		"game_start_button",
		"players_btn_vbox",
		NULL
	};
	gchar **size_group_widget_names[] = {
		size_group_buttons,
		size_group_labels,
		NULL
	};

	DBG_MSG(3, "");

	main_window = create_main_window();
	g_assert(main_window != NULL);

	gui_page[GUI_PAGE_BOARD].win_title   = _("Herní deska - Netboard");
	gui_page[GUI_PAGE_CHAT].win_title    = _("Chat & nastavení hry - Netboard");
	gui_page[GUI_PAGE_STATUS].win_title  = _("Stav - Netboard");
	gui_page[GUI_PAGE_RECORD].win_title  = _("Záznam - Netboard");
	gui_page[GUI_PAGE_GAMELOG].win_title = _("Game Log - Netboard");
	gui_page[GUI_PAGE_NETLOG].win_title  = _("Net Log - Netboard");

	gui_page[GUI_PAGE_BOARD].menuitem_label   = _("_Herní deska");
	gui_page[GUI_PAGE_CHAT].menuitem_label    = _("_Chat & nastavení hry");
	gui_page[GUI_PAGE_STATUS].menuitem_label  = _("_Stav");
	gui_page[GUI_PAGE_RECORD].menuitem_label  = _("_Záznam");
	gui_page[GUI_PAGE_GAMELOG].menuitem_label = _("_Game Log");
	gui_page[GUI_PAGE_NETLOG].menuitem_label  = _("_Net Log");

	mnu = gtk_menu_new ();
	gtk_menu_item_set_submenu (GTK_MENU_ITEM (lookup_widget(main_window, "mnu_detach_tab")), mnu);
	gtk_widget_show (mnu);

	for (i = 0; i < GUI_PAGE_MAX; i++) {
		gui_page[i].widget = lookup_widget(main_window, gui_page[i].widget_name);
		gui_page[i].hide = lookup_widget(main_window, gui_page[i].hide_name);
		if (!gui_page[i].parent_name)
			gui_page[i].parent = gui_page[i].hide;
		else
			gui_page[i].parent = lookup_widget(main_window, gui_page[i].parent_name);

		gui_page[i].menuitem = gtk_check_menu_item_new_with_mnemonic (gui_page[i].menuitem_label);
		gtk_container_add (GTK_CONTAINER (mnu), gui_page[i].menuitem);
		gtk_widget_show (gui_page[i].menuitem);
		g_signal_connect ((gpointer)(gui_page[i].menuitem), "activate",
				G_CALLBACK (on_pref_detach_page_activate), (gpointer) ((int)i));

		if (gui_page[i].notify_icon_name)
			gui_page[i].notify_icon = lookup_widget(main_window, gui_page[i].notify_icon_name);
	}

	
	for (g = 0; size_group_widget_names[g]; g++) {
		size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
		for (i = 0; size_group_widget_names[g][i]; i++) {
			wid = lookup_widget(main_window, size_group_widget_names[g][i]);
			gtk_size_group_add_widget (size_group, wid);
		}
		gtk_size_group_set_mode (size_group, GTK_SIZE_GROUP_HORIZONTAL);
	}
	
	
	/* playerlist */
	gui_playerlist_init();
	gui_update_playerlist();

	/* desk */
	gtk_widget_set_double_buffered(lookup_widget(main_window, "board_drawingarea"), TRUE);

	/* force switch page to chat */
	gtk_notebook_set_current_page(GTK_NOTEBOOK(lookup_widget(main_window, "main_notebook")), GUI_PAGE_CHAT);

	/* register option callbacks */
	gui_opt_callbacks_register_main_window();

	return main_window;
}

void gui_playerlist_init(void)
{
	static const struct {
		int new_col;
		int is_icon;
		char *title;
		int col_id;
		GtkTreeCellDataFunc func;
		char *option;
	} column[] = {
		{ 1, 1, "Stav",			0,	NULL, "pl_col_connected" },
		{ 0, 1, "",			1,	NULL, "pl_col_state" },
		{ 1, 0, "Přezdívka",		2,	NULL, "pl_col_nick" },
		{ 1, 0, "Adresa",		3,	NULL, "pl_col_address" },
		{ 1, 0, "Role",			4,	NULL, "pl_col_role" },
		{ 1, 0, "Skóre",		5,	NULL, "pl_col_score" },
		{ 1, 0, "Popis stavu",		6,	NULL, "pl_col_description" },
		{ 1, 0, "Spojení",		7,	NULL, "pl_col_connection" },
		{ 1, 0, NULL }
	};
	int i, icon_width, icon_height;

	DBG_MSG(2, "");
	
	GtkTreeView *tv = GTK_TREE_VIEW(lookup_widget(main_window, "players_treeview"));
	GtkTreeSelection *ts;
	GtkCellRenderer *rend;
	GtkTreeViewColumn *col = NULL;
	GtkWidget *mnu_item, *mnu;

	gtk_icon_size_lookup(GTK_ICON_SIZE_LARGE_TOOLBAR, &icon_width, &icon_height);
	
	gtk_tree_view_set_model(tv, GTK_TREE_MODEL(record_store));

	/* disable selection */
	ts = gtk_tree_view_get_selection(tv);
	gtk_tree_selection_set_mode(ts, GTK_SELECTION_NONE);

	/* create menu */
	mnu = gtk_menu_new ();
	gtk_menu_item_set_submenu (GTK_MENU_ITEM (lookup_widget(main_window, "mnu_players_columns")), mnu);
	gtk_widget_show (mnu);

	/* add columns */
	for (i = 0; column[i].title; i++) {
		if (!col || column[i].new_col) {
			/* add column */
			col = gtk_tree_view_column_new();
			gtk_tree_view_column_set_title(col, _(column[i].title));

			/* add menuitem */
			mnu_item = gtk_check_menu_item_new_with_mnemonic (_(column[i].title));
			gtk_container_add (GTK_CONTAINER (mnu), mnu_item);
			gtk_widget_show (mnu_item);
			g_signal_connect ((gpointer) mnu_item, "activate", G_CALLBACK (on_players_columns_activate), column[i].option);

			/* store widgets */
			goc_playerlist_column_wid[i].column = col;
			goc_playerlist_column_wid[i].menuitem = mnu_item;
		}
		
		/* create renderer */
		if (column[i].is_icon) {
			rend = gtk_cell_renderer_pixbuf_new();
			g_object_set(rend, "stock-size", GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
		} else {
			rend = gtk_cell_renderer_text_new();
		}
		gtk_tree_view_column_pack_start(col, rend, FALSE);

		/* set data source for renderer */
		if (column[i].func) {
			gtk_tree_view_column_set_cell_data_func(col, rend, column[i].func, NULL, NULL);
		} else {
			gtk_tree_view_column_set_attributes(col, rend, column[i].is_icon ? "stock-id":"text", column[i].col_id, NULL);
		}
		
		/* put column into tree view */
		if (i == 0 || column[i].new_col) {
			gtk_tree_view_append_column(tv, col);
			if (!column[i].is_icon)
				gtk_tree_view_column_set_resizable(col, TRUE);
			//gtk_tree_view_column_set_sort_column_id(col, column[i].col_id);
		}
	}
	assert(i == GOC_PLAYERLIST_COLUMN_WID_SIZE);
}


static void append_text_to (GtkWidget *text_view, const char* text) {
	GtkTextIter iter;
	GtkTextBuffer *buf;
	GtkTextMark *mark;

	assert(text_view != NULL);
	assert(text != NULL);
	
	buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(text_view));
	
	gtk_text_buffer_get_end_iter (buf, &iter);
	gtk_text_buffer_insert(buf, &iter, text, -1);
	
	/* scroll down */
	gtk_text_buffer_place_cursor(buf, &iter);
	mark = gtk_text_buffer_get_insert(buf);
	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(text_view), mark, 0.0, FALSE, 0.0, 1.0);
}


void gui_erase_logs (void)
{
	gtk_text_buffer_set_text(gtk_text_view_get_buffer (GTK_TEXT_VIEW(lookup_widget(main_window, "gamelog_textview"))), "", -1);
	gtk_text_buffer_set_text(gtk_text_view_get_buffer (GTK_TEXT_VIEW(lookup_widget(main_window, "netlog_textview"))), "", -1);
}


void gui_update_expanders(void)
{
	int i, op;
	unsigned char s;

	if (option_get_integer("main", "ui", "autoexpand")) {
		/* first loop:  collapse 
		 * second loop: expand
		 */
		for (op = 0; op <= 1; op++) {
			for (i = 0; gui_expander[i].name; i++) {
				if (!gui_expander[i].widget) {
					gui_expander[i].widget = lookup_widget(main_window, gui_expander[i].name);
				}
				
				s = (gui_expand[status_get(session_status)][status_get(connection_status)] & (1 << i)) != 0;
				if (op == s) {
					gtk_expander_set_expanded(GTK_EXPANDER(gui_expander[i].widget), s);
				}
			}
		}
	}
}


void gui_page_notify(GUI_PAGE page)
{
	static GtkWidget *nb = NULL;
	if (!nb)
		nb = lookup_widget(main_window, "main_notebook");
	
	if (gui_page[page].notify_icon && page != gtk_notebook_get_current_page(GTK_NOTEBOOK(nb)))
		gtk_widget_show(gui_page[page].notify_icon);
}


void gui_append_to_chat(const char *sender, GUI_CHAT_TYPE type, char *fmt, ...)
{
	const char *type_prefix[] = { "\342\200\224 ", NULL, NULL };
	static GtkTextBuffer *tb = NULL;
	static GtkTextView *tv = NULL;
	static GtkLabel *sl = NULL;
	static GtkTextTag *head = NULL, *body = NULL, *msg[GUI_CHAT_TYPE_MAX] = { NULL };
	static GtkTextMark *start_mark = NULL;
	va_list ap;
	GtkTextIter iter, start_iter;
	GtkTextMark *mark;
	char *m;

	assert(fmt != NULL);
	assert(type >= 0);
	assert(type < GUI_CHAT_TYPE_MAX);

	if (!tv) tv = GTK_TEXT_VIEW(lookup_widget(main_window, "chat_textview"));
	if (!sl) sl = GTK_LABEL(lookup_widget(main_window, "statusbar_label"));
	if (!tb) tb = gtk_text_view_get_buffer(tv);

	if (!head) head = gtk_text_buffer_create_tag(tb, "head", "weight", PANGO_WEIGHT_BOLD, "indent", -25, NULL);
	if (!body) body = gtk_text_buffer_create_tag(tb, "body", "left-margin", 25, NULL);
	if (!msg[0]) {
		int i = 0;
		/* sys */ msg[i++] = gtk_text_buffer_create_tag(tb, "msg_sys", NULL);
		/* in  */ msg[i++] = gtk_text_buffer_create_tag(tb, "msg_in",  "pixels-above-lines", 2, "pixels-below-lines", 2, NULL);
		/* out */ msg[i++] = gtk_text_buffer_create_tag(tb, "msg_out", "pixels-above-lines", 2, "pixels-below-lines", 2, NULL);
		assert(i == GUI_CHAT_TYPE_MAX);
	}	

	va_start(ap, fmt);
	if ((m = g_strdup_vprintf(fmt, ap))) {
		/* append \n from previous message */
		gtk_text_buffer_get_end_iter (tb, &iter);
		gtk_text_buffer_insert(tb, &iter, "\n", -1);
		
		/* update message start mark */
		if (start_mark)
			gtk_text_buffer_move_mark(tb, start_mark, &iter);
		else
			start_mark = gtk_text_buffer_create_mark(tb, "last_msg", &iter, TRUE);

		/* append message prefix */
		if (fmt[0] && type_prefix[type]) {
			gtk_text_buffer_insert_with_tags(tb, &iter, type_prefix[type], -1, head, NULL);
		}

		/* append sender */
		if (sender) {
			gtk_text_buffer_insert_with_tags(tb, &iter, sender, -1, head, NULL);
			gtk_text_buffer_insert(tb, &iter, ": ", -1);
		}

		/* append message */
		gtk_text_buffer_insert_with_tags(tb, &iter, m, -1, body, NULL);
		
		/* apply tag on whole message */
		gtk_text_buffer_get_iter_at_mark(tb, &start_iter, start_mark);
		gtk_text_buffer_apply_tag(tb, msg[type], &start_iter, &iter);


		/* show message in statusbar */
		if (type != GUI_CHAT_OUT) {
			if (sender) {
				gchar *s = NULL;
				s = g_markup_printf_escaped ("<b>%s:</b> %s", sender, m);
				gtk_label_set_markup(sl, s);
				g_free (s);
			} else {
				gtk_label_set_text(sl, m);
			}
		}
	}
	g_free(m);
	va_end(ap);
	
	/* scroll down */
	gtk_text_buffer_place_cursor(tb, &iter);
	mark = gtk_text_buffer_get_insert(tb);
	gtk_text_view_scroll_to_mark(tv, mark, 0.0, FALSE, 0.0, 1.0);

	/* show alert icon */
	gui_page_notify(GUI_PAGE_CHAT);
}


void gui_append_to_log(GUI_LOG log_id, char *fmt, ...)
{
	static GtkWidget *lw[GUI_LOG_MAX] = { NULL, NULL };
	char *lw_name[GUI_LOG_MAX] = {
		NULL, "gamelog_textview", "netlog_textview"
	};
	va_list ap;
	char *m;

	assert(log_id < GUI_LOG_MAX);
	assert(log_id >= 0);
	
	if (!lw[1]) {
		int i;
		for (i = 0; i < GUI_LOG_MAX; i++) {
			if (lw_name[i])
				lw[i] = lookup_widget(main_window, lw_name[i]);
		}
	}
	
	va_start(ap, fmt);
	if ((m = g_strdup_vprintf(fmt, ap))) {
		append_text_to(lw[log_id], m);
	}
	g_free(m);
	va_end(ap);
}


void gui_clean_statusbar(void)
{
	gui_set_semaphore(0);
	gui_set_statusbar_clock(0, 0, "");
	gui_set_statusbar_progress(0, 0.0, "");
}


void gui_set_statusbar_clock(int is_visible, int set_icon, gchar *fmt,...)
{
	va_list ap;
	char *m;
	static GtkWidget *sl;
	static const char *icon_name[GUI_ICON_MAX + 1] = {
		"",
		"statusbar_image_tip",
		"statusbar_image_info",
		"statusbar_image_question",
		"statusbar_image_warning",
		"statusbar_image_error",
		NULL
	};
	static GtkWidget *icon[GUI_ICON_MAX];
	static int active_icon = 0;
	int i;
	
	if (!sl) {
		sl = lookup_widget(main_window, "statusbar_clock_label");
		for (i = 0; i < GUI_ICON_MAX; i++) {
			if (icon_name[i] && icon_name[i][0])
				icon[i] = lookup_widget(main_window, icon_name[i]);
			else
				icon[i] = NULL;
		}
	}
	
	if (set_icon < GUI_ICON_MAX && set_icon >= 0) {
		if (icon[active_icon])
			gtk_widget_hide(icon[active_icon]);
		if (icon[set_icon])
			gtk_widget_show(icon[set_icon]);
		active_icon = set_icon;
	}

	if (is_visible)
		gtk_widget_show(sl);
	else
		gtk_widget_hide(sl);
	
	if (fmt) {
		va_start(ap, (char *) fmt);
		if ((m = g_strdup_vprintf((char *) fmt, ap))) {
			gtk_label_set_text(GTK_LABEL(sl), m);
		}
		va_end(ap);
		g_free(m);
	}
}


void gui_set_statusbar_progress(int visible, gdouble fraction, gchar *fmt,...)
{
	va_list ap;
	char *m;
	static GtkWidget *sp;
	
	if (!sp) sp = lookup_widget(main_window, "statusbar_progressbar");
	
	if (visible)
		gtk_widget_show(sp);
	else
		gtk_widget_hide(sp);

	if (fraction > 1.0)
		fraction = 1.0;
	if (fraction < 0.0)
		fraction = 0.0;
	
	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sp), fraction);
	
	if (fmt) {
		va_start(ap, (char *) fmt);
		if ((m = g_strdup_vprintf((char *) fmt, ap))) {
			gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sp), m);
		}
		va_end(ap);
		g_free(m);
	} else {
		gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sp), "");
	}
}


void gui_show_dialog_connect(void)
{
	GtkComboBox *dir_combo;
	const char *last_backend = option_get_string("main", "net", "profile");
	char *cat = NULL, *mod = NULL, *opt = NULL;
	int opt_iter = 0;
	const char *name = NULL, *address = NULL;
	char *last_mod = "";
	GtkListStore *store = NULL;
	GtkTreeIter store_iter;

	last_backend = last_backend ? last_backend : "";
	
	/* vytvoreni dialogu */
	dialog_connect = create_dialog_connect ();
	dir_combo = GTK_COMBO_BOX(lookup_widget(dialog_connect, "profile_combobox"));
	
	store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
	gtk_combo_box_set_model(GTK_COMBO_BOX(dir_combo), GTK_TREE_MODEL(store));
	
	/* nasypani dat */
	for (opt_iter = 0; option_list_opt("network", &opt_iter, &cat, &mod, &opt, NULL); opt_iter++) {
		if (cat && mod && opt) {
			if (strcmp(last_mod, mod) != 0 && (name = option_get_string(cat, mod, "name"))) {
				DBG_MSG(8, "found \"%s\"", name);
				address = option_get_string("network", mod, "default_address");
				
				gtk_list_store_append (store, &store_iter);
				gtk_list_store_set (store, &store_iter,
						0, name ? name : "",
						1, mod ? mod : "",
						2, address ? address : "",
						-1);
				
				if (strcmp(mod, last_backend) == 0)
					gtk_combo_box_set_active_iter(dir_combo, &store_iter);
			}
			last_mod = mod;
		}
	}
	g_object_unref(store);
	
	gtk_entry_set_text(GTK_ENTRY(lookup_widget(dialog_connect, "address_entry")), option_get_string("main", "net", "address"));
	
	/* zobrazeni dialogu */
	gtk_window_set_transient_for(GTK_WINDOW(dialog_connect), GTK_WINDOW(main_window));
	gtk_widget_show (dialog_connect);
}


void gui_show_dialog_game_select(void)
{
	GDir *dir;
	gchar *dir_name;
	GtkTreeStore *store;
	GtkTreeIter iter;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeView *treeview;
	GtkTreeSelection *selection;
	const char *dir_game = option_get_string("main", "dir", "game");
	const char *default_game = option_get_string("main", "ui", "last_game_backend");

	/* nacteni seznamu dostupnych her */
	if (!(dir = g_dir_open(dir_game, 0, NULL))) {
		gui_show_error_message(_("Nepovedlo se načíst seznam her"), _("Nelze otevřít \"%s\":\n%s"), dir_game, g_strerror(errno));
		perror("g_dir_open");
		return;
	}
	
	/* vytvoreni dialogu */
	dialog_game_select = create_dialog_game_select();
	treeview = GTK_TREE_VIEW(lookup_widget(dialog_game_select, "game_select_treeview"));
	
	/* priprava modelu*/
	store = gtk_tree_store_new (1, G_TYPE_STRING);

	/* priprava widgetu */
	gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
	selection = gtk_tree_view_get_selection(treeview);
	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Hra"), renderer, "text", 0, NULL);
	gtk_tree_view_append_column(treeview, column);
	gtk_tree_view_column_set_sort_column_id(column, 0);
	gtk_tree_view_set_search_column (treeview, 0);
	

	/* nasypani dat */
	while((dir_name = (gchar*) g_dir_read_name(dir))) {
		if (dir_name[0] != '.') {
			DBG_MSG(8, "found dir \"%s\"", dir_name);
			gtk_tree_store_append (store, &iter, NULL);
			gtk_tree_store_set(store, &iter, 0, dir_name, -1);
			if (default_game && strcmp(default_game, dir_name) == 0) {
				DBG_MSG(4, "selecting \"%s\"", dir_name);
				gtk_tree_selection_select_iter(selection, &iter);
			}
		}
	}
	g_dir_close(dir);
	g_object_unref(store);

	/* zobrazeni dialogu */
	gtk_window_set_transient_for(GTK_WINDOW(dialog_game_select), GTK_WINDOW(main_window));
	gtk_widget_show (dialog_game_select);
}


void gui_show_error_message_full(GtkWidget *parent, int async, const char *title, const char *fmt, ...)
{
	GtkWidget *dialog;
	char *m;
	va_list ap;

	va_start(ap, fmt);
	if ((m = g_strdup_vprintf(fmt, ap))) {
		dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
				GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_ERROR,
				GTK_BUTTONS_OK,
				title);
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), m);
		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent));
		if (async) {
			gtk_widget_show(dialog);
			g_signal_connect_swapped (dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog);
		} else {
			gtk_dialog_run (GTK_DIALOG (dialog));
			gtk_widget_destroy (dialog);
		}
	}
	va_end(ap);
	g_free(m);
}


void gui_switch_main_page(int page)
{
	static GtkNotebook *nb = NULL;
	if (!nb)
		nb = GTK_NOTEBOOK(lookup_widget(main_window, "main_notebook"));
	
	if (page != gtk_notebook_get_current_page(nb) && option_get_integer("main", "ui", "autoswitch")) {
		gtk_notebook_set_current_page(nb, page);
	}
}


void gui_wait_for_callback(void)
{
	gtk_main_iteration_do(TRUE);
}


void gui_show_option_browser(void)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeView *treeview;

	DBG_MSG(3, "");

	dialog_option_browser = create_dialog_option_browser();
	treeview = GTK_TREE_VIEW(lookup_widget(dialog_option_browser, "option_treeview"));

	option_set_update_callback(gui_update_option_browser);
	
	/* column: option name */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Kategorie"), renderer, "text", 0, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 0);

	/* column: module name */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Modul"), renderer, "text", 1, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 1);

	/* column: option name */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Volba"), renderer, "text", 2, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 2);

	/* column: option value */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Hodnota"), renderer, "text", 3, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 3);
	
	/* column: option type */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Typ"), renderer, "text", 4, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 4);
	
	/* column: option have_cb */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Callback?"), renderer, "text", 5, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, 5);
	
	gui_update_option_browser();
	
	/* show window */
	gtk_window_set_transient_for(GTK_WINDOW(dialog_option_browser), GTK_WINDOW(main_window));
	gtk_widget_show(dialog_option_browser);
}


void gui_update_option_browser(void)
{
	GtkListStore *store;
	GtkTreeIter iter;
	GtkTreeView *treeview = GTK_TREE_VIEW(lookup_widget(dialog_option_browser, "option_treeview"));
	char *name, *cat, *mod;
	const char *value;
	const char *type;
	int i, have_cb;
	GtkAdjustment *vadj;

	if (!dialog_option_browser)
		return;

	DBG_MSG(2, "");

	/* save cursor position */
	vadj = gtk_tree_view_get_vadjustment(treeview);
	
	/* add data to the list store */
	store = gtk_list_store_new (6, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
	gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
	for (i = 0; option_list_opt(NULL, &i, &cat, &mod, &name, &have_cb); i++) {
		if (name && name[0]) {
			value = option_get_string_by_id(i);
			type = option_get_type_name_by_id(i);
			DBG_MSG(6, "adding option [ %s :: %s :: %s ]", cat, mod, name);
			gtk_list_store_append (store, &iter);
			gtk_list_store_set (store, &iter, 0, cat, 1, mod, 2, name, 3, value, 4, type, 5, have_cb ? "ano":"", -1);
		}
	}
	g_object_unref(store);

	/* restore position */
	if (vadj)
		gtk_tree_view_set_vadjustment(treeview, vadj);

	gtk_tree_view_columns_autosize(treeview);

}


void gui_update_playerlist(void)
{
	GtkListStore *store;
	GtkTreeIter iter;
	GtkTreeView *treeview = GTK_TREE_VIEW(lookup_widget(main_window, "players_treeview"));
	char *nick, *address, *role, *score, *conn_state, *description;
	int i = 0, state, connected, show_disconnected;
	GtkAdjustment *vadj;

	DBG_MSG(2, "");

	show_disconnected = option_get_integer("main", "ui", "show_disconnected");

	/* save cursor position */
	vadj = gtk_tree_view_get_vadjustment(treeview);
	
	/* add data to the list store */
	store = gtk_list_store_new (8, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
	gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
	for (i = 0; playerlist_list(&i, &address, &nick, &role, &score, &conn_state, &state, &description, &connected); i++) {
		if (address && (show_disconnected || (!show_disconnected && connected))) {
			DBG_MSG(6, "adding player \"%s\"", address);
			gtk_list_store_append (store, &iter);
			gtk_list_store_set (store, &iter,
					0, show_disconnected ? gui_connect_icon[connected ? S_C_CONNECTED : S_C_OFFLINE] : "",
					1, state ? gui_session_icon[state] : "gtk-spell-check",
					2, nick ? nick : "",
					3, address ? address : "",
					4, role ? role : "",
					5, score ? score : "",
					6, description ? description : "",
					7, conn_state ? conn_state : "",
					-1);
		}
	}
	g_object_unref(store);

	/* restore position */
	if (vadj)
		gtk_tree_view_set_vadjustment(treeview, vadj);

	gtk_tree_view_columns_autosize(treeview);

}


void gui_store_options_with_info(void)
{
	char *err = NULL;

	DBG_MSG(2, "");
	gui_append_to_chat(NULL, GUI_CHAT_SYS, "Ukládám data...");
	if (option_store_to_default()) {
		gui_append_to_chat(NULL, GUI_CHAT_SYS, "Data uložena.");
	} else {
		err = g_locale_to_utf8(strerror(option_last_error), -1, NULL, NULL, NULL);
		gui_append_to_chat(NULL, GUI_CHAT_SYS, "Chyba: %s.", err);
		g_free(err);
	}
}


void gui_role_init(GtkListStore *roles_store)
{
	GtkComboBox *c = GTK_COMBO_BOX(lookup_widget(main_window, "game_role_combobox"));
	
	gtk_combo_box_set_model(c, GTK_TREE_MODEL(roles_store));
}


void gui_role_select(int role_id)
{
	static GtkComboBox *c = NULL;
	if (!c) c = GTK_COMBO_BOX(lookup_widget(main_window, "game_role_combobox"));

	gtk_combo_box_set_active(c, role_id);
}


int gui_exit_question(void)
{
	gint response = GTK_RESPONSE_ACCEPT;
	GtkWidget *d;
	
	if (status_get(session_status) != S_S_IDLE) {
		d = gtk_message_dialog_new(GTK_WINDOW(main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
				GTK_BUTTONS_NONE, _("Opravdu ukončit?"));
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(d),
				_("Ukončení programu způsobí ukončení rozehraných her a uzavření navázaných spojení."));
		gtk_dialog_add_buttons(GTK_DIALOG(d),
				GTK_STOCK_QUIT, GTK_RESPONSE_ACCEPT,
				GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
				NULL);
		gtk_dialog_set_default_response(GTK_DIALOG(d), GTK_RESPONSE_REJECT);
		response = gtk_dialog_run(GTK_DIALOG(d));
		gtk_widget_destroy(d);
	}

	return response == GTK_RESPONSE_ACCEPT;
}


int gui_config_dialog_from_message(MESSAGE * msg, int notify_target)
{
	return gui_config_dialog_from_message_wp(msg, notify_target,
			msg->src != 'O' && dialog_network_profiles ? dialog_network_profiles : main_window);
}


int gui_config_dialog_from_message_wp(MESSAGE * msg, int notify_target, GtkWidget *parent_window)
{
	GtkWidget *dialog = NULL, *dialog_vbox = NULL, *dialog_action_area = NULL, *button = NULL;
	GtkWidget *frame = NULL, *frame_vbox = NULL, *frame_align = NULL, *frame_label = NULL;
	GtkWidget *hbox = NULL, *label = NULL, *widget = NULL;
	GtkWidget *last_vbox = NULL;
	GtkSizeGroup *label_size_group = NULL;
	int min, max, i, sel;
	
	GUI_ODW_LIST *odw = NULL;
	GUI_ODW *odw_item = NULL;
	GUI_ODW_TYPE widget_type = GUI_ODW_T_NONE;
	
	const char *cat = NULL, *mod = NULL, *option = NULL;
	char *field = NULL, *str = NULL, *val_str = NULL, *title = NULL;
	int val_int;

	assert(msg != NULL);
	assert(parent_window != NULL);

	DBG_MSG(3, "");
	
	/* prepare widget list */
	DBG_MSG(5, "prepare widget list...");
	message_get_rewind(msg, MESSAGE_PART_DATA);
	if (!message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_SKIP, MESSAGE_STRING, &cat, MESSAGE_STRING, &mod, MESSAGE_STRING, &title, MESSAGE_END)) {
		return 0;
	}
	
	odw = g_malloc(sizeof(GUI_ODW_LIST));
	odw->list = NULL;
	odw->ok_clicked = 0;
	odw->notify_target = msg->src ? msg->src : 0;
	strncpy(odw->cat, cat, OPTION_MAX_CAT_LEN);
	strncpy(odw->mod, mod, OPTION_MAX_MOD_LEN);
	odw->mem_chunk = g_mem_chunk_new("GUI_ODW_LIST", sizeof(GUI_ODW), sizeof(GUI_ODW) * 32, G_ALLOC_ONLY);
	

	/* prepare dialog */
	DBG_MSG(5, "prepare dialog...");
	dialog = gtk_dialog_new();
	str = g_strdup_printf("%s - Net Board", title);
	gtk_window_set_title(GTK_WINDOW(dialog), str);
	g_free(str);
	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
	gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
	gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
	gtk_window_set_default_size (GTK_WINDOW (dialog), 320, -1);
	gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
	gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE);
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent_window));
	dialog_vbox = GTK_DIALOG(dialog)->vbox;

	label_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
	
	last_vbox = dialog_vbox;
	
	DBG_MSG(5, "add widgets...");
	while (message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &field, MESSAGE_END)) {
		
		widget = NULL;
		
		if (!field) {
			DBG_MSG(3, "Missing field!");
			break;
		}

		DBG_MSG(5, "field: \"%s\"", field);

		/* label */
		if (field[0] == '$' || field[0] == '-' || field[0] == '*' || field[0] == '#' || field[0] == '%') {
			hbox = gtk_hbox_new (FALSE, 2);
			gtk_box_pack_start (GTK_BOX (last_vbox), hbox, FALSE, TRUE, 0);

			str = g_strdup_printf("%s:", field + 1);
			label = gtk_label_new_with_mnemonic (str);
			gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
			gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
			gtk_misc_set_padding (GTK_MISC (label), 4, 0);
			g_free(str);
			
			gtk_size_group_add_widget (label_size_group, label);
		}

		switch (field[0]) {
			case '[': /* add frame */
				DBG_MSG(5, "frame");
				frame = gtk_frame_new(NULL);
				gtk_box_pack_start(GTK_BOX(dialog_vbox), frame, FALSE, TRUE, 0);
				gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);

				frame_align = gtk_alignment_new(0.5, 0.5, 1, 1);
				gtk_container_add(GTK_CONTAINER(frame), frame_align);
				gtk_alignment_set_padding(GTK_ALIGNMENT(frame_align), 0, 4, 12, 0);
				
				frame_vbox = gtk_vbox_new(FALSE, 2);
				gtk_container_add(GTK_CONTAINER(frame_align), frame_vbox);

				if (g_utf8_validate(field + 1, -1, NULL))
					str = g_markup_printf_escaped("<b>%s</b>", field + 1);
				else
					str = "??? (invalid UTF-8)";
				frame_label = gtk_label_new(str);
				gtk_frame_set_label_widget(GTK_FRAME(frame), frame_label);
				gtk_label_set_use_markup(GTK_LABEL(frame_label), TRUE);
				g_free(str);
				
				last_vbox = frame_vbox;
				widget = NULL;
				break;
				
			case '=': /* add simple text */
				DBG_MSG(5, "text");
				widget = gtk_label_new (field + 1);
				gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
				gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
				gtk_label_set_selectable (GTK_LABEL (widget), TRUE);
				gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
				gtk_misc_set_padding (GTK_MISC (widget), 4, 4);
				gtk_box_pack_start (GTK_BOX(last_vbox), widget, FALSE, FALSE, 0);
				
				widget = NULL;
				break;

			case '-': /* add text like text entry */
				DBG_MSG(5, "text fake entry");
				if (message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &option, MESSAGE_END)) {
					widget = gtk_label_new(option ? option : "");
					gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
					gtk_misc_set_alignment (GTK_MISC(widget), 0.0, 0.5);
					gtk_misc_set_padding (GTK_MISC(widget), 0, 2);
					gtk_label_set_selectable (GTK_LABEL(widget), TRUE);
					gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
					widget_type = GUI_ODW_T_NONE;
				} else {
					widget = NULL;
				}
				break;

			case '$': /* add text entry */
			case '*': /* add password entry */
				DBG_MSG(5, "text entry");
				if (message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &option, MESSAGE_END)) {
					widget = gtk_entry_new ();
					if ((val_str = (char*) option_get_string(cat, mod, option)))
						gtk_entry_set_text(GTK_ENTRY(widget), val_str);
					gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);

					if (field[0] == '*')
						gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);

					gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
					gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
					widget_type = GUI_ODW_T_ENTRY;
				} else {
					widget = NULL;
				}
				break;

			case '?': /* check button */
				DBG_MSG(5, "check button");
				if (message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &option, MESSAGE_END)) {
					widget = gtk_check_button_new_with_mnemonic(field + 1);
					val_int = option_get_integer(cat, mod, option);
					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), val_int);
					
					gtk_box_pack_start (GTK_BOX (last_vbox), widget, FALSE, FALSE, 0);
					widget_type = GUI_ODW_T_CHECKBOX;
				} else {
					widget = NULL;
				}
				break;
				
			case '#': /* spin button */
				DBG_MSG(5, "spin button");
				if (message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &option, MESSAGE_INTEGER, &min, MESSAGE_INTEGER, &max, MESSAGE_END)) {
					val_int = option_get_integer(cat, mod, option);
					widget = gtk_spin_button_new_with_range (min, max, 1);
					gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget), (gdouble) val_int);

					gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
					gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
					widget_type = GUI_ODW_T_NUMBER;
				} else {
					widget = NULL;
				}
				break;
				
			case '%': /* combo box */
				if (message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &option, MESSAGE_END)) {
					DBG_MSG(5, "combo box");
					widget = gtk_combo_box_new_text();
					
					i = 0, sel = 0;
					val_str = (char *) option_get_string(odw->cat, odw->mod, option);
					while (message_get_next(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &str, MESSAGE_END) && str[0]) {
						gtk_combo_box_append_text(GTK_COMBO_BOX(widget), str);
						if (val_str && strcmp(str, val_str) == 0)
							sel = i;
						i++;
					}
					gtk_combo_box_set_active(GTK_COMBO_BOX(widget), sel);

					gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
					gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
					widget_type = GUI_ODW_T_COMBO;
				} else {
					widget = NULL;
				}
				break;

			default:
				widget = NULL;
		}
		
		DBG_MSG(5, "add widget info to list");
		if(widget && (odw_item = (GUI_ODW *) g_mem_chunk_alloc0(odw->mem_chunk))) {
			odw_item->type = widget_type;
			odw_item->widget = widget;
			strncpy(odw_item->opt, option, OPTION_MAX_OPT_LEN);
			odw_item->opt[OPTION_MAX_OPT_LEN - 1] = 0;
			odw->list = g_slist_prepend(odw->list, (gpointer) odw_item);
		}
	}


	DBG_MSG(5, "adding dialog action area...");

	/* dialog action area */
	dialog_action_area = GTK_DIALOG(dialog)->action_area;
	gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog_action_area), GTK_BUTTONBOX_END);

	/* add cancel button */
	button = gtk_button_new_from_stock("gtk-cancel");
	gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, GTK_RESPONSE_CANCEL);

	g_signal_connect_data ((gpointer) button, "clicked", G_CALLBACK (gtk_widget_destroy),
			GTK_OBJECT (dialog), NULL, G_CONNECT_AFTER | G_CONNECT_SWAPPED);

	/* add ok button */
	button = gtk_button_new_from_stock("gtk-ok");
	gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, GTK_RESPONSE_OK);
	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
	gtk_widget_grab_default(button);
	g_signal_connect ((gpointer) button, "clicked", G_CALLBACK (on_gui_option_ok_button_clicked), (gpointer) odw);
	
	g_signal_connect ((gpointer) dialog, "destroy", G_CALLBACK (on_gui_option_destroy), (gpointer) odw);
	
	/* show it */
	gtk_widget_show_all(dialog);

	/* clean up */
	g_object_unref(G_OBJECT(label_size_group));

	DBG_MSG(3, "Dialog complete.");
	
	return 0;
}


void gui_show_network_profiles (void)
{
	GtkTreeView *treeview;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	int col = 0;

	/* create dialog */
	dialog_network_profiles = create_dialog_network_profiles();
	gtk_window_set_transient_for(GTK_WINDOW(dialog_network_profiles), GTK_WINDOW(main_window));
	
	treeview = GTK_TREE_VIEW(lookup_widget(dialog_network_profiles, "treeview"));
	
	/* column: id */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("ID"), renderer, "text", col, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, col);
	col++;
	gtk_tree_view_column_set_visible(column, FALSE);

	/* column: name */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Název profilu"), renderer, "text", col, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, col);
	col++;

	/* column: backend */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Síťový modul"), renderer, "text", col, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, col);
	col++;
	
	/* column: address */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Předvolená adresa"), renderer, "text", col, NULL);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, col);
	col++;

	/* show it */
	gtk_widget_show(dialog_network_profiles);
	gui_update_network_profiles();
}


void gui_update_network_profiles (void)
{
	GtkTreeView *treeview = NULL;
	GtkListStore *store = NULL;
	GtkTreeIter iter;
	char *cat = NULL, *mod = NULL, *opt = NULL;
	int opt_iter = 0;
	char *last_mod = "";
	const char *name = NULL, *backend = NULL, *address = NULL;

	if (!dialog_network_profiles)
		return;
	
	/* assign store */
	treeview = GTK_TREE_VIEW(lookup_widget(dialog_network_profiles, "treeview"));
	store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
	gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));

	/* put data */
	for (opt_iter = 0; option_list_opt("network", &opt_iter, &cat, &mod, &opt, NULL); opt_iter++) {
		if (cat && mod && opt) {
			if (strcmp(last_mod, mod) != 0) {
				name = option_get_string(cat, mod, "name");
				backend = option_get_string(cat, mod, "backend");
				address = option_get_string(cat, mod, "default_address");
				gtk_list_store_append (store, &iter);
				gtk_list_store_set (store, &iter,
						0, mod ? mod : "",
						1, name ? name : "",
						2, backend ? backend : "",
						3, address ? address : "",
						-1);
			}
			last_mod = mod;
		}
	}

	g_object_unref(store);
	gtk_tree_view_columns_autosize(treeview);
}

void gui_show_network_profile_editor(char *id, GtkWidget *parent_window)
{
	MESSAGE *msg;
	
	assert(id != NULL);
	assert(parent_window != NULL);

	msg = message_create('F', 'O');
	message_append(msg, MESSAGE_PART_DATA, MESSAGE_STRING, "Odo",
			MESSAGE_STRING, "network", MESSAGE_STRING, id,
			MESSAGE_STRING, _("Úprava síťového profilu"),
			MESSAGE_STRING, _("[Úprava síťového profilu"),
			MESSAGE_STRING, _("-ID Profilu"), MESSAGE_STRING, id,
			MESSAGE_STRING, _("$_Název profilu"), MESSAGE_STRING, "name",
			MESSAGE_STRING, _("$_Síťový modul"), MESSAGE_STRING, "backend",
			MESSAGE_STRING, _("$_Přednastavená adresa"), MESSAGE_STRING, "default_address",
			MESSAGE_STRING, _("%Ú_roveň výpisů"), MESSAGE_STRING, "log_level",
						MESSAGE_STRING, "0: jen chyby",
						MESSAGE_STRING, "1: normální",
						MESSAGE_STRING, "2: verbose",
						MESSAGE_STRING, "3: debug",
						MESSAGE_STRING, "",
			MESSAGE_END);
	gui_config_dialog_from_message_wp(msg, 1, parent_window ? parent_window : main_window);
	message_destroy(msg);
}


void gui_show_network_backend_config(const char *id)
{
	const char *argv[] = { NULL, "-C", NULL, NULL };
	const char *backend = NULL, *dir = NULL;
	gchar *output = NULL, *err_output = NULL;
	int exit_status = 0;
	GError *error = NULL;
	MESSAGE *msg = NULL;
	char *msg_p = NULL;

	backend = option_get_string("network", id, "backend");
	if (backend) {
		argv[0] = backend;
		argv[2] = id;
		dir = option_get_string("main", "dir", "network");
		if (g_spawn_sync(dir, (char **)argv, NULL, 0, NULL, NULL, &output, &err_output, &exit_status, &error)) {
			gui_append_to_netlog("%s\n", err_output);
			msg_p = NULL;
			while ((msg = message_from_string('N', 'O', output, &msg_p))) {
				message_send(msg);
				message_destroy(msg);
			}
		} else {
			gui_show_error_message(_("Backend nemohl být spuštěn"), _("%s"), error->message);
		}
	}
}


void gui_update_main_window_tabbar(void)
{
	int pages = 0, i = 0;
	
	for (i = 0; i < GUI_PAGE_MAX; i++) {
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gui_page[i].menuitem),
				option_get_integer("main", "ui", gui_page[i].option));
		if (GTK_WIDGET_VISIBLE(gui_page[i].parent)) {
			pages++;
		}
	}
	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(lookup_widget(main_window, "main_notebook")), pages > 1);

	if (pages < 1) {
		gtk_widget_hide(lookup_widget(main_window, "main_notebook"));
		gtk_window_resize(GTK_WINDOW(main_window), 1, 1);
	} else {
		gtk_widget_show(lookup_widget(main_window, "main_notebook"));
		GTK_WIDGET_UNSET_FLAGS (lookup_widget(main_window, "main_notebook"), GTK_CAN_FOCUS);
	}
}

void gui_detach_page(GUI_PAGE page)
{
	struct s_gui_page *p = &(gui_page[page]);
	int h, w;
	GdkColor black = { 0, 0, 0, 0 };

	DBG_MSG(3, "");
	
	option_set_integer("main", "ui", p->option, 1);
	
	if (!p->window)
		p->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	
	if (page != GUI_PAGE_BOARD) {
		h = p->widget->allocation.height;
		w = p->widget->allocation.width;
		gtk_window_set_default_size(GTK_WINDOW(p->window), w < 320 ? 320:w, h < 240 ? 240:h);
	}
	gtk_window_set_title(GTK_WINDOW(p->window), p->win_title);
	gtk_window_set_role(GTK_WINDOW(p->window), p->win_class);
	if (page == GUI_PAGE_BOARD)
		gtk_widget_modify_bg(p->window, GTK_STATE_NORMAL, &black);

	g_signal_connect((gpointer) p->window, "destroy",
			G_CALLBACK(on_detached_widget_destroy),
			(gpointer) p->menuitem);
	
	gtk_widget_hide(p->hide);
	gtk_widget_reparent(p->widget, p->window);
	gtk_widget_show(p->widget);
	gtk_widget_show(p->window);

	gui_update_main_window_tabbar();
}


void gui_atach_page(GUI_PAGE page)
{
	struct s_gui_page *p = &(gui_page[page]);
	
	DBG_MSG(3, "");

	option_set_integer("main", "ui", p->option, 0);

	if (p->window) {
		gtk_widget_reparent(p->widget, p->parent);
		gtk_widget_destroy(p->window);
		if (!p->option_tab || option_get_integer("main", "debug", p->option_tab))
			gtk_widget_show(p->hide);
		p->window = NULL;
	}

	gui_update_main_window_tabbar();
}


static void gui_record_renderer_state(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
		GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
{
	int state_id;
	char *cmd;
	gtk_tree_model_get(tree_model, iter, RECORD_COL_CMD, &cmd, RECORD_COL_STATE, (void *) &state_id, -1);
	g_object_set(cell, "text", state_id >= 0 && cmd[0] != 'q' ? status_get_name_by_id(session_status, state_id) : "", NULL);
}

static void gui_record_renderer_cmd(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
		GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
{
	char *cmd, *str;
	gtk_tree_model_get(tree_model, iter, RECORD_COL_CMD, &cmd, -1);
	switch (cmd[0]) {
		case 'i':
			str = "info";
			break;
		case 'c':
			str = "change";
			break;
		case 'q':
			str = "query";
			break;
		default:
			str = cmd;
			break;
			
	}
	g_object_set(cell, "text", str, NULL);
}

static void gui_record_renderer_is_valid(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
		GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
{
	enum { i_none, i_question, i_info, i_change, i_warn, i_max };
	char *icon_name[] = { "", "gtk-dialog-question", "gtk-info", "gtk-yes", "gtk-dialog-warning", NULL };
	int state_id, is_valid;
	char *cmd;
	int icon;

	gtk_tree_model_get(tree_model, iter, RECORD_COL_CMD, &cmd, RECORD_COL_STATE, (void *) &state_id, RECORD_COL_IS_VALID, &is_valid, -1);
	
	switch(cmd[0]) {
		case 'q':
			icon = i_question;
			break;
		case 'i':
			icon = i_info;
			break;
		case 'c':
			icon = i_change;
			break;
		default:
			icon = i_none;
			break;
	}

	if (!is_valid)
		icon = i_warn;

	g_object_set(cell, "stock-id", icon_name[icon], NULL);
}

void gui_record_init(GtkListStore *record_store)
{
	static const struct {
		int new_col;
		int is_icon;
		char *title;
		int col_id;
		GtkTreeCellDataFunc func;
	} column[] = {
		{ 1, 0, "Čas",			RECORD_COL_TIME,	NULL },
		{ 1, 1, "Typ",			RECORD_COL_IS_VALID,	gui_record_renderer_is_valid },
		{ 0, 0, "",			RECORD_COL_CMD,		gui_record_renderer_cmd },
		{ 1, 0, "Adresa",		RECORD_COL_ADDRESS,	NULL },
		{ 1, 0, "Stav",			RECORD_COL_STATE,	gui_record_renderer_state },
		{ 1, 0, "Parametr stavu",	RECORD_COL_STATE_PARAM,	NULL },
		{ 1, 0, "Popis",		RECORD_COL_DESC,	NULL },
		{ 1, 0, NULL }
	};
	int i, icon_width, icon_height;
	
	GtkTreeView *tv = GTK_TREE_VIEW(lookup_widget(main_window, "record_treeview"));
	GtkCellRenderer *rend;
	GtkTreeViewColumn *col = NULL;
	GtkTreeSelection *ts;

	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
	
	gtk_tree_view_set_model(tv, GTK_TREE_MODEL(record_store));

	/* disable selection */
	ts = gtk_tree_view_get_selection(tv);
	gtk_tree_selection_set_mode(ts, GTK_SELECTION_NONE);

	for (i = 0; column[i].title; i++) {
		if (!col || column[i].new_col) {
			col = gtk_tree_view_column_new();
			gtk_tree_view_column_set_title(col, _(column[i].title));
		}
		
		if (column[i].is_icon) {
			rend = gtk_cell_renderer_pixbuf_new();
			g_object_set(rend, "stock-size", GTK_ICON_SIZE_MENU, NULL);
		} else {
			rend = gtk_cell_renderer_text_new();
		}

		gtk_tree_view_column_pack_start(col, rend, FALSE);

		if (column[i].func) {
			gtk_tree_view_column_set_cell_data_func(col, rend, column[i].func, NULL, NULL);
		} else {
			gtk_tree_view_column_set_attributes(col, rend, "text", column[i].col_id, NULL);
		}
		
		if (i == 0 || column[i].new_col) {
			gtk_tree_view_append_column(tv, col);
			gtk_tree_view_column_set_resizable(col, TRUE);
			//gtk_tree_view_column_set_sort_column_id(col, column[i].col_id);
		}
	}
}


void gui_show_dialog_send_message(void)
{
	GtkListStore *store;
	GtkTreeIter store_iter;
	MESSAGE_GET_TARGET_ITER iter_target;
	int target_id;
	const int str_len = 128;
	char str[str_len];
	const char *desc;

	GtkComboBox *cb_from, *cb_to;

	if (dialog_send_message)
		return;
	
	dialog_send_message = create_dialog_send_message();
	
	/* initialize list of targets */
	store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);

	str[str_len - 1] = 0;
	
	/* prepare first field ("none") */
	gtk_list_store_append (store, &store_iter);
	gtk_list_store_set (store, &store_iter, 0, _("žádný"), 1, 0, -1);

	/* connect stores to comboboxes and select "none" */
	cb_from = GTK_COMBO_BOX(lookup_widget(dialog_send_message, "sender_combobox"));
	cb_to   = GTK_COMBO_BOX(lookup_widget(dialog_send_message, "receiver_combobox"));
	gtk_combo_box_set_model(cb_from, GTK_TREE_MODEL(store));
	gtk_combo_box_set_model(cb_to, GTK_TREE_MODEL(store));
	gtk_combo_box_set_active_iter(cb_from, &store_iter);
	gtk_combo_box_set_active_iter(cb_to, &store_iter);
	
	/* add real targets to store */
	message_get_target_id_rewind(&iter_target);
	while ((target_id = message_get_target_id_next(&iter_target)) != -1) {
		desc = message_get_target_description(target_id);
		snprintf(str, str_len - 1, isprint(target_id) ? "%c%s%s":"(%d)%s%s", target_id, desc ? ": ":"", desc ?:"");
		gtk_list_store_append (store, &store_iter);
		gtk_list_store_set (store, &store_iter, 0, str, 1, target_id, -1);
	}

	g_signal_connect ((gpointer) gtk_text_view_get_buffer(GTK_TEXT_VIEW(lookup_widget(dialog_send_message, "body_textview"))),
			"changed", G_CALLBACK (on_dialog_send_message_body_changed), NULL);
	
	/* show it */
	gtk_widget_show(dialog_send_message);
}


void gui_dialog_send_message_get(int *from, int *to, gchar **body)
{
	
	if (from) {
		GtkTreeIter from_iter;
		GtkComboBox *from_combo = GTK_COMBO_BOX(lookup_widget(dialog_send_message, "sender_combobox"));
		GtkTreeModel *from_model = gtk_combo_box_get_model(from_combo);
		gtk_combo_box_get_active_iter(from_combo, &from_iter);
		gtk_tree_model_get(from_model, &from_iter, 1, from, -1);
	}

	if (to) {
		GtkTreeIter to_iter;
		GtkComboBox *to_combo = GTK_COMBO_BOX(lookup_widget(dialog_send_message, "receiver_combobox"));
		GtkTreeModel *to_model = gtk_combo_box_get_model(to_combo);
		gtk_combo_box_get_active_iter(to_combo, &to_iter);
		gtk_tree_model_get(to_model, &to_iter, 1, to, -1);
	}
	
	if (body) {
		GtkTextIter body_start, body_end;
		GtkTextBuffer *body_tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(lookup_widget(dialog_send_message, "body_textview")));
		gtk_text_buffer_get_start_iter(body_tb, &body_start);
		gtk_text_buffer_get_end_iter(body_tb, &body_end);
		*body = gtk_text_buffer_get_text(body_tb, &body_start, &body_end, FALSE);
	}
}

void gui_dialog_send_message_clear_message(void)
{
	gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(lookup_widget(dialog_send_message, "parsed_textview"))), "", -1);
}

void gui_dialog_send_message_add_message(gchar *text)
{
	append_text_to(lookup_widget(dialog_send_message, "parsed_textview"), text);
}

void gui_show_syncing(int show)
{
	static GtkWidget *icon = NULL;
	if (!icon) icon = lookup_widget(main_window, "statusbar_syncing");

	if (show)
		gtk_widget_show(icon);
	else
		gtk_widget_hide(icon);
}

